Coverage Report

Created: 2025-07-11 06:59

/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
}