1 /***********************************************************
2 Copyright (c) 2000, BeOpen.com.
3 Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4 Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
7 See the file "Misc/COPYRIGHT" for information on usage and
8 redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
9 BeOS thread support by Chris Herborth (chrish@qnx.com)
10 ******************************************************************/
12 #include <kernel/OS.h>
13 #include <support/SupportDefs.h>
16 /* ----------------------------------------------------------------------
17 * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
18 * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
20 typedef struct benaphore
{
25 static status_t
benaphore_create( const char *name
, benaphore_t
*ben
);
26 static status_t
benaphore_destroy( benaphore_t
*ben
);
27 static status_t
benaphore_lock( benaphore_t
*ben
);
28 static status_t
benaphore_timedlock( benaphore_t
*ben
, bigtime_t micros
);
29 static status_t
benaphore_unlock( benaphore_t
*ben
);
31 static status_t
benaphore_create( const char *name
, benaphore_t
*ben
)
35 ben
->_sem
= create_sem( 0, name
);
37 if( ben
->_sem
< B_NO_ERROR
) {
47 static status_t
benaphore_destroy( benaphore_t
*ben
)
49 if( ben
->_sem
>= B_NO_ERROR
) {
50 status_t retval
= benaphore_timedlock( ben
, 0 );
52 if( retval
== EOK
|| retval
== EWOULDBLOCK
) {
53 status_t del_retval
= delete_sem( ben
->_sem
);
62 static status_t
benaphore_lock( benaphore_t
*ben
)
64 int32 prev
= atomic_add( &(ben
->_atom
), 1 );
67 return acquire_sem( ben
->_sem
);
73 static status_t
benaphore_timedlock( benaphore_t
*ben
, bigtime_t micros
)
75 int32 prev
= atomic_add( &(ben
->_atom
), 1 );
78 status_t retval
= acquire_sem_etc( ben
->_sem
, 1, B_TIMEOUT
, micros
);
81 case B_WOULD_BLOCK
: /* Fall through... */
97 static status_t
benaphore_unlock( benaphore_t
*ben
)
99 int32 prev
= atomic_add( &(ben
->_atom
), -1 );
102 return release_sem( ben
->_sem
);
108 /* ----------------------------------------------------------------------
111 static void PyThread__init_thread( void )
117 /* ----------------------------------------------------------------------
120 * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
121 * and there's no legacy thread module to support.
124 static int32 thread_count
= 0;
126 int PyThread_start_new_thread( void (*func
)(void *), void *arg
)
128 status_t success
= 0;
130 char name
[B_OS_NAME_LENGTH
];
133 dprintf(("PyThread_start_new_thread called\n"));
135 /* We are so very thread-safe... */
136 this_thread
= atomic_add( &thread_count
, 1 );
137 sprintf( name
, "python thread (%d)", this_thread
);
139 tid
= spawn_thread( (thread_func
)func
, name
,
140 B_NORMAL_PRIORITY
, arg
);
141 if( tid
> B_NO_ERROR
) {
142 success
= resume_thread( tid
);
145 return ( success
== B_NO_ERROR
? 1 : 0 );
148 long PyThread_get_thread_ident( void )
150 /* Presumed to return the current thread's ID... */
152 tid
= find_thread( NULL
);
154 return ( tid
!= B_NAME_NOT_FOUND
? tid
: -1 );
157 static void do_PyThread_exit_thread( int no_cleanup
)
161 dprintf(("PyThread_exit_thread called\n"));
163 /* Thread-safe way to read a variable without a mutex: */
164 threads
= atomic_add( &thread_count
, 0 );
167 /* No threads around, so exit main(). */
174 /* Oh, we're a thread, let's try to exit gracefully... */
175 exit_thread( B_NO_ERROR
);
179 void PyThread_exit_thread( void )
181 do_PyThread_exit_thread(0);
184 void PyThread__exit_thread( void )
186 do_PyThread_exit_thread(1);
190 static void do_PyThread_exit_prog( int status
, int no_cleanup
)
192 dprintf(("PyThread_exit_prog(%d) called\n", status
));
194 /* No need to do anything, the threads get torn down if main() exits. */
203 void PyThread_exit_prog( int status
)
205 do_PyThread_exit_prog(status
, 0);
208 void PyThread__exit_prog( int status
)
210 do_PyThread_exit_prog(status
, 1);
212 #endif /* NO_EXIT_PROG */
214 /* ----------------------------------------------------------------------
218 static int32 lock_count
= 0;
220 PyThread_type_lock
PyThread_allocate_lock( void )
224 char name
[B_OS_NAME_LENGTH
];
227 dprintf(("PyThread_allocate_lock called\n"));
229 lock
= (benaphore_t
*)malloc( sizeof( benaphore_t
) );
231 /* TODO: that's bad, raise MemoryError */
232 return (PyThread_type_lock
)NULL
;
235 this_lock
= atomic_add( &lock_count
, 1 );
236 sprintf( name
, "python lock (%d)", this_lock
);
238 retval
= benaphore_create( name
, lock
);
239 if( retval
!= EOK
) {
240 /* TODO: that's bad, raise an exception */
241 return (PyThread_type_lock
)NULL
;
244 dprintf(("PyThread_allocate_lock() -> %p\n", lock
));
245 return (PyThread_type_lock
) lock
;
248 void PyThread_free_lock( PyThread_type_lock lock
)
252 dprintf(("PyThread_free_lock(%p) called\n", lock
));
254 retval
= benaphore_destroy( (benaphore_t
*)lock
);
255 if( retval
!= EOK
) {
256 /* TODO: that's bad, raise an exception */
261 int PyThread_acquire_lock( PyThread_type_lock lock
, int waitflag
)
266 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock
, waitflag
));
269 retval
= benaphore_lock( (benaphore_t
*)lock
);
271 retval
= benaphore_timedlock( (benaphore_t
*)lock
, 0 );
274 if( retval
== EOK
) {
279 /* TODO: that's bad, raise an exception */
282 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock
, waitflag
, success
));
286 void PyThread_release_lock( PyThread_type_lock lock
)
290 dprintf(("PyThread_release_lock(%p) called\n", lock
));
292 retval
= benaphore_unlock( (benaphore_t
*)lock
);
293 if( retval
!= EOK
) {
294 /* TODO: that's bad, raise an exception */
299 /* ----------------------------------------------------------------------
302 * Guido says not to implement this because it's not used anywhere;
303 * I'll do it anyway, you never know when it might be handy, and it's
306 PyThread_type_sema
PyThread_allocate_sema( int value
)
310 dprintf(("PyThread_allocate_sema called\n"));
312 sema
= create_sem( value
, "python semaphore" );
313 if( sema
< B_NO_ERROR
) {
314 /* TODO: that's bad, raise an exception */
318 dprintf(("PyThread_allocate_sema() -> %p\n", sema
));
319 return (PyThread_type_sema
) sema
;
322 void PyThread_free_sema( PyThread_type_sema sema
)
326 dprintf(("PyThread_free_sema(%p) called\n", sema
));
328 retval
= delete_sem( (sem_id
)sema
);
329 if( retval
!= B_NO_ERROR
) {
330 /* TODO: that's bad, raise an exception */
335 int PyThread_down_sema( PyThread_type_sema sema
, int waitflag
)
339 dprintf(("PyThread_down_sema(%p, %d) called\n", sema
, waitflag
));
342 retval
= acquire_sem( (sem_id
)sema
);
344 retval
= acquire_sem_etc( (sem_id
)sema
, 1, B_TIMEOUT
, 0 );
347 if( retval
!= B_NO_ERROR
) {
348 /* TODO: that's bad, raise an exception */
352 dprintf(("PyThread_down_sema(%p) return\n", sema
));
356 void PyThread_up_sema( PyThread_type_sema sema
)
360 dprintf(("PyThread_up_sema(%p)\n", sema
));
362 retval
= release_sem( (sem_id
)sema
);
363 if( retval
!= B_NO_ERROR
) {
364 /* TODO: that's bad, raise an exception */