blob: f2024f31b9e0c71d302b4347cc5d77c784ef0691 [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 */
132static void _init_thread( void )
133{
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
154 dprintf(("start_new_thread called\n"));
155
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
178static void do_exit_thread( int no_cleanup )
179{
180 int32 threads;
181
182 dprintf(("exit_thread called\n"));
183
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{
202 do_exit_thread(0);
203}
204
205void PyThread__exit_thread( void )
206{
207 do_exit_thread(1);
208}
209
210#ifndef NO_EXIT_PROG
211static void do_exit_prog( int status, int no_cleanup )
212{
213 dprintf(("exit_prog(%d) called\n", status));
214
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{
226 do_exit_prog(status, 0);
227}
228
229void PyThread__exit_prog( int status )
230{
231 do_exit_prog(status, 1);
232}
233#endif /* NO_EXIT_PROG */
234
235/* ----------------------------------------------------------------------
236 * Lock support.
237 */
238
239static int32 lock_count = 0;
240
241type_lock PyThread_allocate_lock( void )
242{
243 benaphore_t *lock;
244 status_t retval;
245 char name[B_OS_NAME_LENGTH];
246 int32 this_lock;
247
248 dprintf(("allocate_lock called\n"));
249
250 lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
251 if( lock == NULL ) {
252 /* TODO: that's bad, raise MemoryError */
253 return (type_lock)NULL;
254 }
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 */
262 return (type_lock)NULL;
263 }
264
265 dprintf(("allocate_lock() -> %lx\n", (long)lock));
266 return (type_lock) lock;
267}
268
269void PyThread_free_lock( type_lock lock )
270{
271 status_t retval;
272
273 dprintf(("free_lock(%lx) called\n", (long)lock));
274
275 retval = benaphore_destroy( (benaphore_t *)lock );
276 if( retval != EOK ) {
277 /* TODO: that's bad, raise an exception */
278 return;
279 }
280}
281
282int PyThread_acquire_lock( type_lock lock, int waitflag )
283{
284 int success;
285 status_t retval;
286
287 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
288
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
303 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
304 return success;
305}
306
307void PyThread_release_lock( type_lock lock )
308{
309 status_t retval;
310
311 dprintf(("release_lock(%lx) called\n", (long)lock));
312
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 */
327type_sema PyThread_allocate_sema( int value )
328{
329 sem_id sema;
330
331 dprintf(("allocate_sema called\n"));
332
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
339 dprintf(("allocate_sema() -> %lx\n", (long) sema));
340 return (type_sema) sema;
341}
342
343void PyThread_free_sema( type_sema sema )
344{
345 status_t retval;
346
347 dprintf(("free_sema(%lx) called\n", (long) sema));
348
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
356int PyThread_down_sema( type_sema sema, int waitflag )
357{
358 status_t retval;
359
360 dprintf(("down_sema(%lx, %d) called\n", (long) sema, waitflag));
361
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
373 dprintf(("down_sema(%lx) return\n", (long) sema));
374 return -1;
375}
376
377void PyThread_up_sema( type_sema sema )
378{
379 status_t retval;
380
381 dprintf(("up_sema(%lx)\n", (long) sema));
382
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}