mirror of
				https://github.com/python/cpython.git
				synced 2025-11-03 19:34:08 +00:00 
			
		
		
		
	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>
		
			
				
	
	
		
			155 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			155 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
#ifndef Py_INTERNAL_PYTHREAD_H
 | 
						|
#define Py_INTERNAL_PYTHREAD_H
 | 
						|
#ifdef __cplusplus
 | 
						|
extern "C" {
 | 
						|
#endif
 | 
						|
 | 
						|
#ifndef Py_BUILD_CORE
 | 
						|
#  error "this header requires Py_BUILD_CORE define"
 | 
						|
#endif
 | 
						|
 | 
						|
#include "dynamic_annotations.h" // _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX
 | 
						|
 | 
						|
// Get _POSIX_THREADS and _POSIX_SEMAPHORES macros if available
 | 
						|
#if (defined(HAVE_UNISTD_H) && !defined(_POSIX_THREADS) \
 | 
						|
                            && !defined(_POSIX_SEMAPHORES))
 | 
						|
#  include <unistd.h>             // _POSIX_THREADS, _POSIX_SEMAPHORES
 | 
						|
#endif
 | 
						|
#if (defined(HAVE_PTHREAD_H) && !defined(_POSIX_THREADS) \
 | 
						|
                             && !defined(_POSIX_SEMAPHORES))
 | 
						|
   // This means pthreads are not implemented in libc headers, hence the macro
 | 
						|
   // not present in <unistd.h>. But they still can be implemented as an
 | 
						|
   // external library (e.g. gnu pth in pthread emulation)
 | 
						|
#  include <pthread.h>            // _POSIX_THREADS, _POSIX_SEMAPHORES
 | 
						|
#endif
 | 
						|
#if !defined(_POSIX_THREADS) && defined(__hpux) && defined(_SC_THREADS)
 | 
						|
   // Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
 | 
						|
   // enough of the POSIX threads package is implemented to support Python
 | 
						|
   // threads.
 | 
						|
   //
 | 
						|
   // This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
 | 
						|
   // a check of __ia64 to verify that we're running on an ia64 system instead
 | 
						|
   // of a pa-risc system.
 | 
						|
#  define _POSIX_THREADS
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if defined(_POSIX_THREADS) || defined(HAVE_PTHREAD_STUBS)
 | 
						|
#  define _USE_PTHREADS
 | 
						|
#endif
 | 
						|
 | 
						|
#if defined(_USE_PTHREADS) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
 | 
						|
// monotonic is supported statically.  It doesn't mean it works on runtime.
 | 
						|
#  define CONDATTR_MONOTONIC
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
#if defined(HAVE_PTHREAD_STUBS)
 | 
						|
#include <stdbool.h>              // bool
 | 
						|
 | 
						|
// pthread_key
 | 
						|
struct py_stub_tls_entry {
 | 
						|
    bool in_use;
 | 
						|
    void *value;
 | 
						|
};
 | 
						|
#endif
 | 
						|
 | 
						|
