diff -r 18c53cd98e71 Modules/_dbmmodule.c --- a/Modules/_dbmmodule.c Tue Aug 14 20:09:51 2012 +0200 +++ b/Modules/_dbmmodule.c Tue Aug 14 20:10:55 2012 +0200 @@ -38,29 +38,59 @@ DBM *di_dbm; } dbmobject; -static PyTypeObject Dbmtype; +static struct PyModuleDef _dbmmodule; -#define is_dbmobject(v) (Py_TYPE(v) == &Dbmtype) +typedef struct { + PyObject *Dbmtype; + PyObject *DbmError; +} _dbmmodulestate; + +#define _dbmmodulestate(o) ((_dbmmodulestate *)PyModule_GetState(o)) + +static int +_dbmmodule_traverse(PyObject *m, visitproc visit, void *arg) +{ + Py_VISIT(_dbmmodulestate(m)->DbmError); + Py_VISIT(_dbmmodulestate(m)->Dbmtype); + return 0; +} + +static int +_dbmmodule_clear(PyObject *m) +{ + Py_CLEAR(_dbmmodulestate(m)->DbmError); + Py_CLEAR(_dbmmodulestate(m)->Dbmtype); + return 0; +} + +static void +_dbmmodule_free(void *m) +{ + _dbmmodule_clear((PyObject *)m); +} + +#define _dbmmodulestate_global ((_dbmmodulestate *)PyModule_GetState(PyState_FindModule(&_dbmmodule))) + +#define is_dbmobject(v) (Py_TYPE(v) == _dbmmodulestate_global->Dbmtype) #define check_dbmobject_open(v) if ((v)->di_dbm == NULL) \ - { PyErr_SetString(DbmError, "DBM object has already been closed"); \ + { PyErr_SetString(_dbmmodulestate_global->DbmError, "DBM object has already been closed"); \ return NULL; } -static PyObject *DbmError; - static PyObject * newdbmobject(char *file, int flags, int mode) { dbmobject *dp; - dp = PyObject_New(dbmobject, &Dbmtype); + dp = PyObject_New(dbmobject, (PyTypeObject *)_dbmmodulestate_global->Dbmtype); if (dp == NULL) return NULL; dp->di_size = -1; if ( (dp->di_dbm = dbm_open(file, flags, mode)) == 0 ) { - PyErr_SetFromErrno(DbmError); + PyErr_SetFromErrno(_dbmmodulestate_global->DbmError); Py_DECREF(dp); return NULL; } + Py_INCREF(_dbmmodulestate_global->Dbmtype); return (PyObject *)dp; } @@ -69,16 +99,20 @@ static void dbm_dealloc(register dbmobject *dp) { + PyTypeObject *type = Py_TYPE(dp); if ( dp->di_dbm ) dbm_close(dp->di_dbm); PyObject_Del(dp); + if((void *)type->tp_dealloc == (void *)dbm_dealloc) { + Py_DECREF(type); + } } static Py_ssize_t dbm_length(dbmobject *dp) { if (dp->di_dbm == NULL) { - PyErr_SetString(DbmError, "DBM object has already been closed"); + PyErr_SetString(_dbmmodulestate_global->DbmError, "DBM object has already been closed"); return -1; } if ( dp->di_size < 0 ) { @@ -112,7 +146,7 @@ } if ( dbm_error(dp->di_dbm) ) { dbm_clearerr(dp->di_dbm); - PyErr_SetString(DbmError, ""); + PyErr_SetString(_dbmmodulestate_global->DbmError, ""); return NULL; } return PyBytes_FromStringAndSize(drec.dptr, drec.dsize); @@ -131,7 +165,7 @@ } krec.dsize = tmp_size; if (dp->di_dbm == NULL) { - PyErr_SetString(DbmError, "DBM object has already been closed"); + PyErr_SetString(_dbmmodulestate_global->DbmError, "DBM object has already been closed"); return -1; } dp->di_size = -1; @@ -150,25 +184,19 @@ drec.dsize = tmp_size; if ( dbm_store(dp->di_dbm, krec, drec, DBM_REPLACE) < 0 ) { dbm_clearerr(dp->di_dbm); - PyErr_SetString(DbmError, + PyErr_SetString(_dbmmodulestate_global->DbmError, "cannot add item to database"); return -1; } } if ( dbm_error(dp->di_dbm) ) { dbm_clearerr(dp->di_dbm); - PyErr_SetString(DbmError, ""); + PyErr_SetString(_dbmmodulestate_global->DbmError, ""); return -1; } return 0; } -static PyMappingMethods dbm_as_mapping = { - (lenfunc)dbm_length, /*mp_length*/ - (binaryfunc)dbm_subscript, /*mp_subscript*/ - (objobjargproc)dbm_ass_sub, /*mp_ass_subscript*/ -}; - static PyObject * dbm__close(register dbmobject *dp, PyObject *unused) { @@ -215,7 +243,7 @@ Py_ssize_t size; if ((dp)->di_dbm == NULL) { - PyErr_SetString(DbmError, + PyErr_SetString(_dbmmodulestate_global->DbmError, "DBM object has already been closed"); return -1; } @@ -239,19 +267,6 @@ return val.dptr != NULL; } -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 */ -}; - static PyObject * dbm_get(register dbmobject *dp, PyObject *args) { @@ -310,7 +325,7 @@ } if (dbm_store(dp->di_dbm, key, val, DBM_INSERT) < 0) { dbm_clearerr(dp->di_dbm); - PyErr_SetString(DbmError, "cannot add item to database"); + PyErr_SetString(_dbmmodulestate_global->DbmError, "cannot add item to database"); Py_DECREF(defvalue); return NULL; } @@ -332,37 +347,26 @@ {NULL, NULL} /* sentinel */ }; -static PyTypeObject Dbmtype = { - PyVarObject_HEAD_INIT(NULL, 0) +static PyType_Slot Dbmtype_slots[] = { + {Py_tp_dealloc, (destructor)dbm_dealloc}, + {Py_sq_contains, dbm_contains}, + {Py_mp_length, (lenfunc)dbm_length}, + {Py_mp_subscript, (binaryfunc)dbm_subscript}, + {Py_mp_ass_subscript, (objobjargproc)dbm_ass_sub}, + {Py_tp_methods, dbm_methods}, + {Py_tp_members, }, + {0, 0} +}; + +static PyType_Spec Dbmtype_spec = { "_dbm.dbm", 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_flags*/ - 0, /*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, }; + /* ----------------------------------------------------------------- */ static PyObject * @@ -386,7 +390,7 @@ else if ( strcmp(flags, "n") == 0 ) iflags = O_RDWR|O_CREAT|O_TRUNC; else { - PyErr_SetString(DbmError, + PyErr_SetString(_dbmmodulestate_global->DbmError, "arg 2 to open should be 'r', 'w', 'c', or 'n'"); return NULL; } @@ -405,34 +409,37 @@ PyModuleDef_HEAD_INIT, "_dbm", NULL, - -1, + sizeof(_dbmmodulestate), dbmmodule_methods, NULL, - NULL, - NULL, - NULL + _dbmmodule_traverse, + _dbmmodule_clear, + _dbmmodule_free }; PyMODINIT_FUNC PyInit__dbm(void) { PyObject *m, *d, *s; - if (PyType_Ready(&Dbmtype) < 0) - return NULL; m = PyModule_Create(&_dbmmodule); if (m == NULL) return NULL; + + _dbmmodulestate(m)->Dbmtype = PyType_FromSpec(&Dbmtype_spec); + if(_dbmmodulestate(m)->Dbmtype == NULL) + return NULL; + d = PyModule_GetDict(m); - if (DbmError == NULL) - DbmError = PyErr_NewException("_dbm.error", - PyExc_IOError, NULL); + if (_dbmmodulestate(m)->DbmError == NULL) + _dbmmodulestate(m)->DbmError = PyErr_NewException("_dbm.error", + PyExc_IOError, NULL); s = PyUnicode_FromString(which_dbm); if (s != NULL) { PyDict_SetItemString(d, "library", s); Py_DECREF(s); } - if (DbmError != NULL) - PyDict_SetItemString(d, "error", DbmError); + if (_dbmmodulestate(m)->DbmError != NULL) + PyDict_SetItemString(d, "error", _dbmmodulestate(m)->DbmError); if (PyErr_Occurred()) { Py_DECREF(m); m = NULL;