Home | History | Annotate | Download | only in Python
      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