mirror of
https://github.com/python/cpython.git
synced 2025-07-07 19:35:27 +00:00
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>
This commit is contained in:
parent
a28a3967ab
commit
0e9c364f4a
14 changed files with 676 additions and 103 deletions
|
@ -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 -1;
|
||||
}
|
||||
*out_id = th;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue