• 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  void
_PyThread_debug_deprecation(void)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 */
109  size_t
PyThread_get_stacksize(void)110  PyThread_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. */
120  int
PyThread_set_stacksize(size_t size)121  PyThread_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  
136  Py_tss_t *
PyThread_tss_alloc(void)137  PyThread_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  
147  void
PyThread_tss_free(Py_tss_t * key)148  PyThread_tss_free(Py_tss_t *key)
149  {
150      if (key != NULL) {
151          PyThread_tss_delete(key);
152          PyMem_RawFree((void *)key);
153      }
154  }
155  
156  int
PyThread_tss_is_created(Py_tss_t * key)157  PyThread_tss_is_created(Py_tss_t *key)
158  {
159      assert(key != NULL);
160      return key->_is_initialized;
161  }
162  
163  
164  PyDoc_STRVAR(threadinfo__doc__,
165  "sys.thread_info\n\
166  \n\
167  A named tuple holding information about the thread implementation.");
168  
169  static 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  
176  static PyStructSequence_Desc threadinfo_desc = {
177      "sys.thread_info",           /* name */
178      threadinfo__doc__,           /* doc */
179      threadinfo_fields,           /* fields */
180      3
181  };
182  
183  static PyTypeObject ThreadInfoType;
184  
185  PyObject*
PyThread_GetInfo(void)186  PyThread_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