8000 bpo-6532: Make the thread id an unsigned integer. (#781) · python/cpython@aefa7eb · GitHub
[go: up one dir, main page]

Skip to content

Commit aefa7eb

Browse files
serhiy-storchakavstinner
authored andcommitted
bpo-6532: Make the thread id an unsigned integer. (#781)
* bpo-6532: Make the thread id an unsigned integer. From C API side the type of results of PyThread_start_new_thread() and PyThread_get_thread_ident(), the id parameter of PyThreadState_SetAsyncExc(), and the thread_id field of PyThreadState changed from "long" to "unsigned long". * Restore a check in thread_get_ident().
1 parent 1e2147b commit aefa7eb

27 files changed

+116
-88
lines changed

Doc/c-api/init.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -830,7 +830,7 @@ been created.
830830
the caller should assume no current thread state is available.
831831
832832
833-
.. c:function:: int PyThreadState_SetAsyncExc(long id, PyObject *exc)
833+
.. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)
834834
835835
Asynchronously raise an exception in a thread. The *id* argument is the thread
836836
id of the target thread; *exc* is the exception object to be raised. This
@@ -840,6 +840,9 @@ been created.
840840
zero if the thread id isn't found. If *exc* is :const:`NULL`, the pending
841841
exception (if any) for the thread is cleared. This raises no exceptions.
842842
843+
.. versionchanged:: 3.7
844+
The type of the *id* parameter changed from :c:type:`long` to
845+
:c:type:`unsigned long`.
843846
844847
.. c:function:: void PyEval_AcquireThread(PyThreadState *tstate)
845848

Doc/whatsnew/3.7.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,16 @@ Deprecated
185185
(Contributed by Serhiy Storchaka in :issue:`28692`.)
186186

187187

188+
Changes in the C API
189+
--------------------
190+
191+
- The type of results of :c:func:`PyThread_start_new_thread` and
192+
:c:func:`PyThread_get_thread_ident`, and the *id* parameter of
193+
:c:func:`PyThreadState_SetAsyncExc` changed from :c:type:`long` to
194+
:c:type:`unsigned long`.
195+
(Contributed by Serhiy Storchaka in :issue:`6532`.)
196+
197+
188198
Removed
189199
=======
190200

Include/pystate.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ typedef struct _ts {
108108
int gilstate_counter;
109109

110110
PyObject *async_exc; /* Asynchronous exception to raise */
111-
long thread_id; /* Thread id where this tstate was created */
111+
unsigned long thread_id; /* Thread id where this tstate was created */
112112

113113
int trash_delete_nesting;
114114
PyObject *trash_delete_later;
@@ -200,7 +200,7 @@ PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void);
200200

201201
PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *);
202202
PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void);
203-
PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *);
203+
PyAPI_FUNC(int) PyThreadState_SetAsyncExc(unsigned long, PyObject *);
204204

205205

206206
/* Variable and macro for in-line access to current thread state */

Include/pythread.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,14 @@ typedef enum PyLockStatus {
1717
PY_LOCK_INTR
1818
} PyLockStatus;
1919

20+
#ifndef Py_LIMITED_API
21+
#define PYTHREAD_INVALID_THREAD_ID ((unsigned long)-1)
22+
#endif
23+
2024
PyAPI_FUNC(void) PyThread_init_thread(void);
21-
PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *);
25+
PyAPI_FUNC(unsigned long) PyThread_start_new_thread(void (*)(void *), void *);
2226
PyAPI_FUNC(void) PyThread_exit_thread(void);
23-
PyAPI_FUNC(long) PyThread_get_thread_ident(void);
27+
PyAPI_FUNC(unsigned long) PyThread_get_thread_ident(void);
2428

2529
PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void);
2630
PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock);

