diff -r de8456d22ca1 Modules/_threadmodule.c --- a/Modules/_threadmodule.c Wed Aug 15 16:55:48 2012 +0200 +++ b/Modules/_threadmodule.c Wed Aug 15 17:04:51 2012 +0200 @@ -13,9 +13,55 @@ #include "pythread.h" -static PyObject *ThreadError; +typedef struct { + PyObject *ThreadError; + PyObject *str_dict; + PyObject *Locktype; + PyObject *RLocktype; + PyObject *localdummytype; + PyObject *localtype; +} threadstate; + +#define thread_state(o) ((threadstate *)PyModule_GetState(o)) + +static int +thread_clear(PyObject *m) +{ + threadstate *state = thread_state(m); + Py_CLEAR(state->ThreadError); + Py_CLEAR(state->str_dict); + Py_CLEAR(state->Locktype); + Py_CLEAR(state->RLocktype); + Py_CLEAR(state->localdummytype); + Py_CLEAR(state->localtype); + return 0; +} + +static int +thread_traverse(PyObject *m, visitproc visit, void *arg) +{ + threadstate *state = thread_state(m); + Py_VISIT(state->ThreadError); + Py_VISIT(state->str_dict); + Py_VISIT(state->Locktype); + Py_VISIT(state->RLocktype); + Py_VISIT(state->localdummytype); + Py_VISIT(state->localtype); + return 0; +} + +static void +thread_free(void *m) +{ + thread_clear((PyObject *)m); +} + +static PyModuleDef threadmodule; + +#define threadstate_global ((threadstate *)PyModule_GetState(PyState_FindModule(&threadmodule))) + static long nb_threads = 0; -static PyObject *str_dict; + /* Lock objects */ @@ -29,6 +75,7 @@ static void lock_dealloc(lockobject *self) { + PyTypeObject *type = Py_TYPE(self); if (self->in_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); if (self->lock_lock != NULL) { @@ -37,6 +84,9 @@ PyThread_release_lock(self->lock_lock); PyThread_free_lock(self->lock_lock); } + if((void *)type->tp_dealloc == (void *)lock_dealloc) { + Py_DECREF(type); + } PyObject_Del(self); } @@ -160,7 +210,7 @@ { /* Sanity check: the lock must be locked */ if (!self->locked) { - PyErr_SetString(ThreadError, "release unlocked lock"); + PyErr_SetString(threadstate_global->ThreadError, "release unlocked lock"); return NULL; } @@ -210,38 +260,35 @@ {NULL, NULL} /* sentinel */ }; -static PyTypeObject Locktype = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "_thread.lock", /*tp_name*/ - sizeof(lockobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)lock_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - 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, /*tp_flags*/ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - offsetof(lockobject, in_weakreflist), /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - lock_methods, /*tp_methods*/ +PyDoc_STRVAR(lock_doc, +"A lock object is a synchronization primitive. To create a lock,\n\ +call the PyThread_allocate_lock() function. Methods are:\n\ +\n\ +acquire() -- lock the lock, possibly blocking until it can be obtained\n\ +release() -- unlock of the lock\n\ +locked() -- test whether the lock is currently locked\n\ +\n\ +A lock is not owned by the thread that locked it; another thread may\n\ +unlock it. A thread attempting to lock a lock that it has already locked\n\ +will block until another thread unlocks it. Deadlocks may ensue."); + +static PyType_Slot Locktype_slots[] = { + {Py_tp_dealloc, (destructor)lock_dealloc}, + {Py_tp_methods, lock_methods}, + {Py_tp_doc, lock_doc}, + {Py_tp_members, }, + {0, 0} }; +static PyType_Spec Locktype_spec = { + "_thread.lock", + sizeof(lockobject), + 0, + Py_TPFLAGS_DEFAULT, + Locktype_slots, +}; + + /* Recursive lock objects */ typedef struct { @@ -255,6 +302,7 @@ static void rlock_dealloc(rlockobject *self) { + PyTypeObject *type = Py_TYPE(self); assert(self->rlock_lock); if (self->in_weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -263,7 +311,10 @@ PyThread_release_lock(self->rlock_lock); PyThread_free_lock(self->rlock_lock); - Py_TYPE(self)->tp_free(self); + type->tp_free(self); + if((void *)type->tp_dealloc == (void *)rlock_dealloc) { + Py_DECREF(type); + } } static PyObject * @@ -313,6 +364,7 @@ return NULL; } self->rlock_count = count; + self->rlock_count = count; Py_RETURN_TRUE; } r = acquire_timed(self->rlock_lock, microseconds); @@ -389,7 +441,7 @@ Py_END_ALLOW_THREADS } if (!r) { - PyErr_SetString(ThreadError, "couldn't acquire lock"); + PyErr_SetString(threadstate_global->ThreadError, "couldn't acquire lock"); return NULL; } assert(self->rlock_count == 0); @@ -455,7 +507,7 @@ self->rlock_lock = PyThread_allocate_lock(); if (self->rlock_lock == NULL) { type->tp_free(self); - PyErr_SetString(ThreadError, "can't allocate lock"); + PyErr_SetString(threadstate_global->ThreadError, "can't allocate lock"); return NULL; } self->in_weakreflist = NULL; @@ -493,53 +545,32 @@ }; -static PyTypeObject RLocktype = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "_thread.RLock", /*tp_name*/ - sizeof(rlockobject), /*tp_size*/ - 0, /*tp_itemsize*/ - /* methods */ - (destructor)rlock_dealloc, /*tp_dealloc*/ - 0, /*tp_print*/ - 0, /*tp_getattr*/ - 0, /*tp_setattr*/ - 0, /*tp_reserved*/ - (reprfunc)rlock_repr, /*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_BASETYPE, /* tp_flags */ - 0, /*tp_doc*/ - 0, /*tp_traverse*/ - 0, /*tp_clear*/ - 0, /*tp_richcompare*/ - offsetof(rlockobject, in_weakreflist), /*tp_weaklistoffset*/ - 0, /*tp_iter*/ - 0, /*tp_iternext*/ - rlock_methods, /*tp_methods*/ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ - rlock_new /* tp_new */ + + + +static PyType_Slot RLocktype_slots[] = { + {Py_tp_dealloc, (destructor)rlock_dealloc}, + {Py_tp_repr, (reprfunc)rlock_repr}, + {Py_tp_methods, rlock_methods}, + {Py_tp_alloc, PyType_GenericAlloc}, + {Py_tp_new, rlock_new}, + {0, 0} }; +static PyType_Spec RLocktype_spec = { + "_thread.RLock", + sizeof(rlockobject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + RLocktype_slots, +}; + + static lockobject * newlockobject(void) { lockobject *self; - self = PyObject_New(lockobject, &Locktype); + self = PyObject_New(lockobject, (PyTypeObject *)threadstate_global->Locktype); if (self == NULL) return NULL; self->lock_lock = PyThread_allocate_lock(); @@ -547,9 +578,10 @@ self->in_weakreflist = NULL; if (self->lock_lock == NULL) { Py_DECREF(self); - PyErr_SetString(ThreadError, "can't allocate lock"); + PyErr_SetString(threadstate_global->ThreadError, "can't allocate lock"); return NULL; } + Py_INCREF(threadstate_global->Locktype); return self; } @@ -605,39 +637,33 @@ static void localdummy_dealloc(localdummyobject *self) { + PyTypeObject *type = Py_TYPE(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); - Py_TYPE(self)->tp_free((PyObject*)self); + type->tp_free((PyObject*)self); + if((void *)type->tp_dealloc == (void *)localdummy_dealloc) { + Py_DECREF(type); + } } -static PyTypeObject localdummytype = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_thread._localdummy", - /* tp_basicsize */ sizeof(localdummyobject), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)localdummy_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 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 */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT, - /* tp_doc */ "Thread-local dummy", - /* tp_traverse */ 0, - /* tp_clear */ 0, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist) + + + +static PyType_Slot localdummytype_slots[] = { + {Py_tp_dealloc, (destructor)localdummy_dealloc}, + {Py_tp_doc, "Thread-local dummy"}, + {0, 0} }; +static PyType_Spec localdummytype_spec = { + "_thread._localdummy", + sizeof(localdummyobject), + 0, + Py_TPFLAGS_DEFAULT, + localdummytype_slots, +}; + + typedef struct { PyObject_HEAD @@ -674,7 +700,8 @@ ldict = PyDict_New(); if (ldict == NULL) goto err; - dummy = (localdummyobject *) localdummytype.tp_alloc(&localdummytype, 0); + dummy = (localdummyobject *)((PyTypeObject *) threadstate_global->localdummytype)->tp_alloc( + (PyTypeObject *)threadstate_global->localdummytype, 0); if (dummy == NULL) goto err; dummy->localdict = ldict; @@ -790,6 +817,7 @@ static void local_dealloc(localobject *self) { + PyTypeObject *type = Py_TYPE(self); /* Weakrefs must be invalidated right now, otherwise they can be used from code called below, which is very dangerous since Py_REFCNT(self) == 0 */ if (self->weakreflist != NULL) @@ -799,7 +827,10 @@ local_clear(self); Py_XDECREF(self->key); - Py_TYPE(self)->tp_free((PyObject*)self); + type->tp_free((PyObject*)self); + if((void *)type->tp_dealloc == (void *)local_dealloc) { + Py_DECREF(type); + } } /* Returns a borrowed reference to the local dict, creating it if necessary */ @@ -832,7 +863,7 @@ } } else { - assert(Py_TYPE(dummy) == &localdummytype); + assert(Py_TYPE(dummy) == (PyTypeObject *)threadstate_global->localdummytype); ldict = ((localdummyobject *) dummy)->localdict; } @@ -849,7 +880,7 @@ if (ldict == NULL) return -1; - r = PyObject_RichCompareBool(name, str_dict, Py_EQ); + r = PyObject_RichCompareBool(name, threadstate_global->str_dict, Py_EQ); if (r == 1) { PyErr_Format(PyExc_AttributeError, "'%.50s' object attribute '%U' is read-only", @@ -864,50 +895,31 @@ static PyObject *local_getattro(localobject *, PyObject *); -static PyTypeObject localtype = { - PyVarObject_HEAD_INIT(NULL, 0) - /* tp_name */ "_thread._local", - /* tp_basicsize */ sizeof(localobject), - /* tp_itemsize */ 0, - /* tp_dealloc */ (destructor)local_dealloc, - /* tp_print */ 0, - /* tp_getattr */ 0, - /* tp_setattr */ 0, - /* tp_reserved */ 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 */ (getattrofunc)local_getattro, - /* tp_setattro */ (setattrofunc)local_setattro, - /* tp_as_buffer */ 0, - /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE - | Py_TPFLAGS_HAVE_GC, - /* tp_doc */ "Thread-local data", - /* tp_traverse */ (traverseproc)local_traverse, - /* tp_clear */ (inquiry)local_clear, - /* tp_richcompare */ 0, - /* tp_weaklistoffset */ offsetof(localobject, weakreflist), - /* tp_iter */ 0, - /* tp_iternext */ 0, - /* tp_methods */ 0, - /* tp_members */ 0, - /* tp_getset */ 0, - /* tp_base */ 0, - /* tp_dict */ 0, /* internal use */ - /* tp_descr_get */ 0, - /* tp_descr_set */ 0, - /* tp_dictoffset */ 0, - /* tp_init */ 0, - /* tp_alloc */ 0, - /* tp_new */ local_new, - /* tp_free */ 0, /* Low-level free-mem routine */ - /* tp_is_gc */ 0, /* For PyObject_IS_GC */ + + + +static PyType_Slot localtype_slots[] = { + {Py_tp_dealloc, (destructor)local_dealloc}, + {Py_tp_getattro, (getattrofunc)local_getattro}, + {Py_tp_setattro, (setattrofunc)local_setattro}, + {Py_tp_doc, "Thread-local data"}, + {Py_tp_traverse, (traverseproc)local_traverse}, + {Py_tp_clear, (inquiry)local_clear}, + {Py_tp_new, local_new}, + {Py_tp_bases, }, + {0, 0} }; +static PyType_Spec localtype_spec = { + "_thread._local", + sizeof(localobject), + 0, + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE + | Py_TPFLAGS_HAVE_GC, + localtype_slots, +}; + + static PyObject * local_getattro(localobject *self, PyObject *name) { @@ -918,7 +930,7 @@ if (ldict == NULL) return NULL; - r = PyObject_RichCompareBool(name, str_dict, Py_EQ); + r = PyObject_RichCompareBool(name, threadstate_global->str_dict, Py_EQ); if (r == 1) { Py_INCREF(ldict); return ldict; @@ -926,7 +938,7 @@ if (r == -1) return NULL; - if (Py_TYPE(self) != &localtype) + if (Py_TYPE(self) != (PyTypeObject *)threadstate_global->localtype) /* use generic lookup for subtypes */ return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict); @@ -951,7 +963,7 @@ if (obj == Py_None) Py_RETURN_NONE; Py_INCREF(obj); - assert(PyObject_TypeCheck(obj, &localtype)); + assert(PyObject_TypeCheck(obj, (PyTypeObject *)threadstate_global->localtype)); /* If the thread-local object is still alive and not being cleared, remove the corresponding local dict */ self = (localobject *) obj; @@ -1066,7 +1078,7 @@ PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); if (ident == -1) { - PyErr_SetString(ThreadError, "can't start new thread"); + PyErr_SetString(threadstate_global->ThreadError, "can't start new thread"); Py_DECREF(func); Py_DECREF(args); Py_XDECREF(keyw); @@ -1137,7 +1149,7 @@ long ident; ident = PyThread_get_thread_ident(); if (ident == -1) { - PyErr_SetString(ThreadError, "no current thread ident"); + PyErr_SetString(threadstate_global->ThreadError, "no current thread ident"); return NULL; } return PyLong_FromLong(ident); @@ -1198,7 +1210,7 @@ return NULL; } if (rc == -2) { - PyErr_SetString(ThreadError, + PyErr_SetString(threadstate_global->ThreadError, "setting stack size not supported"); return NULL; } @@ -1257,28 +1269,17 @@ "This module provides primitive operations to write multi-threaded programs.\n\ The 'threading' module provides a more convenient interface."); -PyDoc_STRVAR(lock_doc, -"A lock object is a synchronization primitive. To create a lock,\n\ -call the PyThread_allocate_lock() function. Methods are:\n\ -\n\ -acquire() -- lock the lock, possibly blocking until it can be obtained\n\ -release() -- unlock of the lock\n\ -locked() -- test whether the lock is currently locked\n\ -\n\ -A lock is not owned by the thread that locked it; another thread may\n\ -unlock it. A thread attempting to lock a lock that it has already locked\n\ -will block until another thread unlocks it. Deadlocks may ensue."); static struct PyModuleDef threadmodule = { PyModuleDef_HEAD_INIT, "_thread", thread_doc, - -1, + sizeof(threadstate), thread_methods, NULL, - NULL, - NULL, - NULL + thread_traverse, + thread_clear, + thread_free }; @@ -1286,22 +1287,40 @@ PyInit__thread(void) { PyObject *m, *d, *timeout_max; - - /* Initialize types: */ - if (PyType_Ready(&localdummytype) < 0) - return NULL; - if (PyType_Ready(&localtype) < 0) - return NULL; - if (PyType_Ready(&Locktype) < 0) - return NULL; - if (PyType_Ready(&RLocktype) < 0) - return NULL; + threadstate *state; /* Create the module and add the functions */ m = PyModule_Create(&threadmodule); if (m == NULL) return NULL; + state = thread_state(m); + + /* Initialize types: */ + state->localdummytype = PyType_FromSpec(&localdummytype_spec); + if (state->localdummytype == NULL) + return NULL; + ((PyTypeObject *)(state->localdummytype))->tp_weaklistoffset = + offsetof(localdummyobject, weakreflist); + + state->localtype = PyType_FromSpec(&localtype_spec); + if (state->localtype == NULL) + return NULL; + ((PyTypeObject *)(state->localtype))->tp_weaklistoffset = + offsetof(localobject, weakreflist); + + state->Locktype = PyType_FromSpec(&Locktype_spec); + if (state->Locktype == NULL) + return NULL; + ((PyTypeObject *)(state->Locktype))->tp_weaklistoffset = + offsetof(lockobject, in_weakreflist); + + state->RLocktype = PyType_FromSpec(&RLocktype_spec); + if (state->RLocktype == NULL) + return NULL; + ((PyTypeObject *)(state->RLocktype))->tp_weaklistoffset = + offsetof(rlockobject, in_weakreflist); + timeout_max = PyFloat_FromDouble(PY_TIMEOUT_MAX / 1000000); if (!timeout_max) return NULL; @@ -1310,26 +1329,25 @@ /* Add a symbolic constant */ d = PyModule_GetDict(m); - ThreadError = PyExc_RuntimeError; - Py_INCREF(ThreadError); + state->ThreadError = PyExc_RuntimeError; + Py_INCREF(state->ThreadError); - PyDict_SetItemString(d, "error", ThreadError); - Locktype.tp_doc = lock_doc; - Py_INCREF(&Locktype); - PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); + PyDict_SetItemString(d, "error", state->ThreadError); + Py_INCREF(state->Locktype); + PyDict_SetItemString(d, "LockType", state->Locktype); - Py_INCREF(&RLocktype); - if (PyModule_AddObject(m, "RLock", (PyObject *)&RLocktype) < 0) + Py_INCREF(state->RLocktype); + if (PyModule_AddObject(m, "RLock", state->RLocktype) < 0) return NULL; - Py_INCREF(&localtype); - if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) + Py_INCREF(state->localtype); + if (PyModule_AddObject(m, "_local", state->localtype) < 0) return NULL; nb_threads = 0; - str_dict = PyUnicode_InternFromString("__dict__"); - if (str_dict == NULL) + state->str_dict = PyUnicode_InternFromString("__dict__"); + if (state->str_dict == NULL) return NULL; /* Initialize the C thread library */