2
/* Posix threads interface (from CPython) */
7
/* The POSIX spec says that implementations supporting the sem_*
8
family of functions must indicate this by defining
10
#ifdef _POSIX_SEMAPHORES
11
/* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so
12
we need to add 0 to make it work there as well. */
13
#if (_POSIX_SEMAPHORES+0) == -1
14
#define HAVE_BROKEN_POSIX_SEMAPHORES
16
#include <semaphore.h>
20
#if !defined(pthread_attr_default)
21
# define pthread_attr_default ((pthread_attr_t *)NULL)
23
#if !defined(pthread_mutexattr_default)
24
# define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL)
26
#if !defined(pthread_condattr_default)
27
# define pthread_condattr_default ((pthread_condattr_t *)NULL)
30
/* Whether or not to use semaphores directly rather than emulating them with
31
* mutexes and condition variables:
33
#if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES)
34
# define USE_SEMAPHORES
36
# undef USE_SEMAPHORES
40
#define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; }
42
/********************* structs ***********/
46
#include <semaphore.h>
48
struct RPyOpaque_ThreadLock {
53
#define RPyOpaque_INITEXPR_ThreadLock { { /* sem */ }, 0 }
55
#else /* no semaphores */
57
/* A pthread mutex isn't sufficient to model the Python lock type
58
(see explanations in CPython's Python/thread_pthread.h */
59
struct RPyOpaque_ThreadLock {
60
char locked; /* 0=unlocked, 1=locked */
62
/* a <cond, mutex> pair to handle an acquire of a locked lock */
63
pthread_cond_t lock_released;
67
#define RPyOpaque_INITEXPR_ThreadLock { \
69
PTHREAD_COND_INITIALIZER, \
70
PTHREAD_MUTEX_INITIALIZER \
72
#endif /* no semaphores */
76
long RPyThreadGetIdent(void);
77
long RPyThreadStart(void (*func)(void *), void *arg);
78
int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock);
79
void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock);
80
int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag);
81
void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock);
82
int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock);
83
void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock);
84
int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag);
85
void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock);
90
#ifndef PYPY_NOT_MAIN_FILE
92
/* XXX This implementation is considered (to quote Tim Peters) "inherently
94
- It does not guarantee the promise that a non-zero integer is returned.
95
- The cast to long is inherently unsafe.
96
- It is not clear that the 'volatile' (for AIX?) and ugly casting in the
97
latter return statement (for Alpha OSF/1) are any longer necessary.
99
long RPyThreadGetIdent(void)
101
volatile pthread_t threadid;
102
/* Jump through some hoops for Alpha OSF/1 */
103
threadid = pthread_self();
104
#if SIZEOF_PTHREAD_T <= SIZEOF_LONG
105
return (long) threadid;
107
return (long) *(long *) &threadid;
111
long RPyThreadStart(void (*func)(void *), void *arg)
115
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
116
pthread_attr_t attrs;
119
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
120
pthread_attr_init(&attrs);
122
#ifdef THREAD_STACK_SIZE
123
pthread_attr_setstacksize(&attrs, THREAD_STACK_SIZE);
125
#if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) && !defined(__FreeBSD__)
126
pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM);
129
status = pthread_create(&th,
130
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
133
(pthread_attr_t*)NULL,
135
(void* (*)(void *))func,
139
#if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED)
140
pthread_attr_destroy(&attrs);
147
#if SIZEOF_PTHREAD_T <= SIZEOF_LONG
150
return (long) *(long *) &th;
155
/************************************************************/
156
#ifdef USE_SEMAPHORES
157
/************************************************************/
159
#include <semaphore.h>
161
int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
163
int status, error = 0;
164
lock->initialized = 0;
165
status = sem_init(&lock->sem, 0, 1);
166
CHECK_STATUS("sem_init");
169
lock->initialized = 1;
173
void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
175
int status, error = 0;
176
if (lock->initialized) {
177
status = sem_destroy(&lock->sem);
178
CHECK_STATUS("sem_destroy");
179
/* 'error' is ignored;
180
CHECK_STATUS already printed an error message */
185
* As of February 2002, Cygwin thread implementations mistakenly report error
186
* codes in the return value of the sem_ calls (like the pthread_ functions).
187
* Correct implementations return -1 and put the code in errno. This supports
191
rpythread_fix_status(int status)
193
return (status == -1) ? errno : status;
196
int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
199
sem_t *thelock = &lock->sem;
200
int status, error = 0;
204
status = rpythread_fix_status(sem_wait(thelock));
206
status = rpythread_fix_status(sem_trywait(thelock));
207
} while (status == EINTR); /* Retry if interrupted by a signal */
210
CHECK_STATUS("sem_wait");
211
} else if (status != EAGAIN) {
212
CHECK_STATUS("sem_trywait");
215
success = (status == 0) ? 1 : 0;
219
void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
221
sem_t *thelock = &lock->sem;
222
int status, error = 0;
224
status = sem_post(thelock);
225
CHECK_STATUS("sem_post");
228
/************************************************************/
229
#else /* no semaphores */
230
/************************************************************/
232
int RPyThreadLockInit(struct RPyOpaque_ThreadLock *lock)
234
int status, error = 0;
236
lock->initialized = 0;
239
status = pthread_mutex_init(&lock->mut,
240
pthread_mutexattr_default);
241
CHECK_STATUS("pthread_mutex_init");
243
status = pthread_cond_init(&lock->lock_released,
244
pthread_condattr_default);
245
CHECK_STATUS("pthread_cond_init");
249
lock->initialized = 1;
253
void RPyOpaqueDealloc_ThreadLock(struct RPyOpaque_ThreadLock *lock)
255
int status, error = 0;
256
if (lock->initialized) {
257
status = pthread_mutex_destroy(&lock->mut);
258
CHECK_STATUS("pthread_mutex_destroy");
260
status = pthread_cond_destroy(&lock->lock_released);
261
CHECK_STATUS("pthread_cond_destroy");
263
/* 'error' is ignored;
264
CHECK_STATUS already printed an error message */
268
int RPyThreadAcquireLock(struct RPyOpaque_ThreadLock *lock, int waitflag)
271
int status, error = 0;
273
status = pthread_mutex_lock( &lock->mut );
274
CHECK_STATUS("pthread_mutex_lock[1]");
275
success = lock->locked == 0;
277
if ( !success && waitflag ) {
278
/* continue trying until we get the lock */
280
/* mut must be locked by me -- part of the condition
282
while ( lock->locked ) {
283
status = pthread_cond_wait(&lock->lock_released,
285
CHECK_STATUS("pthread_cond_wait");
289
if (success) lock->locked = 1;
290
status = pthread_mutex_unlock( &lock->mut );
291
CHECK_STATUS("pthread_mutex_unlock[1]");
293
if (error) success = 0;
297
void RPyThreadReleaseLock(struct RPyOpaque_ThreadLock *lock)
299
int status, error = 0;
301
status = pthread_mutex_lock( &lock->mut );
302
CHECK_STATUS("pthread_mutex_lock[3]");
306
status = pthread_mutex_unlock( &lock->mut );
307
CHECK_STATUS("pthread_mutex_unlock[3]");
309
/* wake up someone (anyone, if any) waiting on the lock */
310
status = pthread_cond_signal( &lock->lock_released );
311
CHECK_STATUS("pthread_cond_signal");
314
/************************************************************/
315
#endif /* no semaphores */
316
/************************************************************/
319
/* Thread-local storage */
320
#define RPyThreadTLS pthread_key_t
322
char *RPyThreadTLS_Create(RPyThreadTLS *result)
324
if (pthread_key_create(result, NULL) != 0)
325
return "out of thread-local storage keys";
330
#define RPyThreadTLS_Get(key) pthread_getspecific(key)
331
#define RPyThreadTLS_Set(key, value) pthread_setspecific(key, value)
334
#endif /* PYPY_NOT_MAIN_FILE */