Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ been created.
the caller should assume no current thread state is available.


.. c:function:: int PyThreadState_SetAsyncExc(long id, PyObject *exc)
.. c:function:: int PyThreadState_SetAsyncExc(unsigned long id, PyObject *exc)

Asynchronously raise an exception in a thread. The *id* argument is the thread
id of the target thread; *exc* is the exception object to be raised. This
Expand All @@ -840,6 +840,9 @@ been created.
zero if the thread id isn't found. If *exc* is :const:`NULL`, the pending
exception (if any) for the thread is cleared. This raises no exceptions.

.. versionchanged:: 3.7
The type of the *id* parameter changed from :c:type:`long` to
:c:type:`unsigned long`.

.. c:function:: void PyEval_AcquireThread(PyThreadState *tstate)

Expand Down
10 changes: 10 additions & 0 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,16 @@ Deprecated
(Contributed by Serhiy Storchaka in :issue:`28692`.)


Changes in the C API
--------------------

- The type of results of :c:func:`PyThread_start_new_thread` and
:c:func:`PyThread_get_thread_ident`, and the *id* parameter of
:c:func:`PyThreadState_SetAsyncExc` changed from :c:type:`long` to
:c:type:`unsigned long`.
(Contributed by Serhiy Storchaka in :issue:`6532`.)


Removed
=======

