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_FiniBuiltin()
11 #include "pycore_pythread.h"
12
13 #ifndef DONT_HAVE_STDIO_H
14 #include <stdio.h>
15 #endif
16
17 #include <stdlib.h>
18
19
20 static void PyThread__init_thread(void); /* Forward */
21
22 #define initialized _PyRuntime.threads.initialized
23
24 void
25 PyThread_init_thread(void)
26 {
27 if (initialized) {
28 return;
29 }
30 initialized = 1;
31 PyThread__init_thread();
32 }
33
34 #if defined(HAVE_PTHREAD_STUBS)
35 # define PYTHREAD_NAME "pthread-stubs"
36 # include "thread_pthread_stubs.h"
37 #elif defined(_USE_PTHREADS) /* AKA _PTHREADS */
38 # if defined(__EMSCRIPTEN__) && !defined(__EMSCRIPTEN_PTHREADS__)
39 # define PYTHREAD_NAME "pthread-stubs"
40 # else
41 # define PYTHREAD_NAME "pthread"
42 # endif
43 # include "thread_pthread.h"
44 #elif defined(NT_THREADS)
45 # define PYTHREAD_NAME "nt"
46 # include "thread_nt.h"
47 #else
48 # error "Require native threads. See https://bugs.python.org/issue31370"
49 #endif
50
51
52 /* return the current thread stack size */
53 size_t
54 PyThread_get_stacksize(void)
55 {
56 return _PyInterpreterState_GET()->threads.stacksize;
57 }
58
59 /* Only platforms defining a THREAD_SET_STACKSIZE() macro
60 in thread_<platform>.h support changing the stack size.
61 Return 0 if stack size is valid,
62 -1 if stack size value is invalid,
63 -2 if setting stack size is not supported. */
64 int
65 PyThread_set_stacksize(size_t size)
66 {
67 #if defined(THREAD_SET_STACKSIZE)
68 return THREAD_SET_STACKSIZE(size);
69 #else
70 return -2;
71 #endif
72 }
73
74
75 /* Thread Specific Storage (TSS) API
76
77 Cross-platform components of TSS API implementation.
78 */
79
80 Py_tss_t *
81 PyThread_tss_alloc(void)
82 {
83 Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
84 if (new_key == NULL) {
85 return NULL;
86 }
87 new_key->_is_initialized = 0;
88 return new_key;
89 }
90
91 void
92 PyThread_tss_free(Py_tss_t *key)
93 {
94 if (key != NULL) {
95 PyThread_tss_delete(key);
96 PyMem_RawFree((void *)key);
97 }
98 }
99
100 int
101 PyThread_tss_is_created(Py_tss_t *key)
102 {
103 assert(key != NULL);
104 return key->_is_initialized;
105 }
106
107
108 PyDoc_STRVAR(threadinfo__doc__,
109 "sys.thread_info\n\
110 \n\
111 A named tuple holding information about the thread implementation.");
112
113 static PyStructSequence_Field threadinfo_fields[] = {
114 {"name", "name of the thread implementation"},
115 {"lock", "name of the lock implementation"},
116 {"version", "name and version of the thread library"},
117 {0}
118 };
119
120 static PyStructSequence_Desc threadinfo_desc = {
121 "sys.thread_info", /* name */
122 threadinfo__doc__, /* doc */
123 threadinfo_fields, /* fields */
124 3
125 };
126
127 static PyTypeObject ThreadInfoType;
128
129 PyObject*
130 PyThread_GetInfo(void)
131 {
132 PyObject *threadinfo, *value;
133 int pos = 0;
134 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
135 && defined(_CS_GNU_LIBPTHREAD_VERSION))
136 char buffer[255];
137 int len;
138 #endif
139
140 PyInterpreterState *interp = _PyInterpreterState_GET();
141 if (_PyStructSequence_InitBuiltin(interp, &ThreadInfoType, &threadinfo_desc) < 0) {
142 return NULL;
143 }
144
145 threadinfo = PyStructSequence_New(&ThreadInfoType);
146 if (threadinfo == NULL)
147 return NULL;
148
149 value = PyUnicode_FromString(PYTHREAD_NAME);
150 if (value == NULL) {
151 Py_DECREF(threadinfo);
152 return NULL;
153 }
154 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
155
156 #ifdef HAVE_PTHREAD_STUBS
157 value = Py_NewRef(Py_None);
158 #elif defined(_POSIX_THREADS)
159 #ifdef USE_SEMAPHORES
160 value = PyUnicode_FromString("semaphore");
161 #else
162 value = PyUnicode_FromString("mutex+cond");
163 #endif
164 if (value == NULL) {
165 Py_DECREF(threadinfo);
166 return NULL;
167 }
168 #else
169 value = Py_NewRef(Py_None);
170 #endif
171 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
172
173 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
174 && defined(_CS_GNU_LIBPTHREAD_VERSION))
175 value = NULL;
176 len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
177 if (1 < len && (size_t)len < sizeof(buffer)) {
178 value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
179 if (value == NULL)
180 PyErr_Clear();
181 }
182 if (value == NULL)
183 #endif
184 {
185 value = Py_NewRef(Py_None);
186 }
187 PyStructSequence_SET_ITEM(threadinfo, pos++, value);
188 return threadinfo;
189 }
190
191
192 void
193 _PyThread_FiniType(PyInterpreterState *interp)
194 {
195 _PyStructSequence_FiniBuiltin(interp, &ThreadInfoType);
196 }