ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/sheepthreads.c
Revision: 1.1
Committed: 2002-02-04T16:58:13Z (22 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

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