ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/SheepShaver/src/Unix/Linux/sheepthreads.c
Revision: 1.1.1.1 (vendor branch)
Committed: 2002-02-04T16:58:13Z (22 years, 5 months ago) by cebix
Content type: text/plain
Branch: cebix
CVS Tags: start
Changes since 1.1: +0 -0 lines
Log Message:
Imported sources

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