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 
fastmutex_create(const char * name,fastmutex_t * mutex)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 
fastmutex_destroy(fastmutex_t * mutex)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 
fastmutex_lock(fastmutex_t * mutex)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 
fastmutex_timedlock(fastmutex_t * mutex,bigtime_t timeout)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 
fastmutex_unlock(fastmutex_t * mutex)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  */
PyThread__init_thread(void)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 
PyThread_start_new_thread(void (* func)(void *),void * arg)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 
PyThread_get_thread_ident(void)125 long PyThread_get_thread_ident(void)
126 {
127     return get_thread_id(NULL);
128 }
129 
130 
PyThread_exit_thread(void)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 
PyThread_allocate_lock(void)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 
PyThread_free_lock(PyThread_type_lock lock)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 
PyThread_acquire_lock(PyThread_type_lock lock,int waitflag)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 
PyThread_release_lock(PyThread_type_lock lock)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