| 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 #include "structmember.h" /* offsetof */ | 6 #include "structmember.h" /* offsetof */ |
| 7 | 7 |
| 8 #ifndef WITH_THREAD | 8 #ifndef WITH_THREAD |
| 9 #error "Error! The rest of Python is not compiled with thread support." | 9 #error "Error! The rest of Python is not compiled with thread support." |
| 10 #error "Rerun configure, adding a --with-threads option." | 10 #error "Rerun configure, adding a --with-threads option." |
| (...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 148 0, /*tp_doc*/ | 148 0, /*tp_doc*/ |
| 149 0, /*tp_traverse*/ | 149 0, /*tp_traverse*/ |
| 150 0, /*tp_clear*/ | 150 0, /*tp_clear*/ |
| 151 0, /*tp_richcompare*/ | 151 0, /*tp_richcompare*/ |
| 152 offsetof(lockobject, in_weakreflist), /*tp_weaklistoffset*/ | 152 offsetof(lockobject, in_weakreflist), /*tp_weaklistoffset*/ |
| 153 0, /*tp_iter*/ | 153 0, /*tp_iter*/ |
| 154 0, /*tp_iternext*/ | 154 0, /*tp_iternext*/ |
| 155 lock_methods, /*tp_methods*/ | 155 lock_methods, /*tp_methods*/ |
| 156 }; | 156 }; |
| 157 | 157 |
| 158 /* Recursive lock objects */ | |
| 159 | |
| 160 typedef struct { | |
| 161 PyObject_HEAD | |
| 162 PyThread_type_lock rlock_lock; | |
| 163 long rlock_owner; | |
| 164 unsigned long rlock_count; | |
| 165 PyObject *in_weakreflist; | |
| 166 } rlockobject; | |
| 167 | |
| 168 static void | |
| 169 rlock_dealloc(rlockobject *self) | |
| 170 { | |
| 171 assert(self->rlock_lock); | |
| 172 if (self->in_weakreflist != NULL) | |
| 173 PyObject_ClearWeakRefs((PyObject *) self); | |
| 174 /* Unlock the lock so it's safe to free it */ | |
| 175 if (self->rlock_count > 0) | |
| 176 PyThread_release_lock(self->rlock_lock); | |
| 177 | |
| 178 PyThread_free_lock(self->rlock_lock); | |
| 179 Py_TYPE(self)->tp_free(self); | |
| 180 } | |
| 181 | |
| 182 static PyObject * | |
| 183 rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) | |
| 184 { | |
| 185 char *kwlist[] = {"blocking", NULL}; | |
| 186 int blocking = 1; | |
| 187 long tid; | |
| 188 int r = 1; | |
| 189 | |
| 190 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:acquire", kwlist, | |
| 191 &blocking)) | |
| 192 return NULL; | |
| 193 | |
| 194 tid = PyThread_get_thread_ident(); | |
| 195 if (self->rlock_count > 0 && tid == self->rlock_owner) { | |
| 196 unsigned long count = self->rlock_count + 1; | |
| 197 if (count <= self->rlock_count) { | |
| 198 PyErr_SetString(PyExc_OverflowError, | |
| 199 "Internal lock count overflowed"); | |
| 200 return NULL; | |
| 201 } | |
| 202 self->rlock_count = count; | |
| 203 Py_RETURN_TRUE; | |
| 204 } | |
| 205 | |
| 206 if (self->rlock_count > 0 || | |
| 207 !PyThread_acquire_lock(self->rlock_lock, 0)) { | |
| 208 if (!blocking) { | |
| 209 Py_RETURN_FALSE; | |
| 210 } | |
| 211 Py_BEGIN_ALLOW_THREADS | |
| 212 r = PyThread_acquire_lock(self->rlock_lock, blocking); | |
| 213 Py_END_ALLOW_THREADS | |
| 214 } | |
| 215 if (r) { | |
| 216 assert(self->rlock_count == 0); | |
| 217 self->rlock_owner = tid; | |
| 218 self->rlock_count = 1; | |
| 219 } | |
| 220 | |
| 221 return PyBool_FromLong((long) r); | |
|
gregory.p.smith
2009/11/07 07:48:05
This explicit (long) cast is unnecessary.
Antoine Pitrou
2009/11/07 15:06:51
On 2009/11/07 07:48:05, gregory.p.smith wrote:
> T
| |
| 222 } | |
| 223 | |
| 224 PyDoc_STRVAR(rlock_acquire_doc, | |
| 225 "acquire([wait]) -> bool\n\ | |
| 226 \n\ | |
| 227 Lock the lock. Without argument, this blocks if the lock is locked\n\ | |
| 228 by another thread, waiting for another thread to release\n\ | |
| 229 the lock, and return None once the lock is acquired.\n\ | |
| 230 With an argument, this will only block if the argument is true,\n\ | |
| 231 and the return value reflects whether the lock is acquired.\n\ | |
| 232 The blocking operation is not interruptible."); | |
| 233 | |
| 234 static PyObject * | |
| 235 rlock_release(rlockobject *self) | |
| 236 { | |
| 237 long tid = PyThread_get_thread_ident(); | |
| 238 | |
| 239 if (self->rlock_count == 0 || self->rlock_owner != tid) { | |
| 240 PyErr_SetString(PyExc_RuntimeError, | |
| 241 "cannot release un-acquired lock"); | |
| 242 return NULL; | |
| 243 } | |
| 244 assert(self->rlock_count > 0); | |
| 245 if (--self->rlock_count == 0) { | |
| 246 PyThread_release_lock(self->rlock_lock); | |
|
gregory.p.smith
2009/11/07 07:48:05
reset self->rlock_owner to 0 before releasing the
Antoine Pitrou
2009/11/07 15:06:51
On 2009/11/07 07:48:05, gregory.p.smith wrote:
> r
| |
| 247 } | |
| 248 Py_RETURN_NONE; | |
| 249 } | |
| 250 | |
| 251 PyDoc_STRVAR(rlock_release_doc, | |
| 252 "release()\n\ | |
| 253 \n\ | |
| 254 Release the lock, allowing another thread that is blocked waiting for\n\ | |
| 255 the lock to acquire the lock. The lock must be in the locked state,\n\ | |
| 256 and must be locked by the same thread that unlocks it."); | |
| 257 | |
| 258 static PyObject * | |
| 259 rlock_acquire_restore(rlockobject *self, PyObject *arg) | |
| 260 { | |
| 261 long owner; | |
| 262 unsigned long count; | |
| 263 int r = 1; | |
| 264 | |
| 265 if (!PyArg_ParseTuple(arg, "kl:_acquire_restore", &count, &owner)) | |
| 266 return NULL; | |
| 267 | |
| 268 if (!PyThread_acquire_lock(self->rlock_lock, 0)) { | |
| 269 Py_BEGIN_ALLOW_THREADS | |
| 270 r = PyThread_acquire_lock(self->rlock_lock, 1); | |
| 271 Py_END_ALLOW_THREADS | |
| 272 } | |
| 273 if (!r) { | |
| 274 PyErr_SetString(ThreadError, "couldn't acquire lock"); | |
| 275 return NULL; | |
| 276 } | |
| 277 assert(self->rlock_count == 0); | |
| 278 self->rlock_owner = owner; | |
| 279 self->rlock_count = count; | |
| 280 Py_RETURN_NONE; | |
| 281 } | |
| 282 | |
| 283 PyDoc_STRVAR(rlock_acquire_restore_doc, | |
| 284 "_acquire_restore(state) -> None\n\ | |
| 285 \n\ | |
| 286 For internal use by `threading.Condition`."); | |
| 287 | |
| 288 static PyObject * | |
| 289 rlock_release_save(rlockobject *self) | |
| 290 { | |
| 291 long owner; | |
| 292 unsigned long count; | |
| 293 | |
| 294 owner = self->rlock_owner; | |
| 295 count = self->rlock_count; | |
| 296 self->rlock_count = 0; | |
| 297 PyThread_release_lock(self->rlock_lock); | |
| 298 return Py_BuildValue("kl", count, owner); | |
| 299 } | |
| 300 | |
| 301 PyDoc_STRVAR(rlock_release_save_doc, | |
| 302 "_release_save() -> tuple\n\ | |
| 303 \n\ | |
| 304 For internal use by `threading.Condition`."); | |
| 305 | |
| 306 | |
| 307 static PyObject * | |
| 308 rlock_is_owned(rlockobject *self) | |
| 309 { | |
| 310 long tid = PyThread_get_thread_ident(); | |
| 311 | |
| 312 if (self->rlock_count > 0 && self->rlock_owner == tid) { | |
| 313 Py_RETURN_TRUE; | |
| 314 } | |
| 315 Py_RETURN_FALSE; | |
| 316 } | |
| 317 | |
| 318 PyDoc_STRVAR(rlock_is_owned_doc, | |
| 319 "_is_owned() -> bool\n\ | |
| 320 \n\ | |
| 321 For internal use by `threading.Condition`."); | |
| 322 | |
| 323 static PyObject * | |
| 324 rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) | |
| 325 { | |
| 326 rlockobject *self; | |
| 327 | |
| 328 self = (rlockobject *) type->tp_alloc(type, 0); | |
| 329 if (self != NULL) { | |
| 330 self->rlock_lock = PyThread_allocate_lock(); | |
| 331 if (self->rlock_lock == NULL) { | |
| 332 Py_TYPE(self)->tp_free(self); | |
| 333 PyErr_SetString(ThreadError, "can't allocate lock"); | |
| 334 return NULL; | |
| 335 } | |
| 336 self->in_weakreflist = NULL; | |
| 337 self->rlock_owner = 0; | |
| 338 self->rlock_count = 0; | |
| 339 } | |
| 340 | |
| 341 return (PyObject *) self; | |
| 342 } | |
| 343 | |
| 344 static PyMethodDef rlock_methods[] = { | |
| 345 {"acquire", (PyCFunction)rlock_acquire, | |
| 346 METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, | |
| 347 {"release", (PyCFunction)rlock_release, | |
| 348 METH_NOARGS, rlock_release_doc}, | |
| 349 {"_is_owned", (PyCFunction)rlock_is_owned, | |
| 350 METH_NOARGS, rlock_is_owned_doc}, | |
| 351 {"_acquire_restore", (PyCFunction)rlock_acquire_restore, | |
| 352 METH_O, rlock_acquire_restore_doc}, | |
| 353 {"_release_save", (PyCFunction)rlock_release_save, | |
| 354 METH_NOARGS, rlock_release_save_doc}, | |
| 355 {"__enter__", (PyCFunction)rlock_acquire, | |
| 356 METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, | |
| 357 {"__exit__", (PyCFunction)rlock_release, | |
| 358 METH_VARARGS, rlock_release_doc}, | |
| 359 {NULL, NULL} /* sentinel */ | |
| 360 }; | |
| 361 | |
| 362 | |
| 363 static PyTypeObject RLocktype = { | |
| 364 PyVarObject_HEAD_INIT(&PyType_Type, 0) | |
| 365 "_thread.RLock", /*tp_name*/ | |
| 366 sizeof(rlockobject), /*tp_size*/ | |
| 367 0, /*tp_itemsize*/ | |
| 368 /* methods */ | |
| 369 (destructor)rlock_dealloc, /*tp_dealloc*/ | |
| 370 0, /*tp_print*/ | |
| 371 0, /*tp_getattr*/ | |
| 372 0, /*tp_setattr*/ | |
| 373 0, /*tp_reserved*/ | |
| 374 0, /*tp_repr*/ | |
| 375 0, /*tp_as_number*/ | |
| 376 0, /*tp_as_sequence*/ | |
| 377 0, /*tp_as_mapping*/ | |
| 378 0, /*tp_hash*/ | |
| 379 0, /*tp_call*/ | |
| 380 0, /*tp_str*/ | |
| 381 0, /*tp_getattro*/ | |
| 382 0, /*tp_setattro*/ | |
| 383 0, /*tp_as_buffer*/ | |
| 384 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ | |
| 385 0, /*tp_doc*/ | |
| 386 0, /*tp_traverse*/ | |
| 387 0, /*tp_clear*/ | |
| 388 0, /*tp_richcompare*/ | |
| 389 offsetof(rlockobject, in_weakreflist), /*tp_weaklistoffset*/ | |
| 390 0, /*tp_iter*/ | |
| 391 0, /*tp_iternext*/ | |
| 392 rlock_methods, /*tp_methods*/ | |
| 393 0, /* tp_members */ | |
| 394 0, /* tp_getset */ | |
| 395 0, /* tp_base */ | |
| 396 0, /* tp_dict */ | |
| 397 0, /* tp_descr_get */ | |
| 398 0, /* tp_descr_set */ | |
| 399 0, /* tp_dictoffset */ | |
| 400 0, /* tp_init */ | |
| 401 PyType_GenericAlloc, /* tp_alloc */ | |
| 402 rlock_new /* tp_new */ | |
| 403 }; | |
| 404 | |
| 158 static lockobject * | 405 static lockobject * |
| 159 newlockobject(void) | 406 newlockobject(void) |
| 160 { | 407 { |
| 161 lockobject *self; | 408 lockobject *self; |
| 162 self = PyObject_New(lockobject, &Locktype); | 409 self = PyObject_New(lockobject, &Locktype); |
| 163 if (self == NULL) | 410 if (self == NULL) |
| 164 return NULL; | 411 return NULL; |
| 165 self->lock_lock = PyThread_allocate_lock(); | 412 self->lock_lock = PyThread_allocate_lock(); |
| 166 self->in_weakreflist = NULL; | 413 self->in_weakreflist = NULL; |
| 167 if (self->lock_lock == NULL) { | 414 if (self->lock_lock == NULL) { |
| (...skipping 576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 744 | 991 |
| 745 PyMODINIT_FUNC | 992 PyMODINIT_FUNC |
| 746 PyInit__thread(void) | 993 PyInit__thread(void) |
| 747 { | 994 { |
| 748 PyObject *m, *d; | 995 PyObject *m, *d; |
| 749 | 996 |
| 750 /* Initialize types: */ | 997 /* Initialize types: */ |
| 751 if (PyType_Ready(&localtype) < 0) | 998 if (PyType_Ready(&localtype) < 0) |
| 752 return NULL; | 999 return NULL; |
| 753 if (PyType_Ready(&Locktype) < 0) | 1000 if (PyType_Ready(&Locktype) < 0) |
| 1001 return NULL; | |
| 1002 if (PyType_Ready(&RLocktype) < 0) | |
| 754 return NULL; | 1003 return NULL; |
| 755 | 1004 |
| 756 /* Create the module and add the functions */ | 1005 /* Create the module and add the functions */ |
| 757 m = PyModule_Create(&threadmodule); | 1006 m = PyModule_Create(&threadmodule); |
| 758 if (m == NULL) | 1007 if (m == NULL) |
| 759 return NULL; | 1008 return NULL; |
| 760 | 1009 |
| 761 /* Add a symbolic constant */ | 1010 /* Add a symbolic constant */ |
| 762 d = PyModule_GetDict(m); | 1011 d = PyModule_GetDict(m); |
| 763 ThreadError = PyErr_NewException("_thread.error", NULL, NULL); | 1012 ThreadError = PyErr_NewException("_thread.error", NULL, NULL); |
| 764 PyDict_SetItemString(d, "error", ThreadError); | 1013 PyDict_SetItemString(d, "error", ThreadError); |
| 765 Locktype.tp_doc = lock_doc; | 1014 Locktype.tp_doc = lock_doc; |
| 766 Py_INCREF(&Locktype); | 1015 Py_INCREF(&Locktype); |
| 767 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); | 1016 PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); |
| 1017 | |
| 1018 Py_INCREF(&RLocktype); | |
| 1019 if (PyModule_AddObject(m, "RLock", (PyObject *)&RLocktype) < 0) | |
| 1020 return NULL; | |
| 768 | 1021 |
| 769 Py_INCREF(&localtype); | 1022 Py_INCREF(&localtype); |
| 770 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) | 1023 if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) |
| 771 return NULL; | 1024 return NULL; |
| 772 | 1025 |
| 773 nb_threads = 0; | 1026 nb_threads = 0; |
| 774 | 1027 |
| 775 /* Initialize the C thread library */ | 1028 /* Initialize the C thread library */ |
| 776 PyThread_init_thread(); | 1029 PyThread_init_thread(); |
| 777 return m; | 1030 return m; |
| 778 } | 1031 } |
| OLD | NEW |