ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/sheepthreads.c
Revision: 1.3
Committed: 2004-01-04T06:55:50Z (20 years, 10 months ago) by gbeauche
Content type: text/plain
Branch: MAIN
Changes since 1.2: +107 -0 lines
Log Message:
Light implementation of pthread_mutexes

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 gbeauche 1.3 static int try_acquire_spinlock(int *lock)
174     {
175     return test_and_set(lock, 1) == 0;
176     }
177    
178 cebix 1.1 static void acquire_spinlock(volatile int *lock)
179     {
180     do {
181     while (*lock) ;
182     } while (test_and_set((int *)lock, 1) != 0);
183     }
184    
185     static void release_spinlock(int *lock)
186     {
187     *lock = 0;
188 gbeauche 1.3 }
189    
190    
191     /*
192     * Initialize mutex
193     */
194    
195     int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *mutex_attr)
196     {
197     // pthread_init_lock
198     mutex->__m_lock.__status = 0;
199     mutex->__m_lock.__spinlock = 0;
200    
201     mutex->__m_kind = mutex_attr ? mutex_attr->__mutexkind : PTHREAD_MUTEX_TIMED_NP;
202     mutex->__m_count = 0;
203     mutex->__m_owner = NULL;
204     return 0;
205     }
206    
207    
208     /*
209     * Destroy mutex
210     */
211    
212     int pthread_mutex_destroy(pthread_mutex_t *mutex)
213     {
214     switch (mutex->__m_kind) {
215     case PTHREAD_MUTEX_TIMED_NP:
216     return (mutex->__m_lock.__status != 0) ? EBUSY : 0;
217     default:
218     return EINVAL;
219     }
220     }
221    
222    
223     /*
224     * Lock mutex
225     */
226    
227     int pthread_mutex_lock(pthread_mutex_t *mutex)
228     {
229     switch (mutex->__m_kind) {
230     case PTHREAD_MUTEX_TIMED_NP:
231     acquire_spinlock(&mutex->__m_lock.__spinlock);
232     return 0;
233     default:
234     return EINVAL;
235     }
236     }
237    
238    
239     /*
240     * Try to lock mutex
241     */
242    
243     int pthread_mutex_trylock(pthread_mutex_t *mutex)
244     {
245     switch (mutex->__m_kind) {
246     case PTHREAD_MUTEX_TIMED_NP:
247     if (!try_acquire_spinlock(&mutex->__m_lock.__spinlock))
248     return EBUSY;
249     return 0;
250     default:
251     return EINVAL;
252     }
253     }
254    
255    
256     /*
257     * Unlock mutex
258     */
259    
260     int pthread_mutex_unlock(pthread_mutex_t *mutex)
261     {
262     switch (mutex->__m_kind) {
263     case PTHREAD_MUTEX_TIMED_NP:
264     release_spinlock(&mutex->__m_lock.__spinlock);
265     return 0;
266     default:
267     return EINVAL;
268     }
269     }
270    
271    
272     /*
273     * Create mutex attribute
274     */
275    
276     int pthread_mutexattr_init(pthread_mutexattr_t *attr)
277     {
278     attr->__mutexkind = PTHREAD_MUTEX_TIMED_NP;
279     return 0;
280     }
281    
282    
283     /*
284     * Destroy mutex attribute
285     */
286    
287     int pthread_mutexattr_destroy(pthread_mutexattr_t *attr)
288     {
289     return 0;
290 cebix 1.1 }
291    
292    
293     /*
294     * Init semaphore
295     */
296    
297     int sem_init(sem_t *sem, int pshared, unsigned int value)
298     {
299     sem->sem_lock.status = 0;
300     sem->sem_lock.spinlock = 0;
301     sem->sem_value = value;
302     sem->sem_waiting = NULL;
303     return 0;
304     }
305    
306    
307     /*
308     * Delete remaphore
309     */
310    
311     int sem_destroy(sem_t *sem)
312     {
313     return 0;
314     }
315    
316    
317     /*
318     * Wait on semaphore
319     */
320    
321     void null_handler(int sig)
322     {
323     }
324    
325     int sem_wait(sem_t *sem)
326     {
327     acquire_spinlock(&sem->sem_lock.spinlock);
328     if (atomic_add((int *)&sem->sem_value, -1) >= 0) {
329     sigset_t mask;
330     if (!sem->sem_lock.status) {
331     struct sigaction sa;
332     sem->sem_lock.status = SIGUSR2;
333     sa.sa_handler = null_handler;
334     sa.sa_flags = SA_RESTART;
335     sigemptyset(&sa.sa_mask);
336     sigaction(sem->sem_lock.status, &sa, NULL);
337     }
338     sem->sem_waiting = (struct _pthread_descr_struct *)getpid();
339     sigemptyset(&mask);
340     sigsuspend(&mask);
341     sem->sem_waiting = NULL;
342     }
343     release_spinlock(&sem->sem_lock.spinlock);
344     return 0;
345     }
346    
347    
348     /*
349     * Post semaphore
350     */
351    
352     int sem_post(sem_t *sem)
353     {
354     acquire_spinlock(&sem->sem_lock.spinlock);
355     atomic_add((int *)&sem->sem_value, 1);
356     if (sem->sem_waiting)
357     kill((pid_t)sem->sem_waiting, sem->sem_lock.status);
358     release_spinlock(&sem->sem_lock.spinlock);
359     return 0;
360     }