diff options
author | Jim Fulton <jim@zope.com> | 2004-07-14 19:11:50 (GMT) |
---|---|---|
committer | Jim Fulton <jim@zope.com> | 2004-07-14 19:11:50 (GMT) |
commit | d15dc06df062fdf0fe8badec2982c6c5e0e28eb0 (patch) | |
tree | e0295c2c22fa7c2e702b37a1d7afd77547a8894f /Modules | |
parent | e827437f45510d9cdd1e7fa561da8084f69ca698 (diff) | |
download | cpython-d15dc06df062fdf0fe8badec2982c6c5e0e28eb0.zip cpython-d15dc06df062fdf0fe8badec2982c6c5e0e28eb0.tar.gz cpython-d15dc06df062fdf0fe8badec2982c6c5e0e28eb0.tar.bz2 |
Implemented thread-local data as proposed on python-dev:
http://mail.python.org/pipermail/python-dev/2004-June/045785.html
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/threadmodule.c | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/Modules/threadmodule.c b/Modules/threadmodule.c index b6b32f7..b398a25 100644 --- a/Modules/threadmodule.c +++ b/Modules/threadmodule.c @@ -158,6 +158,259 @@ static PyTypeObject Locktype = { 0, /*tp_repr*/ }; +/* Thread-local objects */ + +#include "structmember.h" + +typedef struct { + PyObject_HEAD + PyObject *key; + PyObject *args; + PyObject *kw; + PyObject *dict; +} localobject; + +static PyTypeObject localtype; + +static PyObject * +local_new(PyTypeObject *type, PyObject *args, PyObject *kw) +{ + localobject *self; + PyObject *tdict; + + if (type->tp_init == PyBaseObject_Type.tp_init + && ((args && PyObject_IsTrue(args)) + || + (kw && PyObject_IsTrue(kw)) + ) + ) { + PyErr_SetString(PyExc_TypeError, + "Initialization arguments are not supported"); + return NULL; + } + + self = (localobject *)type->tp_alloc(type, 0); + if (self == NULL) + return NULL; + + Py_XINCREF(args); + self->args = args; + Py_XINCREF(kw); + self->kw = kw; + self->dict = NULL; /* making sure */ + self->key = PyString_FromFormat("thread.local.%p", self); + if (self->key == NULL) + goto err; + + self->dict = PyDict_New(); + if (self->dict == NULL) + goto err; + + tdict = PyThreadState_GetDict(); + if (tdict == NULL) { + PyErr_SetString(PyExc_SystemError, + "Couldn't get thread-state dictionary"); + goto err; + } + + if (PyDict_SetItem(tdict, self->key, self->dict) < 0) + goto err; + + return (PyObject *)self; + + err: + Py_DECREF(self); + return NULL; +} + +static int +local_traverse(localobject *self, visitproc visit, void *arg) +{ + Py_VISIT(self->args); + Py_VISIT(self->kw); + Py_VISIT(self->dict); + return 0; +} + +static int +local_clear(localobject *self) +{ + Py_CLEAR(self->key); + Py_CLEAR(self->args); + Py_CLEAR(self->kw); + Py_CLEAR(self->dict); + return 0; +} + +static void +local_dealloc(localobject *self) +{ + PyThreadState *tstate; + if (self->key + && (tstate = PyThreadState_Get()) + && tstate->interp) { + for(tstate = PyInterpreterState_ThreadHead(tstate->interp); + tstate; + tstate = PyThreadState_Next(tstate) + ) + if (tstate->dict && + PyDict_GetItem(tstate->dict, self->key)) + PyDict_DelItem(tstate->dict, self->key); + } + + local_clear(self); + self->ob_type->tp_free((PyObject*)self); +} + +static PyObject * +_ldict(localobject *self) +{ + PyObject *tdict, *ldict; + + tdict = PyThreadState_GetDict(); + if (tdict == NULL) { + PyErr_SetString(PyExc_SystemError, + "Couldn't get thread-state dictionary"); + return NULL; + } + + ldict = PyDict_GetItem(tdict, self->key); + if (ldict == NULL) { + ldict = PyDict_New(); /* we own ldict */ + + if (ldict == NULL) + return NULL; + else { + int i = PyDict_SetItem(tdict, self->key, ldict); + Py_DECREF(ldict); /* now ldict is borowed */ + if (i < 0) + return NULL; + } + + Py_CLEAR(self->dict); + Py_INCREF(ldict); + self->dict = ldict; /* still borrowed */ + + if (self->ob_type->tp_init != PyBaseObject_Type.tp_init && + self->ob_type->tp_init((PyObject*)self, + self->args, self->kw) < 0 + ) { + /* we need to get rid of ldict from thread so + we create a new one the next time we do an attr + acces */ + PyDict_DelItem(tdict, self->key); + return NULL; + } + + } + else if (self->dict != ldict) { + Py_CLEAR(self->dict); + Py_INCREF(ldict); + self->dict = ldict; + } + + return ldict; +} + +static PyObject * +local_getattro(localobject *self, PyObject *name) +{ + PyObject *ldict, *value; + + ldict = _ldict(self); + if (ldict == NULL) + return NULL; + + if (self->ob_type != &localtype) + /* use generic lookup for subtypes */ + return PyObject_GenericGetAttr((PyObject *)self, name); + + /* Optimization: just look in dict ourselves */ + value = PyDict_GetItem(ldict, name); + if (value == NULL) + /* Fall back on generic to get __class__ and __dict__ */ + return PyObject_GenericGetAttr((PyObject *)self, name); + + Py_INCREF(value); + return value; +} + +static int +local_setattro(localobject *self, PyObject *name, PyObject *v) +{ + PyObject *ldict; + + ldict = _ldict(self); + if (ldict == NULL) + return -1; + + return PyObject_GenericSetAttr((PyObject *)self, name, v); +} + +static PyObject * +local_getdict(localobject *self, void *closure) +{ + if (self->dict == NULL) { + PyErr_SetString(PyExc_AttributeError, "__dict__"); + return NULL; + } + + Py_INCREF(self->dict); + return self->dict; +} + +static PyGetSetDef local_getset[] = { + {"__dict__", + (getter)local_getdict, (setter)0, + "Local-data dictionary", + NULL}, + {NULL} /* Sentinel */ +}; + +static PyTypeObject localtype = { + PyObject_HEAD_INIT(NULL) + /* ob_size */ 0, + /* tp_name */ "thread._local", + /* tp_basicsize */ sizeof(localobject), + /* tp_itemsize */ 0, + /* tp_dealloc */ (destructor)local_dealloc, + /* tp_print */ (printfunc)0, + /* tp_getattr */ (getattrfunc)0, + /* tp_setattr */ (setattrfunc)0, + /* tp_compare */ (cmpfunc)0, + /* tp_repr */ (reprfunc)0, + /* tp_as_number */ 0, + /* tp_as_sequence */ 0, + /* tp_as_mapping */ 0, + /* tp_hash */ (hashfunc)0, + /* tp_call */ (ternaryfunc)0, + /* tp_str */ (reprfunc)0, + /* tp_getattro */ (getattrofunc)local_getattro, + /* tp_setattro */ (setattrofunc)local_setattro, + /* tp_as_buffer */ 0, + /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + /* tp_doc */ "Thread-local data", + /* tp_traverse */ (traverseproc)local_traverse, + /* tp_clear */ (inquiry)local_clear, + /* tp_richcompare */ (richcmpfunc)0, + /* tp_weaklistoffset */ (long)0, + /* tp_iter */ (getiterfunc)0, + /* tp_iternext */ (iternextfunc)0, + /* tp_methods */ 0, + /* tp_members */ 0, + /* tp_getset */ local_getset, + /* tp_base */ 0, + /* tp_dict */ 0, /* internal use */ + /* tp_descr_get */ (descrgetfunc)0, + /* tp_descr_set */ (descrsetfunc)0, + /* tp_dictoffset */ offsetof(localobject, dict), + /* tp_init */ (initproc)0, + /* tp_alloc */ (allocfunc)0, + /* tp_new */ (newfunc)local_new, + /* tp_free */ 0, /* Low-level free-mem routine */ + /* tp_is_gc */ (inquiry)0, /* For PyObject_IS_GC */ +}; + /* Module functions */ @@ -389,6 +642,10 @@ PyMODINIT_FUNC initthread(void) { PyObject *m, *d; + + /* Initialize types: */ + if (PyType_Ready(&localtype) < 0) + return; /* Create the module and add the functions */ m = Py_InitModule3("thread", thread_methods, thread_doc); @@ -401,6 +658,9 @@ initthread(void) Py_INCREF(&Locktype); PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); + if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) + return; + /* Initialize the C thread library */ PyThread_init_thread(); } |