Home | History | Annotate | Download | only in Python
      1 /* Threading for AtheOS.
      2    Based on thread_beos.h. */
      3 
      4 #include <atheos/threads.h>
      5 #include <atheos/semaphore.h>
      6 #include <atheos/atomic.h>
      7 #include <errno.h>
      8 #include <string.h>
      9 
     10 /* Missing decl from threads.h */
     11 extern int exit_thread(int);
     12 
     13 
     14 /* Undefine FASTLOCK to play with simple semaphores. */
     15 #define FASTLOCK
     16 
     17 
     18 #ifdef FASTLOCK
     19 
     20 /* Use an atomic counter and a semaphore for maximum speed. */
     21 typedef struct fastmutex {
     22     sem_id sem;
     23     atomic_t count;
     24 } fastmutex_t;
     25 
     26 
     27 static int fastmutex_create(const char *name, fastmutex_t * mutex);
     28 static int fastmutex_destroy(fastmutex_t * mutex);
     29 static int fastmutex_lock(fastmutex_t * mutex);
     30 static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout);
     31 static int fastmutex_unlock(fastmutex_t * mutex);
     32 
     33 
     34 static int fastmutex_create(const char *name, fastmutex_t * mutex)
     35 {
     36     mutex->count = 0;
     37     mutex->sem = create_semaphore(name, 0, 0);
     38     return (mutex->sem < 0) ? -1 : 0;
     39 }
     40 
     41 
     42 static int fastmutex_destroy(fastmutex_t * mutex)
     43 {
     44     if (fastmutex_timedlock(mutex, 0) == 0 || errno == EWOULDBLOCK) {
     45         return delete_semaphore(mutex->sem);
     46     }
     47     return 0;
     48 }
     49 
     50 
     51 static int fastmutex_lock(fastmutex_t * mutex)
     52 {
     53     atomic_t prev = atomic_add(&mutex->count, 1);
     54     if (prev > 0)
     55         return lock_semaphore(mutex->sem);
     56     return 0;
     57 }
     58 
     59 
     60 static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout)
     61 {
     62     atomic_t prev = atomic_add(&mutex->count, 1);
     63     if (prev > 0)
     64         return lock_semaphore_x(mutex->sem, 1, 0, timeout);
     65     return 0;
     66 }
     67 
     68 
     69 static int fastmutex_unlock(fastmutex_t * mutex)
     70 {
     71     atomic_t prev = atomic_add(&mutex->count, -1);
     72     if (prev > 1)
     73         return unlock_semaphore(mutex->sem);
     74     return 0;
     75 }
     76 
     77 
     78 #endif                          /* FASTLOCK */
     79 
     80 
     81 /*
     82  * Initialization.
     83  *
     84  */
     85 static void PyThread__init_thread(void)
     86 {
     87     /* Do nothing. */
     88     return;
     89 }
     90 
     91 
     92 /*
     93  * Thread support.
     94  *
     95  */
     96 
     97 static atomic_t thread_count = 0;
     98 
     99 long PyThread_start_new_thread(void (*func) (void *), void *arg)
    100 {
    101     status_t success = -1;
    102     thread_id tid;
    103     char name[OS_NAME_LENGTH];
    104     atomic_t this_thread;
    105 
    106     dprintf(("PyThread_start_new_thread called\n"));
    107 
    108     this_thread = atomic_add(&thread_count, 1);
    109     PyOS_snprintf(name, sizeof(name), "python thread (%d)", this_thread);
    110 
    111     tid = spawn_thread(name, func, NORMAL_PRIORITY, 0, arg);
    112     if (tid < 0) {
    113         dprintf(("PyThread_start_new_thread spawn_thread failed: %s\n", strerror(errno)));
    114     } else {
    115         success = resume_thread(tid);
    116         if (success < 0) {
    117             dprintf(("PyThread_start_new_thread resume_thread failed: %s\n", strerror(errno)));
    118         }
    119     }
    120 
    121     return (success < 0 ? -1 : tid);
    122 }
    123 
    124 
    125 long PyThread_get_thread_ident(void)
    126 {
    127     return get_thread_id(NULL);
    128 }
    129 
    130 
    131 void PyThread_exit_thread(void)
    132 {
    133     dprintf(("PyThread_exit_thread called\n"));
    134 
    135     /* Thread-safe way to read a variable without a mutex: */
    136     if (atomic_add(&thread_count, 0) == 0) {
    137         /* No threads around, so exit main(). */
    138         exit(0);
    139     } else {
    140         /* We're a thread */
    141         exit_thread(0);
    142     }
    143 }
    144 
    145 
    146 /*
    147  * Lock support.
    148  *
    149  */
    150 
    151 static atomic_t lock_count = 0;
    152 
    153 PyThread_type_lock PyThread_allocate_lock(void)
    154 {
    155 #ifdef FASTLOCK
    156     fastmutex_t *lock;
    157 #else
    158     sem_id sema;
    159 #endif
    160     char name[OS_NAME_LENGTH];
    161     atomic_t this_lock;
    162 
    163     dprintf(("PyThread_allocate_lock called\n"));
    164 
    165 #ifdef FASTLOCK
    166     lock = (fastmutex_t *) malloc(sizeof(fastmutex_t));
    167     if (lock == NULL) {
    168         dprintf(("PyThread_allocate_lock failed: out of memory\n"));
    169         return (PyThread_type_lock) NULL;
    170     }
    171 #endif
    172     this_lock = atomic_add(&lock_count, 1);
    173     PyOS_snprintf(name, sizeof(name), "python lock (%d)", this_lock);
    174 
    175 #ifdef FASTLOCK
    176     if (fastmutex_create(name, lock) < 0) {
    177         dprintf(("PyThread_allocate_lock failed: %s\n",
    178                  strerror(errno)));
    179         free(lock);
    180         lock = NULL;
    181     }
    182     dprintf(("PyThread_allocate_lock()-> %p\n", lock));
    183     return (PyThread_type_lock) lock;
    184 #else
    185     sema = create_semaphore(name, 1, 0);
    186     if (sema < 0) {
    187         dprintf(("PyThread_allocate_lock failed: %s\n",
    188                  strerror(errno)));
    189         sema = 0;
    190     }
    191     dprintf(("PyThread_allocate_lock()-> %p\n", sema));
    192     return (PyThread_type_lock) sema;
    193 #endif
    194 }
    195 
    196 
    197 void PyThread_free_lock(PyThread_type_lock lock)
    198 {
    199     dprintf(("PyThread_free_lock(%p) called\n", lock));
    200 
    201 #ifdef FASTLOCK
    202     if (fastmutex_destroy((fastmutex_t *) lock) < 0) {
    203         dprintf(("PyThread_free_lock(%p) failed: %s\n", lock,
    204                  strerror(errno)));
    205     }
    206     free(lock);
    207 #else
    208     if (delete_semaphore((sem_id) lock) < 0) {
    209         dprintf(("PyThread_free_lock(%p) failed: %s\n", lock,
    210                  strerror(errno)));
    211     }
    212 #endif
    213 }
    214 
    215 
    216 int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
    217 {
    218     int retval;
    219 
    220     dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock,
    221              waitflag));
    222 
    223 #ifdef FASTLOCK
    224     if (waitflag)
    225         retval = fastmutex_lock((fastmutex_t *) lock);
    226     else
    227         retval = fastmutex_timedlock((fastmutex_t *) lock, 0);
    228 #else
    229     if (waitflag)
    230         retval = lock_semaphore((sem_id) lock);
    231     else
    232         retval = lock_semaphore_x((sem_id) lock, 1, 0, 0);
    233 #endif
    234     if (retval < 0) {
    235         dprintf(("PyThread_acquire_lock(%p, %d) failed: %s\n",
    236                  lock, waitflag, strerror(errno)));
    237     }
    238     dprintf(("PyThread_acquire_lock(%p, %d)-> %d\n", lock, waitflag,
    239              retval));
    240     return retval < 0 ? 0 : 1;
    241 }
    242 
    243 
    244 void PyThread_release_lock(PyThread_type_lock lock)
    245 {
    246     dprintf(("PyThread_release_lock(%p) called\n", lock));
    247 
    248 #ifdef FASTLOCK
    249     if (fastmutex_unlock((fastmutex_t *) lock) < 0) {
    250         dprintf(("PyThread_release_lock(%p) failed: %s\n", lock,
    251                  strerror(errno)));
    252     }
    253 #else
    254     if (unlock_semaphore((sem_id) lock) < 0) {
    255         dprintf(("PyThread_release_lock(%p) failed: %s\n", lock,
    256                  strerror(errno)));
    257     }
    258 #endif
    259 }
    260