blob: bdf34673397a269c04298dafad2c487d32c689fb [file] [log] [blame]
Guido van Rossum1984f1e1992-08-04 12:41:02 +00001#include "thread.h"
2
Guido van Rossumf9f2e821992-08-17 08:59:08 +00003#ifdef DEBUG
4#define dprintf(args) printf args
5#else
6#define dprintf(args)
7#endif
8
Guido van Rossum1984f1e1992-08-04 12:41:02 +00009#ifdef __sgi
10#include <stdlib.h>
11#include <stdio.h>
12#include <signal.h>
13#include <sys/types.h>
14#include <sys/prctl.h>
15#include <ulocks.h>
16
Guido van Rossumf9f2e821992-08-17 08:59:08 +000017#define MAXPROC 100 /* max # of threads that can be started */
18
Guido van Rossum1984f1e1992-08-04 12:41:02 +000019static usptr_t *shared_arena;
Guido van Rossumf9f2e821992-08-17 08:59:08 +000020static ulock_t count_lock; /* protection for some variables */
21static ulock_t wait_lock; /* lock used to wait for other threads */
22static int waiting_for_threads; /* protected by count_lock */
23static int nthreads; /* protected by count_lock */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000024static int exit_status;
25static int do_exit;
Guido van Rossumf9f2e821992-08-17 08:59:08 +000026static int exiting; /* we're already exiting (for maybe_exit) */
27static pid_t my_pid; /* PID of main thread */
28static pid_t pidlist[MAXPROC]; /* PIDs of other threads */
29static int maxpidindex; /* # of PIDs in pidlist */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000030#endif
31#ifdef sun
32#include <lwp/lwp.h>
33#include <lwp/stackdep.h>
34
Guido van Rossumf9f2e821992-08-17 08:59:08 +000035#define STACKSIZE 1000 /* stacksize for a thread */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000036#define NSTACKS 2 /* # stacks to be put in cache initialy */
37
38struct lock {
39 int lock_locked;
40 cv_t lock_condvar;
41 mon_t lock_monitor;
42};
43#endif
44#ifdef C_THREADS
45#include <cthreads.h>
46#endif
47
48#ifdef __STDC__
49#define _P(args) args
50#define _P0() (void)
51#define _P1(v,t) (t)
52#define _P2(v1,t1,v2,t2) (t1,t2)
53#else
54#define _P(args) ()
55#define _P0() ()
56#define _P1(v,t) (v) t;
57#define _P2(v1,t1,v2,t2) (v1,v2) t1; t2;
58#endif
59
60static int initialized;
61
Guido van Rossumf9f2e821992-08-17 08:59:08 +000062#ifdef __sgi
63/*
64 * This routine is called as a signal handler when another thread
65 * exits. When that happens, we must see whether we have to exit as
66 * well (because of an exit_prog()) or whether we should continue on.
67 */
68static void exit_sig _P0()
69{
70 dprintf(("exit_sig called\n"));
71 if (exiting && getpid() == my_pid) {
72 dprintf(("already exiting\n"));
73 return;
74 }
75 if (do_exit) {
76 dprintf(("exiting in exit_sig\n"));
77 exit_thread();
78 }
79}
80
81/*
82 * This routune is called when a process calls exit(). If that wasn't
83 * done from the library, we do as if an exit_prog() was intended.
84 */
85static void maybe_exit _P0()
86{
87 dprintf(("maybe_exit called\n"));
88 if (exiting) {
89 dprintf(("already exiting\n"));
90 return;
91 }
92 exit_prog(0);
93}
94#endif
95
96/*
97 * Initialization.
98 */
99void init_thread _P0()
100{
101#ifdef __sgi
102 struct sigaction s;
103#endif
104
105 dprintf(("init_thread called\n"));
106 if (initialized)
107 return;
108 initialized = 1;
109
110#ifdef __sgi
111 my_pid = getpid(); /* so that we know which is the main thread */
112 atexit(maybe_exit);
113 s.sa_handler = exit_sig;
114 sigemptyset(&s.sa_mask);
115 sigaddset(&s.sa_mask, SIGUSR1);
116 s.sa_flags = 0;
117 sigaction(SIGUSR1, &s, 0);
118 prctl(PR_SETEXITSIG, SIGUSR1);
119 usconfig(CONF_ARENATYPE, US_SHAREDONLY);
120 /*usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);*/
121 shared_arena = usinit(tmpnam(0));
122 count_lock = usnewlock(shared_arena);
123 (void) usinitlock(count_lock);
124 wait_lock = usnewlock(shared_arena);
125#endif
126#ifdef sun
127 lwp_setstkcache(STACKSIZE, NSTACKS);
128#endif
129#ifdef C_THREADS
130 cthread_init();
131#endif
132}
133
134/*
135 * Thread support.
136 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000137int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
138{
139#ifdef sun
140 thread_t tid;
141#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000142 int success = 0; /* init not needed when SOLARIS and */
143 /* C_THREADS implemented properly */
144
145 dprintf(("start_new_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000146 if (!initialized)
147 init_thread();
148#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000149 if (ussetlock(count_lock) == 0)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000150 return 0;
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000151 if (maxpidindex >= MAXPROC)
152 success = -1;
153 else {
154 success = sproc(func, PR_SALL, arg);
155 if (success >= 0) {
156 nthreads++;
157 pidlist[maxpidindex++] = success;
158 }
159 }
160 (void) usunsetlock(count_lock);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000161#endif
162#ifdef SOLARIS
163 (void) thread_create(0, 0, func, arg, THREAD_NEW_LWP);
164#endif
165#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000166 success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000167#endif
168#ifdef C_THREADS
169 (void) cthread_fork(func, arg);
170#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000171 return success < 0 ? 0 : 1;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000172}
173
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000174static void do_exit_thread _P1(no_cleanup, int no_cleanup)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000175{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000176 dprintf(("exit_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000177 if (!initialized)
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000178 if (no_cleanup)
179 _exit(0);
180 else
181 exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000182#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000183 (void) ussetlock(count_lock);
184 nthreads--;
185 if (getpid() == my_pid) {
186 /* main thread; wait for other threads to exit */
187 exiting = 1;
188 if (do_exit) {
189 int i;
190
191 /* notify other threads */
192 for (i = 0; i < maxpidindex; i++)
193 (void) kill(pidlist[i], SIGUSR1);
194 }
195 waiting_for_threads = 1;
196 ussetlock(wait_lock);
197 for (;;) {
198 if (nthreads < 0) {
199 dprintf(("really exit (%d)\n", exit_status));
200 if (no_cleanup)
201 _exit(exit_status);
202 else
203 exit(exit_status);
204 }
205 usunsetlock(count_lock);
206 dprintf(("waiting for other threads (%d)\n", nthreads));
207 ussetlock(wait_lock);
208 ussetlock(count_lock);
209 }
210 }
211 /* not the main thread */
212 if (waiting_for_threads) {
213 dprintf(("main thread is waiting\n"));
214 usunsetlock(wait_lock);
215 }
216 (void) usunsetlock(count_lock);
Guido van Rossumff4949e1992-08-05 19:58:53 +0000217 _exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000218#endif
219#ifdef SOLARIS
220 thread_exit();
221#endif
222#ifdef sun
223 lwp_destroy(SELF);
224#endif
225#ifdef C_THREADS
226 cthread_exit(0);
227#endif
228}
229
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000230void exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000231{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000232 do_exit_thread(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000233}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000234
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000235void _exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000236{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000237 do_exit_thread(1);
238}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000239
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000240static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
241{
242 dprintf(("exit_prog(%d) called\n", status));
243 if (!initialized)
244 if (no_cleanup)
245 _exit(status);
246 else
247 exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000248#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000249 do_exit = 1;
250 exit_status = status;
251 do_exit_thread(no_cleanup);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000252#endif
253#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000254 pod_exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000255#endif
256}
257
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000258void exit_prog _P1(status, int status)
259{
260 do_exit_prog(status, 0);
261}
262
263void _exit_prog _P1(status, int status)
264{
265 do_exit_prog(status, 1);
266}
267
268/*
269 * Lock support.
270 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000271type_lock allocate_lock _P0()
272{
273#ifdef __sgi
274 ulock_t lock;
275#endif
276#ifdef sun
277 struct lock *lock;
278 extern char *malloc();
279#endif
280
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000281 dprintf(("allocate_lock called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000282 if (!initialized)
283 init_thread();
284
285#ifdef __sgi
286 lock = usnewlock(shared_arena);
287 (void) usinitlock(lock);
288#endif
289#ifdef sun
290 lock = (struct lock *) malloc(sizeof(struct lock));
291 lock->lock_locked = 0;
292 (void) mon_create(&lock->lock_monitor);
293 (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
294#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000295 dprintf(("allocate_lock() -> %lx\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000296 return (type_lock) lock;
297}
298
299void free_lock _P1(lock, type_lock lock)
300{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000301 dprintf(("free_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000302#ifdef __sgi
303 usfreelock((ulock_t) lock, shared_arena);
304#endif
305#ifdef sun
306 mon_destroy(((struct lock *) lock)->lock_monitor);
307 free((char *) lock);
308#endif
309}
310
311int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
312{
313 int success;
314
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000315 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000316#ifdef __sgi
317 if (waitflag)
318 success = ussetlock((ulock_t) lock);
319 else
320 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
321#endif
322#ifdef sun
323 success = 0;
324
325 (void) mon_enter(((struct lock *) lock)->lock_monitor);
326 if (waitflag)
327 while (((struct lock *) lock)->lock_locked)
328 cv_wait(((struct lock *) lock)->lock_condvar);
329 if (!((struct lock *) lock)->lock_locked) {
330 success = 1;
331 ((struct lock *) lock)->lock_locked = 1;
332 }
333 cv_broadcast(((struct lock *) lock)->lock_condvar);
334 mon_exit(((struct lock *) lock)->lock_monitor);
335#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000336 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000337 return success;
338}
339
340void release_lock _P1(lock, type_lock lock)
341{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000342 dprintf(("release_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000343#ifdef __sgi
344 (void) usunsetlock((ulock_t) lock);
345#endif
346#ifdef sun
347 (void) mon_enter(((struct lock *) lock)->lock_monitor);
348 ((struct lock *) lock)->lock_locked = 0;
349 cv_broadcast(((struct lock *) lock)->lock_condvar);
350 mon_exit(((struct lock *) lock)->lock_monitor);
351#endif
352}
353
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000354/*
355 * Semaphore support.
356 */
357type_sema allocate_sema _P1(value, int value)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000358{
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000359#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000360 usema_t *sema;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000361#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000362
363 dprintf(("allocate_sema called\n"));
364
365#ifdef __sgi
366 sema = usnewsema(shared_arena, value);
367 dprintf(("allocate_sema() -> %lx\n", (long) sema));
368 return (type_sema) sema;
369#endif
370}
371
372void free_sema _P1(sema, type_sema sema)
373{
374 dprintf(("free_sema(%lx) called\n", (long) sema));
375#ifdef __sgi
376 usfreesema((usema_t *) sema, shared_arena);
377#endif
378}
379
380void down_sema _P1(sema, type_sema sema)
381{
382 dprintf(("down_sema(%lx) called\n", (long) sema));
383#ifdef __sgi
384 (void) uspsema((usema_t *) sema);
385#endif
386 dprintf(("down_sema(%lx) return\n", (long) sema));
387}
388
389void up_sema _P1(sema, type_sema sema)
390{
391 dprintf(("up_sema(%lx)\n", (long) sema));
392#ifdef __sgi
393 (void) usvsema((usema_t *) sema);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000394#endif
395}