1
2/* Thread package.
3 This is intended to be usable independently from Python.
4 The implementation for system foobar is in a file thread_foobar.h
5 which is included by this file dependent on config settings.
6 Stuff shared by all thread_*.h files is collected here. */
7
8#include "Python.h"
9#include "pycore_pystate.h" // _PyInterpreterState_GET()
10
11#ifndef _POSIX_THREADS
12/* This means pthreads are not implemented in libc headers, hence the macro
13 not present in unistd.h. But they still can be implemented as an external
14 library (e.g. gnu pth in pthread emulation) */
15# ifdef HAVE_PTHREAD_H
16# include <pthread.h> /* _POSIX_THREADS */
17# endif
18#endif
19
20#ifndef DONT_HAVE_STDIO_H
21#include <stdio.h>
22#endif
23
24#include <stdlib.h>
25
26#ifndef _POSIX_THREADS
27
28/* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
29 enough of the Posix threads package is implemented to support python
30 threads.
31
32 This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
33 a check of __ia64 to verify that we're running on an ia64 system instead
34 of a pa-risc system.
35*/
36#ifdef __hpux
37#ifdef _SC_THREADS
38#define _POSIX_THREADS
39#endif
40#endif
41
42#endif /* _POSIX_THREADS */
43
44
45#ifdef Py_DEBUG
46static int thread_debug = 0;
47#define dprintf(args) (void)((thread_debug & 1) && printf args)
48#define d2printf(args) ((thread_debug & 8) && printf args)
49#else
50#define dprintf(args)
51#define d2printf(args)
52#endif
53
54static int initialized;
55
56static void PyThread__init_thread(void); /* Forward */
57
58void
59PyThread_init_thread(void)
60{
61#ifdef Py_DEBUG
62 const char *p = Py_GETENV("PYTHONTHREADDEBUG");
63
64 if (p) {
65 if (*p)
66 thread_debug = atoi(p);
67 else
68 thread_debug = 1;
69 }
70#endif /* Py_DEBUG */
71 if (initialized)
72 return;
73 initialized = 1;
74 dprintf(("PyThread_init_thread called\n"));
75 PyThread__init_thread();
76}
77
78void
79_PyThread_debug_deprecation(void)
80{
81#ifdef Py_DEBUG
82 if (thread_debug) {
83 // Flush previous dprintf() logs
84 fflush(stdout);
85 if (PyErr_WarnEx(PyExc_DeprecationWarning,
86 "The threading debug (PYTHONTHREADDEBUG environment "
87 "variable) is deprecated and will be removed "
88 "in Python 3.12",
89 0))
90 {
91 _PyErr_WriteUnraisableMsg("at Python startup", NULL);
92 }
93 }
94#endif
95}
96
97#if defined(_POSIX_THREADS)
98# define PYTHREAD_NAME "pthread"
99# include "thread_pthread.h"
100#elif defined(NT_THREADS)
101# define PYTHREAD_NAME "nt"
102# include "thread_nt.h"
103#else
104# error "Require native threads. See https://bugs.python.org/issue31370"
105#endif
106
107
108/* return the current thread stack size */
109size_t
110PyThread_get_stacksize(void)
111{
112 return _PyInterpreterState_GET()->pythread_stacksize;
113}
114
115/* Only platforms defining a THREAD_SET_STACKSIZE() macro
116 in thread_<platform>.h support changing the stack size.
117 Return 0 if stack size is valid,
118 -1 if stack size value is invalid,
119 -2 if setting stack size is not supported. */
120int
121PyThread_set_stacksize(size_t size)
122{
123#if defined(THREAD_SET_STACKSIZE)
124 return THREAD_SET_STACKSIZE(size);
125#else
126 return -2;
127#endif
128}
129
130
131/* Thread Specific Storage (TSS) API
132
133 Cross-platform components of TSS API implementation.
134*/
135
136Py_tss_t *
137PyThread_tss_alloc(void)
138{
139 Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
140 if (new_key == NULL) {
141 return NULL;
142 }
143 new_key->_is_initialized = 0;
144 return new_key;
145}
146
147void
148PyThread_tss_free(Py_tss_t *key)
149{
150 if (key != NULL) {
151 PyThread_tss_delete(key);
152 PyMem_RawFree((void *)key);
153 }
154}
155
156int
157PyThread_tss_is_created(Py_tss_t *key)
158{
159 assert(key != NULL);
160 return key->_is_initialized;
161}
162
163
164PyDoc_STRVAR(threadinfo__doc__,
165"sys.thread_info\n\
166\n\
167A named tuple holding information about the thread implementation.");
168
169static PyStructSequence_Field threadinfo_fields[] = {
170 {"name", "name of the thread implementation"},
171 {"lock", "name of the lock implementation"},
172 {"version", "name and version of the thread library"},
173 {0}
174};
175
176static PyStructSequence_Desc threadinfo_desc = {
177 "sys.thread_info", /* name */
178 threadinfo__doc__, /* doc */
179 threadinfo_fields, /* fields */
180 3
181};
182
183static PyTypeObject ThreadInfoType;
184
185PyObject*
186PyThread_GetInfo(void)
187{
188 PyObject *threadinfo, *value;
189 int pos = 0;
190#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
191 && defined(_CS_GNU_LIBPTHREAD_VERSION))
192 char buffer[255];
193 int len;
194#endif
195
196 if (ThreadInfoType.tp_name == 0) {
197 if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
198 return NULL;
199 }
200
201 threadinfo = PyStructSequence_New(&ThreadInfoType);
202 if (threadinfo == NULL)
203 return NULL;
204
205 value = PyUnicode_FromString(PYTHREAD_NAME);
206 if (value == NULL) {
207 Py_DECREF(threadinfo);
208 return NULL;
209 }
210 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
211
212#ifdef _POSIX_THREADS
213#ifdef USE_SEMAPHORES
214 value = PyUnicode_FromString("semaphore");
215#else
216 value = PyUnicode_FromString("mutex+cond");
217#endif
218 if (value == NULL) {
219 Py_DECREF(threadinfo);
220 return NULL;
221 }
222#else
223 Py_INCREF(Py_None);
224 value = Py_None;
225#endif
226 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
227
228#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
229 && defined(_CS_GNU_LIBPTHREAD_VERSION))
230 value = NULL;
231 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
232 if (1 < len && (size_t)len < sizeof(buffer)) {
233 value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
234 if (value == NULL)
235 PyErr_Clear();
236 }
237 if (value == NULL)
238#endif
239 {
240 Py_INCREF(Py_None);
241 value = Py_None;
242 }
243 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
244 return threadinfo;
245}
246