| OLD | NEW |
| 1 | 1 |
| 2 /* Thread module */ | 2 /* Thread module */ |
| 3 /* Interface to Sjoerd's portable C thread library */ | 3 /* Interface to Sjoerd's portable C thread library */ |
| 4 | 4 |
| 5 #include "Python.h" | 5 #include "Python.h" |
| 6 | 6 |
| 7 #ifndef WITH_THREAD | 7 #ifndef WITH_THREAD |
| 8 #error "Error! The rest of Python is not compiled with thread support." | 8 #error "Error! The rest of Python is not compiled with thread support." |
| 9 #error "Rerun configure, adding a --with-threads option." | 9 #error "Rerun configure, adding a --with-threads option." |
| 10 #error "Then run `make clean' followed by `make'." | 10 #error "Then run `make clean' followed by `make'." |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 157 | 157 |
| 158 /* Thread-local objects */ | 158 /* Thread-local objects */ |
| 159 | 159 |
| 160 #include "structmember.h" | 160 #include "structmember.h" |
| 161 | 161 |
| 162 typedef struct { | 162 typedef struct { |
| 163 PyObject_HEAD | 163 PyObject_HEAD |
| 164 PyObject *key; | 164 PyObject *key; |
| 165 PyObject *args; | 165 PyObject *args; |
| 166 PyObject *kw; | 166 PyObject *kw; |
| 167 PyObject *dict; | |
| 168 } localobject; | 167 } localobject; |
| 169 | 168 |
| 170 static PyObject * | 169 static PyObject * |
| 171 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) | 170 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) |
| 172 { | 171 { |
| 173 localobject *self; | 172 localobject *self; |
| 174 PyObject *tdict; | 173 PyObject *tdict; |
| 174 PyObject *localdict; |
| 175 | 175 |
| 176 if (type->tp_init == PyBaseObject_Type.tp_init | 176 if (type->tp_init == PyBaseObject_Type.tp_init |
| 177 && ((args && PyObject_IsTrue(args)) | 177 && ((args && PyObject_IsTrue(args)) |
| 178 || (kw && PyObject_IsTrue(kw)))) { | 178 || (kw && PyObject_IsTrue(kw)))) { |
| 179 PyErr_SetString(PyExc_TypeError, | 179 PyErr_SetString(PyExc_TypeError, |
| 180 "Initialization arguments are not supported"); | 180 "Initialization arguments are not supported"); |
| 181 return NULL; | 181 return NULL; |
| 182 } | 182 } |
| 183 | 183 |
| 184 self = (localobject *)type->tp_alloc(type, 0); | 184 self = (localobject *)type->tp_alloc(type, 0); |
| 185 if (self == NULL) | 185 if (self == NULL) |
| 186 return NULL; | 186 return NULL; |
| 187 | 187 |
| 188 Py_XINCREF(args); | 188 Py_XINCREF(args); |
| 189 self->args = args; | 189 self->args = args; |
| 190 Py_XINCREF(kw); | 190 Py_XINCREF(kw); |
| 191 self->kw = kw; | 191 self->kw = kw; |
| 192 self->dict = NULL; /* making sure */ | |
| 193 self->key = PyString_FromFormat("thread.local.%p", self); | 192 self->key = PyString_FromFormat("thread.local.%p", self); |
| 194 if (self->key == NULL) | 193 if (self->key == NULL) |
| 195 goto err; | 194 goto err; |
| 196 | 195 |
| 197 » self->dict = PyDict_New(); | 196 » localdict = PyDict_New(); |
| 198 » if (self->dict == NULL) | 197 » if (localdict == NULL) |
| 199 goto err; | 198 goto err; |
| 200 | 199 |
| 201 tdict = PyThreadState_GetDict(); | 200 tdict = PyThreadState_GetDict(); |
| 202 if (tdict == NULL) { | 201 if (tdict == NULL) { |
| 203 PyErr_SetString(PyExc_SystemError, | 202 PyErr_SetString(PyExc_SystemError, |
| 204 "Couldn't get thread-state dictionary"); | 203 "Couldn't get thread-state dictionary"); |
| 205 goto err; | 204 goto err; |
| 206 } | 205 } |
| 207 | 206 |
| 208 » if (PyDict_SetItem(tdict, self->key, self->dict) < 0) | 207 » if (PyDict_SetItem(tdict, self->key, localdict) < 0) { |
| 208 » » Py_DECREF(localdict); |
| 209 goto err; | 209 goto err; |
| 210 } |
| 211 Py_DECREF(localdict); |
| 210 | 212 |
| 211 return (PyObject *)self; | 213 return (PyObject *)self; |
| 212 | 214 |
| 213 err: | 215 err: |
| 214 Py_DECREF(self); | 216 Py_DECREF(self); |
| 215 return NULL; | 217 return NULL; |
| 216 } | 218 } |
| 217 | 219 |
| 218 static int | 220 static int |
| 219 local_traverse(localobject *self, visitproc visit, void *arg) | 221 local_traverse(localobject *self, visitproc visit, void *arg) |
| 220 { | 222 { |
| 221 Py_VISIT(self->args); | 223 Py_VISIT(self->args); |
| 222 Py_VISIT(self->kw); | 224 Py_VISIT(self->kw); |
| 223 Py_VISIT(self->dict); | |
| 224 return 0; | 225 return 0; |
| 225 } | 226 } |
| 226 | 227 |
| 227 static int | 228 static int |
| 228 local_clear(localobject *self) | 229 local_clear(localobject *self) |
| 229 { | 230 { |
| 230 Py_CLEAR(self->key); | 231 Py_CLEAR(self->key); |
| 231 Py_CLEAR(self->args); | 232 Py_CLEAR(self->args); |
| 232 Py_CLEAR(self->kw); | 233 Py_CLEAR(self->kw); |
| 233 Py_CLEAR(self->dict); | |
| 234 return 0; | 234 return 0; |
| 235 } | 235 } |
| 236 | 236 |
| 237 static void | 237 static void |
| 238 local_dealloc(localobject *self) | 238 local_dealloc(localobject *self) |
| 239 { | 239 { |
| 240 PyThreadState *tstate; | 240 PyThreadState *tstate; |
| 241 if (self->key | 241 if (self->key |
| 242 && (tstate = PyThreadState_Get()) | 242 && (tstate = PyThreadState_Get()) |
| 243 && tstate->interp) { | 243 && tstate->interp) { |
| 244 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); | 244 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); |
| 245 tstate; | 245 tstate; |
| 246 tstate = PyThreadState_Next(tstate)) | 246 tstate = PyThreadState_Next(tstate)) |
| 247 if (tstate->dict && | 247 if (tstate->dict && |
| 248 PyDict_GetItem(tstate->dict, self->key)) | 248 PyDict_GetItem(tstate->dict, self->key)) |
| 249 PyDict_DelItem(tstate->dict, self->key); | 249 PyDict_DelItem(tstate->dict, self->key); |
| 250 } | 250 } |
| 251 | 251 |
| 252 local_clear(self); | 252 local_clear(self); |
| 253 Py_TYPE(self)->tp_free((PyObject*)self); | 253 Py_TYPE(self)->tp_free((PyObject*)self); |
| 254 } | 254 } |
| 255 | 255 |
| 256 /* Return borrowed reference to the local dict */ |
| 256 static PyObject * | 257 static PyObject * |
| 257 _ldict(localobject *self) | 258 _ldict(localobject *self) |
| 258 { | 259 { |
| 259 PyObject *tdict, *ldict; | 260 PyObject *tdict, *ldict; |
| 260 | 261 |
| 261 tdict = PyThreadState_GetDict(); | 262 tdict = PyThreadState_GetDict(); |
| 262 if (tdict == NULL) { | 263 if (tdict == NULL) { |
| 263 PyErr_SetString(PyExc_SystemError, | 264 PyErr_SetString(PyExc_SystemError, |
| 264 "Couldn't get thread-state dictionary"); | 265 "Couldn't get thread-state dictionary"); |
| 265 return NULL; | 266 return NULL; |
| 266 } | 267 } |
| 267 | 268 |
| 268 ldict = PyDict_GetItem(tdict, self->key); | 269 ldict = PyDict_GetItem(tdict, self->key); |
| 269 if (ldict == NULL) { | 270 if (ldict == NULL) { |
| 270 ldict = PyDict_New(); /* we own ldict */ | 271 ldict = PyDict_New(); /* we own ldict */ |
| 271 | 272 |
| 272 if (ldict == NULL) | 273 if (ldict == NULL) |
| 273 return NULL; | 274 return NULL; |
| 274 else { | 275 else { |
| 275 int i = PyDict_SetItem(tdict, self->key, ldict); | 276 int i = PyDict_SetItem(tdict, self->key, ldict); |
| 276 Py_DECREF(ldict); /* now ldict is borrowed */ | 277 Py_DECREF(ldict); /* now ldict is borrowed */ |
| 277 if (i < 0) | 278 if (i < 0) |
| 278 return NULL; | 279 return NULL; |
| 279 } | 280 } |
| 280 | |
| 281 Py_CLEAR(self->dict); | |
| 282 Py_INCREF(ldict); | |
| 283 self->dict = ldict; /* still borrowed */ | |
| 284 | 281 |
| 285 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && | 282 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && |
| 286 Py_TYPE(self)->tp_init((PyObject*)self, | 283 Py_TYPE(self)->tp_init((PyObject*)self, |
| 287 self->args, self->kw) < 0) { | 284 self->args, self->kw) < 0) { |
| 288 /* we need to get rid of ldict from thread so | 285 /* we need to get rid of ldict from thread so |
| 289 we create a new one the next time we do an attr | 286 we create a new one the next time we do an attr |
| 290 acces */ | 287 acces */ |
| 291 PyDict_DelItem(tdict, self->key); | 288 PyDict_DelItem(tdict, self->key); |
| 292 return NULL; | 289 return NULL; |
| 293 } | 290 } |
| 294 | 291 |
| 295 } | |
| 296 | |
| 297 /* The call to tp_init above may have caused another thread to run. | |
| 298 Install our ldict again. */ | |
| 299 if (self->dict != ldict) { | |
| 300 Py_CLEAR(self->dict); | |
| 301 Py_INCREF(ldict); | |
| 302 self->dict = ldict; | |
| 303 } | 292 } |
| 304 | 293 |
| 305 return ldict; | 294 return ldict; |
| 306 } | 295 } |
| 307 | 296 |
| 308 static int | 297 static int |
| 309 local_setattro(localobject *self, PyObject *name, PyObject *v) | 298 local_setattro(localobject *self, PyObject *name, PyObject *v) |
| 310 { | 299 { |
| 311 » PyObject *ldict; | 300 » PyObject *ldict = _ldict(self); |
| 312 » | |
| 313 » ldict = _ldict(self); | |
| 314 if (ldict == NULL) | 301 if (ldict == NULL) |
| 315 return -1; | 302 return -1; |
| 316 | 303 |
| 317 » return PyObject_GenericSetAttr((PyObject *)self, name, v); | 304 » if (v != NULL) { |
| 305 » » return PyDict_SetItem(ldict, name, v); |
| 306 » } else { |
| 307 » » int res; |
| 308 » » res = PyDict_DelItem(ldict, name); |
| 309 » » if ((res < 0) && PyErr_ExceptionMatches(PyExc_KeyError)) { |
| 310 » » » PyErr_SetObject(PyExc_AttributeError, name); |
| 311 » » } |
| 312 » » return res; |
| 313 » } |
| 318 } | 314 } |
| 319 | 315 |
| 320 static PyObject * | 316 static PyObject * |
| 321 local_getdict(localobject *self, void *closure) | 317 local_getdict(localobject *self, void *closure) |
| 322 { | 318 { |
| 323 » if (self->dict == NULL) { | 319 » PyObject *ldict = _ldict(self); |
| 320 » if (ldict == NULL) { |
| 324 PyErr_SetString(PyExc_AttributeError, "__dict__"); | 321 PyErr_SetString(PyExc_AttributeError, "__dict__"); |
| 325 return NULL; | 322 return NULL; |
| 326 } | 323 } |
| 327 | 324 |
| 328 » Py_INCREF(self->dict); | 325 » Py_INCREF(ldict); |
| 329 » return self->dict; | 326 » return ldict; |
| 330 } | 327 } |
| 331 | 328 |
| 332 static PyGetSetDef local_getset[] = { | 329 static PyGetSetDef local_getset[] = { |
| 333 {"__dict__", (getter)local_getdict, (setter)NULL, | 330 {"__dict__", (getter)local_getdict, (setter)NULL, |
| 334 "Local-data dictionary", NULL}, | 331 "Local-data dictionary", NULL}, |
| 335 {NULL} /* Sentinel */ | 332 {NULL} /* Sentinel */ |
| 336 }; | 333 }; |
| 337 | 334 |
| 338 static PyObject *local_getattro(localobject *, PyObject *); | 335 static PyObject *local_getattro(localobject *, PyObject *); |
| 339 | 336 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 365 /* tp_weaklistoffset */ 0, | 362 /* tp_weaklistoffset */ 0, |
| 366 /* tp_iter */ 0, | 363 /* tp_iter */ 0, |
| 367 /* tp_iternext */ 0, | 364 /* tp_iternext */ 0, |
| 368 /* tp_methods */ 0, | 365 /* tp_methods */ 0, |
| 369 /* tp_members */ 0, | 366 /* tp_members */ 0, |
| 370 /* tp_getset */ local_getset, | 367 /* tp_getset */ local_getset, |
| 371 /* tp_base */ 0, | 368 /* tp_base */ 0, |
| 372 /* tp_dict */ 0, /* internal use */ | 369 /* tp_dict */ 0, /* internal use */ |
| 373 /* tp_descr_get */ 0, | 370 /* tp_descr_get */ 0, |
| 374 /* tp_descr_set */ 0, | 371 /* tp_descr_set */ 0, |
| 375 » /* tp_dictoffset */ offsetof(localobject, dict), | 372 » /* tp_dictoffset */ 0, |
| 376 /* tp_init */ 0, | 373 /* tp_init */ 0, |
| 377 /* tp_alloc */ 0, | 374 /* tp_alloc */ 0, |
| 378 /* tp_new */ local_new, | 375 /* tp_new */ local_new, |
| 379 /* tp_free */ 0, /* Low-level free-mem routine */ | 376 /* tp_free */ 0, /* Low-level free-mem routine */ |
| 380 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ | 377 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ |
| 381 }; | 378 }; |
| 382 | 379 |
| 383 static PyObject * | 380 static PyObject * |
| 384 local_getattro(localobject *self, PyObject *name) | 381 local_getattro(localobject *self, PyObject *name) |
| 385 { | 382 { |
| 386 PyObject *ldict, *value; | 383 PyObject *ldict, *value; |
| 387 | 384 |
| 388 ldict = _ldict(self); | 385 ldict = _ldict(self); |
| 389 if (ldict == NULL) | 386 if (ldict == NULL) |
| 390 return NULL; | 387 return NULL; |
| 391 | |
| 392 if (Py_TYPE(self) != &localtype) | |
| 393 /* use generic lookup for subtypes */ | |
| 394 return PyObject_GenericGetAttr((PyObject *)self, name); | |
| 395 | 388 |
| 396 /* Optimization: just look in dict ourselves */ | 389 /* Optimization: just look in dict ourselves */ |
| 397 value = PyDict_GetItem(ldict, name); | 390 value = PyDict_GetItem(ldict, name); |
| 398 if (value == NULL) | 391 if (value == NULL) |
| 399 /* Fall back on generic to get __class__ and __dict__ */ | 392 /* Fall back on generic to get __class__ and __dict__ */ |
| 400 return PyObject_GenericGetAttr((PyObject *)self, name); | 393 return PyObject_GenericGetAttr((PyObject *)self, name); |
| 401 | 394 |
| 402 Py_INCREF(value); | 395 Py_INCREF(value); |
| 403 return value; | 396 return value; |
| 404 } | 397 } |
| (...skipping 307 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 712 Py_INCREF(&Locktype); | 705 Py_INCREF(&Locktype); |
| 713 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); | 706 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); |
| 714 | 707 |
| 715 Py_INCREF(&localtype); | 708 Py_INCREF(&localtype); |
| 716 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) | 709 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) |
| 717 return; | 710 return; |
| 718 | 711 |
| 719 /* Initialize the C thread library */ | 712 /* Initialize the C thread library */ |
| 720 PyThread_init_thread(); | 713 PyThread_init_thread(); |
| 721 } | 714 } |
| OLD | NEW |