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 (at) be.com) 7 * in the Be Developer's Newsletter, Issue #26 (http://www.be.com/). 8 */ 9 typedef struct benaphore { 10 sem_id _sem; 11 int32 _atom; 12 } benaphore_t; 13 14 static status_t benaphore_create( const char *name, benaphore_t *ben ); 15 static status_t benaphore_destroy( benaphore_t *ben ); 16 static status_t benaphore_lock( benaphore_t *ben ); 17 static status_t benaphore_timedlock( benaphore_t *ben, bigtime_t micros ); 18 static status_t benaphore_unlock( benaphore_t *ben ); 19 20 static 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 36 static 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 51 static 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 62 static 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 86 static 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 */ 100 static 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 113 static int32 thread_count = 0; 114 115 long 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 138 long 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 147 void 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 169 static int32 lock_count = 0; 170 171 PyThread_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 199 void 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 212 int 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 237 void 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