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 */ 11extern 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. */ 21typedef struct fastmutex { 22 sem_id sem; 23 atomic_t count; 24} fastmutex_t; 25 26 27static int fastmutex_create(const char *name, fastmutex_t * mutex); 28static int fastmutex_destroy(fastmutex_t * mutex); 29static int fastmutex_lock(fastmutex_t * mutex); 30static int fastmutex_timedlock(fastmutex_t * mutex, bigtime_t timeout); 31static int fastmutex_unlock(fastmutex_t * mutex); 32 33 34static 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 42static 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 51static 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 60static 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 69static 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 */ 85static void PyThread__init_thread(void) 86{ 87 /* Do nothing. */ 88 return; 89} 90 91 92/* 93 * Thread support. 94 * 95 */ 96 97static atomic_t thread_count = 0; 98 99long 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 125long PyThread_get_thread_ident(void) 126{ 127 return get_thread_id(NULL); 128} 129 130 131void 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 151static atomic_t lock_count = 0; 152 153PyThread_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 197void 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 216int 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 244void 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