aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/Include/internal/pycore_pythread.h
blob: 9c9a09f60f34418bbd4257bcb6540295df110ab3 (plain) (blame)
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
#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 */