blob: 0dff786436cb160cb29575343c916473b36b2395 [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
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
16
17While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
29
30BeOS thread support by Chris Herborth (chrish@qnx.com)
31******************************************************************/
32
33#include <kernel/OS.h>
34#include <support/SupportDefs.h>
35#include <errno.h>
36
37/* ----------------------------------------------------------------------
38 * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
39 * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
40 */
41typedef struct benaphore {
42 sem_id _sem;
43 int32 _atom;
44} benaphore_t;
45
46static status_t benaphore_create( const char *name, benaphore_t *ben );
47static status_t benaphore_destroy( benaphore_t *ben );
48static status_t benaphore_lock( benaphore_t *ben );
49static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
50static status_t benaphore_unlock( benaphore_t *ben );
51
52static status_t benaphore_create( const char *name, benaphore_t *ben )
53{
54 if( ben != NULL ) {
55 ben->_atom = 0;
56 ben->_sem = create_sem( 0, name );
57
58 if( ben->_sem < B_NO_ERROR ) {
59 return B_BAD_SEM_ID;
60 }
61 } else {
62 return EFAULT;
63 }
64
65 return EOK;
66}
67
68static status_t benaphore_destroy( benaphore_t *ben )
69{
70 if( ben->_sem >= B_NO_ERROR ) {
71 status_t retval = benaphore_timedlock( ben, 0 );
72
73 if( retval == EOK || retval == EWOULDBLOCK ) {
74 status_t del_retval = delete_sem( ben->_sem );
75
76 return del_retval;
77 }
78 }
79
80 return B_BAD_SEM_ID;
81}
82
83static status_t benaphore_lock( benaphore_t *ben )
84{
85 int32 prev = atomic_add( &(ben->_atom), 1 );
86
87 if( prev > 0 ) {
88 return acquire_sem( ben->_sem );
89 }
90
91 return EOK;
92}
93
94static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
95{
96 int32 prev = atomic_add( &(ben->_atom), 1 );
97
98 if( prev > 0 ) {
99 status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
100
101 switch( retval ) {
102 case B_WOULD_BLOCK: /* Fall through... */
103 case B_TIMED_OUT:
104 return EWOULDBLOCK;
105 break;
106 case B_OK:
107 return EOK;
108 break;
109 default:
110 return retval;
111 break;
112 }
113 }
114
115 return EOK;
116}
117
118static status_t benaphore_unlock( benaphore_t *ben )
119{
120 int32 prev = atomic_add( &(ben->_atom), -1 );
121
122 if( prev > 1 ) {
123 return release_sem( ben->_sem );
124 }
125
126 return EOK;
127}
128
129/* ----------------------------------------------------------------------
130 * Initialization.
131 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000132static void PyThread__init_thread( void )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000133{
134 /* Do nothing. */
135 return;
136}
137
138/* ----------------------------------------------------------------------
139 * Thread support.
140 *
141 * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
142 * and there's no legacy thread module to support.
143 */
144
145static int32 thread_count = 0;
146
147int PyThread_start_new_thread( void (*func)(void *), void *arg )
148{
149 status_t success = 0;
150 thread_id tid;
151 char name[B_OS_NAME_LENGTH];
152 int32 this_thread;
153
Guido van Rossum65d5b571998-12-21 19:32:43 +0000154 dprintf(("PyThread_start_new_thread called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000155
156 /* We are so very thread-safe... */
157 this_thread = atomic_add( &thread_count, 1 );
158 sprintf( name, "python thread (%d)", this_thread );
159
160 tid = spawn_thread( (thread_func)func, name,
161 B_NORMAL_PRIORITY, arg );
162 if( tid > B_NO_ERROR ) {
163 success = resume_thread( tid );
164 }
165
166 return ( success == B_NO_ERROR ? 1 : 0 );
167}
168
169long PyThread_get_thread_ident( void )
170{
171 /* Presumed to return the current thread's ID... */
172 thread_id tid;
173 tid = find_thread( NULL );
174
175 return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
176}
177
Guido van Rossum65d5b571998-12-21 19:32:43 +0000178static void do_PyThread_exit_thread( int no_cleanup )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000179{
180 int32 threads;
181
Guido van Rossum65d5b571998-12-21 19:32:43 +0000182 dprintf(("PyThread_exit_thread called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000183
184 /* Thread-safe way to read a variable without a mutex: */
185 threads = atomic_add( &thread_count, 0 );
186
187 if( threads == 0 ) {
188 /* No threads around, so exit main(). */
189 if( no_cleanup ) {
190 _exit(0);
191 } else {
192 exit(0);
193 }
194 } else {
195 /* Oh, we're a thread, let's try to exit gracefully... */
196 exit_thread( B_NO_ERROR );
197 }
198}
199
200void PyThread_exit_thread( void )
201{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000202 do_PyThread_exit_thread(0);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000203}
204
205void PyThread__exit_thread( void )
206{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000207 do_PyThread_exit_thread(1);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000208}
209
210#ifndef NO_EXIT_PROG
Guido van Rossum65d5b571998-12-21 19:32:43 +0000211static void do_PyThread_exit_prog( int status, int no_cleanup )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000212{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000213 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000214
215 /* No need to do anything, the threads get torn down if main() exits. */
216
217 if (no_cleanup) {
218 _exit(status);
219 } else {
220 exit(status);
221 }
222}
223
224void PyThread_exit_prog( int status )
225{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000226 do_PyThread_exit_prog(status, 0);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000227}
228
229void PyThread__exit_prog( int status )
230{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000231 do_PyThread_exit_prog(status, 1);
Guido van Rossum926f7b61998-12-07 21:56:59 +0000232}
233#endif /* NO_EXIT_PROG */
234
235/* ----------------------------------------------------------------------
236 * Lock support.
237 */
238
239static int32 lock_count = 0;
240
Guido van Rossum65d5b571998-12-21 19:32:43 +0000241PyThread_type_lock PyThread_allocate_lock( void )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000242{
243 benaphore_t *lock;
244 status_t retval;
245 char name[B_OS_NAME_LENGTH];
246 int32 this_lock;
247
Guido van Rossum65d5b571998-12-21 19:32:43 +0000248 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000249
250 lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
251 if( lock == NULL ) {
252 /* TODO: that's bad, raise MemoryError */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000253 return (PyThread_type_lock)NULL;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000254 }
255
256 this_lock = atomic_add( &lock_count, 1 );
257 sprintf( name, "python lock (%d)", this_lock );
258
259 retval = benaphore_create( name, lock );
260 if( retval != EOK ) {
261 /* TODO: that's bad, raise an exception */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000262 return (PyThread_type_lock)NULL;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000263 }
264
Guido van Rossum65d5b571998-12-21 19:32:43 +0000265 dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock));
266 return (PyThread_type_lock) lock;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000267}
268
Guido van Rossum65d5b571998-12-21 19:32:43 +0000269void PyThread_free_lock( PyThread_type_lock lock )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000270{
271 status_t retval;
272
Guido van Rossum65d5b571998-12-21 19:32:43 +0000273 dprintf(("PyThread_free_lock(%lx) called\n", (long)lock));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000274
275 retval = benaphore_destroy( (benaphore_t *)lock );
276 if( retval != EOK ) {
277 /* TODO: that's bad, raise an exception */
278 return;
279 }
280}
281
Guido van Rossum65d5b571998-12-21 19:32:43 +0000282int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000283{
284 int success;
285 status_t retval;
286
Guido van Rossum65d5b571998-12-21 19:32:43 +0000287 dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000288
289 if( waitflag ) {
290 retval = benaphore_lock( (benaphore_t *)lock );
291 } else {
292 retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
293 }
294
295 if( retval == EOK ) {
296 success = 1;
297 } else {
298 success = 0;
299
300 /* TODO: that's bad, raise an exception */
301 }
302
Guido van Rossum65d5b571998-12-21 19:32:43 +0000303 dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000304 return success;
305}
306
Guido van Rossum65d5b571998-12-21 19:32:43 +0000307void PyThread_release_lock( PyThread_type_lock lock )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000308{
309 status_t retval;
310
Guido van Rossum65d5b571998-12-21 19:32:43 +0000311 dprintf(("PyThread_release_lock(%lx) called\n", (long)lock));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000312
313 retval = benaphore_unlock( (benaphore_t *)lock );
314 if( retval != EOK ) {
315 /* TODO: that's bad, raise an exception */
316 return;
317 }
318}
319
320/* ----------------------------------------------------------------------
321 * Semaphore support.
322 *
323 * Guido says not to implement this because it's not used anywhere;
324 * I'll do it anyway, you never know when it might be handy, and it's
325 * easy...
326 */
Guido van Rossum65d5b571998-12-21 19:32:43 +0000327PyThread_type_sema PyThread_allocate_sema( int value )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000328{
329 sem_id sema;
330
Guido van Rossum65d5b571998-12-21 19:32:43 +0000331 dprintf(("PyThread_allocate_sema called\n"));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000332
333 sema = create_sem( value, "python semaphore" );
334 if( sema < B_NO_ERROR ) {
335 /* TODO: that's bad, raise an exception */
336 return 0;
337 }
338
Guido van Rossum65d5b571998-12-21 19:32:43 +0000339 dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema));
340 return (PyThread_type_sema) sema;
Guido van Rossum926f7b61998-12-07 21:56:59 +0000341}
342
Guido van Rossum65d5b571998-12-21 19:32:43 +0000343void PyThread_free_sema( PyThread_type_sema sema )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000344{
345 status_t retval;
346
Guido van Rossum65d5b571998-12-21 19:32:43 +0000347 dprintf(("PyThread_free_sema(%lx) called\n", (long) sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000348
349 retval = delete_sem( (sem_id)sema );
350 if( retval != B_NO_ERROR ) {
351 /* TODO: that's bad, raise an exception */
352 return;
353 }
354}
355
Guido van Rossum65d5b571998-12-21 19:32:43 +0000356int PyThread_down_sema( PyThread_type_sema sema, int waitflag )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000357{
358 status_t retval;
359
Guido van Rossum65d5b571998-12-21 19:32:43 +0000360 dprintf(("PyThread_down_sema(%lx, %d) called\n", (long) sema, waitflag));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000361
362 if( waitflag ) {
363 retval = acquire_sem( (sem_id)sema );
364 } else {
365 retval = acquire_sem_etc( (sem_id)sema, 1, B_TIMEOUT, 0 );
366 }
367
368 if( retval != B_NO_ERROR ) {
369 /* TODO: that's bad, raise an exception */
370 return 0;
371 }
372
Guido van Rossum65d5b571998-12-21 19:32:43 +0000373 dprintf(("PyThread_down_sema(%lx) return\n", (long) sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000374 return -1;
375}
376
Guido van Rossum65d5b571998-12-21 19:32:43 +0000377void PyThread_up_sema( PyThread_type_sema sema )
Guido van Rossum926f7b61998-12-07 21:56:59 +0000378{
379 status_t retval;
380
Guido van Rossum65d5b571998-12-21 19:32:43 +0000381 dprintf(("PyThread_up_sema(%lx)\n", (long) sema));
Guido van Rossum926f7b61998-12-07 21:56:59 +0000382
383 retval = release_sem( (sem_id)sema );
384 if( retval != B_NO_ERROR ) {
385 /* TODO: that's bad, raise an exception */
386 return;
387 }
388}