diff options
author | Antoine Pitrou <antoine@python.org> | 2023-11-04 13:59:24 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-04 13:59:24 (GMT) |
commit | 0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09 (patch) | |
tree | 8febb8282c2c1ebd73a18205ec5b9229a99ac4fe /Python/thread_pthread.h | |
parent | a28a3967ab9a189122f895d51d2551f7b3a273b0 (diff) | |
download | cpython-0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09.zip cpython-0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09.tar.gz cpython-0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09.tar.bz2 |
GH-110829: Ensure Thread.join() joins the OS thread (#110848)
Joining a thread now ensures the underlying OS thread has exited. This is required for safer fork() in multi-threaded processes.
---------
Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>
Diffstat (limited to 'Python/thread_pthread.h')
-rw-r--r-- | Python/thread_pthread.h | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/Python/thread_pthread.h b/Python/thread_pthread.h index 76a1f77..a8df544 100644 --- a/Python/thread_pthread.h +++ b/Python/thread_pthread.h @@ -235,8 +235,8 @@ pythread_wrapper(void *arg) return NULL; } -unsigned long -PyThread_start_new_thread(void (*func)(void *), void *arg) +static int +do_start_joinable_thread(void (*func)(void *), void *arg, pthread_t* out_id) { pthread_t th; int status; @@ -252,7 +252,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) if (pthread_attr_init(&attrs) != 0) - return PYTHREAD_INVALID_THREAD_ID; + return -1; #endif #if defined(THREAD_STACK_SIZE) PyThreadState *tstate = _PyThreadState_GET(); @@ -261,7 +261,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) if (tss != 0) { if (pthread_attr_setstacksize(&attrs, tss) != 0) { pthread_attr_destroy(&attrs); - return PYTHREAD_INVALID_THREAD_ID; + return -1; } } #endif @@ -272,7 +272,7 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) pythread_callback *callback = PyMem_RawMalloc(sizeof(pythread_callback)); if (callback == NULL) { - return PYTHREAD_INVALID_THREAD_ID; + return -1; } callback->func = func; @@ -292,11 +292,34 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) if (status != 0) { PyMem_RawFree(callback); - return PYTHREAD_INVALID_THREAD_ID; + return -1; } + *out_id = th; + return 0; +} - pthread_detach(th); +int +PyThread_start_joinable_thread(void (*func)(void *), void *arg, + PyThread_ident_t* ident, PyThread_handle_t* handle) { + pthread_t th = (pthread_t) 0; + if (do_start_joinable_thread(func, arg, &th)) { + return -1; + } + *ident = (PyThread_ident_t) th; + *handle = (PyThread_handle_t) th; + assert(th == (pthread_t) *ident); + assert(th == (pthread_t) *handle); + return 0; +} +unsigned long +PyThread_start_new_thread(void (*func)(void *), void *arg) +{ + pthread_t th = (pthread_t) 0; + if (do_start_joinable_thread(func, arg, &th)) { + return PYTHREAD_INVALID_THREAD_ID; + } + pthread_detach(th); #if SIZEOF_PTHREAD_T <= SIZEOF_LONG return (unsigned long) th; #else @@ -304,20 +327,46 @@ PyThread_start_new_thread(void (*func)(void *), void *arg) #endif } +int +PyThread_join_thread(PyThread_handle_t th) { + return pthread_join((pthread_t) th, NULL); +} + +int +PyThread_detach_thread(PyThread_handle_t th) { + return pthread_detach((pthread_t) th); +} + +void +PyThread_update_thread_after_fork(PyThread_ident_t* ident, PyThread_handle_t* handle) { + // The thread id might have been updated in the forked child + pthread_t th = pthread_self(); + *ident = (PyThread_ident_t) th; + *handle = (PyThread_handle_t) th; + assert(th == (pthread_t) *ident); + assert(th == (pthread_t) *handle); +} + /* XXX This implementation is considered (to quote Tim Peters) "inherently hosed" because: - It does not guarantee the promise that a non-zero integer is returned. - The cast to unsigned long is inherently unsafe. - It is not clear that the 'volatile' (for AIX?) are any longer necessary. */ -unsigned long -PyThread_get_thread_ident(void) -{ +PyThread_ident_t +PyThread_get_thread_ident_ex(void) { volatile pthread_t threadid; if (!initialized) PyThread_init_thread(); threadid = pthread_self(); - return (unsigned long) threadid; + assert(threadid == (pthread_t) (PyThread_ident_t) threadid); + return (PyThread_ident_t) threadid; +} + +unsigned long +PyThread_get_thread_ident(void) +{ + return (unsigned long) PyThread_get_thread_ident_ex(); } #ifdef PY_HAVE_THREAD_NATIVE_ID |