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

# 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 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 }