ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/sheepthreads.c
Revision: 1.2
Committed: 2002-04-21T11:42:30Z (22 years, 7 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.1: +2 -0 lines
Log Message:
Match changes from glibc 2.2 (?)
- #define status as __status
- #define spinlock as __spinlock

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * sheepthreads.c - Minimal pthreads implementation (libpthreads doesn't
3     * like nonstandard stacks)
4     *
5     * SheepShaver (C) 1997-2002 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 stack size */
42     #define STACK_SIZE 65536
43    
44     /* From asm_linux.S */
45     extern int atomic_add(int *var, int add);
46     extern int atomic_and(int *var, int and);
47     extern int atomic_or(int *var, int or);
48     extern int test_and_set(int *var, int val);
49    
50     /* Linux kernel calls */
51     extern int __clone(int (*fn)(void *), void *, int, void *);
52    
53     /* struct sem_t */
54 gbeauche 1.2 #define status __status
55     #define spinlock __spinlock
56 cebix 1.1 #define sem_lock __sem_lock
57     #define sem_value __sem_value
58     #define sem_waiting __sem_waiting
59    
60    
61     /*
62     * Return pthread ID of self
63     */
64    
65     pthread_t pthread_self(void)
66     {
67     return getpid();
68     }
69    
70    
71     /*
72     * Test whether two pthread IDs are equal
73     */
74    
75     int pthread_equal(pthread_t t1, pthread_t t2)
76     {
77     return t1 == t2;
78     }
79    
80    
81     /*
82     * Send signal to thread
83     */
84    
85     int pthread_kill(pthread_t thread, int sig)
86     {
87     if (kill(thread, sig) == -1)
88     return errno;
89     else
90     return 0;
91     }
92    
93    
94     /*
95     * Create pthread
96     */
97    
98     struct new_thread {
99     void *(*fn)(void *);
100     void *arg;
101     };
102    
103     static int start_thread(void *arg)
104     {
105     struct new_thread *nt = (struct new_thread *)arg;
106     nt->fn(nt->arg);
107     return 0;
108     }
109    
110     int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg)
111     {
112     struct new_thread *nt;
113     void *stack;
114     int pid;
115    
116     nt = (struct new_thread *)malloc(sizeof(struct new_thread));
117     nt->fn = start_routine;
118     nt->arg = arg;
119     stack = malloc(STACK_SIZE);
120    
121     pid = __clone(start_thread, (char *)stack + STACK_SIZE - 16, CLONE_VM | CLONE_FS | CLONE_FILES, nt);
122     if (pid == -1) {
123     free(stack);
124     free(nt);
125     return errno;
126     } else {
127     *thread = pid;
128     return 0;
129     }
130     }
131    
132    
133     /*
134     * Join pthread
135     */
136    
137     int pthread_join(pthread_t thread, void **ret)
138     {
139     do {
140     if (waitpid(thread, NULL, 0) >= 0)
141     break;
142     } while (errno == EINTR);
143     if (ret)
144     *ret = NULL;
145     return 0;
146     }
147    
148    
149     /*
150     * Cancel thread
151     */
152    
153     int pthread_cancel(pthread_t thread)
154     {
155     kill(thread, SIGINT);
156     return 0;
157     }
158    
159    
160     /*
161     * Test for cancellation
162     */
163    
164     void pthread_testcancel(void)
165     {
166     }
167    
168    
169     /*
170     * Spinlocks
171     */
172    
173     static void acquire_spinlock(volatile int *lock)
174     {
175     do {
176     while (*lock) ;
177     } while (test_and_set((int *)lock, 1) != 0);
178     }
179    
180     static void release_spinlock(int *lock)
181     {
182     *lock = 0;
183     }
184    
185    
186     /*
187     * Init semaphore
188     */
189    
190     int sem_init(sem_t *sem, int pshared, unsigned int value)
191     {
192     sem->sem_lock.status = 0;
193     sem->sem_lock.spinlock = 0;
194     sem->sem_value = value;
195     sem->sem_waiting = NULL;
196     return 0;
197     }
198    
199    
200     /*
201     * Delete remaphore
202     */
203    
204     int sem_destroy(sem_t *sem)
205     {
206     return 0;
207     }
208    
209    
210     /*
211     * Wait on semaphore
212     */
213    
214     void null_handler(int sig)
215     {
216     }
217    
218     int sem_wait(sem_t *sem)
219     {
220     acquire_spinlock(&sem->sem_lock.spinlock);
221     if (atomic_add((int *)&sem->sem_value, -1) >= 0) {
222     sigset_t mask;
223     if (!sem->sem_lock.status) {
224     struct sigaction sa;
225     sem->sem_lock.status = SIGUSR2;
226     sa.sa_handler = null_handler;
227     sa.sa_flags = SA_RESTART;
228     sigemptyset(&sa.sa_mask);
229     sigaction(sem->sem_lock.status, &sa, NULL);
230     }
231     sem->sem_waiting = (struct _pthread_descr_struct *)getpid();
232     sigemptyset(&mask);
233     sigsuspend(&mask);
234     sem->sem_waiting = NULL;
235     }
236     release_spinlock(&sem->sem_lock.spinlock);
237     return 0;
238     }
239    
240    
241     /*
242     * Post semaphore
243     */
244    
245     int sem_post(sem_t *sem)
246     {
247     acquire_spinlock(&sem->sem_lock.spinlock);
248     atomic_add((int *)&sem->sem_value, 1);
249     if (sem->sem_waiting)
250     kill((pid_t)sem->sem_waiting, sem->sem_lock.status);
251     release_spinlock(&sem->sem_lock.spinlock);
252     return 0;
253     }