blob: 60940bc0d945a280f84c19402735d2c46a488f4a [file] [log] [blame]
Guido van Rossum926f7b61998-12-07 21:56:59 +00001/***********************************************************
2Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
4
5 All Rights Reserved
6
Guido van Rossumfd71b9e2000-06-30 23:50:40 +00007Copyright (c) 2000, BeOpen.com.
8Copyright (c) 1995-2000, Corporation for National Research Initiatives.
9Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
10All rights reserved.
Guido van Rossum926f7b61998-12-07 21:56:59 +000011
Guido van Rossumfd71b9e2000-06-30 23:50:40 +000012See the file "Misc/COPYRIGHT" for information on usage and
13redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
Guido van Rossum926f7b61998-12-07 21:56:59 +000014
15BeOS thread support by Chris Herborth (chrish@qnx.com)
16******************************************************************/
17
18#include <kernel/OS.h>
19#include <support/SupportDefs.h>
20#include <errno.h>
21
22/* ----------------------------------------------------------------------
23 * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
24 * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
25 */
26typedef struct benaphore {
27 sem_id _sem;
28 int32 _atom;
29} benaphore_t;
30
31static status_t benaphore_create( const char *name, benaphore_t *ben );
32static status_t benaphore_destroy( benaphore_t *ben );
33static status_t benaphore_lock( benaphore_t *ben );
34static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
35static status_t benaphore_unlock( benaphore_t *ben );
36
37static status_t benaphore_create( const char *name, benaphore_t *ben )
38{
39 if( ben != NULL ) {
40 ben->_atom = 0;
41 ben->_sem = create_sem( 0, name );
42
43 if( ben->_sem < B_NO_ERROR ) {
44 return B_BAD_SEM_ID;
45 }
46 } else {
47 return EFAULT;
48 }
49
50 return EOK;
51}
52
53static status_t benaphore_destroy( benaphore_t *ben )
54{
55 if( ben->_sem >= B_NO_ERROR ) {
56 status_t retval = benaphore_timedlock( ben, 0 );
57
58 if( retval == EOK || retval == EWOULDBLOCK ) {
59 status_t del_retval = delete_sem( ben->_sem );
60
61 return del_retval;
62 }
63 }
64
65 return B_BAD_SEM_ID;
66}
67
68static status_t benaphore_lock( benaphore_t *ben )
69{
70 int32 prev = atomic_add( &(ben->_atom), 1 );
71
72 if( prev > 0 ) {
73 return acquire_sem( ben->_sem );
74 }
75
76 return EOK;
77}
78
79static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
80{
81 int32 prev = atomic_add( &(ben->_atom), 1 );
82
83 if( prev > 0 ) {
84 status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
85
86 switch( retval ) {
87 case B_WOULD_BLOCK: /* Fall through... */
88 case B_TIMED_OUT:
89 return EWOULDBLOCK;
90 break;
91 case B_OK:
92 return EOK;
93 break;
94 default:
95 return retval;
96 break;
97 }
98 }
99
100 return EOK;
101}
102
103static status_t benaphore_unlock( benaphore_t *ben )
104{
105 int32 prev = atomic_add( &(ben->_atom), -1 );
106
107 if( prev > 1 ) {
108 return release_sem( ben->_sem );
109 }
110
111 return EOK;
112}
113
114/* ----------------------------------------------------------------------
115 * Initialization.
116 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000117static void PyThread__init_thread( void )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000118{
119 /* Do nothing. */
120 return;
121}
122
123/* ----------------------------------------------------------------------
124 * Thread support.
125 *
126 * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
127 * and there's no legacy thread module to support.
128 */
129
130static int32 thread_count = 0;
131
132int PyThread_start_new_thread( void (*func)(void *), void *arg )
133{
134 status_t success = 0;
135 thread_id tid;
136 char name[B_OS_NAME_LENGTH];
137 int32 this_thread;
138
Guido van Rossum65d5b571998-12-21 19:32:43 +0000139 dprintf(("PyThread_start_new_thread called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000140
141 /* We are so very thread-safe... */
142 this_thread = atomic_add( &thread_count, 1 );
143 sprintf( name, "python thread (%d)", this_thread );
144
145 tid = spawn_thread( (thread_func)func, name,
146 B_NORMAL_PRIORITY, arg );
147 if( tid > B_NO_ERROR ) {
148 success = resume_thread( tid );
149 }
150
151 return ( success == B_NO_ERROR ? 1 : 0 );
152}
153
154long PyThread_get_thread_ident( void )
155{
156 /* Presumed to return the current thread's ID... */
157 thread_id tid;
158 tid = find_thread( NULL );
159
160 return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
161}
162
Guido van Rossum65d5b571998-12-21 19:32:43 +0000163static void do_PyThread_exit_thread( int no_cleanup )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000164{
165 int32 threads;
166
Guido van Rossum65d5b571998-12-21 19:32:43 +0000167 dprintf(("PyThread_exit_thread called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000168
169 /* Thread-safe way to read a variable without a mutex: */
170 threads = atomic_add( &thread_count, 0 );
171
172 if( threads == 0 ) {
173 /* No threads around, so exit main(). */
174 if( no_cleanup ) {
175 _exit(0);
176 } else {
177 exit(0);
178 }
179 } else {
180 /* Oh, we're a thread, let's try to exit gracefully... */
181 exit_thread( B_NO_ERROR );
182 }
183}
184
185void PyThread_exit_thread( void )
186{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000187 do_PyThread_exit_thread(0);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000188}
189
190void PyThread__exit_thread( void )
191{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000192 do_PyThread_exit_thread(1);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000193}
194
195#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000196static void do_PyThread_exit_prog( int status, int no_cleanup )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000197{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000198 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000199
200 /* No need to do anything, the threads get torn down if main() exits. */
201
202 if (no_cleanup) {
203 _exit(status);
204 } else {
205 exit(status);
206 }
207}
208
209void PyThread_exit_prog( int status )
210{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000211 do_PyThread_exit_prog(status, 0);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000212}
213
214void PyThread__exit_prog( int status )
215{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000216 do_PyThread_exit_prog(status, 1);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000217}
218#endif /* NO_EXIT_PROG */
219
220/* ----------------------------------------------------------------------
221 * Lock support.
222 */
223
224static int32 lock_count = 0;
225
Guido van Rossum65d5b571998-12-21 19:32:43 +0000226PyThread_type_lock PyThread_allocate_lock( void )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000227{
228 benaphore_t *lock;
229 status_t retval;
230 char name[B_OS_NAME_LENGTH];
231 int32 this_lock;
232
Guido van Rossum65d5b571998-12-21 19:32:43 +0000233 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000234
235 lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
236 if( lock == NULL ) {
237 /* TODO: that's bad, raise MemoryError */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000238 return (PyThread_type_lock)NULL;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000239 }
240
241 this_lock = atomic_add( &lock_count, 1 );
242 sprintf( name, "python lock (%d)", this_lock );
243
244 retval = benaphore_create( name, lock );
245 if( retval != EOK ) {
246 /* TODO: that's bad, raise an exception */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000247 return (PyThread_type_lock)NULL;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000248 }
249
Fred Drakea44d3532000-06-30 15:01:00 +0000250 dprintf(("PyThread_allocate_lock() -> %p\n", lock));
Guido van Rossum65d5b571998-12-21 19:32:43 +0000251 return (PyThread_type_lock) lock;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000252}
253
Guido van Rossum65d5b571998-12-21 19:32:43 +0000254void PyThread_free_lock( PyThread_type_lock lock )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000255{
256 status_t retval;
257
Fred Drakea44d3532000-06-30 15:01:00 +0000258 dprintf(("PyThread_free_lock(%p) called\n", lock));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000259
260 retval = benaphore_destroy( (benaphore_t *)lock );
261 if( retval != EOK ) {
262 /* TODO: that's bad, raise an exception */
263 return;
264 }
265}
266
Guido van Rossum65d5b571998-12-21 19:32:43 +0000267int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000268{
269 int success;
270 status_t retval;
271
Fred Drakea44d3532000-06-30 15:01:00 +0000272 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000273
274 if( waitflag ) {
275 retval = benaphore_lock( (benaphore_t *)lock );
276 } else {
277 retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
278 }
279
280 if( retval == EOK ) {
281 success = 1;
282 } else {
283 success = 0;
284
285 /* TODO: that's bad, raise an exception */
286 }
287
Fred Drakea44d3532000-06-30 15:01:00 +0000288 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000289 return success;
290}
291
Guido van Rossum65d5b571998-12-21 19:32:43 +0000292void PyThread_release_lock( PyThread_type_lock lock )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000293{
294 status_t retval;
295
Fred Drakea44d3532000-06-30 15:01:00 +0000296 dprintf(("PyThread_release_lock(%p) called\n", lock));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000297
298 retval = benaphore_unlock( (benaphore_t *)lock );
299 if( retval != EOK ) {
300 /* TODO: that's bad, raise an exception */
301 return;
302 }
303}
304
305/* ----------------------------------------------------------------------
306 * Semaphore support.
307 *
308 * Guido says not to implement this because it's not used anywhere;
309 * I'll do it anyway, you never know when it might be handy, and it's
310 * easy...
311 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000312PyThread_type_sema PyThread_allocate_sema( int value )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000313{
314 sem_id sema;
315
Guido van Rossum65d5b571998-12-21 19:32:43 +0000316 dprintf(("PyThread_allocate_sema called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000317
318 sema = create_sem( value, "python semaphore" );
319 if( sema < B_NO_ERROR ) {
320 /* TODO: that's bad, raise an exception */
321 return 0;
322 }
323
Fred Drakea44d3532000-06-30 15:01:00 +0000324 dprintf(("PyThread_allocate_sema() -> %p\n", sema));
Guido van Rossum65d5b571998-12-21 19:32:43 +0000325 return (PyThread_type_sema) sema;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000326}
327
Guido van Rossum65d5b571998-12-21 19:32:43 +0000328void PyThread_free_sema( PyThread_type_sema sema )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000329{
330 status_t retval;
331
Fred Drakea44d3532000-06-30 15:01:00 +0000332 dprintf(("PyThread_free_sema(%p) called\n", sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000333
334 retval = delete_sem( (sem_id)sema );
335 if( retval != B_NO_ERROR ) {
336 /* TODO: that's bad, raise an exception */
337 return;
338 }
339}
340
Guido van Rossum65d5b571998-12-21 19:32:43 +0000341int PyThread_down_sema( PyThread_type_sema sema, int waitflag )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000342{
343 status_t retval;
344
Fred Drakea44d3532000-06-30 15:01:00 +0000345 dprintf(("PyThread_down_sema(%p, %d) called\n", sema, waitflag));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000346
347 if( waitflag ) {
348 retval = acquire_sem( (sem_id)sema );
349 } else {
350 retval = acquire_sem_etc( (sem_id)sema, 1, B_TIMEOUT, 0 );
351 }
352
353 if( retval != B_NO_ERROR ) {
354 /* TODO: that's bad, raise an exception */
355 return 0;
356 }
357
Fred Drakea44d3532000-06-30 15:01:00 +0000358 dprintf(("PyThread_down_sema(%p) return\n", sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000359 return -1;
360}
361
Guido van Rossum65d5b571998-12-21 19:32:43 +0000362void PyThread_up_sema( PyThread_type_sema sema )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000363{
364 status_t retval;
365
Fred Drakea44d3532000-06-30 15:01:00 +0000366 dprintf(("PyThread_up_sema(%p)\n", sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000367
368 retval = release_sem( (sem_id)sema );
369 if( retval != B_NO_ERROR ) {
370 /* TODO: that's bad, raise an exception */
371 return;
372 }
373}