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

# User Rev Content
1 gbeauche 1.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