Home | History | Annotate | Download | only in Python
      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 "internal/pystate.h"
     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 #include "pythread.h"
     27 
     28 #ifndef _POSIX_THREADS
     29 
     30 /* Check if we're running on HP-UX and _SC_THREADS is defined. If so, then
     31    enough of the Posix threads package is implemented to support python
     32    threads.
     33 
     34    This is valid for HP-UX 11.23 running on an ia64 system. If needed, add
     35    a check of __ia64 to verify that we're running on an ia64 system instead
     36    of a pa-risc system.
     37 */
     38 #ifdef __hpux
     39 #ifdef _SC_THREADS
     40 #define _POSIX_THREADS
     41 #endif
     42 #endif
     43 
     44 #endif /* _POSIX_THREADS */
     45 
     46 
     47 #ifdef Py_DEBUG
     48 static int thread_debug = 0;
     49 #define dprintf(args)   (void)((thread_debug & 1) && printf args)
     50 #define d2printf(args)  ((thread_debug & 8) && printf args)
     51 #else
     52 #define dprintf(args)
     53 #define d2printf(args)
     54 #endif
     55 
     56 static int initialized;
     57 
     58 static void PyThread__init_thread(void); /* Forward */
     59 
     60 void
     61 PyThread_init_thread(void)
     62 {
     63 #ifdef Py_DEBUG
     64     const char *p = Py_GETENV("PYTHONTHREADDEBUG");
     65 
     66     if (p) {
     67         if (*p)
     68             thread_debug = atoi(p);
     69         else
     70             thread_debug = 1;
     71     }
     72 #endif /* Py_DEBUG */
     73     if (initialized)
     74         return;
     75     initialized = 1;
     76     dprintf(("PyThread_init_thread called\n"));
     77     PyThread__init_thread();
     78 }
     79 
     80 #if defined(_POSIX_THREADS)
     81 #   define PYTHREAD_NAME "pthread"
     82 #   include "thread_pthread.h"
     83 #elif defined(NT_THREADS)
     84 #   define PYTHREAD_NAME "nt"
     85 #   include "thread_nt.h"
     86 #else
     87 #   error "Require native threads. See https://bugs.python.org/issue31370"
     88 #endif
     89 
     90 
     91 /* return the current thread stack size */
     92 size_t
     93 PyThread_get_stacksize(void)
     94 {
     95     return PyThreadState_GET()->interp->pythread_stacksize;
     96 }
     97 
     98 /* Only platforms defining a THREAD_SET_STACKSIZE() macro
     99    in thread_<platform>.h support changing the stack size.
    100    Return 0 if stack size is valid,
    101       -1 if stack size value is invalid,
    102       -2 if setting stack size is not supported. */
    103 int
    104 PyThread_set_stacksize(size_t size)
    105 {
    106 #if defined(THREAD_SET_STACKSIZE)
    107     return THREAD_SET_STACKSIZE(size);
    108 #else
    109     return -2;
    110 #endif
    111 }
    112 
    113 
    114 /* Thread Specific Storage (TSS) API
    115 
    116    Cross-platform components of TSS API implementation.
    117 */
    118 
    119 Py_tss_t *
    120 PyThread_tss_alloc(void)
    121 {
    122     Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
    123     if (new_key == NULL) {
    124         return NULL;
    125     }
    126     new_key->_is_initialized = 0;
    127     return new_key;
    128 }
    129 
    130 void
    131 PyThread_tss_free(Py_tss_t *key)
    132 {
    133     if (key != NULL) {
    134         PyThread_tss_delete(key);
    135         PyMem_RawFree((void *)key);
    136     }
    137 }
    138 
    139 int
    140 PyThread_tss_is_created(Py_tss_t *key)
    141 {
    142     assert(key != NULL);
    143     return key->_is_initialized;
    144 }
    145 
    146 
    147 PyDoc_STRVAR(threadinfo__doc__,
    148 "sys.thread_info\n\
    149 \n\
    150 A struct sequence holding information about the thread implementation.");
    151 
    152 static PyStructSequence_Field threadinfo_fields[] = {
    153     {"name",    "name of the thread implementation"},
    154     {"lock",    "name of the lock implementation"},
    155     {"version", "name and version of the thread library"},
    156     {0}
    157 };
    158 
    159 static PyStructSequence_Desc threadinfo_desc = {
    160     "sys.thread_info",           /* name */
    161     threadinfo__doc__,           /* doc */
    162     threadinfo_fields,           /* fields */
    163     3
    164 };
    165 
    166 static PyTypeObject ThreadInfoType;
    167 
    168 PyObject*
    169 PyThread_GetInfo(void)
    170 {
    171     PyObject *threadinfo, *value;
    172     int pos = 0;
    173 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
    174      && defined(_CS_GNU_LIBPTHREAD_VERSION))
    175     char buffer[255];
    176     int len;
    177 #endif
    178 
    179     if (ThreadInfoType.tp_name == 0) {
    180         if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
    181             return NULL;
    182     }
    183 
    184     threadinfo = PyStructSequence_New(&ThreadInfoType);
    185     if (threadinfo == NULL)
    186         return NULL;
    187 
    188     value = PyUnicode_FromString(PYTHREAD_NAME);
    189     if (value == NULL) {
    190         Py_DECREF(threadinfo);
    191         return NULL;
    192     }
    193     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
    194 
    195 #ifdef _POSIX_THREADS
    196 #ifdef USE_SEMAPHORES
    197     value = PyUnicode_FromString("semaphore");
    198 #else
    199     value = PyUnicode_FromString("mutex+cond");
    200 #endif
    201     if (value == NULL) {
    202         Py_DECREF(threadinfo);
    203         return NULL;
    204     }
    205 #else
    206     Py_INCREF(Py_None);
    207     value = Py_None;
    208 #endif
    209     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
    210 
    211 #if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
    212      && defined(_CS_GNU_LIBPTHREAD_VERSION))
    213     value = NULL;
    214     len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
    215     if (1 < len && (size_t)len < sizeof(buffer)) {
    216         value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
    217         if (value == NULL)
    218             PyErr_Clear();
    219     }
    220     if (value == NULL)
    221 #endif
    222     {
    223         Py_INCREF(Py_None);
    224         value = Py_None;
    225     }
    226     PyStructSequence_SET_ITEM(threadinfo, pos++, value);
    227     return threadinfo;
    228 }
    229