/src/Python-3.8.3/Modules/_threadmodule.c
Line  | Count  | Source  | 
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  | 0  |         && _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  | }  |