summaryrefslogtreecommitdiffstats
path: root/Python/thread_pthread.h
diff options
context:
space:
mode:
authorAntoine Pitrou <antoine@python.org>2023-11-04 13:59:24 (GMT)
committerGitHub <noreply@github.com>2023-11-04 13:59:24 (GMT)
commit0e9c364f4ac18a2237bdbac702b96bcf8ef9cb09 (patch)
tree8febb8282c2c1ebd73a18205ec5b9229a99ac4fe /Python/thread_pthread.h
parenta28a3967ab9a189122f895d51d2551f7b3a273b0 (diff)
downloadcpython-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.h71
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