1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
#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
#include "pycore_llist.h" // struct llist_node
// 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 "cpython/pthread_stubs.h" // PTHREAD_KEYS_MAX
#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
// Linked list of ThreadHandles
struct llist_node handles;
};
#define _pythread_RUNTIME_INIT(pythread) \
{ \
.handles = LLIST_INIT(pythread.handles), \
}
#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);
extern void _PyThread_AfterFork(struct _pythread_runtime_state *state);
#endif /* HAVE_FORK */
// unset: -1 seconds, in nanoseconds
#define PyThread_UNSET_TIMEOUT ((PyTime_t)(-1 * 1000 * 1000 * 1000))
// Exported for the _interpchannels 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 _interpchannels 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);
#ifdef __cplusplus
}
#endif
#endif /* !Py_INTERNAL_PYTHREAD_H */
|