struct _pythread_runtime_state {
 | 
						|
    int initialized;
 | 
						|
 | 
						|
#ifdef _USE_PTHREADS
 | 
						|
    // This matches when thread_pthread.h is used.
 | 
						|
    struct {
 | 
						|
        /* NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported. */
 | 
						|
        pthread_condattr_t *ptr;
 | 
						|
# ifdef CONDATTR_MONOTONIC
 | 
						|
    /* The value to which condattr_monotonic is set. */
 | 
						|
        pthread_condattr_t val;
 | 
						|
# endif
 | 
						|
    } _condattr_monotonic;
 | 
						|
 | 
						|
#endif  // USE_PTHREADS
 | 
						|
 | 
						|
#if defined(HAVE_PTHREAD_STUBS)
 | 
						|
    struct {
 | 
						|
        struct py_stub_tls_entry tls_entries[PTHREAD_KEYS_MAX];
 | 
						|
    } stubs;
 | 
						|
#endif
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
#ifdef HAVE_FORK
 | 
						|
/* Private function to reinitialize a lock at fork in the child process.
 | 
						|
   Reset the lock to the unlocked state.
 | 
						|
   Return 0 on success, return -1 on error. */
 | 
						|
extern int _PyThread_at_fork_reinit(PyThread_type_lock *lock);
 | 
						|
#endif  /* HAVE_FORK */
 | 
						|
 | 
						|
 | 
						|
// unset: -1 seconds, in nanoseconds
 | 
						|
#define PyThread_UNSET_TIMEOUT ((_PyTime_t)(-1 * 1000 * 1000 * 1000))
 | 
						|
 | 
						|
// Exported for the _xxinterpchannels module.
 | 
						|
PyAPI_FUNC(int) PyThread_ParseTimeoutArg(
 | 
						|
    PyObject *arg,
 | 
						|
    int blocking,
 | 
						|
    PY_TIMEOUT_T *timeout);
 | 
						|
 | 
						|
/* Helper to acquire an interruptible lock with a timeout.  If the lock acquire
 | 
						|
 * is interrupted, signal handlers are run, and if they raise an exception,
 | 
						|
 * PY_LOCK_INTR is returned.  Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE
 | 
						|
 * are returned, depending on whether the lock can be acquired within the
 | 
						|
 * timeout.
 | 
						|
 */
 | 
						|
// Exported for the _xxinterpchannels module.
 | 
						|
PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed_with_retries(
 | 
						|
    PyThread_type_lock,
 | 
						|
    PY_TIMEOUT_T microseconds);
 | 
						|
 | 
						|
typedef unsigned long long PyThread_ident_t;
 | 
						|
typedef Py_uintptr_t PyThread_handle_t;
 | 
						|
 | 
						|
#define PY_FORMAT_THREAD_IDENT_T "llu"
 | 
						|
#define Py_PARSE_THREAD_IDENT_T "K"
 | 
						|
 | 
						|
PyAPI_FUNC(PyThread_ident_t) PyThread_get_thread_ident_ex(void);
 | 
						|
 | 
						|
/* Thread joining APIs.
 | 
						|
 *
 | 
						|
 * These APIs have a strict contract:
 | 
						|
 *  - Either PyThread_join_thread or PyThread_detach_thread must be called
 | 
						|
 *    exactly once with the given handle.
 | 
						|
 *  - Calling neither PyThread_join_thread nor PyThread_detach_thread results
 | 
						|
 *    in a resource leak until the end of the process.
 | 
						|
 *  - Any other usage, such as calling both PyThread_join_thread and
 | 
						|
 *    PyThread_detach_thread, or calling them more than once (including
 | 
						|
 *    simultaneously), results in undefined behavior.
 | 
						|
 */
 | 
						|
PyAPI_FUNC(int) PyThread_start_joinable_thread(void (*func)(void *),
 | 
						|
                                               void *arg,
 | 
						|
                                               PyThread_ident_t* ident,
 | 
						|
                                               PyThread_handle_t* handle);
 | 
						|
/*
 | 
						|
 * Join a thread started with `PyThread_start_joinable_thread`.
 | 
						|
 * This function cannot be interrupted. It returns 0 on success,
 | 
						|
 * a non-zero value on failure.
 | 
						|
 */
 | 
						|
PyAPI_FUNC(int) PyThread_join_thread(PyThread_handle_t);
 | 
						|
/*
 | 
						|
 * Detach a thread started with `PyThread_start_joinable_thread`, such
 | 
						|
 * that its resources are relased as soon as it exits.
 | 
						|
 * This function cannot be interrupted. It returns 0 on success,
 | 
						|
 * a non-zero value on failure.
 | 
						|
 */
 | 
						|
PyAPI_FUNC(int) PyThread_detach_thread(PyThread_handle_t);
 | 
						|
 | 
						|
/*
 | 
						|
 * Obtain the new thread ident and handle in a forked child process.
 | 
						|
 */
 | 
						|
PyAPI_FUNC(void) PyThread_update_thread_after_fork(PyThread_ident_t* ident,
 | 
						|
                                                   PyThread_handle_t* handle);
 | 
						|
 | 
						|
#ifdef __cplusplus
 | 
						|
}
 | 
						|
#endif
 | 
						|
#endif /* !Py_INTERNAL_PYTHREAD_H */
 |