[Python-Dev] A little GC confusion

David Abrahams David Abrahams" <david.abrahams@rcn.com
Thu, 21 Feb 2002 08:06:05 -0500


Hi All,

The following extension module (AA) is a reduced example of what I'm doing
to make extension
classes in 2.2. I followed the examples given by typeobject.c. When I
"import AA,pdb" I get a crash in GC. Investigating further, I see this makes
sense: GC is enabled in class_metatype_object, yet class_type_object does
not follow the first rule of objects whose type has GC enabled:

    "The memory for the object must be allocated using PyObject_GC_New()
or PyObject_GC_VarNew()."

So, I guess the question is, how does PyBaseObject_Type (also statically
allocated) get away with it?

TIA,
Dave

----------------

// Copyright David Abrahams 2002. Permission to copy, use,
// modify, sell and distribute this software is granted provided this
// copyright notice appears in all copies. This software is provided
// "as is" without express or implied warranty, and with no claim as
// to its suitability for any purpose.
#include <Python.h>

PyTypeObject class_metatype_object = {
    PyObject_HEAD_INIT(0)
        0,
        "Boost.Python.class",
        PyType_Type.tp_basicsize,
        0,
        0,                                      /* 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_HAVE_GC
  | Py_TPFLAGS_BASETYPE,  /* tp_flags */
        0,                                      /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
        0,                                      /* tp_richcompare */
        0,                                      /* tp_weaklistoffset */
        0,                                      /* tp_iter */
        0,                                      /* tp_iternext */
        0,                                      /* tp_methods */
        0,                                      /* tp_members */
        0,                                      /* tp_getset */
        0, // &PyType_Type,                           /* tp_base */
        0,                                      /* tp_dict */
        0,                                      /* tp_descr_get */
        0,                                      /* tp_descr_set */
        0,                                      /* tp_dictoffset */
        0,                                      /* tp_init */
        0,                                      /* tp_alloc */
        0,
        // PyType_GenericNew                       /* tp_new */
};

// Get the metatype object for all extension classes.
PyObject* class_metatype()
{
    if (class_metatype_object.tp_dict == 0)
    {
        class_metatype_object.ob_type = &PyType_Type;
        class_metatype_object.tp_base = &PyType_Type;
        if (PyType_Ready(&class_metatype_object))
            return 0;
    }
    Py_INCREF(&class_metatype_object);
    return (PyObject*)&class_metatype_object;
}

// Each extension instance will be one of these
typedef struct instance
{
    PyObject_HEAD
    void* objects;
} instance;

static void instance_dealloc(PyObject* inst)
{
    instance* kill_me = (instance*)inst;

    inst->ob_type->tp_free(inst);
}

PyTypeObject class_type_object = {
    PyObject_HEAD_INIT(0) file://&class_metatype_object)
        0,
        "Boost.Python.instance",
        sizeof(PyObject),
        0,
        instance_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_HAVE_GC
  | Py_TPFLAGS_BASETYPE,  /* tp_flags */
        0,                                      /* tp_doc */
        0,                                      /* tp_traverse */
        0,                                      /* tp_clear */
        0,                                      /* tp_richcompare */
        0,                                      /* tp_weaklistoffset */
        0,                                      /* tp_iter */
        0,                                      /* tp_iternext */
        0,                                      /* tp_methods */
        0,                                      /* tp_members */
        0,                                      /* tp_getset */
    0, file://&PyBaseObject_Type,                     /* tp_base */
        0,                                      /* tp_dict */
        0,                                      /* tp_descr_get */
        0,                                      /* tp_descr_set */
        0,                                      /* tp_dictoffset */
        0,                                      /* tp_init */
        PyType_GenericAlloc,                    /* tp_alloc */
        PyType_GenericNew
};

PyObject* class_type()
{
    if (class_type_object.tp_dict == 0)
    {
        class_type_object.ob_type = (PyTypeObject*)class_metatype();
        class_type_object.tp_base = &PyBaseObject_Type;
        if (PyType_Ready(&class_type_object))
            return 0;
    }
    Py_INCREF(&class_type_object);
    return (PyObject*)&class_type_object;
}

PyObject* make_class()
{
    PyObject* bases, *args, *mt, *result;
    bases = PyTuple_New(1);
    PyTuple_SET_ITEM(bases, 0, class_type());

    args = PyTuple_New(3);
    PyTuple_SET_ITEM(args, 0, PyString_FromString("AA"));
    PyTuple_SET_ITEM(args, 1, bases);
    PyTuple_SET_ITEM(args, 2, PyDict_New());

    mt = class_metatype();
    result = PyObject_CallObject(mt, args);
    Py_XDECREF(mt);
    Py_XDECREF(args);
    return result;
}

static PyMethodDef SpamMethods[] = {
    {NULL,      NULL}        /* Sentinel */
};


DL_EXPORT(void)
initAA()
{
    PyObject *m, *d;

    m = Py_InitModule("AA", SpamMethods);
    d = PyModule_GetDict(m);
    PyDict_SetItemString(d, "AA", make_class());
}


+---------------------------------------------------------------+
                  David Abrahams
      C++ Booster (http://www.boost.org)               O__  ==
      Pythonista (http://www.python.org)              c/ /'_ ==
  resume: http://users.rcn.com/abrahams/resume.html  (*) \(*) ==
          email: david.abrahams@rcn.com
+---------------------------------------------------------------+