Armin Rigo avatar Armin Rigo committed 3751a14

I think that this should clean up the (relative) mess of the GC on
some-but-not-all cdata objects. The test still doesn't pass though.

Comments (0)

Files changed (1)

c/_cffi_backend.c

 static PyTypeObject CField_Type;
 static PyTypeObject CData_Type;
 static PyTypeObject CDataOwning_Type;
+static PyTypeObject CDataOwningGC_Type;
 
 #define CTypeDescr_Check(ob)  (Py_TYPE(ob) == &CTypeDescr_Type)
 #define CData_Check(ob)       (Py_TYPE(ob) == &CData_Type ||            \
-                               Py_TYPE(ob) == &CDataOwning_Type)
-#define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type)
+                               Py_TYPE(ob) == &CDataOwning_Type ||      \
+                               Py_TYPE(ob) == &CDataOwningGC_Type)
+#define CDataOwn_Check(ob)    (Py_TYPE(ob) == &CDataOwning_Type ||      \
+                               Py_TYPE(ob) == &CDataOwningGC_Type)
 
 typedef union {
     unsigned char m_char;
     PyObject_Del(cf);
 }
 
-static int
-cfield_traverse(CFieldObject *cf, visitproc visit, void *arg)
-{
-    Py_VISIT(cf->cf_type);
-    return 0;
-}
-
 #undef OFF
 #define OFF(x) offsetof(CFieldObject, x)
 
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT,                         /* tp_flags */
     0,                                          /* tp_doc */
-    (traverseproc)cfield_traverse,              /* tp_traverse */
+    0,                                          /* tp_traverse */
     0,                                          /* tp_clear */
     0,                                          /* tp_richcompare */
     0,                                          /* tp_weaklistoffset */
 
     Py_DECREF(cd->c_type);
 #ifndef CFFI_MEM_LEAK     /* never release anything, tests only */
-    PyObject_Del(cd);
+    Py_TYPE(cd)->tp_free((PyObject *)cd);
 #endif
 }
 
 static void cdataowning_dealloc(CDataObject *cd)
 {
+    assert(!(cd->c_type->ct_flags & (CT_IS_VOID_PTR | CT_FUNCTIONPTR)));
+
     if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
         Py_DECREF(((CDataObject_own_structptr *)cd)->structobj);
     }
-    else if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {
-        PyObject *x = (PyObject *)(cd->c_data + 42);
-        Py_DECREF(x);
-    }
-    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {
-        /* a callback */
-        ffi_closure *closure = (ffi_closure *)cd->c_data;
-        PyObject *args = (PyObject *)(closure->user_data);
-        Py_XDECREF(args);
-        cffi_closure_free(closure);
-    }
 #if defined(CFFI_MEM_DEBUG) || defined(CFFI_MEM_LEAK)
     if (cd->c_type->ct_flags & (CT_PRIMITIVE_ANY | CT_STRUCT | CT_UNION)) {
         assert(cd->c_type->ct_size >= 0);
     cdata_dealloc(cd);
 }
 
-static int cdata_traverse(CDataObject *cd, visitproc visit, void *arg)
+static void cdataowninggc_dealloc(CDataObject *cd)
 {
-    /* XXX needs Py_TPFLAGS_HAVE_GC */
-    Py_VISIT(cd->c_type);
-    return 0;
+    assert(!(cd->c_type->ct_flags & (CT_IS_PTR_TO_OWNED |
+                                     CT_PRIMITIVE_ANY |
+                                     CT_STRUCT | CT_UNION)));
+    PyObject_GC_UnTrack(cd);
+
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        Py_DECREF(x);
+    }
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
+        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        PyObject *args = (PyObject *)(closure->user_data);
+        Py_XDECREF(args);
+        cffi_closure_free(closure);
+    }
+    cdata_dealloc(cd);
 }
 
-static int cdataowning_traverse(CDataObject *cd, visitproc visit, void *arg)
+static int cdataowninggc_traverse(CDataObject *cd, visitproc visit, void *arg)
 {
-    if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
-        Py_VISIT(((CDataObject_own_structptr *)cd)->structobj);
-    }
-    else if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
         PyObject *x = (PyObject *)(cd->c_data + 42);
         Py_VISIT(x);
     }
