1#include <kernel/OS.h>
2#include <support/SupportDefs.h>
3#include <errno.h>
4
5/* ----------------------------------------------------------------------
6 * Fast locking mechanism described by Benoit Schillings (benoit@be.com)
7 * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/).
8 */
9typedef struct benaphore {
10    sem_id _sem;
11    int32  _atom;
12} benaphore_t;
13
14static status_t benaphore_create( const char *name, benaphore_t *ben );
15static status_t benaphore_destroy( benaphore_t *ben );
16static status_t benaphore_lock( benaphore_t *ben );
17static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros );
18static status_t benaphore_unlock( benaphore_t *ben );
19
20static status_t benaphore_create( const char *name, benaphore_t *ben )
21{
22    if( ben != NULL ) {
23        ben->_atom = 0;
24        ben->_sem = create_sem( 0, name );
25
26        if( ben->_sem < B_NO_ERROR ) {
27            return B_BAD_SEM_ID;
28        }
29    } else {
30        return EFAULT;
31    }
32
33    return EOK;
34}
35
36static status_t benaphore_destroy( benaphore_t *ben )
37{
38    if( ben->_sem >= B_NO_ERROR ) {
39        status_t retval = benaphore_timedlock( ben, 0 );
40
41        if( retval == EOK || retval == EWOULDBLOCK ) {
42            status_t del_retval = delete_sem( ben->_sem );
43
44            return del_retval;
45        }
46    }
47
48    return B_BAD_SEM_ID;
49}
50
51static status_t benaphore_lock( benaphore_t *ben )
52{
53    int32 prev = atomic_add( &(ben->_atom), 1 );
54
55    if( prev > 0 ) {
56        return acquire_sem( ben->_sem );
57    }
58
59    return EOK;
60}
61
62static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros )
63{
64    int32 prev = atomic_add( &(ben->_atom), 1 );
65
66    if( prev > 0 ) {
67        status_t retval = acquire_sem_etc( ben->_sem, 1, B_TIMEOUT, micros );
68
69        switch( retval ) {
70        case B_WOULD_BLOCK:             /* Fall through... */
71        case B_TIMED_OUT:
72            return EWOULDBLOCK;
73            break;
74        case B_OK:
75            return EOK;
76            break;
77        default:
78            return retval;
79            break;
80        }
81    }
82
83    return EOK;
84}
85
86static status_t benaphore_unlock( benaphore_t *ben )
87{
88    int32 prev = atomic_add( &(ben->_atom), -1 );
89
90    if( prev > 1 ) {
91        return release_sem( ben->_sem );
92    }
93
94    return EOK;
95}
96
97/* ----------------------------------------------------------------------
98 * Initialization.
99 */
100static void PyThread__init_thread( void )
101{
102    /* Do nothing. */
103    return;
104}
105
106/* ----------------------------------------------------------------------
107 * Thread support.
108 *
109 * Only ANSI C, renamed functions here; you can't use K&R on BeOS,
110 * and there's no legacy thread module to support.
111 */
112
113static int32 thread_count = 0;
114
115long PyThread_start_new_thread( void (*func)(void *), void *arg )
116{
117    status_t success = 0;
118    thread_id tid;
119    char name[B_OS_NAME_LENGTH];
120    int32 this_thread;
121
122    dprintf(("PyThread_start_new_thread called\n"));
123
124    /* We are so very thread-safe... */
125    this_thread = atomic_add( &thread_count, 1 );
126    PyOS_snprintf(name, sizeof(name),
127                  "python thread (%d)", this_thread );
128
129    tid = spawn_thread( (thread_func)func, name,
130                        B_NORMAL_PRIORITY, arg );
131    if( tid > B_NO_ERROR ) {
132        success = resume_thread( tid );
133    }
134
135    return ( success == B_NO_ERROR ? tid : -1 );
136}
137
138long PyThread_get_thread_ident( void )
139{
140    /* Presumed to return the current thread's ID... */
141    thread_id tid;
142    tid = find_thread( NULL );
143
144    return ( tid != B_NAME_NOT_FOUND ? tid : -1 );
145}
146
147void PyThread_exit_thread( void )
148{
149    int32 threads;
150
151    dprintf(("PyThread_exit_thread called\n"));
152
153    /* Thread-safe way to read a variable without a mutex: */
154    threads = atomic_add( &thread_count, 0 );
155
156    if( threads == 0 ) {
157        /* No threads around, so exit main(). */
158        exit(0);
159    } else {
160        /* Oh, we're a thread, let's try to exit gracefully... */
161        exit_thread( B_NO_ERROR );
162    }
163}
164
165/* ----------------------------------------------------------------------
166 * Lock support.
167 */
168
169static int32 lock_count = 0;
170
171PyThread_type_lock PyThread_allocate_lock( void )
172{
173    benaphore_t *lock;
174    status_t retval;
175    char name[B_OS_NAME_LENGTH];
176    int32 this_lock;
177
178    dprintf(("PyThread_allocate_lock called\n"));
179
180    lock = (benaphore_t *)malloc( sizeof( benaphore_t ) );
181    if( lock == NULL ) {
182        /* TODO: that's bad, raise MemoryError */
183        return (PyThread_type_lock)NULL;
184    }
185
186    this_lock = atomic_add( &lock_count, 1 );
187    PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock);
188
189    retval = benaphore_create( name, lock );
190    if( retval != EOK ) {
191        /* TODO: that's bad, raise an exception */
192        return (PyThread_type_lock)NULL;
193    }
194
195    dprintf(("PyThread_allocate_lock() -> %p\n", lock));
196    return (PyThread_type_lock) lock;
197}
198
199void PyThread_free_lock( PyThread_type_lock lock )
200{
201    status_t retval;
202
203    dprintf(("PyThread_free_lock(%p) called\n", lock));
204
205    retval = benaphore_destroy( (benaphore_t *)lock );
206    if( retval != EOK ) {
207        /* TODO: that's bad, raise an exception */
208        return;
209    }
210}
211
212int PyThread_acquire_lock( PyThread_type_lock lock, int waitflag )
213{
214    int success;
215    status_t retval;
216
217    dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
218
219    if( waitflag ) {
220        retval = benaphore_lock( (benaphore_t *)lock );
221    } else {
222        retval = benaphore_timedlock( (benaphore_t *)lock, 0 );
223    }
224
225    if( retval == EOK ) {
226        success = 1;
227    } else {
228        success = 0;
229
230        /* TODO: that's bad, raise an exception */
231    }
232
233    dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
234    return success;
235}
236
237void PyThread_release_lock( PyThread_type_lock lock )
238{
239    status_t retval;
240
241    dprintf(("PyThread_release_lock(%p) called\n", lock));
242
243    retval = benaphore_unlock( (benaphore_t *)lock );
244    if( retval != EOK ) {
245        /* TODO: that's bad, raise an exception */
246        return;
247    }
248}
249