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