Changeset 391 for python/trunk/Modules/threadmodule.c
- Timestamp:
- Mar 19, 2014, 11:31:01 PM (11 years ago)
- Location:
- python/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
python/trunk
-
Property svn:mergeinfo
set to
/python/vendor/Python-2.7.6 merged eligible /python/vendor/current merged eligible
-
Property svn:mergeinfo
set to
-
python/trunk/Modules/threadmodule.c
r2 r391 4 4 5 5 #include "Python.h" 6 #include "structmember.h" /* offsetof */ 6 7 7 8 #ifndef WITH_THREAD … … 14 15 15 16 static PyObject *ThreadError; 16 17 static PyObject *str_dict; 18 static long nb_threads = 0; 17 19 18 20 /* Lock objects */ 19 21 20 22 typedef struct { 21 PyObject_HEAD 22 PyThread_type_lock lock_lock; 23 PyObject_HEAD 24 PyThread_type_lock lock_lock; 25 PyObject *in_weakreflist; 23 26 } lockobject; 24 27 … … 26 29 lock_dealloc(lockobject *self) 27 30 { 28 assert(self->lock_lock); 29 /* Unlock the lock so it's safe to free it */ 30 PyThread_acquire_lock(self->lock_lock, 0); 31 PyThread_release_lock(self->lock_lock); 32 33 PyThread_free_lock(self->lock_lock); 34 PyObject_Del(self); 31 if (self->in_weakreflist != NULL) 32 PyObject_ClearWeakRefs((PyObject *) self); 33 if (self->lock_lock != NULL) { 34 /* Unlock the lock so it's safe to free it */ 35 PyThread_acquire_lock(self->lock_lock, 0); 36 PyThread_release_lock(self->lock_lock); 37 38 PyThread_free_lock(self->lock_lock); 39 } 40 PyObject_Del(self); 35 41 } 36 42 … … 38 44 lock_PyThread_acquire_lock(lockobject *self, PyObject *args) 39 45 { 40 41 42 43 44 45 46 47 48 49 46 int i = 1; 47 48 if (!PyArg_ParseTuple(args, "|i:acquire", &i)) 49 return NULL; 50 51 Py_BEGIN_ALLOW_THREADS 52 i = PyThread_acquire_lock(self->lock_lock, i); 53 Py_END_ALLOW_THREADS 54 55 return PyBool_FromLong((long)i); 50 56 } 51 57 52 58 PyDoc_STRVAR(acquire_doc, 53 "acquire([wait]) -> None orbool\n\59 "acquire([wait]) -> bool\n\ 54 60 (acquire_lock() is an obsolete synonym)\n\ 55 61 \n\ 56 62 Lock the lock. Without argument, this blocks if the lock is already\n\ 57 63 locked (even by the same thread), waiting for another thread to release\n\ 58 the lock, and return None once the lock is acquired.\n\64 the lock, and return True once the lock is acquired.\n\ 59 65 With an argument, this will only block if the argument is true,\n\ 60 66 and the return value reflects whether the lock is acquired.\n\ … … 64 70 lock_PyThread_release_lock(lockobject *self) 65 71 { 66 67 68 69 70 71 72 73 74 75 72 /* Sanity check: the lock must be locked */ 73 if (PyThread_acquire_lock(self->lock_lock, 0)) { 74 PyThread_release_lock(self->lock_lock); 75 PyErr_SetString(ThreadError, "release unlocked lock"); 76 return NULL; 77 } 78 79 PyThread_release_lock(self->lock_lock); 80 Py_INCREF(Py_None); 81 return Py_None; 76 82 } 77 83 … … 87 93 lock_locked_lock(lockobject *self) 88 94 { 89 90 91 92 93 95 if (PyThread_acquire_lock(self->lock_lock, 0)) { 96 PyThread_release_lock(self->lock_lock); 97 return PyBool_FromLong(0L); 98 } 99 return PyBool_FromLong(1L); 94 100 } 95 101 … … 101 107 102 108 static PyMethodDef lock_methods[] = { 103 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock, 104 105 {"acquire", (PyCFunction)lock_PyThread_acquire_lock, 106 107 {"release_lock", (PyCFunction)lock_PyThread_release_lock, 108 109 {"release", (PyCFunction)lock_PyThread_release_lock, 110 111 {"locked_lock", (PyCFunction)lock_locked_lock, 112 113 {"locked", (PyCFunction)lock_locked_lock, 114 115 116 117 118 119 {NULL, NULL}/* sentinel */109 {"acquire_lock", (PyCFunction)lock_PyThread_acquire_lock, 110 METH_VARARGS, acquire_doc}, 111 {"acquire", (PyCFunction)lock_PyThread_acquire_lock, 112 METH_VARARGS, acquire_doc}, 113 {"release_lock", (PyCFunction)lock_PyThread_release_lock, 114 METH_NOARGS, release_doc}, 115 {"release", (PyCFunction)lock_PyThread_release_lock, 116 METH_NOARGS, release_doc}, 117 {"locked_lock", (PyCFunction)lock_locked_lock, 118 METH_NOARGS, locked_doc}, 119 {"locked", (PyCFunction)lock_locked_lock, 120 METH_NOARGS, locked_doc}, 121 {"__enter__", (PyCFunction)lock_PyThread_acquire_lock, 122 METH_VARARGS, acquire_doc}, 123 {"__exit__", (PyCFunction)lock_PyThread_release_lock, 124 METH_VARARGS, release_doc}, 125 {NULL} /* sentinel */ 120 126 }; 121 127 122 static PyObject *123 lock_getattr(lockobject *self, char *name)124 {125 return Py_FindMethod(lock_methods, (PyObject *)self, name);126 }127 128 128 static PyTypeObject Locktype = { 129 PyVarObject_HEAD_INIT(&PyType_Type, 0) 130 "thread.lock", /*tp_name*/ 131 sizeof(lockobject), /*tp_size*/ 132 0, /*tp_itemsize*/ 133 /* methods */ 134 (destructor)lock_dealloc, /*tp_dealloc*/ 135 0, /*tp_print*/ 136 (getattrfunc)lock_getattr, /*tp_getattr*/ 137 0, /*tp_setattr*/ 138 0, /*tp_compare*/ 139 0, /*tp_repr*/ 129 PyVarObject_HEAD_INIT(&PyType_Type, 0) 130 "thread.lock", /*tp_name*/ 131 sizeof(lockobject), /*tp_size*/ 132 0, /*tp_itemsize*/ 133 /* methods */ 134 (destructor)lock_dealloc, /*tp_dealloc*/ 135 0, /*tp_print*/ 136 0, /*tp_getattr*/ 137 0, /*tp_setattr*/ 138 0, /*tp_compare*/ 139 0, /*tp_repr*/ 140 0, /* tp_as_number */ 141 0, /* tp_as_sequence */ 142 0, /* tp_as_mapping */ 143 0, /* tp_hash */ 144 0, /* tp_call */ 145 0, /* tp_str */ 146 0, /* tp_getattro */ 147 0, /* tp_setattro */ 148 0, /* tp_as_buffer */ 149 Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ 150 0, /* tp_doc */ 151 0, /* tp_traverse */ 152 0, /* tp_clear */ 153 0, /* tp_richcompare */ 154 offsetof(lockobject, in_weakreflist), /* tp_weaklistoffset */ 155 0, /* tp_iter */ 156 0, /* tp_iternext */ 157 lock_methods, /* tp_methods */ 140 158 }; 141 159 … … 143 161 newlockobject(void) 144 162 { 145 lockobject *self; 146 self = PyObject_New(lockobject, &Locktype); 147 if (self == NULL) 148 return NULL; 149 self->lock_lock = PyThread_allocate_lock(); 150 if (self->lock_lock == NULL) { 151 PyObject_Del(self); 152 self = NULL; 153 PyErr_SetString(ThreadError, "can't allocate lock"); 154 } 155 return self; 163 lockobject *self; 164 self = PyObject_New(lockobject, &Locktype); 165 if (self == NULL) 166 return NULL; 167 self->lock_lock = PyThread_allocate_lock(); 168 self->in_weakreflist = NULL; 169 if (self->lock_lock == NULL) { 170 Py_DECREF(self); 171 PyErr_SetString(ThreadError, "can't allocate lock"); 172 return NULL; 173 } 174 return self; 156 175 } 157 176 … … 160 179 #include "structmember.h" 161 180 181 /* Quick overview: 182 183 We need to be able to reclaim reference cycles as soon as possible 184 (both when a thread is being terminated, or a thread-local object 185 becomes unreachable from user data). Constraints: 186 - it must not be possible for thread-state dicts to be involved in 187 reference cycles (otherwise the cyclic GC will refuse to consider 188 objects referenced from a reachable thread-state dict, even though 189 local_dealloc would clear them) 190 - the death of a thread-state dict must still imply destruction of the 191 corresponding local dicts in all thread-local objects. 192 193 Our implementation uses small "localdummy" objects in order to break 194 the reference chain. These trivial objects are hashable (using the 195 default scheme of identity hashing) and weakrefable. 196 Each thread-state holds a separate localdummy for each local object 197 (as a /strong reference/), 198 and each thread-local object holds a dict mapping /weak references/ 199 of localdummies to local dicts. 200 201 Therefore: 202 - only the thread-state dict holds a strong reference to the dummies 203 - only the thread-local object holds a strong reference to the local dicts 204 - only outside objects (application- or library-level) hold strong 205 references to the thread-local objects 206 - as soon as a thread-state dict is destroyed, the weakref callbacks of all 207 dummies attached to that thread are called, and destroy the corresponding 208 local dicts from thread-local objects 209 - as soon as a thread-local object is destroyed, its local dicts are 210 destroyed and its dummies are manually removed from all thread states 211 - the GC can do its work correctly when a thread-local object is dangling, 212 without any interference from the thread-state dicts 213 214 As an additional optimization, each localdummy holds a borrowed reference 215 to the corresponding localdict. This borrowed reference is only used 216 by the thread-local object which has created the localdummy, which should 217 guarantee that the localdict still exists when accessed. 218 */ 219 162 220 typedef struct { 163 PyObject_HEAD 164 PyObject *key; 165 PyObject *args; 166 PyObject *kw; 167 PyObject *dict; 221 PyObject_HEAD 222 PyObject *localdict; /* Borrowed reference! */ 223 PyObject *weakreflist; /* List of weak references to self */ 224 } localdummyobject; 225 226 static void 227 localdummy_dealloc(localdummyobject *self) 228 { 229 if (self->weakreflist != NULL) 230 PyObject_ClearWeakRefs((PyObject *) self); 231 Py_TYPE(self)->tp_free((PyObject*)self); 232 } 233 234 static PyTypeObject localdummytype = { 235 PyVarObject_HEAD_INIT(NULL, 0) 236 /* tp_name */ "_thread._localdummy", 237 /* tp_basicsize */ sizeof(localdummyobject), 238 /* tp_itemsize */ 0, 239 /* tp_dealloc */ (destructor)localdummy_dealloc, 240 /* tp_print */ 0, 241 /* tp_getattr */ 0, 242 /* tp_setattr */ 0, 243 /* tp_reserved */ 0, 244 /* tp_repr */ 0, 245 /* tp_as_number */ 0, 246 /* tp_as_sequence */ 0, 247 /* tp_as_mapping */ 0, 248 /* tp_hash */ 0, 249 /* tp_call */ 0, 250 /* tp_str */ 0, 251 /* tp_getattro */ 0, 252 /* tp_setattro */ 0, 253 /* tp_as_buffer */ 0, 254 /* tp_flags */ Py_TPFLAGS_DEFAULT, 255 /* tp_doc */ "Thread-local dummy", 256 /* tp_traverse */ 0, 257 /* tp_clear */ 0, 258 /* tp_richcompare */ 0, 259 /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist) 260 }; 261 262 263 typedef struct { 264 PyObject_HEAD 265 PyObject *key; 266 PyObject *args; 267 PyObject *kw; 268 PyObject *weakreflist; /* List of weak references to self */ 269 /* A {localdummy weakref -> localdict} dict */ 270 PyObject *dummies; 271 /* The callback for weakrefs to localdummies */ 272 PyObject *wr_callback; 168 273 } localobject; 169 274 275 /* Forward declaration */ 276 static PyObject *_ldict(localobject *self); 277 static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakref); 278 279 /* Create and register the dummy for the current thread. 280 Returns a borrowed reference of the corresponding local dict */ 281 static PyObject * 282 _local_create_dummy(localobject *self) 283 { 284 PyObject *tdict, *ldict = NULL, *wr = NULL; 285 localdummyobject *dummy = NULL; 286 int r; 287 288 tdict = PyThreadState_GetDict(); 289 if (tdict == NULL) { 290 PyErr_SetString(PyExc_SystemError, 291 "Couldn't get thread-state dictionary"); 292 goto err; 293 } 294 295 ldict = PyDict_New(); 296 if (ldict == NULL) 297 goto err; 298 dummy = (localdummyobject *) localdummytype.tp_alloc(&localdummytype, 0); 299 if (dummy == NULL) 300 goto err; 301 dummy->localdict = ldict; 302 wr = PyWeakref_NewRef((PyObject *) dummy, self->wr_callback); 303 if (wr == NULL) 304 goto err; 305 306 /* As a side-effect, this will cache the weakref's hash before the 307 dummy gets deleted */ 308 r = PyDict_SetItem(self->dummies, wr, ldict); 309 if (r < 0) 310 goto err; 311 Py_CLEAR(wr); 312 r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy); 313 if (r < 0) 314 goto err; 315 Py_CLEAR(dummy); 316 317 Py_DECREF(ldict); 318 return ldict; 319 320 err: 321 Py_XDECREF(ldict); 322 Py_XDECREF(wr); 323 Py_XDECREF(dummy); 324 return NULL; 325 } 326 170 327 static PyObject * 171 328 local_new(PyTypeObject *type, PyObject *args, PyObject *kw) 172 329 { 173 localobject *self; 174 PyObject *tdict; 175 176 if (type->tp_init == PyBaseObject_Type.tp_init 177 && ((args && PyObject_IsTrue(args)) 178 || (kw && PyObject_IsTrue(kw)))) { 179 PyErr_SetString(PyExc_TypeError, 180 "Initialization arguments are not supported"); 181 return NULL; 182 } 183 184 self = (localobject *)type->tp_alloc(type, 0); 185 if (self == NULL) 186 return NULL; 187 188 Py_XINCREF(args); 189 self->args = args; 190 Py_XINCREF(kw); 191 self->kw = kw; 192 self->dict = NULL; /* making sure */ 193 self->key = PyString_FromFormat("thread.local.%p", self); 194 if (self->key == NULL) 195 goto err; 196 197 self->dict = PyDict_New(); 198 if (self->dict == NULL) 199 goto err; 200 201 tdict = PyThreadState_GetDict(); 202 if (tdict == NULL) { 203 PyErr_SetString(PyExc_SystemError, 204 "Couldn't get thread-state dictionary"); 205 goto err; 206 } 207 208 if (PyDict_SetItem(tdict, self->key, self->dict) < 0) 209 goto err; 210 211 return (PyObject *)self; 330 localobject *self; 331 PyObject *wr; 332 static PyMethodDef wr_callback_def = { 333 "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O 334 }; 335 336 if (type->tp_init == PyBaseObject_Type.tp_init 337 && ((args && PyObject_IsTrue(args)) 338 || (kw && PyObject_IsTrue(kw)))) { 339 PyErr_SetString(PyExc_TypeError, 340 "Initialization arguments are not supported"); 341 return NULL; 342 } 343 344 self = (localobject *)type->tp_alloc(type, 0); 345 if (self == NULL) 346 return NULL; 347 348 Py_XINCREF(args); 349 self->args = args; 350 Py_XINCREF(kw); 351 self->kw = kw; 352 self->key = PyString_FromFormat("thread.local.%p", self); 353 if (self->key == NULL) 354 goto err; 355 356 self->dummies = PyDict_New(); 357 if (self->dummies == NULL) 358 goto err; 359 360 /* We use a weak reference to self in the callback closure 361 in order to avoid spurious reference cycles */ 362 wr = PyWeakref_NewRef((PyObject *) self, NULL); 363 if (wr == NULL) 364 goto err; 365 self->wr_callback = PyCFunction_New(&wr_callback_def, wr); 366 Py_DECREF(wr); 367 if (self->wr_callback == NULL) 368 goto err; 369 370 if (_local_create_dummy(self) == NULL) 371 goto err; 372 373 return (PyObject *)self; 212 374 213 375 err: 214 215 376 Py_DECREF(self); 377 return NULL; 216 378 } 217 379 … … 219 381 local_traverse(localobject *self, visitproc visit, void *arg) 220 382 { 221 222 223 Py_VISIT(self->dict);224 383 Py_VISIT(self->args); 384 Py_VISIT(self->kw); 385 Py_VISIT(self->dummies); 386 return 0; 225 387 } 226 388 … … 228 390 local_clear(localobject *self) 229 391 { 230 Py_CLEAR(self->args); 231 Py_CLEAR(self->kw); 232 Py_CLEAR(self->dict); 233 return 0; 392 PyThreadState *tstate; 393 Py_CLEAR(self->args); 394 Py_CLEAR(self->kw); 395 Py_CLEAR(self->dummies); 396 Py_CLEAR(self->wr_callback); 397 /* Remove all strong references to dummies from the thread states */ 398 if (self->key 399 && (tstate = PyThreadState_Get()) 400 && tstate->interp) { 401 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); 402 tstate; 403 tstate = PyThreadState_Next(tstate)) 404 if (tstate->dict && 405 PyDict_GetItem(tstate->dict, self->key)) 406 PyDict_DelItem(tstate->dict, self->key); 407 } 408 return 0; 234 409 } 235 410 … … 237 412 local_dealloc(localobject *self) 238 413 { 239 PyThreadState *tstate; 240 if (self->key 241 && (tstate = PyThreadState_Get()) 242 && tstate->interp) { 243 for(tstate = PyInterpreterState_ThreadHead(tstate->interp); 244 tstate; 245 tstate = PyThreadState_Next(tstate)) 246 if (tstate->dict && 247 PyDict_GetItem(tstate->dict, self->key)) 248 PyDict_DelItem(tstate->dict, self->key); 249 } 250 251 Py_XDECREF(self->key); 252 local_clear(self); 253 Py_TYPE(self)->tp_free((PyObject*)self); 254 } 255 414 /* Weakrefs must be invalidated right now, otherwise they can be used 415 from code called below, which is very dangerous since Py_REFCNT(self) == 0 */ 416 if (self->weakreflist != NULL) 417 PyObject_ClearWeakRefs((PyObject *) self); 418 419 PyObject_GC_UnTrack(self); 420 421 local_clear(self); 422 Py_XDECREF(self->key); 423 Py_TYPE(self)->tp_free((PyObject*)self); 424 } 425 426 /* Returns a borrowed reference to the local dict, creating it if necessary */ 256 427 static PyObject * 257 428 _ldict(localobject *self) 258 429 { 259 PyObject *tdict, *ldict; 260 261 tdict = PyThreadState_GetDict(); 262 if (tdict == NULL) { 263 PyErr_SetString(PyExc_SystemError, 264 "Couldn't get thread-state dictionary"); 265 return NULL; 266 } 267 268 ldict = PyDict_GetItem(tdict, self->key); 269 if (ldict == NULL) { 270 ldict = PyDict_New(); /* we own ldict */ 271 272 if (ldict == NULL) 273 return NULL; 274 else { 275 int i = PyDict_SetItem(tdict, self->key, ldict); 276 Py_DECREF(ldict); /* now ldict is borrowed */ 277 if (i < 0) 278 return NULL; 279 } 280 281 Py_CLEAR(self->dict); 282 Py_INCREF(ldict); 283 self->dict = ldict; /* still borrowed */ 284 285 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && 286 Py_TYPE(self)->tp_init((PyObject*)self, 287 self->args, self->kw) < 0) { 288 /* we need to get rid of ldict from thread so 289 we create a new one the next time we do an attr 290 acces */ 291 PyDict_DelItem(tdict, self->key); 292 return NULL; 293 } 294 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 } 304 305 return ldict; 430 PyObject *tdict, *ldict, *dummy; 431 432 tdict = PyThreadState_GetDict(); 433 if (tdict == NULL) { 434 PyErr_SetString(PyExc_SystemError, 435 "Couldn't get thread-state dictionary"); 436 return NULL; 437 } 438 439 dummy = PyDict_GetItem(tdict, self->key); 440 if (dummy == NULL) { 441 ldict = _local_create_dummy(self); 442 if (ldict == NULL) 443 return NULL; 444 445 if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && 446 Py_TYPE(self)->tp_init((PyObject*)self, 447 self->args, self->kw) < 0) { 448 /* we need to get rid of ldict from thread so 449 we create a new one the next time we do an attr 450 access */ 451 PyDict_DelItem(tdict, self->key); 452 return NULL; 453 } 454 } 455 else { 456 assert(Py_TYPE(dummy) == &localdummytype); 457 ldict = ((localdummyobject *) dummy)->localdict; 458 } 459 460 return ldict; 306 461 } 307 462 … … 309 464 local_setattro(localobject *self, PyObject *name, PyObject *v) 310 465 { 311 PyObject *ldict; 312 313 ldict = _ldict(self); 314 if (ldict == NULL) 315 return -1; 316 317 return PyObject_GenericSetAttr((PyObject *)self, name, v); 318 } 319 320 static PyObject * 321 local_getdict(localobject *self, void *closure) 322 { 323 if (self->dict == NULL) { 324 PyErr_SetString(PyExc_AttributeError, "__dict__"); 325 return NULL; 326 } 327 328 Py_INCREF(self->dict); 329 return self->dict; 330 } 331 332 static PyGetSetDef local_getset[] = { 333 {"__dict__", (getter)local_getdict, (setter)NULL, 334 "Local-data dictionary", NULL}, 335 {NULL} /* Sentinel */ 466 PyObject *ldict; 467 int r; 468 469 ldict = _ldict(self); 470 if (ldict == NULL) 471 return -1; 472 473 r = PyObject_RichCompareBool(name, str_dict, Py_EQ); 474 if (r == 1) { 475 PyErr_Format(PyExc_AttributeError, 476 "'%.50s' object attribute '__dict__' is read-only", 477 Py_TYPE(self)->tp_name); 478 return -1; 479 } 480 if (r == -1) 481 return -1; 482 483 return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict); 484 } 485 486 static PyObject *local_getattro(localobject *, PyObject *); 487 488 static PyTypeObject localtype = { 489 PyVarObject_HEAD_INIT(NULL, 0) 490 /* tp_name */ "thread._local", 491 /* tp_basicsize */ sizeof(localobject), 492 /* tp_itemsize */ 0, 493 /* tp_dealloc */ (destructor)local_dealloc, 494 /* tp_print */ 0, 495 /* tp_getattr */ 0, 496 /* tp_setattr */ 0, 497 /* tp_compare */ 0, 498 /* tp_repr */ 0, 499 /* tp_as_number */ 0, 500 /* tp_as_sequence */ 0, 501 /* tp_as_mapping */ 0, 502 /* tp_hash */ 0, 503 /* tp_call */ 0, 504 /* tp_str */ 0, 505 /* tp_getattro */ (getattrofunc)local_getattro, 506 /* tp_setattro */ (setattrofunc)local_setattro, 507 /* tp_as_buffer */ 0, 508 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE 509 | Py_TPFLAGS_HAVE_GC, 510 /* tp_doc */ "Thread-local data", 511 /* tp_traverse */ (traverseproc)local_traverse, 512 /* tp_clear */ (inquiry)local_clear, 513 /* tp_richcompare */ 0, 514 /* tp_weaklistoffset */ offsetof(localobject, weakreflist), 515 /* tp_iter */ 0, 516 /* tp_iternext */ 0, 517 /* tp_methods */ 0, 518 /* tp_members */ 0, 519 /* tp_getset */ 0, 520 /* tp_base */ 0, 521 /* tp_dict */ 0, /* internal use */ 522 /* tp_descr_get */ 0, 523 /* tp_descr_set */ 0, 524 /* tp_dictoffset */ 0, 525 /* tp_init */ 0, 526 /* tp_alloc */ 0, 527 /* tp_new */ local_new, 528 /* tp_free */ 0, /* Low-level free-mem routine */ 529 /* tp_is_gc */ 0, /* For PyObject_IS_GC */ 336 530 }; 337 531 338 static PyObject *local_getattro(localobject *, PyObject *);339 340 static PyTypeObject localtype = {341 PyVarObject_HEAD_INIT(NULL, 0)342 /* tp_name */ "thread._local",343 /* tp_basicsize */ sizeof(localobject),344 /* tp_itemsize */ 0,345 /* tp_dealloc */ (destructor)local_dealloc,346 /* tp_print */ 0,347 /* tp_getattr */ 0,348 /* tp_setattr */ 0,349 /* tp_compare */ 0,350 /* tp_repr */ 0,351 /* tp_as_number */ 0,352 /* tp_as_sequence */ 0,353 /* tp_as_mapping */ 0,354 /* tp_hash */ 0,355 /* tp_call */ 0,356 /* tp_str */ 0,357 /* tp_getattro */ (getattrofunc)local_getattro,358 /* tp_setattro */ (setattrofunc)local_setattro,359 /* tp_as_buffer */ 0,360 /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,361 /* tp_doc */ "Thread-local data",362 /* tp_traverse */ (traverseproc)local_traverse,363 /* tp_clear */ (inquiry)local_clear,364 /* tp_richcompare */ 0,365 /* tp_weaklistoffset */ 0,366 /* tp_iter */ 0,367 /* tp_iternext */ 0,368 /* tp_methods */ 0,369 /* tp_members */ 0,370 /* tp_getset */ local_getset,371 /* tp_base */ 0,372 /* tp_dict */ 0, /* internal use */373 /* tp_descr_get */ 0,374 /* tp_descr_set */ 0,375 /* tp_dictoffset */ offsetof(localobject, dict),376 /* tp_init */ 0,377 /* tp_alloc */ 0,378 /* tp_new */ local_new,379 /* tp_free */ 0, /* Low-level free-mem routine */380 /* tp_is_gc */ 0, /* For PyObject_IS_GC */381 };382 383 532 static PyObject * 384 533 local_getattro(localobject *self, PyObject *name) 385 534 { 386 PyObject *ldict, *value; 387 388 ldict = _ldict(self); 389 if (ldict == NULL) 390 return NULL; 391 392 if (Py_TYPE(self) != &localtype) 393 /* use generic lookup for subtypes */ 394 return PyObject_GenericGetAttr((PyObject *)self, name); 395 396 /* Optimization: just look in dict ourselves */ 397 value = PyDict_GetItem(ldict, name); 398 if (value == NULL) 399 /* Fall back on generic to get __class__ and __dict__ */ 400 return PyObject_GenericGetAttr((PyObject *)self, name); 401 402 Py_INCREF(value); 403 return value; 535 PyObject *ldict, *value; 536 int r; 537 538 ldict = _ldict(self); 539 if (ldict == NULL) 540 return NULL; 541 542 r = PyObject_RichCompareBool(name, str_dict, Py_EQ); 543 if (r == 1) { 544 Py_INCREF(ldict); 545 return ldict; 546 } 547 if (r == -1) 548 return NULL; 549 550 if (Py_TYPE(self) != &localtype) 551 /* use generic lookup for subtypes */ 552 return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict); 553 554 /* Optimization: just look in dict ourselves */ 555 value = PyDict_GetItem(ldict, name); 556 if (value == NULL) 557 /* Fall back on generic to get __class__ and __dict__ */ 558 return _PyObject_GenericGetAttrWithDict((PyObject *)self, name, ldict); 559 560 Py_INCREF(value); 561 return value; 562 } 563 564 /* Called when a dummy is destroyed. */ 565 static PyObject * 566 _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) 567 { 568 PyObject *obj; 569 localobject *self; 570 assert(PyWeakref_CheckRef(localweakref)); 571 obj = PyWeakref_GET_OBJECT(localweakref); 572 if (obj == Py_None) 573 Py_RETURN_NONE; 574 Py_INCREF(obj); 575 assert(PyObject_TypeCheck(obj, &localtype)); 576 /* If the thread-local object is still alive and not being cleared, 577 remove the corresponding local dict */ 578 self = (localobject *) obj; 579 if (self->dummies != NULL) { 580 PyObject *ldict; 581 ldict = PyDict_GetItem(self->dummies, dummyweakref); 582 if (ldict != NULL) { 583 PyDict_DelItem(self->dummies, dummyweakref); 584 } 585 if (PyErr_Occurred()) 586 PyErr_WriteUnraisable(obj); 587 } 588 Py_DECREF(obj); 589 Py_RETURN_NONE; 404 590 } 405 591 … … 407 593 408 594 struct bootstate { 409 PyInterpreterState *interp; 410 PyObject *func; 411 PyObject *args; 412 PyObject *keyw; 595 PyInterpreterState *interp; 596 PyObject *func; 597 PyObject *args; 598 PyObject *keyw; 599 PyThreadState *tstate; 413 600 }; 414 601 … … 416 603 t_bootstrap(void *boot_raw) 417 604 { 418 struct bootstate *boot = (struct bootstate *) boot_raw; 419 PyThreadState *tstate; 420 PyObject *res; 421 422 tstate = PyThreadState_New(boot->interp); 423 424 PyEval_AcquireThread(tstate); 425 res = PyEval_CallObjectWithKeywords( 426 boot->func, boot->args, boot->keyw); 427 if (res == NULL) { 428 if (PyErr_ExceptionMatches(PyExc_SystemExit)) 429 PyErr_Clear(); 430 else { 431 PyObject *file; 432 PySys_WriteStderr( 433 "Unhandled exception in thread started by "); 434 file = PySys_GetObject("stderr"); 435 if (file) 436 PyFile_WriteObject(boot->func, file, 0); 437 else 438 PyObject_Print(boot->func, stderr, 0); 439 PySys_WriteStderr("\n"); 440 PyErr_PrintEx(0); 441 } 442 } 443 else 444 Py_DECREF(res); 445 Py_DECREF(boot->func); 446 Py_DECREF(boot->args); 447 Py_XDECREF(boot->keyw); 448 PyMem_DEL(boot_raw); 449 PyThreadState_Clear(tstate); 450 PyThreadState_DeleteCurrent(); 451 PyThread_exit_thread(); 605 struct bootstate *boot = (struct bootstate *) boot_raw; 606 PyThreadState *tstate; 607 PyObject *res; 608 609 tstate = boot->tstate; 610 tstate->thread_id = PyThread_get_thread_ident(); 611 _PyThreadState_Init(tstate); 612 PyEval_AcquireThread(tstate); 613 nb_threads++; 614 res = PyEval_CallObjectWithKeywords( 615 boot->func, boot->args, boot->keyw); 616 if (res == NULL) { 617 if (PyErr_ExceptionMatches(PyExc_SystemExit)) 618 PyErr_Clear(); 619 else { 620 PyObject *file; 621 PyObject *exc, *value, *tb; 622 PyErr_Fetch(&exc, &value, &tb); 623 PySys_WriteStderr( 624 "Unhandled exception in thread started by "); 625 file = PySys_GetObject("stderr"); 626 if (file) 627 PyFile_WriteObject(boot->func, file, 0); 628 else 629 PyObject_Print(boot->func, stderr, 0); 630 PySys_WriteStderr("\n"); 631 PyErr_Restore(exc, value, tb); 632 PyErr_PrintEx(0); 633 } 634 } 635 else 636 Py_DECREF(res); 637 Py_DECREF(boot->func); 638 Py_DECREF(boot->args); 639 Py_XDECREF(boot->keyw); 640 PyMem_DEL(boot_raw); 641 nb_threads--; 642 PyThreadState_Clear(tstate); 643 PyThreadState_DeleteCurrent(); 644 PyThread_exit_thread(); 452 645 } 453 646 … … 455 648 thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) 456 649 { 457 PyObject *func, *args, *keyw = NULL; 458 struct bootstate *boot; 459 long ident; 460 461 if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, 462 &func, &args, &keyw)) 463 return NULL; 464 if (!PyCallable_Check(func)) { 465 PyErr_SetString(PyExc_TypeError, 466 "first arg must be callable"); 467 return NULL; 468 } 469 if (!PyTuple_Check(args)) { 470 PyErr_SetString(PyExc_TypeError, 471 "2nd arg must be a tuple"); 472 return NULL; 473 } 474 if (keyw != NULL && !PyDict_Check(keyw)) { 475 PyErr_SetString(PyExc_TypeError, 476 "optional 3rd arg must be a dictionary"); 477 return NULL; 478 } 479 boot = PyMem_NEW(struct bootstate, 1); 480 if (boot == NULL) 481 return PyErr_NoMemory(); 482 boot->interp = PyThreadState_GET()->interp; 483 boot->func = func; 484 boot->args = args; 485 boot->keyw = keyw; 486 Py_INCREF(func); 487 Py_INCREF(args); 488 Py_XINCREF(keyw); 489 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ 490 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); 491 if (ident == -1) { 492 PyErr_SetString(ThreadError, "can't start new thread"); 493 Py_DECREF(func); 494 Py_DECREF(args); 495 Py_XDECREF(keyw); 496 PyMem_DEL(boot); 497 return NULL; 498 } 499 return PyInt_FromLong(ident); 650 PyObject *func, *args, *keyw = NULL; 651 struct bootstate *boot; 652 long ident; 653 654 if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, 655 &func, &args, &keyw)) 656 return NULL; 657 if (!PyCallable_Check(func)) { 658 PyErr_SetString(PyExc_TypeError, 659 "first arg must be callable"); 660 return NULL; 661 } 662 if (!PyTuple_Check(args)) { 663 PyErr_SetString(PyExc_TypeError, 664 "2nd arg must be a tuple"); 665 return NULL; 666 } 667 if (keyw != NULL && !PyDict_Check(keyw)) { 668 PyErr_SetString(PyExc_TypeError, 669 "optional 3rd arg must be a dictionary"); 670 return NULL; 671 } 672 boot = PyMem_NEW(struct bootstate, 1); 673 if (boot == NULL) 674 return PyErr_NoMemory(); 675 boot->interp = PyThreadState_GET()->interp; 676 boot->func = func; 677 boot->args = args; 678 boot->keyw = keyw; 679 boot->tstate = _PyThreadState_Prealloc(boot->interp); 680 if (boot->tstate == NULL) { 681 PyMem_DEL(boot); 682 return PyErr_NoMemory(); 683 } 684 Py_INCREF(func); 685 Py_INCREF(args); 686 Py_XINCREF(keyw); 687 PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ 688 ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); 689 if (ident == -1) { 690 PyErr_SetString(ThreadError, "can't start new thread"); 691 Py_DECREF(func); 692 Py_DECREF(args); 693 Py_XDECREF(keyw); 694 PyThreadState_Clear(boot->tstate); 695 PyMem_DEL(boot); 696 return NULL; 697 } 698 return PyInt_FromLong(ident); 500 699 } 501 700 … … 514 713 thread_PyThread_exit_thread(PyObject *self) 515 714 { 516 517 715 PyErr_SetNone(PyExc_SystemExit); 716 return NULL; 518 717 } 519 718 520 719 PyDoc_STRVAR(exit_doc, 521 720 "exit()\n\ 522 ( PyThread_exit_thread() is an obsolete synonym)\n\721 (exit_thread() is an obsolete synonym)\n\ 523 722 \n\ 524 723 This is synonymous to ``raise SystemExit''. It will cause the current\n\ … … 528 727 thread_PyThread_interrupt_main(PyObject * self) 529 728 { 530 531 532 729 PyErr_SetInterrupt(); 730 Py_INCREF(Py_None); 731 return Py_None; 533 732 } 534 733 … … 540 739 ); 541 740 542 #ifndef NO_EXIT_PROG543 static PyObject *544 thread_PyThread_exit_prog(PyObject *self, PyObject *args)545 {546 int sts;547 if (!PyArg_ParseTuple(args, "i:exit_prog", &sts))548 return NULL;549 Py_Exit(sts); /* Calls PyThread_exit_prog(sts) or _PyThread_exit_prog(sts) */550 for (;;) { } /* Should not be reached */551 }552 #endif553 554 741 static lockobject *newlockobject(void); 555 742 … … 557 744 thread_PyThread_allocate_lock(PyObject *self) 558 745 { 559 746 return (PyObject *) newlockobject(); 560 747 } 561 748 … … 564 751 (allocate() is an obsolete synonym)\n\ 565 752 \n\ 566 Create a new lock object. See LockType.__doc__for information about locks.");753 Create a new lock object. See help(LockType) for information about locks."); 567 754 568 755 static PyObject * 569 756 thread_get_ident(PyObject *self) 570 757 { 571 572 573 574 575 576 577 758 long ident; 759 ident = PyThread_get_thread_ident(); 760 if (ident == -1) { 761 PyErr_SetString(ThreadError, "no current thread ident"); 762 return NULL; 763 } 764 return PyInt_FromLong(ident); 578 765 } 579 766 … … 590 777 591 778 static PyObject * 779 thread__count(PyObject *self) 780 { 781 return PyInt_FromLong(nb_threads); 782 } 783 784 PyDoc_STRVAR(_count_doc, 785 "_count() -> integer\n\ 786 \n\ 787 \ 788 Return the number of currently running Python threads, excluding \n\ 789 the main thread. The returned number comprises all threads created\n\ 790 through `start_new_thread()` as well as `threading.Thread`, and not\n\ 791 yet finished.\n\ 792 \n\ 793 This function is meant for internal and specialized purposes only.\n\ 794 In most applications `threading.enumerate()` should be used instead."); 795 796 static PyObject * 592 797 thread_stack_size(PyObject *self, PyObject *args) 593 798 { 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 799 size_t old_size; 800 Py_ssize_t new_size = 0; 801 int rc; 802 803 if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size)) 804 return NULL; 805 806 if (new_size < 0) { 807 PyErr_SetString(PyExc_ValueError, 808 "size must be 0 or a positive value"); 809 return NULL; 810 } 811 812 old_size = PyThread_get_stacksize(); 813 814 rc = PyThread_set_stacksize((size_t) new_size); 815 if (rc == -1) { 816 PyErr_Format(PyExc_ValueError, 817 "size not valid: %zd bytes", 818 new_size); 819 return NULL; 820 } 821 if (rc == -2) { 822 PyErr_SetString(ThreadError, 823 "setting stack size not supported"); 824 return NULL; 825 } 826 827 return PyInt_FromSsize_t((Py_ssize_t) old_size); 623 828 } 624 829 … … 644 849 645 850 static PyMethodDef thread_methods[] = { 646 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, 647 METH_VARARGS, 648 start_new_doc}, 649 {"start_new", (PyCFunction)thread_PyThread_start_new_thread, 650 METH_VARARGS, 651 start_new_doc}, 652 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock, 653 METH_NOARGS, allocate_doc}, 654 {"allocate", (PyCFunction)thread_PyThread_allocate_lock, 655 METH_NOARGS, allocate_doc}, 656 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread, 657 METH_NOARGS, exit_doc}, 658 {"exit", (PyCFunction)thread_PyThread_exit_thread, 659 METH_NOARGS, exit_doc}, 660 {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main, 661 METH_NOARGS, interrupt_doc}, 662 {"get_ident", (PyCFunction)thread_get_ident, 663 METH_NOARGS, get_ident_doc}, 664 {"stack_size", (PyCFunction)thread_stack_size, 665 METH_VARARGS, 666 stack_size_doc}, 667 #ifndef NO_EXIT_PROG 668 {"exit_prog", (PyCFunction)thread_PyThread_exit_prog, 669 METH_VARARGS}, 670 #endif 671 {NULL, NULL} /* sentinel */ 851 {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, 852 METH_VARARGS, 853 start_new_doc}, 854 {"start_new", (PyCFunction)thread_PyThread_start_new_thread, 855 METH_VARARGS, 856 start_new_doc}, 857 {"allocate_lock", (PyCFunction)thread_PyThread_allocate_lock, 858 METH_NOARGS, allocate_doc}, 859 {"allocate", (PyCFunction)thread_PyThread_allocate_lock, 860 METH_NOARGS, allocate_doc}, 861 {"exit_thread", (PyCFunction)thread_PyThread_exit_thread, 862 METH_NOARGS, exit_doc}, 863 {"exit", (PyCFunction)thread_PyThread_exit_thread, 864 METH_NOARGS, exit_doc}, 865 {"interrupt_main", (PyCFunction)thread_PyThread_interrupt_main, 866 METH_NOARGS, interrupt_doc}, 867 {"get_ident", (PyCFunction)thread_get_ident, 868 METH_NOARGS, get_ident_doc}, 869 {"_count", (PyCFunction)thread__count, 870 METH_NOARGS, _count_doc}, 871 {"stack_size", (PyCFunction)thread_stack_size, 872 METH_VARARGS, 873 stack_size_doc}, 874 {NULL, NULL} /* sentinel */ 672 875 }; 673 876 … … 694 897 initthread(void) 695 898 { 696 PyObject *m, *d; 697 698 /* Initialize types: */ 699 if (PyType_Ready(&localtype) < 0) 700 return; 701 702 /* Create the module and add the functions */ 703 m = Py_InitModule3("thread", thread_methods, thread_doc); 704 if (m == NULL) 705 return; 706 707 /* Add a symbolic constant */ 708 d = PyModule_GetDict(m); 709 ThreadError = PyErr_NewException("thread.error", NULL, NULL); 710 PyDict_SetItemString(d, "error", ThreadError); 711 Locktype.tp_doc = lock_doc; 712 Py_INCREF(&Locktype); 713 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); 714 715 Py_INCREF(&localtype); 716 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) 717 return; 718 719 /* Initialize the C thread library */ 720 PyThread_init_thread(); 721 } 899 PyObject *m, *d; 900 901 /* Initialize types: */ 902 if (PyType_Ready(&localdummytype) < 0) 903 return; 904 if (PyType_Ready(&localtype) < 0) 905 return; 906 907 /* Create the module and add the functions */ 908 m = Py_InitModule3("thread", thread_methods, thread_doc); 909 if (m == NULL) 910 return; 911 912 /* Add a symbolic constant */ 913 d = PyModule_GetDict(m); 914 ThreadError = PyErr_NewException("thread.error", NULL, NULL); 915 PyDict_SetItemString(d, "error", ThreadError); 916 Locktype.tp_doc = lock_doc; 917 if (PyType_Ready(&Locktype) < 0) 918 return; 919 Py_INCREF(&Locktype); 920 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); 921 922 Py_INCREF(&localtype); 923 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) 924 return; 925 926 nb_threads = 0; 927 928 str_dict = PyString_InternFromString("__dict__"); 929 if (str_dict == NULL) 930 return; 931 932 /* Initialize the C thread library */ 933 PyThread_init_thread(); 934 }
Note:
See TracChangeset
for help on using the changeset viewer.