/src/Python-3.8.3/Modules/_threadmodule.c
Line | Count | Source (jump to first uncovered line) |
1 | | |
2 | | /* Thread module */ |
3 | | /* Interface to Sjoerd's portable C thread library */ |
4 | | |
5 | | #include "Python.h" |
6 | | #include "pycore_pylifecycle.h" |
7 | | #include "pycore_pystate.h" |
8 | | #include "structmember.h" /* offsetof */ |
9 | | #include "pythread.h" |
10 | | |
11 | | static PyObject *ThreadError; |
12 | | static PyObject *str_dict; |
13 | | |
14 | | _Py_IDENTIFIER(stderr); |
15 | | _Py_IDENTIFIER(flush); |
16 | | |
17 | | /* Lock objects */ |
18 | | |
19 | | typedef struct { |
20 | | PyObject_HEAD |
21 | | PyThread_type_lock lock_lock; |
22 | | PyObject *in_weakreflist; |
23 | | char locked; /* for sanity checking */ |
24 | | } lockobject; |
25 | | |
26 | | static void |
27 | | lock_dealloc(lockobject *self) |
28 | 724 | { |
29 | 724 | if (self->in_weakreflist != NULL) |
30 | 0 | PyObject_ClearWeakRefs((PyObject *) self); |
31 | 724 | if (self->lock_lock != NULL) { |
32 | | /* Unlock the lock so it's safe to free it */ |
33 | 724 | if (self->locked) |
34 | 0 | PyThread_release_lock(self->lock_lock); |
35 | 724 | PyThread_free_lock(self->lock_lock); |
36 | 724 | } |
37 | 724 | PyObject_Del(self); |
38 | 724 | } |
39 | | |
40 | | /* Helper to acquire an interruptible lock with a timeout. If the lock acquire |
41 | | * is interrupted, signal handlers are run, and if they raise an exception, |
42 | | * PY_LOCK_INTR is returned. Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE |
43 | | * are returned, depending on whether the lock can be acquired within the |
44 | | * timeout. |
45 | | */ |
46 | | static PyLockStatus |
47 | | acquire_timed(PyThread_type_lock lock, _PyTime_t timeout) |
48 | 859 | { |
49 | 859 | PyLockStatus r; |
50 | 859 | _PyTime_t endtime = 0; |
51 | 859 | _PyTime_t microseconds; |
52 | | |
53 | 859 | if (timeout > 0) |
54 | 0 | endtime = _PyTime_GetMonotonicClock() + timeout; |
55 | | |
56 | 859 | do { |
57 | 859 | microseconds = _PyTime_AsMicroseconds(timeout, _PyTime_ROUND_CEILING); |
58 | | |
59 | | /* first a simple non-blocking try without releasing the GIL */ |
60 | 859 | r = PyThread_acquire_lock_timed(lock, 0, 0); |
61 | 859 | if (r == PY_LOCK_FAILURE && microseconds != 0) { |
62 | 0 | Py_BEGIN_ALLOW_THREADS |
63 | 0 | r = PyThread_acquire_lock_timed(lock, microseconds, 1); |
64 | 0 | Py_END_ALLOW_THREADS |
65 | 0 | } |
66 | | |
67 | 859 | if (r == PY_LOCK_INTR) { |
68 | | /* Run signal handlers if we were interrupted. Propagate |
69 | | * exceptions from signal handlers, such as KeyboardInterrupt, by |
70 | | * passing up PY_LOCK_INTR. */ |
71 | 0 | if (Py_MakePendingCalls() < 0) { |
72 | 0 | return PY_LOCK_INTR; |
73 | 0 | } |
74 | | |
75 | | /* If we're using a timeout, recompute the timeout after processing |
76 | | * signals, since those can take time. */ |
77 | 0 | if (timeout > 0) { |
78 | 0 | timeout = endtime - _PyTime_GetMonotonicClock(); |
79 | | |
80 | | /* Check for negative values, since those mean block forever. |
81 | | */ |
82 | 0 | if (timeout < 0) { |
83 | 0 | r = PY_LOCK_FAILURE; |
84 | 0 | } |
85 | 0 | } |
86 | 0 | } |
87 | 859 | } while (r == PY_LOCK_INTR); /* Retry if we were interrupted. */ |
88 | | |
89 | 859 | return r; |
90 | 859 | } |
91 | | |
92 | | static int |
93 | | lock_acquire_parse_args(PyObject *args, PyObject *kwds, |
94 | | _PyTime_t *timeout) |
95 | 876 | { |
96 | 876 | char *kwlist[] = {"blocking", "timeout", NULL}; |
97 | 876 | int blocking = 1; |
98 | 876 | PyObject *timeout_obj = NULL; |
99 | 876 | const _PyTime_t unset_timeout = _PyTime_FromSeconds(-1); |
100 | | |
101 | 876 | *timeout = unset_timeout ; |
102 | | |
103 | 876 | if (!PyArg_ParseTupleAndKeywords(args, kwds, "|iO:acquire", kwlist, |
104 | 876 | &blocking, &timeout_obj)) |
105 | 0 | return -1; |
106 | | |
107 | 876 | if (timeout_obj |
108 | 876 | && _PyTime_FromSecondsObject(timeout, |
109 | 0 | timeout_obj, _PyTime_ROUND_TIMEOUT) < 0) |
110 | 0 | return -1; |
111 | | |
112 | 876 | if (!blocking && *timeout != unset_timeout ) { |
113 | 0 | PyErr_SetString(PyExc_ValueError, |
114 | 0 | "can't specify a timeout for a non-blocking call"); |
115 | 0 | return -1; |
116 | 0 | } |
117 | 876 | if (*timeout < 0 && *timeout != unset_timeout) { |
118 | 0 | PyErr_SetString(PyExc_ValueError, |
119 | 0 | "timeout value must be positive"); |
120 | 0 | return -1; |
121 | 0 | } |
122 | 876 | if (!blocking) |
123 | 1 | *timeout = 0; |
124 | 875 | else if (*timeout != unset_timeout) { |
125 | 0 | _PyTime_t microseconds; |
126 | |
|
127 | 0 | microseconds = _PyTime_AsMicroseconds(*timeout, _PyTime_ROUND_TIMEOUT); |
128 | 0 | if (microseconds >= PY_TIMEOUT_MAX) { |
129 | 0 | PyErr_SetString(PyExc_OverflowError, |
130 | 0 | "timeout value is too large"); |
131 | 0 | return -1; |
132 | 0 | } |
133 | 0 | } |
134 | 876 | return 0; |
135 | 876 | } |
136 | | |
137 | | static PyObject * |
138 | | lock_PyThread_acquire_lock(lockobject *self, PyObject *args, PyObject *kwds) |
139 | 841 | { |
140 | 841 | _PyTime_t timeout; |
141 | 841 | PyLockStatus r; |
142 | | |
143 | 841 | if (lock_acquire_parse_args(args, kwds, &timeout) < 0) |
144 | 0 | return NULL; |
145 | | |
146 | 841 | r = acquire_timed(self->lock_lock, timeout); |
147 | 841 | if (r == PY_LOCK_INTR) { |
148 | 0 | return NULL; |
149 | 0 | } |
150 | | |
151 | 841 | if (r == PY_LOCK_ACQUIRED) |
152 | 840 | self->locked = 1; |
153 | 841 | return PyBool_FromLong(r == PY_LOCK_ACQUIRED); |
154 | 841 | } |
155 | | |
156 | | PyDoc_STRVAR(acquire_doc, |
157 | | "acquire(blocking=True, timeout=-1) -> bool\n\ |
158 | | (acquire_lock() is an obsolete synonym)\n\ |
159 | | \n\ |
160 | | Lock the lock. Without argument, this blocks if the lock is already\n\ |
161 | | locked (even by the same thread), waiting for another thread to release\n\ |
162 | | the lock, and return True once the lock is acquired.\n\ |
163 | | With an argument, this will only block if the argument is true,\n\ |
164 | | and the return value reflects whether the lock is acquired.\n\ |
165 | | The blocking operation is interruptible."); |
166 | | |
167 | | static PyObject * |
168 | | lock_PyThread_release_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) |
169 | 839 | { |
170 | | /* Sanity check: the lock must be locked */ |
171 | 839 | if (!self->locked) { |
172 | 0 | PyErr_SetString(ThreadError, "release unlocked lock"); |
173 | 0 | return NULL; |
174 | 0 | } |
175 | | |
176 | 839 | PyThread_release_lock(self->lock_lock); |
177 | 839 | self->locked = 0; |
178 | 839 | Py_RETURN_NONE; |
179 | 839 | } |
180 | | |
181 | | PyDoc_STRVAR(release_doc, |
182 | | "release()\n\ |
183 | | (release_lock() is an obsolete synonym)\n\ |
184 | | \n\ |
185 | | Release the lock, allowing another thread that is blocked waiting for\n\ |
186 | | the lock to acquire the lock. The lock must be in the locked state,\n\ |
187 | | but it needn't be locked by the same thread that unlocks it."); |
188 | | |
189 | | static PyObject * |
190 | | lock_locked_lock(lockobject *self, PyObject *Py_UNUSED(ignored)) |
191 | 0 | { |
192 | 0 | return PyBool_FromLong((long)self->locked); |
193 | 0 | } |
194 | | |
195 | | PyDoc_STRVAR(locked_doc, |
196 | | "locked() -> bool\n\ |
197 | | (locked_lock() is an obsolete synonym)\n\ |
198 | | \n\ |
199 | | Return whether the lock is in the locked state."); |
200 | | |
201 | | static PyObject * |
202 | | lock_repr(lockobject *self) |
203 | 0 | { |
204 | 0 | return PyUnicode_FromFormat("<%s %s object at %p>", |
205 | 0 | self->locked ? "locked" : "unlocked", Py_TYPE(self)->tp_name, self); |
206 | 0 | } |
207 | | |
208 | | static PyMethodDef lock_methods[] = { |
209 | | {"acquire_lock", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, |
210 | | METH_VARARGS | METH_KEYWORDS, acquire_doc}, |
211 | | {"acquire", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, |
212 | | METH_VARARGS | METH_KEYWORDS, acquire_doc}, |
213 | | {"release_lock", (PyCFunction)lock_PyThread_release_lock, |
214 | | METH_NOARGS, release_doc}, |
215 | | {"release", (PyCFunction)lock_PyThread_release_lock, |
216 | | METH_NOARGS, release_doc}, |
217 | | {"locked_lock", (PyCFunction)lock_locked_lock, |
218 | | METH_NOARGS, locked_doc}, |
219 | | {"locked", (PyCFunction)lock_locked_lock, |
220 | | METH_NOARGS, locked_doc}, |
221 | | {"__enter__", (PyCFunction)(void(*)(void))lock_PyThread_acquire_lock, |
222 | | METH_VARARGS | METH_KEYWORDS, acquire_doc}, |
223 | | {"__exit__", (PyCFunction)lock_PyThread_release_lock, |
224 | | METH_VARARGS, release_doc}, |
225 | | {NULL, NULL} /* sentinel */ |
226 | | }; |
227 | | |
228 | | static PyTypeObject Locktype = { |
229 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
230 | | "_thread.lock", /*tp_name*/ |
231 | | sizeof(lockobject), /*tp_basicsize*/ |
232 | | 0, /*tp_itemsize*/ |
233 | | /* methods */ |
234 | | (destructor)lock_dealloc, /*tp_dealloc*/ |
235 | | 0, /*tp_vectorcall_offset*/ |
236 | | 0, /*tp_getattr*/ |
237 | | 0, /*tp_setattr*/ |
238 | | 0, /*tp_as_async*/ |
239 | | (reprfunc)lock_repr, /*tp_repr*/ |
240 | | 0, /*tp_as_number*/ |
241 | | 0, /*tp_as_sequence*/ |
242 | | 0, /*tp_as_mapping*/ |
243 | | 0, /*tp_hash*/ |
244 | | 0, /*tp_call*/ |
245 | | 0, /*tp_str*/ |
246 | | 0, /*tp_getattro*/ |
247 | | 0, /*tp_setattro*/ |
248 | | 0, /*tp_as_buffer*/ |
249 | | Py_TPFLAGS_DEFAULT, /*tp_flags*/ |
250 | | 0, /*tp_doc*/ |
251 | | 0, /*tp_traverse*/ |
252 | | 0, /*tp_clear*/ |
253 | | 0, /*tp_richcompare*/ |
254 | | offsetof(lockobject, in_weakreflist), /*tp_weaklistoffset*/ |
255 | | 0, /*tp_iter*/ |
256 | | 0, /*tp_iternext*/ |
257 | | lock_methods, /*tp_methods*/ |
258 | | }; |
259 | | |
260 | | /* Recursive lock objects */ |
261 | | |
262 | | typedef struct { |
263 | | PyObject_HEAD |
264 | | PyThread_type_lock rlock_lock; |
265 | | unsigned long rlock_owner; |
266 | | unsigned long rlock_count; |
267 | | PyObject *in_weakreflist; |
268 | | } rlockobject; |
269 | | |
270 | | static void |
271 | | rlock_dealloc(rlockobject *self) |
272 | 0 | { |
273 | 0 | if (self->in_weakreflist != NULL) |
274 | 0 | PyObject_ClearWeakRefs((PyObject *) self); |
275 | | /* self->rlock_lock can be NULL if PyThread_allocate_lock() failed |
276 | | in rlock_new() */ |
277 | 0 | if (self->rlock_lock != NULL) { |
278 | | /* Unlock the lock so it's safe to free it */ |
279 | 0 | if (self->rlock_count > 0) |
280 | 0 | PyThread_release_lock(self->rlock_lock); |
281 | |
|
282 | 0 | PyThread_free_lock(self->rlock_lock); |
283 | 0 | } |
284 | 0 | Py_TYPE(self)->tp_free(self); |
285 | 0 | } |
286 | | |
287 | | static PyObject * |
288 | | rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds) |
289 | 35 | { |
290 | 35 | _PyTime_t timeout; |
291 | 35 | unsigned long tid; |
292 | 35 | PyLockStatus r = PY_LOCK_ACQUIRED; |
293 | | |
294 | 35 | if (lock_acquire_parse_args(args, kwds, &timeout) < 0) |
295 | 0 | return NULL; |
296 | | |
297 | 35 | tid = PyThread_get_thread_ident(); |
298 | 35 | if (self->rlock_count > 0 && tid == self->rlock_owner) { |
299 | 17 | unsigned long count = self->rlock_count + 1; |
300 | 17 | if (count <= self->rlock_count) { |
301 | 0 | PyErr_SetString(PyExc_OverflowError, |
302 | 0 | "Internal lock count overflowed"); |
303 | 0 | return NULL; |
304 | 0 | } |
305 | 17 | self->rlock_count = count; |
306 | 17 | Py_RETURN_TRUE; |
307 | 17 | } |
308 | 18 | r = acquire_timed(self->rlock_lock, timeout); |
309 | 18 | if (r == PY_LOCK_ACQUIRED) { |
310 | 18 | assert(self->rlock_count == 0); |
311 | 18 | self->rlock_owner = tid; |
312 | 18 | self->rlock_count = 1; |
313 | 18 | } |
314 | 0 | else if (r == PY_LOCK_INTR) { |
315 | 0 | return NULL; |
316 | 0 | } |
317 | | |
318 | 18 | return PyBool_FromLong(r == PY_LOCK_ACQUIRED); |
319 | 18 | } |
320 | | |
321 | | PyDoc_STRVAR(rlock_acquire_doc, |
322 | | "acquire(blocking=True) -> bool\n\ |
323 | | \n\ |
324 | | Lock the lock. `blocking` indicates whether we should wait\n\ |
325 | | for the lock to be available or not. If `blocking` is False\n\ |
326 | | and another thread holds the lock, the method will return False\n\ |
327 | | immediately. If `blocking` is True and another thread holds\n\ |
328 | | the lock, the method will wait for the lock to be released,\n\ |
329 | | take it and then return True.\n\ |
330 | | (note: the blocking operation is interruptible.)\n\ |
331 | | \n\ |
332 | | In all other cases, the method will return True immediately.\n\ |
333 | | Precisely, if the current thread already holds the lock, its\n\ |
334 | | internal counter is simply incremented. If nobody holds the lock,\n\ |
335 | | the lock is taken and its internal counter initialized to 1."); |
336 | | |
337 | | static PyObject * |
338 | | rlock_release(rlockobject *self, PyObject *Py_UNUSED(ignored)) |
339 | 35 | { |
340 | 35 | unsigned long tid = PyThread_get_thread_ident(); |
341 | | |
342 | 35 | if (self->rlock_count == 0 || self->rlock_owner != tid) { |
343 | 0 | PyErr_SetString(PyExc_RuntimeError, |
344 | 0 | "cannot release un-acquired lock"); |
345 | 0 | return NULL; |
346 | 0 | } |
347 | 35 | if (--self->rlock_count == 0) { |
348 | 18 | self->rlock_owner = 0; |
349 | 18 | PyThread_release_lock(self->rlock_lock); |
350 | 18 | } |
351 | 35 | Py_RETURN_NONE; |
352 | 35 | } |
353 | | |
354 | | PyDoc_STRVAR(rlock_release_doc, |
355 | | "release()\n\ |
356 | | \n\ |
357 | | Release the lock, allowing another thread that is blocked waiting for\n\ |
358 | | the lock to acquire the lock. The lock must be in the locked state,\n\ |
359 | | and must be locked by the same thread that unlocks it; otherwise a\n\ |
360 | | `RuntimeError` is raised.\n\ |
361 | | \n\ |
362 | | Do note that if the lock was acquire()d several times in a row by the\n\ |
363 | | current thread, release() needs to be called as many times for the lock\n\ |
364 | | to be available for other threads."); |
365 | | |
366 | | static PyObject * |
367 | | rlock_acquire_restore(rlockobject *self, PyObject *args) |
368 | 0 | { |
369 | 0 | unsigned long owner; |
370 | 0 | unsigned long count; |
371 | 0 | int r = 1; |
372 | |
|
373 | 0 | if (!PyArg_ParseTuple(args, "(kk):_acquire_restore", &count, &owner)) |
374 | 0 | return NULL; |
375 | | |
376 | 0 | if (!PyThread_acquire_lock(self->rlock_lock, 0)) { |
377 | 0 | Py_BEGIN_ALLOW_THREADS |
378 | 0 | r = PyThread_acquire_lock(self->rlock_lock, 1); |
379 | 0 | Py_END_ALLOW_THREADS |
380 | 0 | } |
381 | 0 | if (!r) { |
382 | 0 | PyErr_SetString(ThreadError, "couldn't acquire lock"); |
383 | 0 | return NULL; |
384 | 0 | } |
385 | 0 | assert(self->rlock_count == 0); |
386 | 0 | self->rlock_owner = owner; |
387 | 0 | self->rlock_count = count; |
388 | 0 | Py_RETURN_NONE; |
389 | 0 | } |
390 | | |
391 | | PyDoc_STRVAR(rlock_acquire_restore_doc, |
392 | | "_acquire_restore(state) -> None\n\ |
393 | | \n\ |
394 | | For internal use by `threading.Condition`."); |
395 | | |
396 | | static PyObject * |
397 | | rlock_release_save(rlockobject *self, PyObject *Py_UNUSED(ignored)) |
398 | 0 | { |
399 | 0 | unsigned long owner; |
400 | 0 | unsigned long count; |
401 | |
|
402 | 0 | if (self->rlock_count == 0) { |
403 | 0 | PyErr_SetString(PyExc_RuntimeError, |
404 | 0 | "cannot release un-acquired lock"); |
405 | 0 | return NULL; |
406 | 0 | } |
407 | | |
408 | 0 | owner = self->rlock_owner; |
409 | 0 | count = self->rlock_count; |
410 | 0 | self->rlock_count = 0; |
411 | 0 | self->rlock_owner = 0; |
412 | 0 | PyThread_release_lock(self->rlock_lock); |
413 | 0 | return Py_BuildValue("kk", count, owner); |
414 | 0 | } |
415 | | |
416 | | PyDoc_STRVAR(rlock_release_save_doc, |
417 | | "_release_save() -> tuple\n\ |
418 | | \n\ |
419 | | For internal use by `threading.Condition`."); |
420 | | |
421 | | |
422 | | static PyObject * |
423 | | rlock_is_owned(rlockobject *self, PyObject *Py_UNUSED(ignored)) |
424 | 0 | { |
425 | 0 | unsigned long tid = PyThread_get_thread_ident(); |
426 | |
|
427 | 0 | if (self->rlock_count > 0 && self->rlock_owner == tid) { |
428 | 0 | Py_RETURN_TRUE; |
429 | 0 | } |
430 | 0 | Py_RETURN_FALSE; |
431 | 0 | } |
432 | | |
433 | | PyDoc_STRVAR(rlock_is_owned_doc, |
434 | | "_is_owned() -> bool\n\ |
435 | | \n\ |
436 | | For internal use by `threading.Condition`."); |
437 | | |
438 | | static PyObject * |
439 | | rlock_new(PyTypeObject *type, PyObject *args, PyObject *kwds) |
440 | 3 | { |
441 | 3 | rlockobject *self; |
442 | | |
443 | 3 | self = (rlockobject *) type->tp_alloc(type, 0); |
444 | 3 | if (self != NULL) { |
445 | 3 | self->in_weakreflist = NULL; |
446 | 3 | self->rlock_owner = 0; |
447 | 3 | self->rlock_count = 0; |
448 | | |
449 | 3 | self->rlock_lock = PyThread_allocate_lock(); |
450 | 3 | if (self->rlock_lock == NULL) { |
451 | 0 | Py_DECREF(self); |
452 | 0 | PyErr_SetString(ThreadError, "can't allocate lock"); |
453 | 0 | return NULL; |
454 | 0 | } |
455 | 3 | } |
456 | | |
457 | 3 | return (PyObject *) self; |
458 | 3 | } |
459 | | |
460 | | static PyObject * |
461 | | rlock_repr(rlockobject *self) |
462 | 0 | { |
463 | 0 | return PyUnicode_FromFormat("<%s %s object owner=%ld count=%lu at %p>", |
464 | 0 | self->rlock_count ? "locked" : "unlocked", |
465 | 0 | Py_TYPE(self)->tp_name, self->rlock_owner, |
466 | 0 | self->rlock_count, self); |
467 | 0 | } |
468 | | |
469 | | |
470 | | static PyMethodDef rlock_methods[] = { |
471 | | {"acquire", (PyCFunction)(void(*)(void))rlock_acquire, |
472 | | METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, |
473 | | {"release", (PyCFunction)rlock_release, |
474 | | METH_NOARGS, rlock_release_doc}, |
475 | | {"_is_owned", (PyCFunction)rlock_is_owned, |
476 | | METH_NOARGS, rlock_is_owned_doc}, |
477 | | {"_acquire_restore", (PyCFunction)rlock_acquire_restore, |
478 | | METH_VARARGS, rlock_acquire_restore_doc}, |
479 | | {"_release_save", (PyCFunction)rlock_release_save, |
480 | | METH_NOARGS, rlock_release_save_doc}, |
481 | | {"__enter__", (PyCFunction)(void(*)(void))rlock_acquire, |
482 | | METH_VARARGS | METH_KEYWORDS, rlock_acquire_doc}, |
483 | | {"__exit__", (PyCFunction)rlock_release, |
484 | | METH_VARARGS, rlock_release_doc}, |
485 | | {NULL, NULL} /* sentinel */ |
486 | | }; |
487 | | |
488 | | |
489 | | static PyTypeObject RLocktype = { |
490 | | PyVarObject_HEAD_INIT(&PyType_Type, 0) |
491 | | "_thread.RLock", /*tp_name*/ |
492 | | sizeof(rlockobject), /*tp_basicsize*/ |
493 | | 0, /*tp_itemsize*/ |
494 | | /* methods */ |
495 | | (destructor)rlock_dealloc, /*tp_dealloc*/ |
496 | | 0, /*tp_vectorcall_offset*/ |
497 | | 0, /*tp_getattr*/ |
498 | | 0, /*tp_setattr*/ |
499 | | 0, /*tp_as_async*/ |
500 | | (reprfunc)rlock_repr, /*tp_repr*/ |
501 | | 0, /*tp_as_number*/ |
502 | | 0, /*tp_as_sequence*/ |
503 | | 0, /*tp_as_mapping*/ |
504 | | 0, /*tp_hash*/ |
505 | | 0, /*tp_call*/ |
506 | | 0, /*tp_str*/ |
507 | | 0, /*tp_getattro*/ |
508 | | 0, /*tp_setattro*/ |
509 | | 0, /*tp_as_buffer*/ |
510 | | Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ |
511 | | 0, /*tp_doc*/ |
512 | | 0, /*tp_traverse*/ |
513 | | 0, /*tp_clear*/ |
514 | | 0, /*tp_richcompare*/ |
515 | | offsetof(rlockobject, in_weakreflist), /*tp_weaklistoffset*/ |
516 | | 0, /*tp_iter*/ |
517 | | 0, /*tp_iternext*/ |
518 | | rlock_methods, /*tp_methods*/ |
519 | | 0, /* tp_members */ |
520 | | 0, /* tp_getset */ |
521 | | 0, /* tp_base */ |
522 | | 0, /* tp_dict */ |
523 | | 0, /* tp_descr_get */ |
524 | | 0, /* tp_descr_set */ |
525 | | 0, /* tp_dictoffset */ |
526 | | 0, /* tp_init */ |
527 | | PyType_GenericAlloc, /* tp_alloc */ |
528 | | rlock_new /* tp_new */ |
529 | | }; |
530 | | |
531 | | static lockobject * |
532 | | newlockobject(void) |
533 | 728 | { |
534 | 728 | lockobject *self; |
535 | 728 | self = PyObject_New(lockobject, &Locktype); |
536 | 728 | if (self == NULL) |
537 | 0 | return NULL; |
538 | 728 | self->lock_lock = PyThread_allocate_lock(); |
539 | 728 | self->locked = 0; |
540 | 728 | self->in_weakreflist = NULL; |
541 | 728 | if (self->lock_lock == NULL) { |
542 | 0 | Py_DECREF(self); |
543 | 0 | PyErr_SetString(ThreadError, "can't allocate lock"); |
544 | 0 | return NULL; |
545 | 0 | } |
546 | 728 | return self; |
547 | 728 | } |
548 | | |
549 | | /* Thread-local objects */ |
550 | | |
551 | | #include "structmember.h" |
552 | | |
553 | | /* Quick overview: |
554 | | |
555 | | We need to be able to reclaim reference cycles as soon as possible |
556 | | (both when a thread is being terminated, or a thread-local object |
557 | | becomes unreachable from user data). Constraints: |
558 | | - it must not be possible for thread-state dicts to be involved in |
559 | | reference cycles (otherwise the cyclic GC will refuse to consider |
560 | | objects referenced from a reachable thread-state dict, even though |
561 | | local_dealloc would clear them) |
562 | | - the death of a thread-state dict must still imply destruction of the |
563 | | corresponding local dicts in all thread-local objects. |
564 | | |
565 | | Our implementation uses small "localdummy" objects in order to break |
566 | | the reference chain. These trivial objects are hashable (using the |
567 | | default scheme of identity hashing) and weakrefable. |
568 | | Each thread-state holds a separate localdummy for each local object |
569 | | (as a /strong reference/), |
570 | | and each thread-local object holds a dict mapping /weak references/ |
571 | | of localdummies to local dicts. |
572 | | |
573 | | Therefore: |
574 | | - only the thread-state dict holds a strong reference to the dummies |
575 | | - only the thread-local object holds a strong reference to the local dicts |
576 | | - only outside objects (application- or library-level) hold strong |
577 | | references to the thread-local objects |
578 | | - as soon as a thread-state dict is destroyed, the weakref callbacks of all |
579 | | dummies attached to that thread are called, and destroy the corresponding |
580 | | local dicts from thread-local objects |
581 | | - as soon as a thread-local object is destroyed, its local dicts are |
582 | | destroyed and its dummies are manually removed from all thread states |
583 | | - the GC can do its work correctly when a thread-local object is dangling, |
584 | | without any interference from the thread-state dicts |
585 | | |
586 | | As an additional optimization, each localdummy holds a borrowed reference |
587 | | to the corresponding localdict. This borrowed reference is only used |
588 | | by the thread-local object which has created the localdummy, which should |
589 | | guarantee that the localdict still exists when accessed. |
590 | | */ |
591 | | |
592 | | typedef struct { |
593 | | PyObject_HEAD |
594 | | PyObject *localdict; /* Borrowed reference! */ |
595 | | PyObject *weakreflist; /* List of weak references to self */ |
596 | | } localdummyobject; |
597 | | |
598 | | static void |
599 | | localdummy_dealloc(localdummyobject *self) |
600 | 0 | { |
601 | 0 | if (self->weakreflist != NULL) |
602 | 0 | PyObject_ClearWeakRefs((PyObject *) self); |
603 | 0 | Py_TYPE(self)->tp_free((PyObject*)self); |
604 | 0 | } |
605 | | |
606 | | static PyTypeObject localdummytype = { |
607 | | PyVarObject_HEAD_INIT(NULL, 0) |
608 | | /* tp_name */ "_thread._localdummy", |
609 | | /* tp_basicsize */ sizeof(localdummyobject), |
610 | | /* tp_itemsize */ 0, |
611 | | /* tp_dealloc */ (destructor)localdummy_dealloc, |
612 | | /* tp_vectorcall_offset */ 0, |
613 | | /* tp_getattr */ 0, |
614 | | /* tp_setattr */ 0, |
615 | | /* tp_as_async */ 0, |
616 | | /* tp_repr */ 0, |
617 | | /* tp_as_number */ 0, |
618 | | /* tp_as_sequence */ 0, |
619 | | /* tp_as_mapping */ 0, |
620 | | /* tp_hash */ 0, |
621 | | /* tp_call */ 0, |
622 | | /* tp_str */ 0, |
623 | | /* tp_getattro */ 0, |
624 | | /* tp_setattro */ 0, |
625 | | /* tp_as_buffer */ 0, |
626 | | /* tp_flags */ Py_TPFLAGS_DEFAULT, |
627 | | /* tp_doc */ "Thread-local dummy", |
628 | | /* tp_traverse */ 0, |
629 | | /* tp_clear */ 0, |
630 | | /* tp_richcompare */ 0, |
631 | | /* tp_weaklistoffset */ offsetof(localdummyobject, weakreflist) |
632 | | }; |
633 | | |
634 | | |
635 | | typedef struct { |
636 | | PyObject_HEAD |
637 | | PyObject *key; |
638 | | PyObject *args; |
639 | | PyObject *kw; |
640 | | PyObject *weakreflist; /* List of weak references to self */ |
641 | | /* A {localdummy weakref -> localdict} dict */ |
642 | | PyObject *dummies; |
643 | | /* The callback for weakrefs to localdummies */ |
644 | | PyObject *wr_callback; |
645 | | } localobject; |
646 | | |
647 | | /* Forward declaration */ |
648 | | static PyObject *_ldict(localobject *self); |
649 | | static PyObject *_localdummy_destroyed(PyObject *meth_self, PyObject *dummyweakref); |
650 | | |
651 | | /* Create and register the dummy for the current thread. |
652 | | Returns a borrowed reference of the corresponding local dict */ |
653 | | static PyObject * |
654 | | _local_create_dummy(localobject *self) |
655 | 0 | { |
656 | 0 | PyObject *tdict, *ldict = NULL, *wr = NULL; |
657 | 0 | localdummyobject *dummy = NULL; |
658 | 0 | int r; |
659 | |
|
660 | 0 | tdict = PyThreadState_GetDict(); |
661 | 0 | if (tdict == NULL) { |
662 | 0 | PyErr_SetString(PyExc_SystemError, |
663 | 0 | "Couldn't get thread-state dictionary"); |
664 | 0 | goto err; |
665 | 0 | } |
666 | | |
667 | 0 | ldict = PyDict_New(); |
668 | 0 | if (ldict == NULL) |
669 | 0 | goto err; |
670 | 0 | dummy = (localdummyobject *) localdummytype.tp_alloc(&localdummytype, 0); |
671 | 0 | if (dummy == NULL) |
672 | 0 | goto err; |
673 | 0 | dummy->localdict = ldict; |
674 | 0 | wr = PyWeakref_NewRef((PyObject *) dummy, self->wr_callback); |
675 | 0 | if (wr == NULL) |
676 | 0 | goto err; |
677 | | |
678 | | /* As a side-effect, this will cache the weakref's hash before the |
679 | | dummy gets deleted */ |
680 | 0 | r = PyDict_SetItem(self->dummies, wr, ldict); |
681 | 0 | if (r < 0) |
682 | 0 | goto err; |
683 | 0 | Py_CLEAR(wr); |
684 | 0 | r = PyDict_SetItem(tdict, self->key, (PyObject *) dummy); |
685 | 0 | if (r < 0) |
686 | 0 | goto err; |
687 | 0 | Py_CLEAR(dummy); |
688 | |
|
689 | 0 | Py_DECREF(ldict); |
690 | 0 | return ldict; |
691 | | |
692 | 0 | err: |
693 | 0 | Py_XDECREF(ldict); |
694 | 0 | Py_XDECREF(wr); |
695 | 0 | Py_XDECREF(dummy); |
696 | 0 | return NULL; |
697 | 0 | } |
698 | | |
699 | | static PyObject * |
700 | | local_new(PyTypeObject *type, PyObject *args, PyObject *kw) |
701 | 0 | { |
702 | 0 | localobject *self; |
703 | 0 | PyObject *wr; |
704 | 0 | static PyMethodDef wr_callback_def = { |
705 | 0 | "_localdummy_destroyed", (PyCFunction) _localdummy_destroyed, METH_O |
706 | 0 | }; |
707 | |
|
708 | 0 | if (type->tp_init == PyBaseObject_Type.tp_init) { |
709 | 0 | int rc = 0; |
710 | 0 | if (args != NULL) |
711 | 0 | rc = PyObject_IsTrue(args); |
712 | 0 | if (rc == 0 && kw != NULL) |
713 | 0 | rc = PyObject_IsTrue(kw); |
714 | 0 | if (rc != 0) { |
715 | 0 | if (rc > 0) |
716 | 0 | PyErr_SetString(PyExc_TypeError, |
717 | 0 | "Initialization arguments are not supported"); |
718 | 0 | return NULL; |
719 | 0 | } |
720 | 0 | } |
721 | | |
722 | 0 | self = (localobject *)type->tp_alloc(type, 0); |
723 | 0 | if (self == NULL) |
724 | 0 | return NULL; |
725 | | |
726 | 0 | Py_XINCREF(args); |
727 | 0 | self->args = args; |
728 | 0 | Py_XINCREF(kw); |
729 | 0 | self->kw = kw; |
730 | 0 | self->key = PyUnicode_FromFormat("thread.local.%p", self); |
731 | 0 | if (self->key == NULL) |
732 | 0 | goto err; |
733 | | |
734 | 0 | self->dummies = PyDict_New(); |
735 | 0 | if (self->dummies == NULL) |
736 | 0 | goto err; |
737 | | |
738 | | /* We use a weak reference to self in the callback closure |
739 | | in order to avoid spurious reference cycles */ |
740 | 0 | wr = PyWeakref_NewRef((PyObject *) self, NULL); |
741 | 0 | if (wr == NULL) |
742 | 0 | goto err; |
743 | 0 | self->wr_callback = PyCFunction_NewEx(&wr_callback_def, wr, NULL); |
744 | 0 | Py_DECREF(wr); |
745 | 0 | if (self->wr_callback == NULL) |
746 | 0 | goto err; |
747 | | |
748 | 0 | if (_local_create_dummy(self) == NULL) |
749 | 0 | goto err; |
750 | | |
751 | 0 | return (PyObject *)self; |
752 | | |
753 | 0 | err: |
754 | 0 | Py_DECREF(self); |
755 | 0 | return NULL; |
756 | 0 | } |
757 | | |
758 | | static int |
759 | | local_traverse(localobject *self, visitproc visit, void *arg) |
760 | 0 | { |
761 | 0 | Py_VISIT(self->args); |
762 | 0 | Py_VISIT(self->kw); |
763 | 0 | Py_VISIT(self->dummies); |
764 | 0 | return 0; |
765 | 0 | } |
766 | | |
767 | | static int |
768 | | local_clear(localobject *self) |
769 | 0 | { |
770 | 0 | PyThreadState *tstate; |
771 | 0 | Py_CLEAR(self->args); |
772 | 0 | Py_CLEAR(self->kw); |
773 | 0 | Py_CLEAR(self->dummies); |
774 | 0 | Py_CLEAR(self->wr_callback); |
775 | | /* Remove all strong references to dummies from the thread states */ |
776 | 0 | if (self->key |
777 | 0 | && (tstate = PyThreadState_Get()) |
778 | 0 | && tstate->interp) { |
779 | 0 | for(tstate = PyInterpreterState_ThreadHead(tstate->interp); |
780 | 0 | tstate; |
781 | 0 | tstate = PyThreadState_Next(tstate)) |
782 | 0 | if (tstate->dict && PyDict_GetItem(tstate->dict, self->key)) { |
783 | 0 | if (PyDict_DelItem(tstate->dict, self->key)) { |
784 | 0 | PyErr_Clear(); |
785 | 0 | } |
786 | 0 | } |
787 | 0 | } |
788 | 0 | return 0; |
789 | 0 | } |
790 | | |
791 | | static void |
792 | | local_dealloc(localobject *self) |
793 | 0 | { |
794 | | /* Weakrefs must be invalidated right now, otherwise they can be used |
795 | | from code called below, which is very dangerous since Py_REFCNT(self) == 0 */ |
796 | 0 | if (self->weakreflist != NULL) |
797 | 0 | PyObject_ClearWeakRefs((PyObject *) self); |
798 | |
|
799 | 0 | PyObject_GC_UnTrack(self); |
800 | |
|
801 | 0 | local_clear(self); |
802 | 0 | Py_XDECREF(self->key); |
803 | 0 | Py_TYPE(self)->tp_free((PyObject*)self); |
804 | 0 | } |
805 | | |
806 | | /* Returns a borrowed reference to the local dict, creating it if necessary */ |
807 | | static PyObject * |
808 | | _ldict(localobject *self) |
809 | 0 | { |
810 | 0 | PyObject *tdict, *ldict, *dummy; |
811 | |
|
812 | 0 | tdict = PyThreadState_GetDict(); |
813 | 0 | if (tdict == NULL) { |
814 | 0 | PyErr_SetString(PyExc_SystemError, |
815 | 0 | "Couldn't get thread-state dictionary"); |
816 | 0 | return NULL; |
817 | 0 | } |
818 | | |
819 | 0 | dummy = PyDict_GetItemWithError(tdict, self->key); |
820 | 0 | if (dummy == NULL) { |
821 | 0 | if (PyErr_Occurred()) { |
822 | 0 | return NULL; |
823 | 0 | } |
824 | 0 | ldict = _local_create_dummy(self); |
825 | 0 | if (ldict == NULL) |
826 | 0 | return NULL; |
827 | | |
828 | 0 | if (Py_TYPE(self)->tp_init != PyBaseObject_Type.tp_init && |
829 | 0 | Py_TYPE(self)->tp_init((PyObject*)self, |
830 | 0 | self->args, self->kw) < 0) { |
831 | | /* we need to get rid of ldict from thread so |
832 | | we create a new one the next time we do an attr |
833 | | access */ |
834 | 0 | PyDict_DelItem(tdict, self->key); |
835 | 0 | return NULL; |
836 | 0 | } |
837 | 0 | } |
838 | 0 | else { |
839 | 0 | assert(Py_TYPE(dummy) == &localdummytype); |
840 | 0 | ldict = ((localdummyobject *) dummy)->localdict; |
841 | 0 | } |
842 | | |
843 | 0 | return ldict; |
844 | 0 | } |
845 | | |
846 | | static int |
847 | | local_setattro(localobject *self, PyObject *name, PyObject *v) |
848 | 0 | { |
849 | 0 | PyObject *ldict; |
850 | 0 | int r; |
851 | |
|
852 | 0 | ldict = _ldict(self); |
853 | 0 | if (ldict == NULL) |
854 | 0 | return -1; |
855 | | |
856 | 0 | r = PyObject_RichCompareBool(name, str_dict, Py_EQ); |
857 | 0 | if (r == 1) { |
858 | 0 | PyErr_Format(PyExc_AttributeError, |
859 | 0 | "'%.50s' object attribute '%U' is read-only", |
860 | 0 | Py_TYPE(self)->tp_name, name); |
861 | 0 | return -1; |
862 | 0 | } |
863 | 0 | if (r == -1) |
864 | 0 | return -1; |
865 | | |
866 | 0 | return _PyObject_GenericSetAttrWithDict((PyObject *)self, name, v, ldict); |
867 | 0 | } |
868 | | |
869 | | static PyObject *local_getattro(localobject *, PyObject *); |
870 | | |
871 | | static PyTypeObject localtype = { |
872 | | PyVarObject_HEAD_INIT(NULL, 0) |
873 | | /* tp_name */ "_thread._local", |
874 | | /* tp_basicsize */ sizeof(localobject), |
875 | | /* tp_itemsize */ 0, |
876 | | /* tp_dealloc */ (destructor)local_dealloc, |
877 | | /* tp_vectorcall_offset */ 0, |
878 | | /* tp_getattr */ 0, |
879 | | /* tp_setattr */ 0, |
880 | | /* tp_as_async */ 0, |
881 | | /* tp_repr */ 0, |
882 | | /* tp_as_number */ 0, |
883 | | /* tp_as_sequence */ 0, |
884 | | /* tp_as_mapping */ 0, |
885 | | /* tp_hash */ 0, |
886 | | /* tp_call */ 0, |
887 | | /* tp_str */ 0, |
888 | | /* tp_getattro */ (getattrofunc)local_getattro, |
889 | | /* tp_setattro */ (setattrofunc)local_setattro, |
890 | | /* tp_as_buffer */ 0, |
891 | | /* tp_flags */ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
892 | | | Py_TPFLAGS_HAVE_GC, |
893 | | /* tp_doc */ "Thread-local data", |
894 | | /* tp_traverse */ (traverseproc)local_traverse, |
895 | | /* tp_clear */ (inquiry)local_clear, |
896 | | /* tp_richcompare */ 0, |
897 | | /* tp_weaklistoffset */ offsetof(localobject, weakreflist), |
898 | | /* tp_iter */ 0, |
899 | | /* tp_iternext */ 0, |
900 | | /* tp_methods */ 0, |
901 | | /* tp_members */ 0, |
902 | | /* tp_getset */ 0, |
903 | | /* tp_base */ 0, |
904 | | /* tp_dict */ 0, /* internal use */ |
905 | | /* tp_descr_get */ 0, |
906 | | /* tp_descr_set */ 0, |
907 | | /* tp_dictoffset */ 0, |
908 | | /* tp_init */ 0, |
909 | | /* tp_alloc */ 0, |
910 | | /* tp_new */ local_new, |
911 | | /* tp_free */ 0, /* Low-level free-mem routine */ |
912 | | /* tp_is_gc */ 0, /* For PyObject_IS_GC */ |
913 | | }; |
914 | | |
915 | | static PyObject * |
916 | | local_getattro(localobject *self, PyObject *name) |
917 | 0 | { |
918 | 0 | PyObject *ldict, *value; |
919 | 0 | int r; |
920 | |
|
921 | 0 | ldict = _ldict(self); |
922 | 0 | if (ldict == NULL) |
923 | 0 | return NULL; |
924 | | |
925 | 0 | r = PyObject_RichCompareBool(name, str_dict, Py_EQ); |
926 | 0 | if (r == 1) { |
927 | 0 | Py_INCREF(ldict); |
928 | 0 | return ldict; |
929 | 0 | } |
930 | 0 | if (r == -1) |
931 | 0 | return NULL; |
932 | | |
933 | 0 | if (Py_TYPE(self) != &localtype) |
934 | | /* use generic lookup for subtypes */ |
935 | 0 | return _PyObject_GenericGetAttrWithDict( |
936 | 0 | (PyObject *)self, name, ldict, 0); |
937 | | |
938 | | /* Optimization: just look in dict ourselves */ |
939 | 0 | value = PyDict_GetItemWithError(ldict, name); |
940 | 0 | if (value != NULL) { |
941 | 0 | Py_INCREF(value); |
942 | 0 | return value; |
943 | 0 | } |
944 | 0 | else if (PyErr_Occurred()) { |
945 | 0 | return NULL; |
946 | 0 | } |
947 | | /* Fall back on generic to get __class__ and __dict__ */ |
948 | 0 | return _PyObject_GenericGetAttrWithDict( |
949 | 0 | (PyObject *)self, name, ldict, 0); |
950 | 0 | } |
951 | | |
952 | | /* Called when a dummy is destroyed. */ |
953 | | static PyObject * |
954 | | _localdummy_destroyed(PyObject *localweakref, PyObject *dummyweakref) |
955 | 0 | { |
956 | 0 | PyObject *obj; |
957 | 0 | localobject *self; |
958 | 0 | assert(PyWeakref_CheckRef(localweakref)); |
959 | 0 | obj = PyWeakref_GET_OBJECT(localweakref); |
960 | 0 | if (obj == Py_None) |
961 | 0 | Py_RETURN_NONE; |
962 | 0 | Py_INCREF(obj); |
963 | 0 | assert(PyObject_TypeCheck(obj, &localtype)); |
964 | | /* If the thread-local object is still alive and not being cleared, |
965 | | remove the corresponding local dict */ |
966 | 0 | self = (localobject *) obj; |
967 | 0 | if (self->dummies != NULL) { |
968 | 0 | PyObject *ldict; |
969 | 0 | ldict = PyDict_GetItemWithError(self->dummies, dummyweakref); |
970 | 0 | if (ldict != NULL) { |
971 | 0 | PyDict_DelItem(self->dummies, dummyweakref); |
972 | 0 | } |
973 | 0 | if (PyErr_Occurred()) |
974 | 0 | PyErr_WriteUnraisable(obj); |
975 | 0 | } |
976 | 0 | Py_DECREF(obj); |
977 | 0 | Py_RETURN_NONE; |
978 | 0 | } |
979 | | |
980 | | /* Module functions */ |
981 | | |
982 | | struct bootstate { |
983 | | PyInterpreterState *interp; |
984 | | PyObject *func; |
985 | | PyObject *args; |
986 | | PyObject *keyw; |
987 | | PyThreadState *tstate; |
988 | | }; |
989 | | |
990 | | static void |
991 | | t_bootstrap(void *boot_raw) |
992 | 0 | { |
993 | 0 | struct bootstate *boot = (struct bootstate *) boot_raw; |
994 | 0 | PyThreadState *tstate; |
995 | 0 | PyObject *res; |
996 | |
|
997 | 0 | tstate = boot->tstate; |
998 | 0 | tstate->thread_id = PyThread_get_thread_ident(); |
999 | 0 | _PyThreadState_Init(&_PyRuntime, tstate); |
1000 | 0 | PyEval_AcquireThread(tstate); |
1001 | 0 | tstate->interp->num_threads++; |
1002 | 0 | res = PyObject_Call(boot->func, boot->args, boot->keyw); |
1003 | 0 | if (res == NULL) { |
1004 | 0 | if (PyErr_ExceptionMatches(PyExc_SystemExit)) |
1005 | | /* SystemExit is ignored silently */ |
1006 | 0 | PyErr_Clear(); |
1007 | 0 | else { |
1008 | 0 | _PyErr_WriteUnraisableMsg("in thread started by", boot->func); |
1009 | 0 | } |
1010 | 0 | } |
1011 | 0 | else { |
1012 | 0 | Py_DECREF(res); |
1013 | 0 | } |
1014 | 0 | Py_DECREF(boot->func); |
1015 | 0 | Py_DECREF(boot->args); |
1016 | 0 | Py_XDECREF(boot->keyw); |
1017 | 0 | PyMem_DEL(boot_raw); |
1018 | 0 | tstate->interp->num_threads--; |
1019 | 0 | PyThreadState_Clear(tstate); |
1020 | 0 | PyThreadState_DeleteCurrent(); |
1021 | 0 | PyThread_exit_thread(); |
1022 | 0 | } |
1023 | | |
1024 | | static PyObject * |
1025 | | thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs) |
1026 | 0 | { |
1027 | 0 | PyObject *func, *args, *keyw = NULL; |
1028 | 0 | struct bootstate *boot; |
1029 | 0 | unsigned long ident; |
1030 | |
|
1031 | 0 | if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3, |
1032 | 0 | &func, &args, &keyw)) |
1033 | 0 | return NULL; |
1034 | 0 | if (!PyCallable_Check(func)) { |
1035 | 0 | PyErr_SetString(PyExc_TypeError, |
1036 | 0 | "first arg must be callable"); |
1037 | 0 | return NULL; |
1038 | 0 | } |
1039 | 0 | if (!PyTuple_Check(args)) { |
1040 | 0 | PyErr_SetString(PyExc_TypeError, |
1041 | 0 | "2nd arg must be a tuple"); |
1042 | 0 | return NULL; |
1043 | 0 | } |
1044 | 0 | if (keyw != NULL && !PyDict_Check(keyw)) { |
1045 | 0 | PyErr_SetString(PyExc_TypeError, |
1046 | 0 | "optional 3rd arg must be a dictionary"); |
1047 | 0 | return NULL; |
1048 | 0 | } |
1049 | 0 | boot = PyMem_NEW(struct bootstate, 1); |
1050 | 0 | if (boot == NULL) |
1051 | 0 | return PyErr_NoMemory(); |
1052 | 0 | boot->interp = _PyInterpreterState_Get(); |
1053 | 0 | boot->func = func; |
1054 | 0 | boot->args = args; |
1055 | 0 | boot->keyw = keyw; |
1056 | 0 | boot->tstate = _PyThreadState_Prealloc(boot->interp); |
1057 | 0 | if (boot->tstate == NULL) { |
1058 | 0 | PyMem_DEL(boot); |
1059 | 0 | return PyErr_NoMemory(); |
1060 | 0 | } |
1061 | 0 | Py_INCREF(func); |
1062 | 0 | Py_INCREF(args); |
1063 | 0 | Py_XINCREF(keyw); |
1064 | 0 | PyEval_InitThreads(); /* Start the interpreter's thread-awareness */ |
1065 | 0 | ident = PyThread_start_new_thread(t_bootstrap, (void*) boot); |
1066 | 0 | if (ident == PYTHREAD_INVALID_THREAD_ID) { |
1067 | 0 | PyErr_SetString(ThreadError, "can't start new thread"); |
1068 | 0 | Py_DECREF(func); |
1069 | 0 | Py_DECREF(args); |
1070 | 0 | Py_XDECREF(keyw); |
1071 | 0 | PyThreadState_Clear(boot->tstate); |
1072 | 0 | PyMem_DEL(boot); |
1073 | 0 | return NULL; |
1074 | 0 | } |
1075 | 0 | return PyLong_FromUnsignedLong(ident); |
1076 | 0 | } |
1077 | | |
1078 | | PyDoc_STRVAR(start_new_doc, |
1079 | | "start_new_thread(function, args[, kwargs])\n\ |
1080 | | (start_new() is an obsolete synonym)\n\ |
1081 | | \n\ |
1082 | | Start a new thread and return its identifier. The thread will call the\n\ |
1083 | | function with positional arguments from the tuple args and keyword arguments\n\ |
1084 | | taken from the optional dictionary kwargs. The thread exits when the\n\ |
1085 | | function returns; the return value is ignored. The thread will also exit\n\ |
1086 | | when the function raises an unhandled exception; a stack trace will be\n\ |
1087 | | printed unless the exception is SystemExit.\n"); |
1088 | | |
1089 | | static PyObject * |
1090 | | thread_PyThread_exit_thread(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1091 | 0 | { |
1092 | 0 | PyErr_SetNone(PyExc_SystemExit); |
1093 | 0 | return NULL; |
1094 | 0 | } |
1095 | | |
1096 | | PyDoc_STRVAR(exit_doc, |
1097 | | "exit()\n\ |
1098 | | (exit_thread() is an obsolete synonym)\n\ |
1099 | | \n\ |
1100 | | This is synonymous to ``raise SystemExit''. It will cause the current\n\ |
1101 | | thread to exit silently unless the exception is caught."); |
1102 | | |
1103 | | static PyObject * |
1104 | | thread_PyThread_interrupt_main(PyObject * self, PyObject *Py_UNUSED(ignored)) |
1105 | 0 | { |
1106 | 0 | PyErr_SetInterrupt(); |
1107 | 0 | Py_RETURN_NONE; |
1108 | 0 | } |
1109 | | |
1110 | | PyDoc_STRVAR(interrupt_doc, |
1111 | | "interrupt_main()\n\ |
1112 | | \n\ |
1113 | | Raise a KeyboardInterrupt in the main thread.\n\ |
1114 | | A subthread can use this function to interrupt the main thread." |
1115 | | ); |
1116 | | |
1117 | | static lockobject *newlockobject(void); |
1118 | | |
1119 | | static PyObject * |
1120 | | thread_PyThread_allocate_lock(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1121 | 727 | { |
1122 | 727 | return (PyObject *) newlockobject(); |
1123 | 727 | } |
1124 | | |
1125 | | PyDoc_STRVAR(allocate_doc, |
1126 | | "allocate_lock() -> lock object\n\ |
1127 | | (allocate() is an obsolete synonym)\n\ |
1128 | | \n\ |
1129 | | Create a new lock object. See help(type(threading.Lock())) for\n\ |
1130 | | information about locks."); |
1131 | | |
1132 | | static PyObject * |
1133 | | thread_get_ident(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1134 | 865 | { |
1135 | 865 | unsigned long ident = PyThread_get_thread_ident(); |
1136 | 865 | if (ident == PYTHREAD_INVALID_THREAD_ID) { |
1137 | 0 | PyErr_SetString(ThreadError, "no current thread ident"); |
1138 | 0 | return NULL; |
1139 | 0 | } |
1140 | 865 | return PyLong_FromUnsignedLong(ident); |
1141 | 865 | } |
1142 | | |
1143 | | PyDoc_STRVAR(get_ident_doc, |
1144 | | "get_ident() -> integer\n\ |
1145 | | \n\ |
1146 | | Return a non-zero integer that uniquely identifies the current thread\n\ |
1147 | | amongst other threads that exist simultaneously.\n\ |
1148 | | This may be used to identify per-thread resources.\n\ |
1149 | | Even though on some platforms threads identities may appear to be\n\ |
1150 | | allocated consecutive numbers starting at 1, this behavior should not\n\ |
1151 | | be relied upon, and the number should be seen purely as a magic cookie.\n\ |
1152 | | A thread's identity may be reused for another thread after it exits."); |
1153 | | |
1154 | | #ifdef PY_HAVE_THREAD_NATIVE_ID |
1155 | | static PyObject * |
1156 | | thread_get_native_id(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1157 | 1 | { |
1158 | 1 | unsigned long native_id = PyThread_get_thread_native_id(); |
1159 | 1 | return PyLong_FromUnsignedLong(native_id); |
1160 | 1 | } |
1161 | | |
1162 | | PyDoc_STRVAR(get_native_id_doc, |
1163 | | "get_native_id() -> integer\n\ |
1164 | | \n\ |
1165 | | Return a non-negative integer identifying the thread as reported\n\ |
1166 | | by the OS (kernel). This may be used to uniquely identify a\n\ |
1167 | | particular thread within a system."); |
1168 | | #endif |
1169 | | |
1170 | | static PyObject * |
1171 | | thread__count(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1172 | 0 | { |
1173 | 0 | PyInterpreterState *interp = _PyInterpreterState_Get(); |
1174 | 0 | return PyLong_FromLong(interp->num_threads); |
1175 | 0 | } |
1176 | | |
1177 | | PyDoc_STRVAR(_count_doc, |
1178 | | "_count() -> integer\n\ |
1179 | | \n\ |
1180 | | \ |
1181 | | Return the number of currently running Python threads, excluding\n\ |
1182 | | the main thread. The returned number comprises all threads created\n\ |
1183 | | through `start_new_thread()` as well as `threading.Thread`, and not\n\ |
1184 | | yet finished.\n\ |
1185 | | \n\ |
1186 | | This function is meant for internal and specialized purposes only.\n\ |
1187 | | In most applications `threading.enumerate()` should be used instead."); |
1188 | | |
1189 | | static void |
1190 | | release_sentinel(void *wr_raw) |
1191 | 0 | { |
1192 | 0 | PyObject *wr = _PyObject_CAST(wr_raw); |
1193 | | /* Tricky: this function is called when the current thread state |
1194 | | is being deleted. Therefore, only simple C code can safely |
1195 | | execute here. */ |
1196 | 0 | PyObject *obj = PyWeakref_GET_OBJECT(wr); |
1197 | 0 | lockobject *lock; |
1198 | 0 | if (obj != Py_None) { |
1199 | 0 | assert(Py_TYPE(obj) == &Locktype); |
1200 | 0 | lock = (lockobject *) obj; |
1201 | 0 | if (lock->locked) { |
1202 | 0 | PyThread_release_lock(lock->lock_lock); |
1203 | 0 | lock->locked = 0; |
1204 | 0 | } |
1205 | 0 | } |
1206 | | /* Deallocating a weakref with a NULL callback only calls |
1207 | | PyObject_GC_Del(), which can't call any Python code. */ |
1208 | 0 | Py_DECREF(wr); |
1209 | 0 | } |
1210 | | |
1211 | | static PyObject * |
1212 | | thread__set_sentinel(PyObject *self, PyObject *Py_UNUSED(ignored)) |
1213 | 1 | { |
1214 | 1 | PyObject *wr; |
1215 | 1 | PyThreadState *tstate = PyThreadState_Get(); |
1216 | 1 | lockobject *lock; |
1217 | | |
1218 | 1 | if (tstate->on_delete_data != NULL) { |
1219 | | /* We must support the re-creation of the lock from a |
1220 | | fork()ed child. */ |
1221 | 0 | assert(tstate->on_delete == &release_sentinel); |
1222 | 0 | wr = (PyObject *) tstate->on_delete_data; |
1223 | 0 | tstate->on_delete = NULL; |
1224 | 0 | tstate->on_delete_data = NULL; |
1225 | 0 | Py_DECREF(wr); |
1226 | 0 | } |
1227 | 1 | lock = newlockobject(); |
1228 | 1 | if (lock == NULL) |
1229 | 0 | return NULL; |
1230 | | /* The lock is owned by whoever called _set_sentinel(), but the weakref |
1231 | | hangs to the thread state. */ |
1232 | 1 | wr = PyWeakref_NewRef((PyObject *) lock, NULL); |
1233 | 1 | if (wr == NULL) { |
1234 | 0 | Py_DECREF(lock); |
1235 | 0 | return NULL; |
1236 | 0 | } |
1237 | 1 | tstate->on_delete_data = (void *) wr; |
1238 | 1 | tstate->on_delete = &release_sentinel; |
1239 | 1 | return (PyObject *) lock; |
1240 | 1 | } |
1241 | | |
1242 | | PyDoc_STRVAR(_set_sentinel_doc, |
1243 | | "_set_sentinel() -> lock\n\ |
1244 | | \n\ |
1245 | | Set a sentinel lock that will be released when the current thread\n\ |
1246 | | state is finalized (after it is untied from the interpreter).\n\ |
1247 | | \n\ |
1248 | | This is a private API for the threading module."); |
1249 | | |
1250 | | static PyObject * |
1251 | | thread_stack_size(PyObject *self, PyObject *args) |
1252 | 0 | { |
1253 | 0 | size_t old_size; |
1254 | 0 | Py_ssize_t new_size = 0; |
1255 | 0 | int rc; |
1256 | |
|
1257 | 0 | if (!PyArg_ParseTuple(args, "|n:stack_size", &new_size)) |
1258 | 0 | return NULL; |
1259 | | |
1260 | 0 | if (new_size < 0) { |
1261 | 0 | PyErr_SetString(PyExc_ValueError, |
1262 | 0 | "size must be 0 or a positive value"); |
1263 | 0 | return NULL; |
1264 | 0 | } |
1265 | | |
1266 | 0 | old_size = PyThread_get_stacksize(); |
1267 | |
|
1268 | 0 | rc = PyThread_set_stacksize((size_t) new_size); |
1269 | 0 | if (rc == -1) { |
1270 | 0 | PyErr_Format(PyExc_ValueError, |
1271 | 0 | "size not valid: %zd bytes", |
1272 | 0 | new_size); |
1273 | 0 | return NULL; |
1274 | 0 | } |
1275 | 0 | if (rc == -2) { |
1276 | 0 | PyErr_SetString(ThreadError, |
1277 | 0 | "setting stack size not supported"); |
1278 | 0 | return NULL; |
1279 | 0 | } |
1280 | | |
1281 | 0 | return PyLong_FromSsize_t((Py_ssize_t) old_size); |
1282 | 0 | } |
1283 | | |
1284 | | PyDoc_STRVAR(stack_size_doc, |
1285 | | "stack_size([size]) -> size\n\ |
1286 | | \n\ |
1287 | | Return the thread stack size used when creating new threads. The\n\ |
1288 | | optional size argument specifies the stack size (in bytes) to be used\n\ |
1289 | | for subsequently created threads, and must be 0 (use platform or\n\ |
1290 | | configured default) or a positive integer value of at least 32,768 (32k).\n\ |
1291 | | If changing the thread stack size is unsupported, a ThreadError\n\ |
1292 | | exception is raised. If the specified size is invalid, a ValueError\n\ |
1293 | | exception is raised, and the stack size is unmodified. 32k bytes\n\ |
1294 | | currently the minimum supported stack size value to guarantee\n\ |
1295 | | sufficient stack space for the interpreter itself.\n\ |
1296 | | \n\ |
1297 | | Note that some platforms may have particular restrictions on values for\n\ |
1298 | | the stack size, such as requiring a minimum stack size larger than 32 KiB or\n\ |
1299 | | requiring allocation in multiples of the system memory page size\n\ |
1300 | | - platform documentation should be referred to for more information\n\ |
1301 | | (4 KiB pages are common; using multiples of 4096 for the stack size is\n\ |
1302 | | the suggested approach in the absence of more specific information)."); |
1303 | | |
1304 | | static int |
1305 | | thread_excepthook_file(PyObject *file, PyObject *exc_type, PyObject *exc_value, |
1306 | | PyObject *exc_traceback, PyObject *thread) |
1307 | 0 | { |
1308 | 0 | _Py_IDENTIFIER(name); |
1309 | | /* print(f"Exception in thread {thread.name}:", file=file) */ |
1310 | 0 | if (PyFile_WriteString("Exception in thread ", file) < 0) { |
1311 | 0 | return -1; |
1312 | 0 | } |
1313 | | |
1314 | 0 | PyObject *name = NULL; |
1315 | 0 | if (thread != Py_None) { |
1316 | 0 | if (_PyObject_LookupAttrId(thread, &PyId_name, &name) < 0) { |
1317 | 0 | return -1; |
1318 | 0 | } |
1319 | 0 | } |
1320 | 0 | if (name != NULL) { |
1321 | 0 | if (PyFile_WriteObject(name, file, Py_PRINT_RAW) < 0) { |
1322 | 0 | Py_DECREF(name); |
1323 | 0 | return -1; |
1324 | 0 | } |
1325 | 0 | Py_DECREF(name); |
1326 | 0 | } |
1327 | 0 | else { |
1328 | 0 | unsigned long ident = PyThread_get_thread_ident(); |
1329 | 0 | PyObject *str = PyUnicode_FromFormat("%lu", ident); |
1330 | 0 | if (str != NULL) { |
1331 | 0 | if (PyFile_WriteObject(str, file, Py_PRINT_RAW) < 0) { |
1332 | 0 | Py_DECREF(str); |
1333 | 0 | return -1; |
1334 | 0 | } |
1335 | 0 | Py_DECREF(str); |
1336 | 0 | } |
1337 | 0 | else { |
1338 | 0 | PyErr_Clear(); |
1339 | |
|
1340 | 0 | if (PyFile_WriteString("<failed to get thread name>", file) < 0) { |
1341 | 0 | return -1; |
1342 | 0 | } |
1343 | 0 | } |
1344 | 0 | } |
1345 | | |
1346 | 0 | if (PyFile_WriteString(":\n", file) < 0) { |
1347 | 0 | return -1; |
1348 | 0 | } |
1349 | | |
1350 | | /* Display the traceback */ |
1351 | 0 | _PyErr_Display(file, exc_type, exc_value, exc_traceback); |
1352 | | |
1353 | | /* Call file.flush() */ |
1354 | 0 | PyObject *res = _PyObject_CallMethodId(file, &PyId_flush, NULL); |
1355 | 0 | if (!res) { |
1356 | 0 | return -1; |
1357 | 0 | } |
1358 | 0 | Py_DECREF(res); |
1359 | |
|
1360 | 0 | return 0; |
1361 | 0 | } |
1362 | | |
1363 | | |
1364 | | PyDoc_STRVAR(ExceptHookArgs__doc__, |
1365 | | "ExceptHookArgs\n\ |
1366 | | \n\ |
1367 | | Type used to pass arguments to threading.excepthook."); |
1368 | | |
1369 | | static PyTypeObject ExceptHookArgsType; |
1370 | | |
1371 | | static PyStructSequence_Field ExceptHookArgs_fields[] = { |
1372 | | {"exc_type", "Exception type"}, |
1373 | | {"exc_value", "Exception value"}, |
1374 | | {"exc_traceback", "Exception traceback"}, |
1375 | | {"thread", "Thread"}, |
1376 | | {0} |
1377 | | }; |
1378 | | |
1379 | | static PyStructSequence_Desc ExceptHookArgs_desc = { |
1380 | | .name = "_thread.ExceptHookArgs", |
1381 | | .doc = ExceptHookArgs__doc__, |
1382 | | .fields = ExceptHookArgs_fields, |
1383 | | .n_in_sequence = 4 |
1384 | | }; |
1385 | | |
1386 | | |
1387 | | static PyObject * |
1388 | | thread_excepthook(PyObject *self, PyObject *args) |
1389 | 0 | { |
1390 | 0 | if (Py_TYPE(args) != &ExceptHookArgsType) { |
1391 | 0 | PyErr_SetString(PyExc_TypeError, |
1392 | 0 | "_thread.excepthook argument type " |
1393 | 0 | "must be ExceptHookArgs"); |
1394 | 0 | return NULL; |
1395 | 0 | } |
1396 | | |
1397 | | /* Borrowed reference */ |
1398 | 0 | PyObject *exc_type = PyStructSequence_GET_ITEM(args, 0); |
1399 | 0 | if (exc_type == PyExc_SystemExit) { |
1400 | | /* silently ignore SystemExit */ |
1401 | 0 | Py_RETURN_NONE; |
1402 | 0 | } |
1403 | | |
1404 | | /* Borrowed references */ |
1405 | 0 | PyObject *exc_value = PyStructSequence_GET_ITEM(args, 1); |
1406 | 0 | PyObject *exc_tb = PyStructSequence_GET_ITEM(args, 2); |
1407 | 0 | PyObject *thread = PyStructSequence_GET_ITEM(args, 3); |
1408 | |
|
1409 | 0 | PyObject *file = _PySys_GetObjectId(&PyId_stderr); |
1410 | 0 | if (file == NULL || file == Py_None) { |
1411 | 0 | if (thread == Py_None) { |
1412 | | /* do nothing if sys.stderr is None and thread is None */ |
1413 | 0 | Py_RETURN_NONE; |
1414 | 0 | } |
1415 | | |
1416 | 0 | file = PyObject_GetAttrString(thread, "_stderr"); |
1417 | 0 | if (file == NULL) { |
1418 | 0 | return NULL; |
1419 | 0 | } |
1420 | 0 | if (file == Py_None) { |
1421 | 0 | Py_DECREF(file); |
1422 | | /* do nothing if sys.stderr is None and sys.stderr was None |
1423 | | when the thread was created */ |
1424 | 0 | Py_RETURN_NONE; |
1425 | 0 | } |
1426 | 0 | } |
1427 | 0 | else { |
1428 | 0 | Py_INCREF(file); |
1429 | 0 | } |
1430 | | |
1431 | 0 | int res = thread_excepthook_file(file, exc_type, exc_value, exc_tb, |
1432 | 0 | thread); |
1433 | 0 | Py_DECREF(file); |
1434 | 0 | if (res < 0) { |
1435 | 0 | return NULL; |
1436 | 0 | } |
1437 | | |
1438 | 0 | Py_RETURN_NONE; |
1439 | 0 | } |
1440 | | |
1441 | | PyDoc_STRVAR(excepthook_doc, |
1442 | | "excepthook(exc_type, exc_value, exc_traceback, thread)\n\ |
1443 | | \n\ |
1444 | | Handle uncaught Thread.run() exception."); |
1445 | | |
1446 | | static PyMethodDef thread_methods[] = { |
1447 | | {"start_new_thread", (PyCFunction)thread_PyThread_start_new_thread, |
1448 | | METH_VARARGS, start_new_doc}, |
1449 | | {"start_new", (PyCFunction)thread_PyThread_start_new_thread, |
1450 | | METH_VARARGS, start_new_doc}, |
1451 | | {"allocate_lock", thread_PyThread_allocate_lock, |
1452 | | METH_NOARGS, allocate_doc}, |
1453 | | {"allocate", thread_PyThread_allocate_lock, |
1454 | | METH_NOARGS, allocate_doc}, |
1455 | | {"exit_thread", thread_PyThread_exit_thread, |
1456 | | METH_NOARGS, exit_doc}, |
1457 | | {"exit", thread_PyThread_exit_thread, |
1458 | | METH_NOARGS, exit_doc}, |
1459 | | {"interrupt_main", thread_PyThread_interrupt_main, |
1460 | | METH_NOARGS, interrupt_doc}, |
1461 | | {"get_ident", thread_get_ident, |
1462 | | METH_NOARGS, get_ident_doc}, |
1463 | | #ifdef PY_HAVE_THREAD_NATIVE_ID |
1464 | | {"get_native_id", thread_get_native_id, |
1465 | | METH_NOARGS, get_native_id_doc}, |
1466 | | #endif |
1467 | | {"_count", thread__count, |
1468 | | METH_NOARGS, _count_doc}, |
1469 | | {"stack_size", (PyCFunction)thread_stack_size, |
1470 | | METH_VARARGS, stack_size_doc}, |
1471 | | {"_set_sentinel", thread__set_sentinel, |
1472 | | METH_NOARGS, _set_sentinel_doc}, |
1473 | | {"_excepthook", thread_excepthook, |
1474 | | METH_O, excepthook_doc}, |
1475 | | {NULL, NULL} /* sentinel */ |
1476 | | }; |
1477 | | |
1478 | | |
1479 | | /* Initialization function */ |
1480 | | |
1481 | | PyDoc_STRVAR(thread_doc, |
1482 | | "This module provides primitive operations to write multi-threaded programs.\n\ |
1483 | | The 'threading' module provides a more convenient interface."); |
1484 | | |
1485 | | PyDoc_STRVAR(lock_doc, |
1486 | | "A lock object is a synchronization primitive. To create a lock,\n\ |
1487 | | call threading.Lock(). Methods are:\n\ |
1488 | | \n\ |
1489 | | acquire() -- lock the lock, possibly blocking until it can be obtained\n\ |
1490 | | release() -- unlock of the lock\n\ |
1491 | | locked() -- test whether the lock is currently locked\n\ |
1492 | | \n\ |
1493 | | A lock is not owned by the thread that locked it; another thread may\n\ |
1494 | | unlock it. A thread attempting to lock a lock that it has already locked\n\ |
1495 | | will block until another thread unlocks it. Deadlocks may ensue."); |
1496 | | |
1497 | | static struct PyModuleDef threadmodule = { |
1498 | | PyModuleDef_HEAD_INIT, |
1499 | | "_thread", |
1500 | | thread_doc, |
1501 | | -1, |
1502 | | thread_methods, |
1503 | | NULL, |
1504 | | NULL, |
1505 | | NULL, |
1506 | | NULL |
1507 | | }; |
1508 | | |
1509 | | |
1510 | | PyMODINIT_FUNC |
1511 | | PyInit__thread(void) |
1512 | 14 | { |
1513 | 14 | PyObject *m, *d, *v; |
1514 | 14 | double time_max; |
1515 | 14 | double timeout_max; |
1516 | 14 | PyInterpreterState *interp = _PyInterpreterState_Get(); |
1517 | | |
1518 | | /* Initialize types: */ |
1519 | 14 | if (PyType_Ready(&localdummytype) < 0) |
1520 | 0 | return NULL; |
1521 | 14 | if (PyType_Ready(&localtype) < 0) |
1522 | 0 | return NULL; |
1523 | 14 | if (PyType_Ready(&Locktype) < 0) |
1524 | 0 | return NULL; |
1525 | 14 | if (PyType_Ready(&RLocktype) < 0) |
1526 | 0 | return NULL; |
1527 | 14 | if (ExceptHookArgsType.tp_name == NULL) { |
1528 | 14 | if (PyStructSequence_InitType2(&ExceptHookArgsType, |
1529 | 14 | &ExceptHookArgs_desc) < 0) { |
1530 | 0 | return NULL; |
1531 | 0 | } |
1532 | 14 | } |
1533 | | |
1534 | | /* Create the module and add the functions */ |
1535 | 14 | m = PyModule_Create(&threadmodule); |
1536 | 14 | if (m == NULL) |
1537 | 0 | return NULL; |
1538 | | |
1539 | 14 | timeout_max = (_PyTime_t)PY_TIMEOUT_MAX * 1e-6; |
1540 | 14 | time_max = _PyTime_AsSecondsDouble(_PyTime_MAX); |
1541 | 14 | timeout_max = Py_MIN(timeout_max, time_max); |
1542 | | /* Round towards minus infinity */ |
1543 | 14 | timeout_max = floor(timeout_max); |
1544 | | |
1545 | 14 | v = PyFloat_FromDouble(timeout_max); |
1546 | 14 | if (!v) |
1547 | 0 | return NULL; |
1548 | 14 | if (PyModule_AddObject(m, "TIMEOUT_MAX", v) < 0) |
1549 | 0 | return NULL; |
1550 | | |
1551 | | /* Add a symbolic constant */ |
1552 | 14 | d = PyModule_GetDict(m); |
1553 | 14 | ThreadError = PyExc_RuntimeError; |
1554 | 14 | Py_INCREF(ThreadError); |
1555 | | |
1556 | 14 | PyDict_SetItemString(d, "error", ThreadError); |
1557 | 14 | Locktype.tp_doc = lock_doc; |
1558 | 14 | Py_INCREF(&Locktype); |
1559 | 14 | PyDict_SetItemString(d, "LockType", (PyObject *)&Locktype); |
1560 | | |
1561 | 14 | Py_INCREF(&RLocktype); |
1562 | 14 | if (PyModule_AddObject(m, "RLock", (PyObject *)&RLocktype) < 0) |
1563 | 0 | return NULL; |
1564 | | |
1565 | 14 | Py_INCREF(&localtype); |
1566 | 14 | if (PyModule_AddObject(m, "_local", (PyObject *)&localtype) < 0) |
1567 | 0 | return NULL; |
1568 | | |
1569 | 14 | Py_INCREF(&ExceptHookArgsType); |
1570 | 14 | if (PyModule_AddObject(m, "_ExceptHookArgs", |
1571 | 14 | (PyObject *)&ExceptHookArgsType) < 0) |
1572 | 0 | return NULL; |
1573 | | |
1574 | 14 | interp->num_threads = 0; |
1575 | | |
1576 | 14 | str_dict = PyUnicode_InternFromString("__dict__"); |
1577 | 14 | if (str_dict == NULL) |
1578 | 0 | return NULL; |
1579 | | |
1580 | | /* Initialize the C thread library */ |
1581 | 14 | PyThread_init_thread(); |
1582 | 14 | return m; |
1583 | 14 | } |