thread.c 5.28 KB
Newer Older
1

2 3 4 5 6
/* Thread package.
   This is intended to be usable independently from Python.
   The implementation for system foobar is in a file thread_foobar.h
   which is included by this file dependent on config settings.
   Stuff shared by all thread_*.h files is collected here. */
7

8
#include "Python.h"
9
#include "internal/pystate.h"
10

11 12 13 14 15 16 17 18 19
#ifndef _POSIX_THREADS
/* This means pthreads are not implemented in libc headers, hence the macro
   not present in unistd.h. But they still can be implemented as an external
   library (e.g. gnu pth in pthread emulation) */
# ifdef HAVE_PTHREAD_H
#  include <pthread.h> /* _POSIX_THREADS */
# endif
#endif

20
#ifndef DONT_HAVE_STDIO_H
21
#include <stdio.h>
22
#endif
23

Sjoerd Mullender's avatar
Sjoerd Mullender committed
24
#include <stdlib.h>
25

26
#include "pythread.h"
27 28 29

#ifndef _POSIX_THREADS

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 33 34
   threads.

   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 37 38 39 40 41 42 43
   of a pa-risc system.
*/
#ifdef __hpux
#ifdef _SC_THREADS
#define _POSIX_THREADS
#endif
#endif

Sjoerd Mullender's avatar
Sjoerd Mullender committed
44
#endif /* _POSIX_THREADS */
45 46


47
#ifdef Py_DEBUG
48
static int thread_debug = 0;
49 50
#define dprintf(args)   (void)((thread_debug & 1) && printf args)
#define d2printf(args)  ((thread_debug & 8) && printf args)
51 52 53
#else
#define dprintf(args)
#define d2printf(args)
Sjoerd Mullender's avatar
Sjoerd Mullender committed
54
#endif
55

56 57
static int initialized;

58
static void PyThread__init_thread(void); /* Forward */
59

60 61
void
PyThread_init_thread(void)
62
{
63
#ifdef Py_DEBUG
64 65 66 67 68 69 70 71
    char *p = Py_GETENV("PYTHONTHREADDEBUG");

    if (p) {
        if (*p)
            thread_debug = atoi(p);
        else
            thread_debug = 1;
    }
72
#endif /* Py_DEBUG */
73 74 75 76 77
    if (initialized)
        return;
    initialized = 1;
    dprintf(("PyThread_init_thread called\n"));
    PyThread__init_thread();
78 79
}

80 81 82 83 84 85 86
#if defined(_POSIX_THREADS)
#   define PYTHREAD_NAME "pthread"
#   include "thread_pthread.h"
#elif defined(NT_THREADS)
#   define PYTHREAD_NAME "nt"
#   include "thread_nt.h"
#else
87
#   error "Require native threads. See https://bugs.python.org/issue31370"
Guido van Rossum's avatar
Guido van Rossum committed
88 89
#endif

90

91 92 93 94
/* return the current thread stack size */
size_t
PyThread_get_stacksize(void)
{
95
    return PyThreadState_GET()->interp->pythread_stacksize;
96 97 98 99 100
}

/* Only platforms defining a THREAD_SET_STACKSIZE() macro
   in thread_<platform>.h support changing the stack size.
   Return 0 if stack size is valid,
101 102
      -1 if stack size value is invalid,
      -2 if setting stack size is not supported. */
103 104 105 106
int
PyThread_set_stacksize(size_t size)
{
#if defined(THREAD_SET_STACKSIZE)
107
    return THREAD_SET_STACKSIZE(size);
108
#else
109
    return -2;
110 111 112
#endif
}

113

114
/* Thread Specific Storage (TSS) API
115

116 117
   Cross-platform components of TSS API implementation.
*/
118

119 120 121 122 123 124 125 126 127 128
Py_tss_t *
PyThread_tss_alloc(void)
{
    Py_tss_t *new_key = (Py_tss_t *)PyMem_RawMalloc(sizeof(Py_tss_t));
    if (new_key == NULL) {
        return NULL;
    }
    new_key->_is_initialized = 0;
    return new_key;
}
129

130 131 132 133 134 135 136 137
void
PyThread_tss_free(Py_tss_t *key)
{
    if (key != NULL) {
        PyThread_tss_delete(key);
        PyMem_RawFree((void *)key);
    }
}
138

139 140 141 142 143 144
int
PyThread_tss_is_created(Py_tss_t *key)
{
    assert(key != NULL);
    return key->_is_initialized;
}
145

146

147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
PyDoc_STRVAR(threadinfo__doc__,
"sys.thread_info\n\
\n\
A struct sequence holding information about the thread implementation.");

static PyStructSequence_Field threadinfo_fields[] = {
    {"name",    "name of the thread implementation"},
    {"lock",    "name of the lock implementation"},
    {"version", "name and version of the thread library"},
    {0}
};

static PyStructSequence_Desc threadinfo_desc = {
    "sys.thread_info",           /* name */
    threadinfo__doc__,           /* doc */
    threadinfo_fields,           /* fields */
    3
};

static PyTypeObject ThreadInfoType;

168
PyObject*
169
PyThread_GetInfo(void)
170
{
171 172
    PyObject *threadinfo, *value;
    int pos = 0;
173 174
#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
     && defined(_CS_GNU_LIBPTHREAD_VERSION))
175 176
    char buffer[255];
    int len;
177
#endif
178

179 180 181 182
    if (ThreadInfoType.tp_name == 0) {
        if (PyStructSequence_InitType2(&ThreadInfoType, &threadinfo_desc) < 0)
            return NULL;
    }
183 184 185

    threadinfo = PyStructSequence_New(&ThreadInfoType);
    if (threadinfo == NULL)
186 187 188
        return NULL;

    value = PyUnicode_FromString(PYTHREAD_NAME);
189 190 191 192 193
    if (value == NULL) {
        Py_DECREF(threadinfo);
        return NULL;
    }
    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
194 195 196 197 198 199 200

#ifdef _POSIX_THREADS
#ifdef USE_SEMAPHORES
    value = PyUnicode_FromString("semaphore");
#else
    value = PyUnicode_FromString("mutex+cond");
#endif
201 202
    if (value == NULL) {
        Py_DECREF(threadinfo);
203
        return NULL;
204 205 206 207 208 209
    }
#else
    Py_INCREF(Py_None);
    value = Py_None;
#endif
    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
210

211 212 213
#if (defined(_POSIX_THREADS) && defined(HAVE_CONFSTR) \
     && defined(_CS_GNU_LIBPTHREAD_VERSION))
    value = NULL;
214
    len = confstr(_CS_GNU_LIBPTHREAD_VERSION, buffer, sizeof(buffer));
215
    if (1 < len && (size_t)len < sizeof(buffer)) {
216 217
        value = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
        if (value == NULL)
218
            PyErr_Clear();
219
    }
220
    if (value == NULL)
221
#endif
222 223 224 225 226 227
    {
        Py_INCREF(Py_None);
        value = Py_None;
    }
    PyStructSequence_SET_ITEM(threadinfo, pos++, value);
    return threadinfo;
228
}