• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #ifndef Py_INTERNAL_PYTHREAD_H
2 #define Py_INTERNAL_PYTHREAD_H
3 #ifdef __cplusplus
4 extern "C" {
5 #endif
6 
7 #ifndef Py_BUILD_CORE
8 #  error "this header requires Py_BUILD_CORE define"
9 #endif
10 
11 #include "dynamic_annotations.h" // _Py_ANNOTATE_PURE_HAPPENS_BEFORE_MUTEX
12 #include "pycore_llist.h"        // struct llist_node
13 
14 // Get _POSIX_THREADS and _POSIX_SEMAPHORES macros if available
15 #if (defined(HAVE_UNISTD_H) && !defined(_POSIX_THREADS) \
16                             && !defined(_POSIX_SEMAPHORES))
17 #  include <unistd.h>             // _POSIX_THREADS, _POSIX_SEMAPHORES
18 #endif
19 #if (defined(HAVE_PTHREAD_H) && !defined(_POSIX_THREADS) \
20                              && !defined(_POSIX_SEMAPHORES))
21    // This means pthreads are not implemented in libc headers, hence the macro
22    // not present in <unistd.h>. But they still can be implemented as an
23    // external library (e.g. gnu pth in pthread emulation)
24 #  include <pthread.h>            // _POSIX_THREADS, _POSIX_SEMAPHORES
25 #endif
26 #if !defined(_POSIX_THREADS) && defined(__hpux) && defined(_SC_THREADS)
27    // Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
28    // enough of the POSIX threads package is implemented to support Python
29    // threads.
30    //
31    // This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
32    // a check of __ia64 to verify that we're running on an ia64 system instead
33    // of a pa-risc system.
34 #  define _POSIX_THREADS
35 #endif
36 
37 
38 #if defined(_POSIX_THREADS) || defined(HAVE_PTHREAD_STUBS)
39 #  define _USE_PTHREADS
40 #endif
41 
42 #if defined(_USE_PTHREADS) && defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC)
43 // monotonic is supported statically.  It doesn't mean it works on runtime.
44 #  define CONDATTR_MONOTONIC
45 #endif
46 
47 
48 #if defined(HAVE_PTHREAD_STUBS)
49 #include "cpython/pthread_stubs.h"  // PTHREAD_KEYS_MAX
50 #include <stdbool.h>                // bool
51 
52 // pthread_key
53 struct py_stub_tls_entry {
54     bool in_use;
55     void *value;
56 };
57 #endif
58 
59 struct _pythread_runtime_state {
60     int initialized;
61 
62 #ifdef _USE_PTHREADS
63     // This matches when thread_pthread.h is used.
64     struct {
65         /* NULL when pthread_condattr_setclock(CLOCK_MONOTONIC) is not supported. */
66         pthread_condattr_t *ptr;
67 # ifdef CONDATTR_MONOTONIC
68     /* The value to which condattr_monotonic is set. */
69         pthread_condattr_t val;
70 # endif
71     } _condattr_monotonic;
72 
73 #endif  // USE_PTHREADS
74 
75 #if defined(HAVE_PTHREAD_STUBS)
76     struct {
77         struct py_stub_tls_entry tls_entries[PTHREAD_KEYS_MAX];
78     } stubs;
79 #endif
80 
81     // Linked list of ThreadHandles
82     struct llist_node handles;
83 };
84 
85 #define _pythread_RUNTIME_INIT(pythread) \
86     { \
87         .handles = LLIST_INIT(pythread.handles), \
88     }
89 
90 #ifdef HAVE_FORK
91 /* Private function to reinitialize a lock at fork in the child process.
92    Reset the lock to the unlocked state.
93    Return 0 on success, return -1 on error. */
94 extern int _PyThread_at_fork_reinit(PyThread_type_lock *lock);
95 extern void _PyThread_AfterFork(struct _pythread_runtime_state *state);
96 #endif  /* HAVE_FORK */
97 
98 
99 // unset: -1 seconds, in nanoseconds
100 #define PyThread_UNSET_TIMEOUT ((PyTime_t)(-1 * 1000 * 1000 * 1000))
101 
102 // Exported for the _interpchannels module.
103 PyAPI_FUNC(int) PyThread_ParseTimeoutArg(
104     PyObject *arg,
105     int blocking,
106     PY_TIMEOUT_T *timeout);
107 
108 /* Helper to acquire an interruptible lock with a timeout.  If the lock acquire
109  * is interrupted, signal handlers are run, and if they raise an exception,
110  * PY_LOCK_INTR is returned.  Otherwise, PY_LOCK_ACQUIRED or PY_LOCK_FAILURE
111  * are returned, depending on whether the lock can be acquired within the
112  * timeout.
113  */
114 // Exported for the _interpchannels module.
115 PyAPI_FUNC(PyLockStatus) PyThread_acquire_lock_timed_with_retries(
116     PyThread_type_lock,
117     PY_TIMEOUT_T microseconds);
118 
119 typedef unsigned long long PyThread_ident_t;
120 typedef Py_uintptr_t PyThread_handle_t;
121 
122 #define PY_FORMAT_THREAD_IDENT_T "llu"
123 #define Py_PARSE_THREAD_IDENT_T "K"
124 
125 PyAPI_FUNC(PyThread_ident_t) PyThread_get_thread_ident_ex(void);
126 
127 /* Thread joining APIs.
128  *
129  * These APIs have a strict contract:
130  *  - Either PyThread_join_thread or PyThread_detach_thread must be called
131  *    exactly once with the given handle.
132  *  - Calling neither PyThread_join_thread nor PyThread_detach_thread results
133  *    in a resource leak until the end of the process.
134  *  - Any other usage, such as calling both PyThread_join_thread and
135  *    PyThread_detach_thread, or calling them more than once (including
136  *    simultaneously), results in undefined behavior.
137  */
138 PyAPI_FUNC(int) PyThread_start_joinable_thread(void (*func)(void *),
139                                                void *arg,
140                                                PyThread_ident_t* ident,
141                                                PyThread_handle_t* handle);
142 /*
143  * Join a thread started with `PyThread_start_joinable_thread`.
144  * This function cannot be interrupted. It returns 0 on success,
145  * a non-zero value on failure.
146  */
147 PyAPI_FUNC(int) PyThread_join_thread(PyThread_handle_t);
148 /*
149  * Detach a thread started with `PyThread_start_joinable_thread`, such
150  * that its resources are relased as soon as it exits.
151  * This function cannot be interrupted. It returns 0 on success,
152  * a non-zero value on failure.
153  */
154 PyAPI_FUNC(int) PyThread_detach_thread(PyThread_handle_t);
155 
156 #ifdef __cplusplus
157 }
158 #endif
159 #endif /* !Py_INTERNAL_PYTHREAD_H */
160