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