Expand Down
4 changes: 2 additions & 2 deletions Include/pystate.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ typedef struct _ts {
int gilstate_counter;

PyObject *async_exc; /* Asynchronous exception to raise */
long thread_id; /* Thread id where this tstate was created */
unsigned long thread_id; /* Thread id where this tstate was created */

int trash_delete_nesting;
PyObject *trash_delete_later;
Expand Down Expand Up @@ -200,7 +200,7 @@ PyAPI_FUNC(PyThreadState *) _PyThreadState_UncheckedGet(void);

PyAPI_FUNC(PyThreadState *) PyThreadState_Swap(PyThreadState *);
PyAPI_FUNC(PyObject *) PyThreadState_GetDict(void);
PyAPI_FUNC(int) PyThreadState_SetAsyncExc(long, PyObject *);
PyAPI_FUNC(int) PyThreadState_SetAsyncExc(unsigned long, PyObject *);


/* Variable and macro for in-line access to current thread state */
Expand Down
8 changes: 6 additions & 2 deletions Include/pythread.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ typedef enum PyLockStatus {
PY_LOCK_INTR
} PyLockStatus;

#ifndef Py_LIMITED_API
#define PYTHREAD_INVALID_THREAD_ID ((unsigned long)-1)
#endif

PyAPI_FUNC(void) PyThread_init_thread(void);
PyAPI_FUNC(long) PyThread_start_new_thread(void (*)(void *), void *);
PyAPI_FUNC(unsigned long) PyThread_start_new_thread(void (*)(void *), void *);
PyAPI_FUNC(void) PyThread_exit_thread(void);
PyAPI_FUNC(long) PyThread_get_thread_ident(void);
PyAPI_FUNC(unsigned long) PyThread_get_thread_ident(void);

PyAPI_FUNC(PyThread_type_lock) PyThread_allocate_lock(void);
PyAPI_FUNC(void) PyThread_free_lock(PyThread_type_lock);
Expand Down
2 changes: 1 addition & 1 deletion Lib/_dummy_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def get_ident():
available, it is safe to assume that the current process is the
only thread. Thus a constant can be safely returned.
"""
return -1
return 1

def allocate_lock():
"""Dummy implementation of _thread.allocate_lock()."""
Expand Down
3 changes: 1 addition & 2 deletions Lib/test/test_dummy_thread.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,8 +111,7 @@ def test_exit(self):
def test_ident(self):
self.assertIsInstance(_thread.get_ident(), int,
"_thread.get_ident() returned a non-integer")
self.assertNotEqual(_thread.get_ident(), 0,
"_thread.get_ident() returned 0")
self.assertGreater(_thread.get_ident(), 0)

def test_LockType(self):
self.assertIsInstance(_thread.allocate_lock(), _thread.LockType,
Expand Down
3 changes: 3 additions & 0 deletions Lib/test/test_sys.py
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,9 @@ def g456():
thread_id = thread_info[0]

d = sys._current_frames()
for tid in d:
self.assertIsInstance(tid, int)
self.assertGreater(tid, 0)

main_id = threading.get_ident()
self.assertIn(main_id, d)
Expand Down
9 changes: 6 additions & 3 deletions Lib/test/test_threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ def test_PyThreadState_SetAsyncExc(self):
ctypes = import_module("ctypes")

set_async_exc = ctypes.pythonapi.PyThreadState_SetAsyncExc
set_async_exc.argtypes = (ctypes.c_ulong, ctypes.py_object)

class AsyncExc(Exception):
pass
Expand All @@ -189,9 +190,11 @@ class AsyncExc(Exception):

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

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

# Now raise an exception in the worker thread.
Expand All @@ -250,7 +253,7 @@ def run(self):
self.assertFalse(t.finished)
if verbose:
print(" attempting to raise asynch exception in worker")
result = set_async_exc(ctypes.c_long(t.id), exception)
result = set_async_exc(t.id, exception)
self.assertEqual(result, 1) # one thread state modified
if verbose:
print(" waiting for worker to say it caught the exception")
Expand Down
4 changes: 2 additions & 2 deletions Lib/threading.py
Original file line number Diff line number Diff line change
Expand Up @@ -993,14 +993,14 @@ def _delete(self):
#
# Must take care to not raise an exception if _dummy_thread is being
# used (and thus this module is being used as an instance of
# dummy_threading). _dummy_thread.get_ident() always returns -1 since
# dummy_threading). _dummy_thread.get_ident() always returns 1 since
# there is only one thread if _dummy_thread is being used. Thus
# len(_active) is always <= 1 here, and any Thread instance created
# overwrites the (if any) thread currently registered in _active.
#
# An instance of _MainThread is always created by 'threading'. This
# gets overwritten the instant an instance of Thread is created; both
# threads return -1 from _dummy_thread.get_ident() and thus have the
# threads return 1 from _dummy_thread.get_ident() and thus have the
# same key in the dict. So when the _MainThread instance created by
# 'threading' tries to clean itself up when atexit calls this method
# it gets a KeyError if another Thread instance was created.
Expand Down
4 changes: 4 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,10 @@ Windows
C API
-----

- bpo-6532: The type of results of PyThread_start_new_thread() and
PyThread_get_thread_ident(), and the id parameter of
PyThreadState_SetAsyncExc() changed from "long" to "unsigned long".

- Issue #27867: Function PySlice_GetIndicesEx() is deprecated and replaced with
a macro if Py_LIMITED_API is not set or set to the value between 0x03050400
and 0x03060000 (not including) or 0x03060100 or higher. Added functions
Expand Down
2 changes: 1 addition & 1 deletion Modules/_io/bufferedio.c
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ typedef struct {

#ifdef WITH_THREAD
PyThread_type_lock lock;
volatile long owner;
volatile unsigned long owner;
#endif

Py_ssize_t buffer_size;
Expand Down
2 changes: 1 addition & 1 deletion Modules/_multiprocessing/semaphore.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ enum { RECURSIVE_MUTEX, SEMAPHORE };
typedef struct {
PyObject_HEAD
SEM_HANDLE handle;
long last_tid;
unsigned long last_tid;
int count;
int maxvalue;
int kind;
Expand Down
2 changes: 1 addition & 1 deletion Modules/_sqlite/connection.c
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ int pysqlite_check_thread(pysqlite_Connection* self)
if (PyThread_get_thread_ident() != self->thread_ident) {
PyErr_Format(pysqlite_ProgrammingError,
"SQLite objects created in a thread can only be used in that same thread."
"The object was created in thread id %ld and this is thread id %ld",
"The object was created in thread id %lu and this is thread id %lu",
self->thread_ident, PyThread_get_thread_ident());
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion Modules/_sqlite/connection.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ typedef struct
int initialized;

/* thread identification of the thread the connection was created in */
long thread_ident;
unsigned long thread_ident;

pysqlite_Cache* statement_cache;

Expand Down
3 changes: 1 addition & 2 deletions Modules/_ssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -5032,8 +5032,7 @@ static PyThread_type_lock *_ssl_locks = NULL;
static void
_ssl_threadid_callback(CRYPTO_THREADID *id)
{
CRYPTO_THREADID_set_numeric(id,
(unsigned long)PyThread_get_thread_ident());
CRYPTO_THREADID_set_numeric(id, PyThread_get_thread_ident());
}
#else
/* deprecated CRYPTO_set_id_callback() API. */
Expand Down
29 changes: 14 additions & 15 deletions Modules/_threadmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ static PyTypeObject Locktype = {
typedef struct {
PyObject_HEAD
PyThread_type_lock rlock_lock;
long rlock_owner;
unsigned long rlock_owner;
unsigned long rlock_count;
PyObject *in_weakreflist;
} rlockobject;
Expand All @@ -293,7 +293,7 @@ static PyObject *
rlock_acquire(rlockobject *self, PyObject *args, PyObject *kwds)
{
_PyTime_t timeout;
long tid;
unsigned long tid;
PyLockStatus r = PY_LOCK_ACQUIRED;

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

if (self->rlock_count == 0 || self->rlock_owner != tid) {
PyErr_SetString(PyExc_RuntimeError,
Expand Down Expand Up @@ -371,11 +371,11 @@ to be available for other threads.");
static PyObject *
rlock_acquire_restore(rlockobject *self, PyObject *args)
{
long owner;
unsigned long owner;
unsigned long count;
int r = 1;

if (!PyArg_ParseTuple(args, "(kl):_acquire_restore", &count, &owner))
if (!PyArg_ParseTuple(args, "(kk):_acquire_restore", &count, &owner))
return NULL;

if (!PyThread_acquire_lock(self->rlock_lock, 0)) {
Expand All @@ -401,7 +401,7 @@ For internal use by `threading.Condition`.");
static PyObject *
rlock_release_save(rlockobject *self)
{
long owner;
unsigned long owner;
unsigned long count;

if (self->rlock_count == 0) {
Expand All @@ -415,7 +415,7 @@ rlock_release_save(rlockobject *self)
self->rlock_count = 0;
self->rlock_owner = 0;
PyThread_release_lock(self->rlock_lock);
return Py_BuildValue("kl", count, owner);
return Py_BuildValue("kk", count, owner);
}

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

if (self->rlock_count > 0 && self->rlock_owner == tid) {
Py_RETURN_TRUE;
Expand Down Expand Up @@ -1031,7 +1031,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
{
PyObject *func, *args, *keyw = NULL;
struct bootstate *boot;
long ident;
unsigned long ident;

if (!PyArg_UnpackTuple(fargs, "start_new_thread", 2, 3,
&func, &args, &keyw))
Expand Down Expand Up @@ -1068,7 +1068,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
Py_XINCREF(keyw);
PyEval_InitThreads(); /* Start the interpreter's thread-awareness */
ident = PyThread_start_new_thread(t_bootstrap, (void*) boot);
if (ident == -1) {
if (ident == PYTHREAD_INVALID_THREAD_ID) {
PyErr_SetString(ThreadError, "can't start new thread");
Py_DECREF(func);
Py_DECREF(args);
Expand All @@ -1077,7 +1077,7 @@ thread_PyThread_start_new_thread(PyObject *self, PyObject *fargs)
PyMem_DEL(boot);
return NULL;
}
return PyLong_FromLong(ident);
return PyLong_FromUnsignedLong(ident);
}

PyDoc_STRVAR(start_new_doc,
Expand Down Expand Up @@ -1137,13 +1137,12 @@ information about locks.");
static PyObject *
thread_get_ident(PyObject *self)
{
long ident;
ident = PyThread_get_thread_ident();
if (ident == -1) {
unsigned long ident = PyThread_get_thread_ident();
if (ident == PYTHREAD_INVALID_THREAD_ID) {
PyErr_SetString(ThreadError, "no current thread ident");
return NULL;
}
return PyLong_FromLong(ident);
return PyLong_FromUnsignedLong(ident);
}

PyDoc_STRVAR(get_ident_doc,
Expand Down
9 changes: 5 additions & 4 deletions Modules/clinic/signalmodule.c.h
Original file line number Diff line number Diff line change
Expand Up @@ -395,16 +395,17 @@ PyDoc_STRVAR(signal_pthread_kill__doc__,
{"pthread_kill", (PyCFunction)signal_pthread_kill, METH_FASTCALL, signal_pthread_kill__doc__},

static PyObject *
signal_pthread_kill_impl(PyObject *module, long thread_id, int signalnum);
signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
int signalnum);

static PyObject *
signal_pthread_kill(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObject *kwnames)
{
PyObject *return_value = NULL;
long thread_id;
unsigned long thread_id;
int signalnum;

if (!_PyArg_ParseStack(args, nargs, "li:pthread_kill",
if (!_PyArg_ParseStack(args, nargs, "ki:pthread_kill",
&thread_id, &signalnum)) {
goto exit;
}
Expand Down Expand Up @@ -463,4 +464,4 @@ signal_pthread_kill(PyObject *module, PyObject **args, Py_ssize_t nargs, PyObjec
#ifndef SIGNAL_PTHREAD_KILL_METHODDEF
#define SIGNAL_PTHREAD_KILL_METHODDEF
#endif /* !defined(SIGNAL_PTHREAD_KILL_METHODDEF) */
/*[clinic end generated code: output=fab3dba32c058588 input=a9049054013a1b77]*/
/*[clinic end generated code: output=c1a3f374b2c77e5d input=a9049054013a1b77]*/
2 changes: 1 addition & 1 deletion Modules/faulthandler.c
Original file line number Diff line number Diff line change
Expand Up @@ -678,7 +678,7 @@ faulthandler_dump_traceback_later(PyObject *self,
/* Arm these locks to serve as events when released */
PyThread_acquire_lock(thread.running, 1);

if (PyThread_start_new_thread(faulthandler_thread, NULL) == -1) {
if (PyThread_start_new_thread(faulthandler_thread, NULL) == PYTHREAD_INVALID_THREAD_ID) {
PyThread_release_lock(thread.running);
Py_CLEAR(thread.file);
PyMem_Free(header);
Expand Down
9 changes: 5 additions & 4 deletions Modules/signalmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ module signal
#ifdef WITH_THREAD
#include <sys/types.h> /* For pid_t */
#include "pythread.h"
static long main_thread;
static unsigned long main_thread;
static pid_t main_pid;
#endif

Expand Down Expand Up @@ -1088,16 +1088,17 @@ signal_sigtimedwait_impl(PyObject *module, PyObject *sigset,
/*[clinic input]
signal.pthread_kill

thread_id: long
thread_id: unsigned_long(bitwise=True)
signalnum: int
/

Send a signal to a thread.
[clinic start generated code]*/

static PyObject *
signal_pthread_kill_impl(PyObject *module, long thread_id, int signalnum)
/*[clinic end generated code: output=2a09ce41f1c4228a input=77ed6a3b6f2a8122]*/
signal_pthread_kill_impl(PyObject *module, unsigned long thread_id,
int signalnum)
/*[clinic end generated code: output=7629919b791bc27f input=1d901f2c7bb544ff]*/
{
int err;

Expand Down
2 changes: 1 addition & 1 deletion Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ static long dxp[256];
#include "pythread.h"

static PyThread_type_lock pending_lock = 0; /* for pending calls */
static long main_thread = 0;
static unsigned long main_thread = 0;
/* This single variable consolidates all requests to break out of the fast path
in the eval loop. */
static _Py_atomic_int eval_breaker = {0};
Expand Down
Loading