diff -r 4790a3cb00ed Modules/_gdbmmodule.c --- a/Modules/_gdbmmodule.c Tue Aug 14 20:21:24 2012 +0200 +++ b/Modules/_gdbmmodule.c Tue Aug 14 20:28:33 2012 +0200 @@ -29,22 +29,50 @@ supported."); typedef struct { + PyObject *Dbmtype; + PyObject *DbmError; +} _gdbmstate; + +#define _gdbmstate(o) ((_gdbmstate *)PyModule_GetState(o)) + +static int +_gdbm_clear(PyObject *m) +{ + Py_CLEAR(_gdbmstate(m)->Dbmtype); + Py_CLEAR(_gdbmstate(m)->DbmError); + return 0; +} + +static int +_gdbm_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(_gdbmstate(m)->Dbmtype); + Py_VISIT(_gdbmstate(m)->DbmError); + return 0; +} + +static void +_gdbm_free(void *m) +{ + _gdbm_clear((PyObject *)m); +} + +static struct PyModuleDef _gdbmmodule; + +#define _gdbmstate_global ((_gdbmstate *)PyModule_GetState(PyState_FindModule(&_gdbmmodule))) + +typedef struct { PyObject_HEAD int di_size; /* -1 means recompute */ GDBM_FILE di_dbm; } dbmobject; -static PyTypeObject Dbmtype; -#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype) +#define is_dbmobject(v) (Py_TYPE(v) == (PyTypeObject *)_gdbmstate_global->Dbmtype) #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \ - { PyErr_SetString(DbmError, "GDBM object has already been closed"); \ + { PyErr_SetString(_gdbmstate_global->DbmError, "GDBM object has already been closed"); \ return NULL; } - - -static PyObject *DbmError; - PyDoc_STRVAR(gdbm_object__doc__, "This object represents a GDBM database.\n\ GDBM objects behave like mappings (dictionaries), except that keys and\n\ @@ -60,16 +88,17 @@ { dbmobject *dp; - dp = PyObject_New(dbmobject, &Dbmtype); + dp = PyObject_New(dbmobject, (PyTypeObject *)_gdbmstate_global->Dbmtype); if (dp == NULL) return NULL; + Py_INCREF(_gdbmstate_global->Dbmtype); dp->di_size = -1; errno = 0; if ((dp->di_dbm = gdbm_open(file, 0, flags, mode, NULL)) == 0) { if (errno != 0) - PyErr_SetFromErrno(DbmError); + PyErr_SetFromErrno(_gdbmstate_global->DbmError); else - PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); + PyErr_SetString(_gdbmstate_global->DbmError, gdbm_strerror(gdbm_errno)); Py_DECREF(dp); return NULL; } @@ -81,8 +110,12 @@ static void dbm_dealloc(register dbmobject *dp) { + PyTypeObject *type = Py_TYPE(dp); if (dp->di_dbm) gdbm_close(dp->di_dbm); + if((void *)type->tp_dealloc == (void *)dbm_dealloc) { + Py_DECREF(type); + } PyObject_Del(dp); } @@ -90,7 +123,7 @@ dbm_length(dbmobject *dp) { if (dp->di_dbm == NULL) { - PyErr_SetString(DbmError, "GDBM object has already been closed"); + PyErr_SetString(_gdbmstate_global->DbmError, "GDBM object has already been closed"); return -1; } if (dp->di_size < 0) { @@ -121,7 +154,7 @@ return NULL; if (dp->di_dbm == NULL) { - PyErr_SetString(DbmError, + PyErr_SetString(_gdbmstate_global->DbmError, "GDBM object has already been closed"); return NULL; } @@ -168,7 +201,7 @@ return -1; } if (dp->di_dbm == NULL) { - PyErr_SetString(DbmError, + PyErr_SetString(_gdbmstate_global->DbmError, "GDBM object has already been closed"); return -1; } @@ -188,9 +221,9 @@ errno = 0; if (gdbm_store(dp->di_dbm, krec, drec, GDBM_REPLACE) < 0) { if (errno != 0) - PyErr_SetFromErrno(DbmError); + PyErr_SetFromErrno(_gdbmstate_global->DbmError); else - PyErr_SetString(DbmError, + PyErr_SetString(_gdbmstate_global->DbmError, gdbm_strerror(gdbm_errno)); return -1; } @@ -221,12 +254,6 @@ return res; } -static PyMappingMethods dbm_as_mapping = { - (lenfunc)dbm_length, /*mp_length*/ - (binaryfunc)dbm_subscript, /*mp_subscript*/ - (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/ -}; - PyDoc_STRVAR(dbm_close__doc__, "close() -> None\n\ Closes the database."); @@ -292,7 +319,7 @@ datum key; if ((dp)->di_dbm == NULL) { - PyErr_SetString(DbmError, + PyErr_SetString(_gdbmstate_global->DbmError, "GDBM object has already been closed"); return -1; } @@ -307,19 +334,6 @@ return gdbm_exists(dp->di_dbm, key); } -static PySequenceMethods dbm_as_sequence = { - 0, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - 0, /* sq_item */ - 0, /* sq_slice */ - 0, /* sq_ass_item */ - 0, /* sq_ass_slice */ - dbm_contains, /* sq_contains */ - 0, /* sq_inplace_concat */ - 0, /* sq_inplace_repeat */ -}; - PyDoc_STRVAR(dbm_firstkey__doc__, "firstkey() -> key\n\ It's possible to loop over every key in the database using this method\n\ @@ -393,9 +407,9 @@ errno = 0; if (gdbm_reorganize(dp->di_dbm) < 0) { if (errno != 0) - PyErr_SetFromErrno(DbmError); + PyErr_SetFromErrno(_gdbmstate_global->DbmError); else - PyErr_SetString(DbmError, gdbm_strerror(gdbm_errno)); + PyErr_SetString(_gdbmstate_global->DbmError, gdbm_strerror(gdbm_errno)); return NULL; } Py_INCREF(Py_None); @@ -428,37 +442,27 @@ {NULL, NULL} /* sentinel */ }; -static PyTypeObject Dbmtype = { - PyVarObject_HEAD_INIT(0, 0) +static PyType_Slot Dbmtype_slots[] = { + {Py_tp_doc, gdbm_object__doc__}, + {Py_tp_dealloc, (destructor)dbm_dealloc}, + {Py_sq_contains, dbm_contains}, + {Py_mp_length, dbm_length}, + {Py_mp_subscript, dbm_subscript}, + {Py_mp_ass_subscript, dbm_ass_sub}, + {Py_tp_methods, dbm_methods}, + {Py_tp_members, }, + {0, 0} +}; + +static PyType_Spec Dbmtype_spec = { "_gdbm.gdbm", sizeof(dbmobject), 0, - (destructor)dbm_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 0, /*tp_repr*/ - 0, /*tp_as_number*/ - &dbm_as_sequence, /*tp_as_sequence*/ - &dbm_as_mapping, /*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, /*tp_xxx4*/ - gdbm_object__doc__, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - 0, /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - dbm_methods, /*tp_methods*/ + Py_TPFLAGS_DEFAULT, + Dbmtype_slots, }; + /* ----------------------------------------------------------------- */ PyDoc_STRVAR(dbmopen__doc__, @@ -509,7 +513,7 @@ iflags = GDBM_NEWDB; break; default: - PyErr_SetString(DbmError, + PyErr_SetString(_gdbmstate_global->DbmError, "First flag must be one of 'r', 'w', 'c' or 'n'"); return NULL; } @@ -534,7 +538,7 @@ default: PyOS_snprintf(buf, sizeof(buf), "Flag '%c' is not supported.", *flags); - PyErr_SetString(DbmError, buf); + PyErr_SetString(_gdbmstate_global->DbmError, buf); return NULL; } } @@ -564,27 +568,36 @@ PyModuleDef_HEAD_INIT, "_gdbm", gdbmmodule__doc__, - -1, + sizeof(_gdbmstate), dbmmodule_methods, NULL, - NULL, - NULL, - NULL + _gdbm_traverse, + _gdbm_clear, + _gdbm_free }; PyMODINIT_FUNC PyInit__gdbm(void) { PyObject *m, *d, *s; - if (PyType_Ready(&Dbmtype) < 0) + m = PyState_FindModule(&_gdbmmodule); + if(!m){ + m = PyModule_Create(&_gdbmmodule); + if (m == NULL) return NULL; - m = PyModule_Create(&_gdbmmodule); - if (m == NULL) + } else { + Py_INCREF(m); + return m; + } + + _gdbmstate(m)->Dbmtype = PyType_FromSpec(&Dbmtype_spec); + if (_gdbmstate(m)->Dbmtype == NULL) return NULL; + d = PyModule_GetDict(m); - DbmError = PyErr_NewException("_gdbm.error", PyExc_IOError, NULL); - if (DbmError != NULL) { - PyDict_SetItemString(d, "error", DbmError); + _gdbmstate(m)->DbmError = PyErr_NewException("_gdbm.error", PyExc_IOError, NULL); + if (_gdbmstate(m)->DbmError != NULL) { + PyDict_SetItemString(d, "error", _gdbmstate(m)->DbmError); s = PyUnicode_FromString(dbmmodule_open_flags); PyDict_SetItemString(d, "open_flags", s); Py_DECREF(s);