• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
46 static 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 
54 static int initialized;
55 
56 static void PyThread__init_thread(void); /* Forward */
57 
58 void
PyThread_init_thread(void)59 PyThread_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 
78 #if defined(_POSIX_THREADS)
79 #   define PYTHREAD_NAME "pthread"
80 #   include "thread_pthread.h"
81 #elif defined(NT_THREADS)
82 #   define PYTHREAD_NAME "nt"
83 #   include "thread_nt.h"
84 #else
85 #   error "Require native threads. See https://bugs.python.org/issue31370"
86 #endif
87 
88 
89 /* return the current thread stack size */
90 size_t
PyThread_get_stacksize(void)91 PyThread_get_stacksize(void)
92 {
93     return _PyInterpreterState_GET()->pythread_stacksize;
94 }
95 
96 /* Only platforms defining a THREAD_SET_STACKSIZE() macro
97    in thread_<platform>.h support changing the stack size.
98    Return 0 if stack size is valid,
99       -1 if stack size value is invalid,
100       -2 if setting stack size is not supported. */
101 int
PyThread_set_stacksize(size_t size)102 PyThread_set_stacksize(size_t size)
103 {
104 #if defined(THREAD_SET_STACKSIZE)
105     return THREAD_SET_STACKSIZE(size);
106 #else
107     return -2;
108 #endif
109 }
110 
111 
112 /* Thread Specific Storage (TSS) API
113 
114    Cross-platform components of TSS API implementation.
115 */
116 
117 Py_tss_t *
PyThread_tss_alloc(void)118 PyThread_tss_alloc(void)
119 {
120     Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
121     if (new_key == NULL) {
122         return NULL;
123     }
124     new_key->_is_initialized = 0;
125     return new_key;
126 }
127 
128 void
PyThread_tss_free(Py_tss_t * key)129 PyThread_tss_free(Py_tss_t *key)
130 {
131     if (key != NULL) {
132         PyThread_tss_delete(key);
133         PyMem_RawFree((void *)key);
134     }
135 }
136 
137 int
PyThread_tss_is_created(Py_tss_t * key)138 PyThread_tss_is_created(Py_tss_t *key)
139 {
140     assert(key != NULL);
141     return key->_is_initialized;
142 }
143 
144 
145 PyDoc_STRVAR(threadinfo__doc__,
146 "sys.thread_info\n\
147 \n\
148 A named tuple holding information about the thread implementation.");
149 
150 static PyStructSequence_Field threadinfo_fields[] = {
151     {"name",    "name of the thread implementation"},
152     {"lock",    "name of the lock implementation"},
153     {"version", "name and version of the thread library"},
154     {0}
155 };
156 
157 static PyStructSequence_Desc threadinfo_desc = {
158     "sys.thread_info",           /* name */
159     threadinfo__doc__,           /* doc */
160     threadinfo_fields,           /* fields */
161     3
162 };
163 
164 static PyTypeObject ThreadInfoType;
165 
166 PyObject*
PyThread_GetInfo(void)167 PyThread_GetInfo(void)
168 {
169     PyObject *threadinfo, *value;
170     int pos = 0;
171 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
172      && defined(_CS_GNU_LIBPTHREAD_VERSION))
173     char buffer[255];
174     int len;
175 #endif
176 
177     if (ThreadInfoType.tp_name == 0) {
178         if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
179             return NULL;
180     }
181 
182     threadinfo = PyStructSequence_New(&ThreadInfoType);
183     if (threadinfo == NULL)
184         return NULL;
185 
186     value = PyUnicode_FromString(PYTHREAD_NAME);
187     if (value == NULL) {
188         Py_DECREF(threadinfo);
189         return NULL;
190     }
191     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
192 
193 #ifdef _POSIX_THREADS
194 #ifdef USE_SEMAPHORES
195     value = PyUnicode_FromString("semaphore");
196 #else
197     value = PyUnicode_FromString("mutex+cond");
198 #endif
199     if (value == NULL) {
200         Py_DECREF(threadinfo);
201         return NULL;
202     }
203 #else
204     Py_INCREF(Py_None);
205     value = Py_None;
206 #endif
207     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
208 
209 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
210      && defined(_CS_GNU_LIBPTHREAD_VERSION))
211     value = NULL;
212     len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
213     if (1 < len && (size_t)len < sizeof(buffer)) {
214         value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
215         if (value == NULL)
216             PyErr_Clear();
217     }
218     if (value == NULL)
219 #endif
220     {
221         Py_INCREF(Py_None);
222         value = Py_None;
223     }
224     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
225     return threadinfo;
226 }
227