Home | History | Annotate | Download | only in Python
      1 
      2 /* GNU pth threads interface
      3    http://www.gnu.org/software/pth
      4    2000-05-03 Andy Dustman <andy (at) dustman.net>
      5 
      6    Adapted from Posix threads interface
      7    12 May 1997 -- david arnold <davida (at) pobox.com>
      8  */
      9 
     10 #include <stdlib.h>
     11 #include <string.h>
     12 #include <pth.h>
     13 
     14 /* A pth mutex isn't sufficient to model the Python lock type
     15  * because pth mutexes can be acquired multiple times by the
     16  * same thread.
     17  *
     18  * The pth_lock struct implements a Python lock as a "locked?" bit
     19  * and a <condition, mutex> pair.  In general, if the bit can be acquired
     20  * instantly, it is, else the pair is used to block the thread until the
     21  * bit is cleared.
     22  */
     23 
     24 typedef struct {
     25     char             locked; /* 0=unlocked, 1=locked */
     26     /* a <cond, mutex> pair to handle an acquire of a locked lock */
     27     pth_cond_t   lock_released;
     28     pth_mutex_t  mut;
     29 } pth_lock;
     30 
     31 #define CHECK_STATUS(name)  if (status == -1) { printf("%d ", status); perror(name); error = 1; }
     32 
     33 pth_attr_t PyThread_attr;
     34 
     35 /*
     36  * Initialization.
     37  */
     38 
     39 static void PyThread__init_thread(void)
     40 {
     41     pth_init();
     42     PyThread_attr = pth_attr_new();
     43     pth_attr_set(PyThread_attr, PTH_ATTR_STACK_SIZE, 1<<18);
     44     pth_attr_set(PyThread_attr, PTH_ATTR_JOINABLE, FALSE);
     45 }
     46 
     47 /*
     48  * Thread support.
     49  */
     50 
     51 
     52 long PyThread_start_new_thread(void (*func)(void *), void *arg)
     53 {
     54     pth_t th;
     55     dprintf(("PyThread_start_new_thread called\n"));
     56     if (!initialized)
     57         PyThread_init_thread();
     58 
     59     th = pth_spawn(PyThread_attr,
     60                              (void* (*)(void *))func,
     61                              (void *)arg
     62                              );
     63 
     64     return th;
     65 }
     66 
     67 long PyThread_get_thread_ident(void)
     68 {
     69     volatile pth_t threadid;
     70     if (!initialized)
     71         PyThread_init_thread();
     72     /* Jump through some hoops for Alpha OSF/1 */
     73     threadid = pth_self();
     74     return (long) *(long *) &threadid;
     75 }
     76 
     77 void PyThread_exit_thread(void)
     78 {
     79     dprintf(("PyThread_exit_thread called\n"));
     80     if (!initialized) {
     81         exit(0);
     82     }
     83 }
     84 
     85 /*
     86  * Lock support.
     87  */
     88 PyThread_type_lock PyThread_allocate_lock(void)
     89 {
     90     pth_lock *lock;
     91     int status, error = 0;
     92 
     93     dprintf(("PyThread_allocate_lock called\n"));
     94     if (!initialized)
     95         PyThread_init_thread();
     96 
     97     lock = (pth_lock *) malloc(sizeof(pth_lock));
     98     memset((void *)lock, '\0', sizeof(pth_lock));
     99     if (lock) {
    100         lock->locked = 0;
    101         status = pth_mutex_init(&lock->mut);
    102         CHECK_STATUS("pth_mutex_init");
    103         status = pth_cond_init(&lock->lock_released);
    104         CHECK_STATUS("pth_cond_init");
    105         if (error) {
    106             free((void *)lock);
    107             lock = NULL;
    108         }
    109     }
    110     dprintf(("PyThread_allocate_lock() -> %p\n", lock));
    111     return (PyThread_type_lock) lock;
    112 }
    113 
    114 void PyThread_free_lock(PyThread_type_lock lock)
    115 {
    116     pth_lock *thelock = (pth_lock *)lock;
    117 
    118     dprintf(("PyThread_free_lock(%p) called\n", lock));
    119 
    120     free((void *)thelock);
    121 }
    122 
    123 int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
    124 {
    125     int success;
    126     pth_lock *thelock = (pth_lock *)lock;
    127     int status, error = 0;
    128 
    129     dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
    130 
    131     status = pth_mutex_acquire(&thelock->mut, !waitflag, NULL);
    132     CHECK_STATUS("pth_mutex_acquire[1]");
    133     success = thelock->locked == 0;
    134     if (success) thelock->locked = 1;
    135     status = pth_mutex_release( &thelock->mut );
    136     CHECK_STATUS("pth_mutex_release[1]");
    137 
    138     if ( !success && waitflag ) {
    139         /* continue trying until we get the lock */
    140 
    141         /* mut must be locked by me -- part of the condition
    142          * protocol */
    143         status = pth_mutex_acquire( &thelock->mut, !waitflag, NULL );
    144         CHECK_STATUS("pth_mutex_acquire[2]");
    145         while ( thelock->locked ) {
    146             status = pth_cond_await(&thelock->lock_released,
    147                                     &thelock->mut, NULL);
    148             CHECK_STATUS("pth_cond_await");
    149         }
    150         thelock->locked = 1;
    151         status = pth_mutex_release( &thelock->mut );
    152         CHECK_STATUS("pth_mutex_release[2]");
    153         success = 1;
    154     }
    155     if (error) success = 0;
    156     dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
    157     return success;
    158 }
    159 
    160 void PyThread_release_lock(PyThread_type_lock lock)
    161 {
    162     pth_lock *thelock = (pth_lock *)lock;
    163     int status, error = 0;
    164 
    165     dprintf(("PyThread_release_lock(%p) called\n", lock));
    166 
    167     status = pth_mutex_acquire( &thelock->mut, 0, NULL );
    168     CHECK_STATUS("pth_mutex_acquire[3]");
    169 
    170     thelock->locked = 0;
    171 
    172     status = pth_mutex_release( &thelock->mut );
    173     CHECK_STATUS("pth_mutex_release[3]");
    174 
    175     /* wake up someone (anyone, if any) waiting on the lock */
    176     status = pth_cond_notify( &thelock->lock_released, 0 );
    177     CHECK_STATUS("pth_cond_notify");
    178 }
    179