ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/NetBSD/sheepthreads.c
Revision: 1.1
Committed: 2005-02-20T18:06:40Z (19 years, 7 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Log Message:
Implement SheepThreads on NetBSD/ppc so that sigaltstack()s are really used

File Contents

# Content
1 /*
2 * sheepthreads.c - Minimal pthreads implementation (libpthread doesn't
3 * like sigaltstack)
4 *
5 * SheepShaver (C) 1997-2005 Christian Bauer and Marc Hellwig
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21
22 /*
23 * NOTES:
24 * - pthread_cancel() kills the thread immediately
25 * - Semaphores are VERY restricted: the only supported use is to have one
26 * thread sem_wait() on the semaphore while other threads sem_post() it
27 * (i.e. to use the semaphore as a signal)
28 */
29
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <unistd.h>
35 #include <signal.h>
36 #include <sched.h>
37 #include <pthread.h>
38 #include <semaphore.h>
39
40
41 /* Thread descriptor */
42 struct __pthread_st {
43 unsigned int tid;
44 };
45
46 /* Thread stack size */
47 #define STACK_SIZE 65536
48
49 /* From asm_linux.S */
50 extern int atomic_add(int *var, int add);
51 extern int atomic_and(int *var, int and);
52 extern int atomic_or(int *var, int or);
53 extern int test_and_set(int *var, int val);
54
55 /* Linux kernel calls */
56 extern int __clone(int (*fn)(void *), void *, int, void *);
57
58 /* struct sem_t */
59 struct _sem_st {
60 #define SEM_MAGIC 0x09fa4012
61 unsigned int sem_magic;
62 struct {
63 int status;
64 int spinlock;
65 } sem_lock;
66 int sem_value;
67 pid_t sem_waiting;
68 };
69
70 /* Wait for "clone" children only (Linux 2.4+ specific) */
71 #ifndef __WCLONE
72 #define __WCLONE 0
73 #endif
74
75
76 /*
77 * Return pthread ID of self
78 */
79
80 pthread_t pthread_self(void)
81 {
82 static struct __pthread_st self_st;
83 static pthread_t self = NULL;
84 if (self == NULL) {
85 self = &self_st;
86 self->tid = getpid();
87 }
88 return self;
89 }
90
91
92 /*
93 * Test whether two pthread IDs are equal
94 */
95
96 int pthread_equal(pthread_t t1, pthread_t t2)
97 {
98 return t1 == t2;
99 }
100
101
102 /*
103 * Send signal to thread
104 */
105
106 int pthread_kill(pthread_t thread, int sig)
107 {
108 if (kill(thread->tid, sig) == -1)
109 return errno;
110 else
111 return 0;
112 }
113
114
115 /*
116 * Create pthread
117 */
118
119 struct new_thread {
120 void *(*fn)(void *);
121 void *arg;
122 };
123
124 static int start_thread(void *arg)
125 {
126 struct new_thread *nt = (struct new_thread *)arg;
127 nt->fn(nt->arg);
128 return 0;
129 }
130
131 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
132 {
133 struct new_thread *nt;
134 void *stack;
135 int pid;
136
137 nt = (struct new_thread *)malloc(sizeof(struct new_thread));
138 nt->fn = start_routine;
139 nt->arg = arg;
140 stack = malloc(STACK_SIZE);
141
142 pid = __clone(start_thread, (char *)stack + STACK_SIZE - 16, CLONE_VM | CLONE_FS | CLONE_FILES, nt);
143 if (pid == -1) {
144 free(stack);
145 free(nt);
146 return errno;
147 } else {
148 *thread = malloc(sizeof(**thread));
149 if (*thread == NULL)
150 return -1;
151 (*thread)->tid = pid;
152 return 0;
153 }
154 }
155
156
157 /*
158 * Join pthread
159 */
160
161 int pthread_join(pthread_t thread, void **ret)
162 {
163 do {
164 if (waitpid(thread->tid, NULL, __WCLONE) >= 0);
165 break;
166 } while (errno == EINTR);
167 if (ret)
168 *ret = NULL;
169 return 0;
170 }
171
172
173 /*
174 * Cancel thread
175 */
176
177 int pthread_cancel(pthread_t thread)
178 {
179 kill(thread->tid, SIGINT);
180 thread->tid = (unsigned int)-1;
181 free(thread);
182 return 0;
183 }
184
185
186 /*
187 * Test for cancellation
188 */
189
190 void pthread_testcancel(void)
191 {
192 }
193
194
195 /*
196 * Spinlocks
197 */
198
199 static int try_acquire_spinlock(int *lock)
200 {
201 return test_and_set(lock, 1) == 0;
202 }
203
204 static void acquire_spinlock(volatile int *lock)
205 {
206 do {
207 while (*lock) ;
208 } while (test_and_set((int *)lock, 1) != 0);
209 }
210
211 static void release_spinlock(int *lock)
212 {
213 *lock = 0;
214 }
215
216
217 /*
218 * Initialize mutex
219 */
220
221 int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr)
222 {
223 mutex->ptm_magic = _PT_MUTEX_MAGIC;
224 mutex->ptm_lock = 0;
225 mutex->ptm_owner = NULL;
226 return 0;
227 }
228
229
230 /*
231 * Destroy mutex
232 */
233
234 int pthread_mutex_destroy(pthread_mutex_t *mutex)
235 {
236 if (mutex->ptm_magic != _PT_MUTEX_MAGIC)
237 return EINVAL;
238 if (mutex->ptm_lock != 0)
239 return EBUSY;
240
241 mutex->ptm_magic = _PT_MUTEX_DEAD;
242 return 0;
243 }
244
245
246 /*
247 * Lock mutex
248 */
249
250 int pthread_mutex_lock(pthread_mutex_t *mutex)
251 {
252 if (mutex->ptm_magic != _PT_MUTEX_MAGIC)
253 return EINVAL;
254
255 acquire_spinlock(&mutex->ptm_lock);
256 return 0;
257 }
258
259
260 /*
261 * Try to lock mutex
262 */
263
264 int pthread_mutex_trylock(pthread_mutex_t *mutex)
265 {
266 if (mutex->ptm_magic != _PT_MUTEX_MAGIC)
267 return EINVAL;
268
269 if (!try_acquire_spinlock(&mutex->ptm_lock))
270 return EBUSY;
271 return 0;
272 }
273
274
275 /*
276 * Unlock mutex
277 */
278
279 int pthread_mutex_unlock(pthread_mutex_t *mutex)
280 {
281 if (mutex->ptm_magic != _PT_MUTEX_MAGIC)
282 return EINVAL;
283
284 release_spinlock(&mutex->ptm_lock);
285 return 0;
286 }
287
288
289 /*
290 * Create mutex attribute
291 */
292
293 int pthread_mutexattr_init(pthread_mutexattr_t *attr)
294 {
295 attr->ptma_magic = _PT_MUTEXATTR_MAGIC;
296 return 0;
297 }
298
299
300 /*
301 * Destroy mutex attribute
302 */
303
304 int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
305 {
306 if (attr->ptma_magic != _PT_MUTEXATTR_MAGIC)
307 return EINVAL;
308 return 0;
309 }
310
311
312 /*
313 * Init semaphore
314 */
315
316 int sem_init(sem_t *psem, int pshared, unsigned int value)
317 {
318 sem_t sem = malloc(sizeof(*sem));
319 if (sem == NULL) {
320 errno = ENOSPC;
321 return 0;
322 }
323 *psem = sem;
324 sem->sem_magic = SEM_MAGIC;
325 sem->sem_lock.status = 0;
326 sem->sem_lock.spinlock = 0;
327 sem->sem_value = value;
328 sem->sem_waiting = 0;
329 return 0;
330 }
331
332
333 /*
334 * Delete remaphore
335 */
336
337 int sem_destroy(sem_t *sem)
338 {
339 if (sem == NULL || *sem == NULL || (*sem)->sem_magic != SEM_MAGIC) {
340 errno = EINVAL;
341 return -1;
342 }
343
344 free(*sem);
345 return 0;
346 }
347
348
349 /*
350 * Wait on semaphore
351 */
352
353 void null_handler(int sig)
354 {
355 }
356
357 int sem_wait(sem_t *psem)
358 {
359 sem_t sem;
360 if (psem == NULL || (sem = *psem) == NULL || sem->sem_magic != SEM_MAGIC) {
361 errno = EINVAL;
362 return -1;
363 }
364 acquire_spinlock(&sem->sem_lock.spinlock);
365 if (sem->sem_value > 0)
366 atomic_add(&sem->sem_value, -1);
367 else {
368 sigset_t mask;
369 if (!sem->sem_lock.status) {
370 struct sigaction sa;
371 sem->sem_lock.status = SIGUSR2;
372 sa.sa_handler = null_handler;
373 sa.sa_flags = SA_RESTART;
374 sigemptyset(&sa.sa_mask);
375 sigaction(sem->sem_lock.status, &sa, NULL);
376 }
377 sem->sem_waiting = getpid();
378 sigemptyset(&mask);
379 sigsuspend(&mask);
380 sem->sem_waiting = 0;
381 }
382 release_spinlock(&sem->sem_lock.spinlock);
383 return 0;
384 }
385
386
387 /*
388 * Post semaphore
389 */
390
391 int sem_post(sem_t *psem)
392 {
393 sem_t sem;
394 if (psem == NULL || (sem = *psem) == NULL || sem->sem_magic != SEM_MAGIC) {
395 errno = EINVAL;
396 return -1;
397 }
398 acquire_spinlock(&sem->sem_lock.spinlock);
399 if (sem->sem_waiting == 0)
400 atomic_add(&sem->sem_value, 1);
401 else
402 kill(sem->sem_waiting, sem->sem_lock.status);
403 release_spinlock(&sem->sem_lock.spinlock);
404 return 0;
405 }
406
407
408 /*
409 * Simple producer/consumer test program
410 */
411
412 #ifdef TEST
413 #include <stdio.h>
414
415 static sem_t p_sem, c_sem;
416 static int data = 0;
417
418 static void *producer_func(void *arg)
419 {
420 int i, n = (int)arg;
421 for (i = 0; i < n; i++) {
422 sem_wait(&p_sem);
423 data++;
424 sem_post(&c_sem);
425 }
426 return NULL;
427 }
428
429 static void *consumer_func(void *arg)
430 {
431 int i, n = (int)arg;
432 for (i = 0; i < n; i++) {
433 sem_wait(&c_sem);
434 printf("data: %d\n", data);
435 sem_post(&p_sem);
436 }
437 sleep(1); // for testing pthread_join()
438 return NULL;
439 }
440
441 int main(void)
442 {
443 pthread_t producer_thread, consumer_thread;
444 static const int N = 5;
445
446 if (sem_init(&c_sem, 0, 0) < 0)
447 return 1;
448 if (sem_init(&p_sem, 0, 1) < 0)
449 return 2;
450 if (pthread_create(&producer_thread, NULL, producer_func, (void *)N) != 0)
451 return 3;
452 if (pthread_create(&consumer_thread, NULL, consumer_func, (void *)N) != 0)
453 return 4;
454 pthread_join(producer_thread, NULL);
455 pthread_join(consumer_thread, NULL);
456 sem_destroy(&p_sem);
457 sem_destroy(&c_sem);
458 if (data != N)
459 return 5;
460 return 0;
461 }
462 #endif