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

# Content
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 status __status
55 #define spinlock __spinlock
56 #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 int try_acquire_spinlock(int *lock)
174 {
175 return test_and_set(lock, 1) == 0;
176 }
177
178 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 }
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 }
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 }