-    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
         ffi_closure *closure = (ffi_closure *)cd->c_data;
         PyObject *args = (PyObject *)(closure->user_data);
         Py_VISIT(args);
     }
-    return cdata_traverse(cd, visit, arg);
+    return 0;
+}
+
+static int cdataowninggc_clear(CDataObject *cd)
+{
+    if (cd->c_type->ct_flags & CT_IS_VOID_PTR) {        /* a handle */
+        PyObject *x = (PyObject *)(cd->c_data + 42);
+        Py_INCREF(Py_None);
+        cd->c_data = ((char *)Py_None) - 42;
+        Py_DECREF(x);
+    }
+    else if (cd->c_type->ct_flags & CT_FUNCTIONPTR) {   /* a callback */
+        ffi_closure *closure = (ffi_closure *)cd->c_data;
+        PyObject *args = (PyObject *)(closure->user_data);
+        closure->user_data = NULL;
+        Py_XDECREF(args);
+    }
+    return 0;
 }
 
 static PyObject *cdata_float(CDataObject *cd);  /*forward*/
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
     0,                                          /* tp_doc */
-    (traverseproc)cdata_traverse,               /* tp_traverse */
+    0,                                          /* tp_traverse */
     0,                                          /* tp_clear */
     cdata_richcompare,                          /* tp_richcompare */
     offsetof(CDataObject, c_weakreflist),       /* tp_weaklistoffset */
     0,                                          /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES, /* tp_flags */
     0,                                          /* tp_doc */
-    (traverseproc)cdataowning_traverse,         /* tp_traverse */
+    0,                                          /* tp_traverse */
     0,                                          /* tp_clear */
     0,                                          /* tp_richcompare */
     0,                                          /* tp_weaklistoffset */
     &CData_Type,                                /* tp_base */
 };
 
+static PyTypeObject CDataOwningGC_Type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "_cffi_backend.CDataOwnGC",
+    sizeof(CDataObject),
+    0,
+    (destructor)cdataowninggc_dealloc,          /* tp_dealloc */
+    0,                                          /* tp_print */
+    0,                                          /* tp_getattr */
+    0,                                          /* tp_setattr */
+    0,                                          /* tp_compare */
+    0,                                          /* tp_repr */
+    0,                                          /* tp_as_number */
+    0,                                          /* tp_as_sequence */
+    0,                                          /* tp_as_mapping */
+    0,                                          /* tp_hash */
+    0,                                          /* tp_call */
+    0,                                          /* tp_str */
+    0,                                          /* tp_getattro */
+    0,                                          /* tp_setattro */
+    0,                                          /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_CHECKTYPES  /* tp_flags */
+                       | Py_TPFLAGS_HAVE_GC,
+    0,                                          /* tp_doc */
+    (traverseproc)cdataowninggc_traverse,       /* tp_traverse */
+    (inquiry)cdataowninggc_clear,               /* tp_clear */
+    0,                                          /* tp_richcompare */
+    0,                                          /* tp_weaklistoffset */
+    0,                                          /* tp_iter */
+    0,                                          /* tp_iternext */
+    0,                                          /* tp_methods */
+    0,                                          /* tp_members */
+    0,                                          /* tp_getset */
+    &CDataOwning_Type,                          /* tp_base */
+};
+
 /************************************************************/
 
 typedef struct {
 
     closure = cffi_closure_alloc();
 
-    cd = PyObject_New(CDataObject, &CDataOwning_Type);
+    cd = PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
     if (cd == NULL)
         goto error;
     Py_INCREF(ct);
         return NULL;
     }
 
-    cd = allocate_owning_object(sizeof(CDataObject), ct);
+    cd = (CDataObject *)PyObject_GC_New(CDataObject, &CDataOwningGC_Type);
     if (cd == NULL)
         return NULL;
-
+    Py_INCREF(ct);
+    cd->c_type = ct;
     Py_INCREF(x);
     cd->c_data = ((char *)x) - 42;
+    cd->c_weakreflist = NULL;
     return (PyObject *)cd;
 }
 
         INITERROR;
     if (PyType_Ready(&CDataOwning_Type) < 0)
         INITERROR;
+    if (PyType_Ready(&CDataOwningGC_Type) < 0)
+        INITERROR;
     if (PyType_Ready(&CDataIter_Type) < 0)
         INITERROR;
     if (PyType_Ready(&MiniBuffer_Type) < 0)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.