blob: 149190fcf1dc510857c387923cecbf87025c313b [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
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +00004static int thread_debug = 0;
5#define dprintf(args) (thread_debug && printf args)
Guido van Rossumf9f2e821992-08-17 08:59:08 +00006#else
7#define dprintf(args)
8#endif
9
Guido van Rossum1984f1e1992-08-04 12:41:02 +000010#ifdef __sgi
11#include <stdlib.h>
12#include <stdio.h>
13#include <signal.h>
14#include <sys/types.h>
15#include <sys/prctl.h>
16#include <ulocks.h>
17
Guido van Rossumf9f2e821992-08-17 08:59:08 +000018#define MAXPROC 100 /* max # of threads that can be started */
19
Guido van Rossum1984f1e1992-08-04 12:41:02 +000020static usptr_t *shared_arena;
Guido van Rossumf9f2e821992-08-17 08:59:08 +000021static ulock_t count_lock; /* protection for some variables */
22static ulock_t wait_lock; /* lock used to wait for other threads */
23static int waiting_for_threads; /* protected by count_lock */
24static int nthreads; /* protected by count_lock */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000025static int exit_status;
26static int do_exit;
Guido van Rossumf9f2e821992-08-17 08:59:08 +000027static int exiting; /* we're already exiting (for maybe_exit) */
28static pid_t my_pid; /* PID of main thread */
29static pid_t pidlist[MAXPROC]; /* PIDs of other threads */
30static int maxpidindex; /* # of PIDs in pidlist */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000031#endif
32#ifdef sun
33#include <lwp/lwp.h>
34#include <lwp/stackdep.h>
35
Guido van Rossumf9f2e821992-08-17 08:59:08 +000036#define STACKSIZE 1000 /* stacksize for a thread */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000037#define NSTACKS 2 /* # stacks to be put in cache initialy */
38
39struct lock {
40 int lock_locked;
41 cv_t lock_condvar;
42 mon_t lock_monitor;
43};
44#endif
45#ifdef C_THREADS
46#include <cthreads.h>
47#endif
48
49#ifdef __STDC__
50#define _P(args) args
51#define _P0() (void)
52#define _P1(v,t) (t)
53#define _P2(v1,t1,v2,t2) (t1,t2)
54#else
55#define _P(args) ()
56#define _P0() ()
57#define _P1(v,t) (v) t;
58#define _P2(v1,t1,v2,t2) (v1,v2) t1; t2;
59#endif
60
61static int initialized;
62
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +000063#ifdef __sgi
64/*
65 * This routine is called as a signal handler when another thread
66 * exits. When that happens, we must see whether we have to exit as
67 * well (because of an exit_prog()) or whether we should continue on.
68 */
69static void exit_sig _P0()
70{
71 dprintf(("exit_sig called\n"));
72 if (exiting && getpid() == my_pid) {
73 dprintf(("already exiting\n"));
74 return;
75 }
76 if (do_exit) {
77 dprintf(("exiting in exit_sig\n"));
78 exit_thread();
79 }
80}
81
82/*
83 * This routine is called when a process calls exit(). If that wasn't
84 * done from the library, we do as if an exit_prog() was intended.
85 */
86static void maybe_exit _P0()
87{
88 dprintf(("maybe_exit called\n"));
89 if (exiting) {
90 dprintf(("already exiting\n"));
91 return;
92 }
93 exit_prog(0);
94}
95#endif
96
97/*
98 * Initialization.
99 */
100void init_thread _P0()
101{
102#ifdef __sgi
103 struct sigaction s;
104#endif
105
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000106#ifdef DEBUG
107 thread_debug = getenv("THREADDEBUG") != 0;
108#endif
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000109 dprintf(("init_thread called\n"));
110 if (initialized)
111 return;
112 initialized = 1;
113
114#ifdef __sgi
115 my_pid = getpid(); /* so that we know which is the main thread */
116 atexit(maybe_exit);
117 s.sa_handler = exit_sig;
118 sigemptyset(&s.sa_mask);
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000119 /*sigaddset(&s.sa_mask, SIGUSR1);*/
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000120 s.sa_flags = 0;
121 sigaction(SIGUSR1, &s, 0);
122 prctl(PR_SETEXITSIG, SIGUSR1);
123 usconfig(CONF_ARENATYPE, US_SHAREDONLY);
124 /*usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);*/
125 shared_arena = usinit(tmpnam(0));
126 count_lock = usnewlock(shared_arena);
127 (void) usinitlock(count_lock);
128 wait_lock = usnewlock(shared_arena);
129#endif
130#ifdef sun
131 lwp_setstkcache(STACKSIZE, NSTACKS);
132#endif
133#ifdef C_THREADS
134 cthread_init();
135#endif
136}
137
138/*
139 * Thread support.
140 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000141int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
142{
143#ifdef sun
144 thread_t tid;
145#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000146 int success = 0; /* init not needed when SOLARIS and */
147 /* C_THREADS implemented properly */
148
149 dprintf(("start_new_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000150 if (!initialized)
151 init_thread();
152#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000153 if (ussetlock(count_lock) == 0)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000154 return 0;
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000155 if (maxpidindex >= MAXPROC)
156 success = -1;
157 else {
158 success = sproc(func, PR_SALL, arg);
159 if (success >= 0) {
160 nthreads++;
161 pidlist[maxpidindex++] = success;
162 }
163 }
164 (void) usunsetlock(count_lock);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000165#endif
166#ifdef SOLARIS
167 (void) thread_create(0, 0, func, arg, THREAD_NEW_LWP);
168#endif
169#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000170 success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000171#endif
172#ifdef C_THREADS
173 (void) cthread_fork(func, arg);
174#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000175 return success < 0 ? 0 : 1;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000176}
177
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000178static void do_exit_thread _P1(no_cleanup, int no_cleanup)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000179{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000180 dprintf(("exit_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000181 if (!initialized)
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000182 if (no_cleanup)
183 _exit(0);
184 else
185 exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000186#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000187 (void) ussetlock(count_lock);
188 nthreads--;
189 if (getpid() == my_pid) {
190 /* main thread; wait for other threads to exit */
191 exiting = 1;
192 if (do_exit) {
193 int i;
194
195 /* notify other threads */
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000196 if (nthreads >= 0) {
197 dprintf(("kill other threads\n"));
198 for (i = 0; i < maxpidindex; i++)
199 (void) kill(pidlist[i], SIGKILL);
200 _exit(exit_status);
201 }
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000202 }
203 waiting_for_threads = 1;
204 ussetlock(wait_lock);
205 for (;;) {
206 if (nthreads < 0) {
207 dprintf(("really exit (%d)\n", exit_status));
208 if (no_cleanup)
209 _exit(exit_status);
210 else
211 exit(exit_status);
212 }
213 usunsetlock(count_lock);
214 dprintf(("waiting for other threads (%d)\n", nthreads));
215 ussetlock(wait_lock);
216 ussetlock(count_lock);
217 }
218 }
219 /* not the main thread */
220 if (waiting_for_threads) {
221 dprintf(("main thread is waiting\n"));
222 usunsetlock(wait_lock);
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000223 } else if (do_exit)
224 (void) kill(my_pid, SIGUSR1);
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000225 (void) usunsetlock(count_lock);
Guido van Rossumff4949e1992-08-05 19:58:53 +0000226 _exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000227#endif
228#ifdef SOLARIS
229 thread_exit();
230#endif
231#ifdef sun
232 lwp_destroy(SELF);
233#endif
234#ifdef C_THREADS
235 cthread_exit(0);
236#endif
237}
238
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000239void exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000240{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000241 do_exit_thread(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000242}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000243
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000244void _exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000245{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000246 do_exit_thread(1);
247}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000248
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000249static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
250{
251 dprintf(("exit_prog(%d) called\n", status));
252 if (!initialized)
253 if (no_cleanup)
254 _exit(status);
255 else
256 exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000257#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000258 do_exit = 1;
259 exit_status = status;
260 do_exit_thread(no_cleanup);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000261#endif
262#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000263 pod_exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000264#endif
265}
266
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000267void exit_prog _P1(status, int status)
268{
269 do_exit_prog(status, 0);
270}
271
272void _exit_prog _P1(status, int status)
273{
274 do_exit_prog(status, 1);
275}
276
277/*
278 * Lock support.
279 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000280type_lock allocate_lock _P0()
281{
282#ifdef __sgi
283 ulock_t lock;
284#endif
285#ifdef sun
286 struct lock *lock;
287 extern char *malloc();
288#endif
289
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000290 dprintf(("allocate_lock called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000291 if (!initialized)
292 init_thread();
293
294#ifdef __sgi
295 lock = usnewlock(shared_arena);
296 (void) usinitlock(lock);
297#endif
298#ifdef sun
299 lock = (struct lock *) malloc(sizeof(struct lock));
300 lock->lock_locked = 0;
301 (void) mon_create(&lock->lock_monitor);
302 (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
303#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000304 dprintf(("allocate_lock() -> %lx\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000305 return (type_lock) lock;
306}
307
308void free_lock _P1(lock, type_lock lock)
309{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000310 dprintf(("free_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000311#ifdef __sgi
312 usfreelock((ulock_t) lock, shared_arena);
313#endif
314#ifdef sun
315 mon_destroy(((struct lock *) lock)->lock_monitor);
316 free((char *) lock);
317#endif
318}
319
320int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
321{
322 int success;
323
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000324 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000325#ifdef __sgi
326 if (waitflag)
327 success = ussetlock((ulock_t) lock);
328 else
329 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
330#endif
331#ifdef sun
332 success = 0;
333
334 (void) mon_enter(((struct lock *) lock)->lock_monitor);
335 if (waitflag)
336 while (((struct lock *) lock)->lock_locked)
337 cv_wait(((struct lock *) lock)->lock_condvar);
338 if (!((struct lock *) lock)->lock_locked) {
339 success = 1;
340 ((struct lock *) lock)->lock_locked = 1;
341 }
342 cv_broadcast(((struct lock *) lock)->lock_condvar);
343 mon_exit(((struct lock *) lock)->lock_monitor);
344#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000345 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000346 return success;
347}
348
349void release_lock _P1(lock, type_lock lock)
350{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000351 dprintf(("release_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000352#ifdef __sgi
353 (void) usunsetlock((ulock_t) lock);
354#endif
355#ifdef sun
356 (void) mon_enter(((struct lock *) lock)->lock_monitor);
357 ((struct lock *) lock)->lock_locked = 0;
358 cv_broadcast(((struct lock *) lock)->lock_condvar);
359 mon_exit(((struct lock *) lock)->lock_monitor);
360#endif
361}
362
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000363/*
364 * Semaphore support.
365 */
366type_sema allocate_sema _P1(value, int value)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000367{
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000368#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000369 usema_t *sema;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000370#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000371
372 dprintf(("allocate_sema called\n"));
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000373 if (!initialized)
374 init_thread();
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000375
376#ifdef __sgi
377 sema = usnewsema(shared_arena, value);
378 dprintf(("allocate_sema() -> %lx\n", (long) sema));
379 return (type_sema) sema;
380#endif
381}
382
383void free_sema _P1(sema, type_sema sema)
384{
385 dprintf(("free_sema(%lx) called\n", (long) sema));
386#ifdef __sgi
387 usfreesema((usema_t *) sema, shared_arena);
388#endif
389}
390
391void down_sema _P1(sema, type_sema sema)
392{
393 dprintf(("down_sema(%lx) called\n", (long) sema));
394#ifdef __sgi
395 (void) uspsema((usema_t *) sema);
396#endif
397 dprintf(("down_sema(%lx) return\n", (long) sema));
398}
399
400void up_sema _P1(sema, type_sema sema)
401{
402 dprintf(("up_sema(%lx)\n", (long) sema));
403#ifdef __sgi
404 (void) usvsema((usema_t *) sema);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000405#endif
406}