|
1 |
|
2 /* Posix threads interface */ |
|
3 |
|
4 #include <stdlib.h> |
|
5 #include <string.h> |
|
6 #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) |
|
7 #define destructor xxdestructor |
|
8 #endif |
|
9 #include <pthread.h> |
|
10 #if defined(__APPLE__) || defined(HAVE_PTHREAD_DESTRUCTOR) |
|
11 #undef destructor |
|
12 #endif |
|
13 #include <signal.h> |
|
14 |
|
15 /* The POSIX spec requires that use of pthread_attr_setstacksize |
|
16 be conditional on _POSIX_THREAD_ATTR_STACKSIZE being defined. */ |
|
17 #ifdef _POSIX_THREAD_ATTR_STACKSIZE |
|
18 #ifndef THREAD_STACK_SIZE |
|
19 #define THREAD_STACK_SIZE 0 /* use default stack size */ |
|
20 #endif |
|
21 /* for safety, ensure a viable minimum stacksize */ |
|
22 #define THREAD_STACK_MIN 0x8000 /* 32kB */ |
|
23 #else /* !_POSIX_THREAD_ATTR_STACKSIZE */ |
|
24 #ifdef THREAD_STACK_SIZE |
|
25 #error "THREAD_STACK_SIZE defined but _POSIX_THREAD_ATTR_STACKSIZE undefined" |
|
26 #endif |
|
27 #endif |
|
28 |
|
29 /* The POSIX spec says that implementations supporting the sem_* |
|
30 family of functions must indicate this by defining |
|
31 _POSIX_SEMAPHORES. */ |
|
32 #ifdef _POSIX_SEMAPHORES |
|
33 /* On FreeBSD 4.x, _POSIX_SEMAPHORES is defined empty, so |
|
34 we need to add 0 to make it work there as well. */ |
|
35 #if (_POSIX_SEMAPHORES+0) == -1 |
|
36 #define HAVE_BROKEN_POSIX_SEMAPHORES |
|
37 #else |
|
38 #include <semaphore.h> |
|
39 #include <errno.h> |
|
40 #endif |
|
41 #endif |
|
42 |
|
43 /* Before FreeBSD 5.4, system scope threads was very limited resource |
|
44 in default setting. So the process scope is preferred to get |
|
45 enough number of threads to work. */ |
|
46 #ifdef __FreeBSD__ |
|
47 #include <osreldate.h> |
|
48 #if __FreeBSD_version >= 500000 && __FreeBSD_version < 504101 |
|
49 #undef PTHREAD_SYSTEM_SCHED_SUPPORTED |
|
50 #endif |
|
51 #endif |
|
52 |
|
53 #if !defined(pthread_attr_default) |
|
54 # define pthread_attr_default ((pthread_attr_t *)NULL) |
|
55 #endif |
|
56 #if !defined(pthread_mutexattr_default) |
|
57 # define pthread_mutexattr_default ((pthread_mutexattr_t *)NULL) |
|
58 #endif |
|
59 #if !defined(pthread_condattr_default) |
|
60 # define pthread_condattr_default ((pthread_condattr_t *)NULL) |
|
61 #endif |
|
62 |
|
63 |
|
64 /* Whether or not to use semaphores directly rather than emulating them with |
|
65 * mutexes and condition variables: |
|
66 */ |
|
67 #if defined(_POSIX_SEMAPHORES) && !defined(HAVE_BROKEN_POSIX_SEMAPHORES) |
|
68 # define USE_SEMAPHORES |
|
69 #else |
|
70 # undef USE_SEMAPHORES |
|
71 #endif |
|
72 |
|
73 |
|
74 /* On platforms that don't use standard POSIX threads pthread_sigmask() |
|
75 * isn't present. DEC threads uses sigprocmask() instead as do most |
|
76 * other UNIX International compliant systems that don't have the full |
|
77 * pthread implementation. |
|
78 */ |
|
79 #if defined(HAVE_PTHREAD_SIGMASK) && !defined(HAVE_BROKEN_PTHREAD_SIGMASK) |
|
80 # define SET_THREAD_SIGMASK pthread_sigmask |
|
81 #else |
|
82 # define SET_THREAD_SIGMASK sigprocmask |
|
83 #endif |
|
84 |
|
85 |
|
86 /* A pthread mutex isn't sufficient to model the Python lock type |
|
87 * because, according to Draft 5 of the docs (P1003.4a/D5), both of the |
|
88 * following are undefined: |
|
89 * -> a thread tries to lock a mutex it already has locked |
|
90 * -> a thread tries to unlock a mutex locked by a different thread |
|
91 * pthread mutexes are designed for serializing threads over short pieces |
|
92 * of code anyway, so wouldn't be an appropriate implementation of |
|
93 * Python's locks regardless. |
|
94 * |
|
95 * The pthread_lock struct implements a Python lock as a "locked?" bit |
|
96 * and a <condition, mutex> pair. In general, if the bit can be acquired |
|
97 * instantly, it is, else the pair is used to block the thread until the |
|
98 * bit is cleared. 9 May 1994 tim@ksr.com |
|
99 */ |
|
100 |
|
101 typedef struct { |
|
102 char locked; /* 0=unlocked, 1=locked */ |
|
103 /* a <cond, mutex> pair to handle an acquire of a locked lock */ |
|
104 pthread_cond_t lock_released; |
|
105 pthread_mutex_t mut; |
|
106 } pthread_lock; |
|
107 |
|
108 #define CHECK_STATUS(name) if (status != 0) { perror(name); error = 1; } |
|
109 |
|
110 /* |
|
111 * Initialization. |
|
112 */ |
|
113 |
|
114 #ifdef _HAVE_BSDI |
|
115 static |
|
116 void _noop(void) |
|
117 { |
|
118 } |
|
119 |
|
120 static void |
|
121 PyThread__init_thread(void) |
|
122 { |
|
123 /* DO AN INIT BY STARTING THE THREAD */ |
|
124 static int dummy = 0; |
|
125 pthread_t thread1; |
|
126 pthread_create(&thread1, NULL, (void *) _noop, &dummy); |
|
127 pthread_join(thread1, NULL); |
|
128 } |
|
129 |
|
130 #else /* !_HAVE_BSDI */ |
|
131 |
|
132 static void |
|
133 PyThread__init_thread(void) |
|
134 { |
|
135 #if defined(_AIX) && defined(__GNUC__) |
|
136 pthread_init(); |
|
137 #endif |
|
138 } |
|
139 |
|
140 #endif /* !_HAVE_BSDI */ |
|
141 |
|
142 /* |
|
143 * Thread support. |
|
144 */ |
|
145 |
|
146 |
|
147 long |
|
148 PyThread_start_new_thread(void (*func)(void *), void *arg) |
|
149 { |
|
150 pthread_t th; |
|
151 int status; |
|
152 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) |
|
153 pthread_attr_t attrs; |
|
154 #endif |
|
155 #if defined(THREAD_STACK_SIZE) |
|
156 size_t tss; |
|
157 #endif |
|
158 |
|
159 dprintf(("PyThread_start_new_thread called\n")); |
|
160 if (!initialized) |
|
161 PyThread_init_thread(); |
|
162 |
|
163 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) |
|
164 if (pthread_attr_init(&attrs) != 0) |
|
165 return -1; |
|
166 #endif |
|
167 #if defined(THREAD_STACK_SIZE) |
|
168 tss = (_pythread_stacksize != 0) ? _pythread_stacksize |
|
169 : THREAD_STACK_SIZE; |
|
170 if (tss != 0) { |
|
171 if (pthread_attr_setstacksize(&attrs, tss) != 0) { |
|
172 pthread_attr_destroy(&attrs); |
|
173 return -1; |
|
174 } |
|
175 } |
|
176 #endif |
|
177 #if defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) |
|
178 pthread_attr_setscope(&attrs, PTHREAD_SCOPE_SYSTEM); |
|
179 #endif |
|
180 |
|
181 status = pthread_create(&th, |
|
182 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) |
|
183 &attrs, |
|
184 #else |
|
185 (pthread_attr_t*)NULL, |
|
186 #endif |
|
187 (void* (*)(void *))func, |
|
188 (void *)arg |
|
189 ); |
|
190 |
|
191 #if defined(THREAD_STACK_SIZE) || defined(PTHREAD_SYSTEM_SCHED_SUPPORTED) |
|
192 pthread_attr_destroy(&attrs); |
|
193 #endif |
|
194 if (status != 0) |
|
195 return -1; |
|
196 |
|
197 pthread_detach(th); |
|
198 |
|
199 #if SIZEOF_PTHREAD_T <= SIZEOF_LONG |
|
200 return (long) th; |
|
201 #else |
|
202 return (long) *(long *) &th; |
|
203 #endif |
|
204 } |
|
205 |
|
206 /* XXX This implementation is considered (to quote Tim Peters) "inherently |
|
207 hosed" because: |
|
208 - It does not guarantee the promise that a non-zero integer is returned. |
|
209 - The cast to long is inherently unsafe. |
|
210 - It is not clear that the 'volatile' (for AIX?) and ugly casting in the |
|
211 latter return statement (for Alpha OSF/1) are any longer necessary. |
|
212 */ |
|
213 long |
|
214 PyThread_get_thread_ident(void) |
|
215 { |
|
216 volatile pthread_t threadid; |
|
217 if (!initialized) |
|
218 PyThread_init_thread(); |
|
219 /* Jump through some hoops for Alpha OSF/1 */ |
|
220 threadid = pthread_self(); |
|
221 #if SIZEOF_PTHREAD_T <= SIZEOF_LONG |
|
222 return (long) threadid; |
|
223 #else |
|
224 return (long) *(long *) &threadid; |
|
225 #endif |
|
226 } |
|
227 |
|
228 static void |
|
229 do_PyThread_exit_thread(int no_cleanup) |
|
230 { |
|
231 dprintf(("PyThread_exit_thread called\n")); |
|
232 if (!initialized) { |
|
233 if (no_cleanup) |
|
234 _exit(0); |
|
235 else |
|
236 exit(0); |
|
237 } |
|
238 } |
|
239 |
|
240 void |
|
241 PyThread_exit_thread(void) |
|
242 { |
|
243 do_PyThread_exit_thread(0); |
|
244 } |
|
245 |
|
246 void |
|
247 PyThread__exit_thread(void) |
|
248 { |
|
249 do_PyThread_exit_thread(1); |
|
250 } |
|
251 |
|
252 #ifndef NO_EXIT_PROG |
|
253 static void |
|
254 do_PyThread_exit_prog(int status, int no_cleanup) |
|
255 { |
|
256 dprintf(("PyThread_exit_prog(%d) called\n", status)); |
|
257 if (!initialized) |
|
258 if (no_cleanup) |
|
259 _exit(status); |
|
260 else |
|
261 exit(status); |
|
262 } |
|
263 |
|
264 void |
|
265 PyThread_exit_prog(int status) |
|
266 { |
|
267 do_PyThread_exit_prog(status, 0); |
|
268 } |
|
269 |
|
270 void |
|
271 PyThread__exit_prog(int status) |
|
272 { |
|
273 do_PyThread_exit_prog(status, 1); |
|
274 } |
|
275 #endif /* NO_EXIT_PROG */ |
|
276 |
|
277 #ifdef USE_SEMAPHORES |
|
278 |
|
279 /* |
|
280 * Lock support. |
|
281 */ |
|
282 |
|
283 PyThread_type_lock |
|
284 PyThread_allocate_lock(void) |
|
285 { |
|
286 sem_t *lock; |
|
287 int status, error = 0; |
|
288 |
|
289 dprintf(("PyThread_allocate_lock called\n")); |
|
290 if (!initialized) |
|
291 PyThread_init_thread(); |
|
292 |
|
293 lock = (sem_t *)malloc(sizeof(sem_t)); |
|
294 |
|
295 if (lock) { |
|
296 status = sem_init(lock,0,1); |
|
297 CHECK_STATUS("sem_init"); |
|
298 |
|
299 if (error) { |
|
300 free((void *)lock); |
|
301 lock = NULL; |
|
302 } |
|
303 } |
|
304 |
|
305 dprintf(("PyThread_allocate_lock() -> %p\n", lock)); |
|
306 return (PyThread_type_lock)lock; |
|
307 } |
|
308 |
|
309 void |
|
310 PyThread_free_lock(PyThread_type_lock lock) |
|
311 { |
|
312 sem_t *thelock = (sem_t *)lock; |
|
313 int status, error = 0; |
|
314 |
|
315 dprintf(("PyThread_free_lock(%p) called\n", lock)); |
|
316 |
|
317 if (!thelock) |
|
318 return; |
|
319 |
|
320 status = sem_destroy(thelock); |
|
321 CHECK_STATUS("sem_destroy"); |
|
322 |
|
323 free((void *)thelock); |
|
324 } |
|
325 |
|
326 /* |
|
327 * As of February 2002, Cygwin thread implementations mistakenly report error |
|
328 * codes in the return value of the sem_ calls (like the pthread_ functions). |
|
329 * Correct implementations return -1 and put the code in errno. This supports |
|
330 * either. |
|
331 */ |
|
332 static int |
|
333 fix_status(int status) |
|
334 { |
|
335 return (status == -1) ? errno : status; |
|
336 } |
|
337 |
|
338 int |
|
339 PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) |
|
340 { |
|
341 int success; |
|
342 sem_t *thelock = (sem_t *)lock; |
|
343 int status, error = 0; |
|
344 |
|
345 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); |
|
346 |
|
347 do { |
|
348 if (waitflag) |
|
349 status = fix_status(sem_wait(thelock)); |
|
350 else |
|
351 status = fix_status(sem_trywait(thelock)); |
|
352 } while (status == EINTR); /* Retry if interrupted by a signal */ |
|
353 |
|
354 if (waitflag) { |
|
355 CHECK_STATUS("sem_wait"); |
|
356 } else if (status != EAGAIN) { |
|
357 CHECK_STATUS("sem_trywait"); |
|
358 } |
|
359 |
|
360 success = (status == 0) ? 1 : 0; |
|
361 |
|
362 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); |
|
363 return success; |
|
364 } |
|
365 |
|
366 void |
|
367 PyThread_release_lock(PyThread_type_lock lock) |
|
368 { |
|
369 sem_t *thelock = (sem_t *)lock; |
|
370 int status, error = 0; |
|
371 |
|
372 dprintf(("PyThread_release_lock(%p) called\n", lock)); |
|
373 |
|
374 status = sem_post(thelock); |
|
375 CHECK_STATUS("sem_post"); |
|
376 } |
|
377 |
|
378 #else /* USE_SEMAPHORES */ |
|
379 |
|
380 /* |
|
381 * Lock support. |
|
382 */ |
|
383 PyThread_type_lock |
|
384 PyThread_allocate_lock(void) |
|
385 { |
|
386 pthread_lock *lock; |
|
387 int status, error = 0; |
|
388 |
|
389 dprintf(("PyThread_allocate_lock called\n")); |
|
390 if (!initialized) |
|
391 PyThread_init_thread(); |
|
392 |
|
393 lock = (pthread_lock *) malloc(sizeof(pthread_lock)); |
|
394 if (lock) { |
|
395 memset((void *)lock, '\0', sizeof(pthread_lock)); |
|
396 lock->locked = 0; |
|
397 |
|
398 status = pthread_mutex_init(&lock->mut, |
|
399 pthread_mutexattr_default); |
|
400 CHECK_STATUS("pthread_mutex_init"); |
|
401 |
|
402 status = pthread_cond_init(&lock->lock_released, |
|
403 pthread_condattr_default); |
|
404 CHECK_STATUS("pthread_cond_init"); |
|
405 |
|
406 if (error) { |
|
407 free((void *)lock); |
|
408 lock = 0; |
|
409 } |
|
410 } |
|
411 |
|
412 dprintf(("PyThread_allocate_lock() -> %p\n", lock)); |
|
413 return (PyThread_type_lock) lock; |
|
414 } |
|
415 |
|
416 void |
|
417 PyThread_free_lock(PyThread_type_lock lock) |
|
418 { |
|
419 pthread_lock *thelock = (pthread_lock *)lock; |
|
420 int status, error = 0; |
|
421 |
|
422 dprintf(("PyThread_free_lock(%p) called\n", lock)); |
|
423 |
|
424 status = pthread_mutex_destroy( &thelock->mut ); |
|
425 CHECK_STATUS("pthread_mutex_destroy"); |
|
426 |
|
427 status = pthread_cond_destroy( &thelock->lock_released ); |
|
428 CHECK_STATUS("pthread_cond_destroy"); |
|
429 |
|
430 free((void *)thelock); |
|
431 } |
|
432 |
|
433 int |
|
434 PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) |
|
435 { |
|
436 int success; |
|
437 pthread_lock *thelock = (pthread_lock *)lock; |
|
438 int status, error = 0; |
|
439 |
|
440 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); |
|
441 |
|
442 status = pthread_mutex_lock( &thelock->mut ); |
|
443 CHECK_STATUS("pthread_mutex_lock[1]"); |
|
444 success = thelock->locked == 0; |
|
445 |
|
446 if ( !success && waitflag ) { |
|
447 /* continue trying until we get the lock */ |
|
448 |
|
449 /* mut must be locked by me -- part of the condition |
|
450 * protocol */ |
|
451 while ( thelock->locked ) { |
|
452 status = pthread_cond_wait(&thelock->lock_released, |
|
453 &thelock->mut); |
|
454 CHECK_STATUS("pthread_cond_wait"); |
|
455 } |
|
456 success = 1; |
|
457 } |
|
458 if (success) thelock->locked = 1; |
|
459 status = pthread_mutex_unlock( &thelock->mut ); |
|
460 CHECK_STATUS("pthread_mutex_unlock[1]"); |
|
461 |
|
462 if (error) success = 0; |
|
463 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); |
|
464 return success; |
|
465 } |
|
466 |
|
467 void |
|
468 PyThread_release_lock(PyThread_type_lock lock) |
|
469 { |
|
470 pthread_lock *thelock = (pthread_lock *)lock; |
|
471 int status, error = 0; |
|
472 |
|
473 dprintf(("PyThread_release_lock(%p) called\n", lock)); |
|
474 |
|
475 status = pthread_mutex_lock( &thelock->mut ); |
|
476 CHECK_STATUS("pthread_mutex_lock[3]"); |
|
477 |
|
478 thelock->locked = 0; |
|
479 |
|
480 status = pthread_mutex_unlock( &thelock->mut ); |
|
481 CHECK_STATUS("pthread_mutex_unlock[3]"); |
|
482 |
|
483 /* wake up someone (anyone, if any) waiting on the lock */ |
|
484 status = pthread_cond_signal( &thelock->lock_released ); |
|
485 CHECK_STATUS("pthread_cond_signal"); |
|
486 } |
|
487 |
|
488 #endif /* USE_SEMAPHORES */ |
|
489 |
|
490 /* set the thread stack size. |
|
491 * Return 0 if size is valid, -1 if size is invalid, |
|
492 * -2 if setting stack size is not supported. |
|
493 */ |
|
494 static int |
|
495 _pythread_pthread_set_stacksize(size_t size) |
|
496 { |
|
497 #if defined(THREAD_STACK_SIZE) |
|
498 pthread_attr_t attrs; |
|
499 size_t tss_min; |
|
500 int rc = 0; |
|
501 #endif |
|
502 |
|
503 /* set to default */ |
|
504 if (size == 0) { |
|
505 _pythread_stacksize = 0; |
|
506 return 0; |
|
507 } |
|
508 |
|
509 #if defined(THREAD_STACK_SIZE) |
|
510 #if defined(PTHREAD_STACK_MIN) |
|
511 tss_min = PTHREAD_STACK_MIN > THREAD_STACK_MIN ? PTHREAD_STACK_MIN |
|
512 : THREAD_STACK_MIN; |
|
513 #else |
|
514 tss_min = THREAD_STACK_MIN; |
|
515 #endif |
|
516 if (size >= tss_min) { |
|
517 /* validate stack size by setting thread attribute */ |
|
518 if (pthread_attr_init(&attrs) == 0) { |
|
519 rc = pthread_attr_setstacksize(&attrs, size); |
|
520 pthread_attr_destroy(&attrs); |
|
521 if (rc == 0) { |
|
522 _pythread_stacksize = size; |
|
523 return 0; |
|
524 } |
|
525 } |
|
526 } |
|
527 return -1; |
|
528 #else |
|
529 return -2; |
|
530 #endif |
|
531 } |
|
532 |
|
533 #define THREAD_SET_STACKSIZE(x) _pythread_pthread_set_stacksize(x) |