Lib/_dummy_thread.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ def get_ident():
6969
available, it is safe to assume that the current process is the
7070
only thread. Thus a constant can be safely returned.
7171
"""
72-
return -1
72+
return 1
7373

7474
def allocate_lock():
7575
"""Dummy implementation of _thread.allocate_lock()."""

Lib/test/test_dummy_thread.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,7 @@ def test_exit(self):
111111
def test_ident(self):
112112
self.assertIsInstance(_thread.get_ident(), int,
113113
"_thread.get_ident() returned a non-integer")
114-
self.assertNotEqual(_thread.get_ident(), 0,
115-
"_thread.get_ident() returned 0")
114+
self.assertGreater(_thread.get_ident(), 0)
116115

117116
def test_LockType(self):
118117
self.assertIsInstance(_thread.allocate_lock(), _thread.LockType,

Lib/test/test_sys.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -393,6 +393,9 @@ def g456():
393393
thread_id = thread_info[0]
394394

395395
d = sys._current_frames()
396+
for tid in d:
397+
self.assertIsInstance(tid, int)
398+
self.assertGreater(tid, 0)
396399

397400
main_id = threading.get_ident()
398401
self.assertIn(main_id, d)

Lib/test/test_threading.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ def test_PyThreadState_SetAsyncExc(self):
181181
ctypes = import_module("ctypes")
182182

183183
set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc
184+
set_async_exc.argtypes = (ctypes.c_ulong, ctypes.py_object)
184185

185186
class AsyncExc(Exception):
186187
pass
@@ -189,9 +190,11 @@ class AsyncExc(Exception):
189190

190191
# First check it works when setting the exception from the same thread.
191192
tid = threading.get_ident()
193+
self.assertIsInstance(tid, int)
194+
self.assertGreater(tid, 0)
192195

193196
try:
194-
result = set_async_exc(ctypes.c_long(tid), exception)
197+
result = set_async_exc(tid, exception)
195198
# The exception is async, so we might have to keep the VM busy until
196199
# it notices.
197200
while True:
@@ -237,7 +240,7 @@ def run(self):
237240
# Try a thread id that doesn't make sense.
238241
if verbose:
239242
print(" trying nonsensical thread id")
240- result = set_async_exc(ctypes.c_long(-1), exception)
243+
result = set_async_exc(-1, exception)
241244
self.assertEqual(result, 0) # no thread states modified
242245

243246
# Now raise an exception in the worker thread.
@@ -250,7 +253,7 @@ def run(self):
250253
self.assertFalse(t.finished)
251254
if verbose:
252255
print(" attempting to raise asynch exception in worker")
253-
result = set_async_exc(ctypes.c_long(t.id), exception)
256+
result = set_async_exc(t.id, exception)
254257
self.assertEqual(result, 1) # one thread state modified
255258
if verbose:
256259
print(" waiting for worker to say it caught the exception")

Lib/threading.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -993,14 +993,14 @@ def _delete(self):
993993
#
994994
# Must take care to not raise an exception if _dummy_thread is being
995995
# used (and thus this module is being used as an instance of
996-
# dummy_threading). _dummy_thread.get_ident() always returns -1 since
996+
# dummy_threading). _dummy_thread.get_ident() always returns 1 since
997997
# there is only one thread if _dummy_thread is being used. Thus
998998
# len(_active) is always <= 1 here, and any Thread instance created
999999
# overwrites the (if any) thread currently registered in _active.
10001000
#
10011001
# An instance of _MainThread is always created by 'threading'. This
10021002
# gets overwritten the instant an instance of Thread is created; both
1003-
# threads return -1 from _dummy_thread.get_ident() and thus have the
1003+
# threads return 1 from _dummy_thread.get_ident() and thus have the
10041004
# same key in the dict. So when the _MainThread instance created by
10051005
# 'threading' tries to clean itself up when atexit calls this method
10061006
# it gets a KeyError if another Thread instance was created.

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -813,6 +813,10 @@ Windows
813813
C API
814814
-----
815815

816+
- bpo-6532: The type of results of PyThread_start_new_thread() and
817+
PyThread_get_thread_ident(), and the id parameter of
818+
PyThreadState_SetAsyncExc() changed from "long" to "unsigned long".
819+
816820
- Issue #27867: Function PySlice_GetIndicesEx() is deprecated and replaced with
817821
a macro if Py_LIMITED_API is not set or set to the value between 0x03050400
818822
and 0x03060000 (not including) or 0x03060100 or higher. Added functions

Modules/_io/bufferedio.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ typedef struct {
239239

240240
#ifdef WITH_THREAD
241241
PyThread_type_lock lock;
242-
volatile long owner;
242+
volatile unsigned long owner;
243243
#endif
244244

245245
Py_ssize_t buffer_size;

Modules/_multiprocessing/semaphore.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ enum { RECURSIVE_MUTEX, SEMAPHORE };
1414
typedef struct {
1515
PyObject_HEAD
1616
SEM_HANDLE handle;
17-
long last_tid;
17+
unsigned long last_tid;
1818
int count;
1919
int maxvalue;
2020
int kind;

Modules/_sqlite/connection.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1125,7 +1125,7 @@ int pysqlite_check_thread(pysqlite_Connection* self)
11251125
if (PyThread_get_thread_ident() != self->thread_ident) {
11261126
PyErr_Format(pysqlite_ProgrammingError,
11271127
"SQLite objects created in a thread can only be used in that same thread."
1128-
"The object was created in thread id %ld and this is thread id %ld",
1128+
"The object was created in thread id % 10000 lu and this is thread id %lu",
11291129
self->thread_ident, PyThread_get_thread_ident());
11301130
return 0;
11311131
}

Modules/_sqlite/connection.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ typedef struct
6161
int initialized;
6262

6363
/* thread identification of the thread the connection was created in */
64-
long thread_ident;
64+
unsigned long thread_ident;
6565

6666
pysqlite_Cache* statement_cache;
6767

Modules/_ssl.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5032,8 +5032,7 @@ static PyThread_type_lock *_ssl_locks = NULL;
50325032
static void
50335033
_ssl_threadid_callback(CRYPTO_THREADID *id)
50345034
{
5035-
CRYPTO_THREADID_set_numeric(id,
5036-
(unsigned long)PyThread_get_thread_ident());
5035+
CRYPTO_THREADID_set_numeric(id, PyThread_get_thread_ident());
50375036
}
50385037
#else
50395038
/* deprecated CRYPTO_set_id_callback() API. */

Modules/_threadmodule.c

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,7 @@ static PyTypeObject Locktype = {
267267
typedef struct {
268268
PyObject_HEAD
269269
PyThread_type_lock rlock_lock;
270-
long rlock_owner;
270+
unsigned long rlock_owner;
271271
unsigned long rlock_count;
272272
PyObject *in_weakreflist;
273273
} rlockobject;
@@ -293,7 +293,7 @@ static PyObject *
293293
rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds)
294294
{
295295
_PyTime_t timeout;
296-
long tid;
296+
unsigned long tid;
297297
PyLockStatus r = PY_LOCK_ACQUIRED;
298298

299299
if (lock_acquire_parse_args(args, kwds, &timeout) < 0)
@@ -342,7 +342,7 @@ the lock is taken and its internal counter initialized to 1.");
342342
static PyObject *
343343
rlock_release(rlockobject *self)
344344
{
345-
long tid = PyThread_get_thread_ident();
345+
unsigned long tid = PyThread_get_thread_ident();
346346

347347
if (self->rlock_count == 0 || self->rlock_owner != tid) {
348348
PyErr_SetString(PyExc_RuntimeError,
@@ -371,11 +371,11 @@ to be available for other threads.");
371371
static PyObject *
372372
rlock_acquire_restore(rlockobject *self, PyObject *args)
373373
{
374-
long owner;
374+
unsigned long owner;
375375
unsigned long count;
376376
int r = 1;
377377

378-
if (!PyArg_ParseTuple(args, "(kl):_acquire_restore", &count, &owner))
378+
if (!PyArg_ParseTuple(args, "(kk):_acquire_restore", &count, &owner))
379379
return NULL;
380380

381381
if (!PyThread_acquire_lock(self->rlock_lock, 0)) {
@@ -401,7 +401,7 @@ For internal use by `threading.Condition`.");
401401
static PyObject *
402402
rlock_release_save(rlockobject *self)
403403
{
404-
long owner;
404+
unsigned long owner;
405405
unsigned long count;
406406

407407
if (self->rlock_count == 0) {
@@ -415,7 +415,7 @@ rlock_release_save(rlockobject *self)
415415
self->rlock_count = 0;
416416
self->rlock_owner = 0;
417417
PyThread_release_lock(self->rlock_lock);
418-
return Py_BuildValue("kl", count, owner);
418+
return Py_BuildValue("kk", count, owner);
419419
}
420420

421421
PyDoc_STRVAR(rlock_release_save_doc,
@@ -427,7 +427,7 @@ For internal use by `threading.Condition`.");
427427
static PyObject *
428428
rlock_is_owned(rlockobject *self)
429429
{
430-
long tid = PyThread_get_thread_ident();
430+
unsigned long tid = PyThread_get_thread_ident();
431431

432432
if (self->rlock_count > 0 && self->rlock_owner == tid) {
433433
Py_RETURN_TRUE;
@@ -1031,7 +1031,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
10311031
{
10321032
PyObject *func, *args, *keyw = NULL;
10331033
struct bootstate *boot;
1034-
long ident;
1034+
unsigned long ident;
10351035

10361036
if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
10371037
&func, &args, &keyw))
@@ -1068,7 +1068,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
10681068
Py_XINCREF(keyw);
10691069
PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
10701070
ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
1071-
if (ident == -1) {
1071+
if (ident == PYTHREAD_INVALID_THREAD_ID) {
10721072
PyErr_SetString(ThreadError, "can't start new thread");
10731073
Py_DECREF(func);
10741074
Py_DECREF(args);
@@ -1077,7 +1077,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
10771077
PyMem_DEL(boot);
10781078
return NULL;
10791079
}
1080-
return PyLong_FromLong(ident);
1080+
return PyLong_FromUnsignedLong(ident);
10811081
}
10821082

10831083
PyDoc_STRVAR(start_new_doc,
@@ -1137,13 +1137,12 @@ information about locks.");
11371137
static PyObject *
11381138
thread_get_ident(PyObject *self)
11391139
{
1140-
long ident;
1141-
ident = PyThread_get_thread_ident();
1142-
if (ident == -1) {
1140+
unsigned long ident = PyThread_get_thread_ident();
1141+
if (ident == PYTHREAD_INVALID_THREAD_ID) {
11431142
PyErr_SetString(ThreadError, "no current thread ident");
11441143
return NULL;
11451144
}
1146-
return PyLong_FromLong(ident);
1145+
return PyLong_FromUnsignedLong(ident);
11471146
}
11481147

11491148
PyDoc_STRVAR(get_ident_doc,

Modules/clinic/signalmodule.c.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -395,16 +395,17 @@ PyDoc_STRVAR(signal_pthread_kill__doc__,
395395
{"pthread_kill", (PyCFunction)signal_pthread_kill, METH_FASTCALL, signal_pthread_kill__doc__},
396396

397397
static PyObject *
398-
signal_pthread_kill_impl(PyObject *module, long thread_id, int signalnum);
398+
signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
399+
int signalnum);
399400

400401
static PyObject *
401402
signal_pthread_kill(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
402403
{
403404
PyObject *return_value = NULL;
404-
long thread_id;
405+
unsigned long thread_id;
405406
int signalnum;
406407

407-
if (!_PyArg_ParseStack(args, nargs, "li:pthread_kill",
408+
if (!_PyArg_ParseStack(args, nargs, "ki:pthread_kill",
408409
&thread_id, &signalnum)) {
409410
goto exit;
410411
}
@@ -463,4 +464,4 @@ signal_pthread_kill(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObjec
463464
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
464465
#define SIGNAL_PTHREAD_KILL_METHODDEF
465466
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
466-
/*[clinic end generated code: output=fab3dba32c058588 input=a9049054013a1b77]*/
467+
/*[clinic end generated code: output=c1a3f374b2c77e5d input=a9049054013a1b77]*/

Modules/faulthandler.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ faulthandler_dump_traceback_later(PyObject *self,
678678
/* Arm these locks to serve as events when released */
679679
PyThread_acquire_lock(thread.running, 1);
680680

681-
if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) {
681+
if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
682682
PyThread_release_lock(thread.running);
683683
Py_CLEAR(thread.file);
684684
PyMem_Free(header);

Modules/signalmodule.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ module signal
8888
#ifdef WITH_THREAD
8989
#include <sys/types.h> /* For pid_t */
9090
#include "pythread.h"
91-
static long main_thread;
91+
static unsigned long main_thread;
9292
static pid_t main_pid;
9393
#endif
9494

@@ -1088,16 +1088,17 @@ signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
10881088
/*[clinic input]
10891089
signal.pthread_kill
10901090
1091-
thread_id: long
1091+
thread_id: unsigned_long(bitwise=True)
10921092
signalnum: int
10931093
/
10941094
10951095
Send a signal to a thread.
10961096
[clinic start generated code]*/
10971097

10981098
static PyObject *
1099-
signal_pthread_kill_impl(PyObject *module, long thread_id, int signalnum)
1100-
/*[clinic end generated code: output=2a09ce41f1c4228a input=77ed6a3b6f2a8122]*/
1099+
signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
1100+
int signalnum)
1101+
/*[clinic end generated code: output=7629919b791bc27f input=1d901f2c7bb544ff]*/
11011102
{
11021103
int err;
11031104

Python/ceval.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ static long dxp[256];
148148
#include "pythread.h"
149149

150150
static PyThread_type_lock pending_lock = 0; /* for pending calls */
151-
static long main_thread = 0;
151+
static unsigned long main_thread = 0;
152152
/* This single variable consolidates all requests to break out of the fast path
153153
in the eval loop. */
154154
static _Py_atomic_int eval_breaker = {0};

0 commit comments

Comments
 (0)
0