blob: 1f2ae9de3b02259fad79d47d205ebc57cc746d47 [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>
Sjoerd Mullendere8934121993-01-13 12:08:48 +000017#include <errno.h>
Guido van Rossum1984f1e1992-08-04 12:41:02 +000018
Guido van Rossumf9f2e821992-08-17 08:59:08 +000019#define MAXPROC 100 /* max # of threads that can be started */
20
Guido van Rossum1984f1e1992-08-04 12:41:02 +000021static usptr_t *shared_arena;
Guido van Rossumf9f2e821992-08-17 08:59:08 +000022static ulock_t count_lock; /* protection for some variables */
23static ulock_t wait_lock; /* lock used to wait for other threads */
24static int waiting_for_threads; /* protected by count_lock */
25static int nthreads; /* protected by count_lock */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000026static int exit_status;
Sjoerd Mullendered59d201993-01-06 13:36:38 +000027static int do_exit; /* indicates that the program is to exit */
Guido van Rossumf9f2e821992-08-17 08:59:08 +000028static int exiting; /* we're already exiting (for maybe_exit) */
29static pid_t my_pid; /* PID of main thread */
30static pid_t pidlist[MAXPROC]; /* PIDs of other threads */
31static int maxpidindex; /* # of PIDs in pidlist */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000032#endif
33#ifdef sun
34#include <lwp/lwp.h>
35#include <lwp/stackdep.h>
36
Guido van Rossumf9f2e821992-08-17 08:59:08 +000037#define STACKSIZE 1000 /* stacksize for a thread */
Guido van Rossum1984f1e1992-08-04 12:41:02 +000038#define NSTACKS 2 /* # stacks to be put in cache initialy */
39
40struct lock {
41 int lock_locked;
42 cv_t lock_condvar;
43 mon_t lock_monitor;
44};
45#endif
46#ifdef C_THREADS
47#include <cthreads.h>
48#endif
49
50#ifdef __STDC__
51#define _P(args) args
52#define _P0() (void)
53#define _P1(v,t) (t)
54#define _P2(v1,t1,v2,t2) (t1,t2)
55#else
56#define _P(args) ()
57#define _P0() ()
58#define _P1(v,t) (v) t;
59#define _P2(v1,t1,v2,t2) (v1,v2) t1; t2;
60#endif
61
62static int initialized;
63
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +000064#ifdef __sgi
65/*
66 * This routine is called as a signal handler when another thread
67 * exits. When that happens, we must see whether we have to exit as
68 * well (because of an exit_prog()) or whether we should continue on.
69 */
70static void exit_sig _P0()
71{
72 dprintf(("exit_sig called\n"));
73 if (exiting && getpid() == my_pid) {
74 dprintf(("already exiting\n"));
75 return;
76 }
77 if (do_exit) {
78 dprintf(("exiting in exit_sig\n"));
79 exit_thread();
80 }
81}
82
83/*
84 * This routine is called when a process calls exit(). If that wasn't
85 * done from the library, we do as if an exit_prog() was intended.
86 */
87static void maybe_exit _P0()
88{
89 dprintf(("maybe_exit called\n"));
90 if (exiting) {
91 dprintf(("already exiting\n"));
92 return;
93 }
94 exit_prog(0);
95}
96#endif
97
98/*
99 * Initialization.
100 */
101void init_thread _P0()
102{
103#ifdef __sgi
104 struct sigaction s;
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000105#ifdef USE_DL
106 long addr, size;
107#endif
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000108#endif
109
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000110#ifdef DEBUG
111 thread_debug = getenv("THREADDEBUG") != 0;
112#endif
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000113 if (initialized)
114 return;
115 initialized = 1;
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000116 dprintf(("init_thread called\n"));
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000117
118#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000119#ifdef USE_DL
120 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
121 perror("usconfig - CONF_INITSIZE (check)");
122 if (usconfig(CONF_INITSIZE, size) < 0)
123 perror("usconfig - CONF_INITSIZE (reset)");
124 addr = (long) dl_getrange(size + sizeof(ushdr_t));
125 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
126 errno = 0;
127 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
128 perror("usconfig - CONF_ATTACHADDR (set)");
129#endif
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000130 if (usconfig(CONF_INITUSERS, 16) < 0)
131 perror("usconfig - CONF_INITUSERS");
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000132 my_pid = getpid(); /* so that we know which is the main thread */
133 atexit(maybe_exit);
134 s.sa_handler = exit_sig;
135 sigemptyset(&s.sa_mask);
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000136 /*sigaddset(&s.sa_mask, SIGUSR1);*/
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000137 s.sa_flags = 0;
138 sigaction(SIGUSR1, &s, 0);
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000139 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
140 perror("prctl - PR_SETEXITSIG");
141 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
142 perror("usconfig - CONF_ARENATYPE");
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000143 /*usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);*/
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000144 if ((shared_arena = usinit(tmpnam(0))) == 0)
145 perror("usinit");
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000146#ifdef USE_DL
147 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
148 perror("usconfig - CONF_ATTACHADDR (reset)");
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000149#endif
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000150 if ((count_lock = usnewlock(shared_arena)) == NULL)
151 perror("usnewlock (count_lock)");
152 (void) usinitlock(count_lock);
153 if ((wait_lock = usnewlock(shared_arena)) == NULL)
154 perror("usnewlock (wait_lock)");
155 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000156#endif
157#ifdef sun
158 lwp_setstkcache(STACKSIZE, NSTACKS);
159#endif
160#ifdef C_THREADS
161 cthread_init();
162#endif
163}
164
165/*
166 * Thread support.
167 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000168int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
169{
170#ifdef sun
171 thread_t tid;
172#endif
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000173#if defined(__sgi) && defined(USE_DL)
174 long addr, size;
175 static int local_initialized = 0;
176#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000177 int success = 0; /* init not needed when SOLARIS and */
178 /* C_THREADS implemented properly */
179
180 dprintf(("start_new_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000181 if (!initialized)
182 init_thread();
183#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000184 switch (ussetlock(count_lock)) {
185 case 0: return 0;
186 case -1: perror("ussetlock (count_lock)");
187 }
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000188 if (maxpidindex >= MAXPROC)
189 success = -1;
190 else {
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000191#ifdef USE_DL
192 if (!local_initialized) {
193 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
194 perror("usconfig - CONF_INITSIZE (check)");
195 if (usconfig(CONF_INITSIZE, size) < 0)
196 perror("usconfig - CONF_INITSIZE (reset)");
197 addr = (long) dl_getrange(size + sizeof(ushdr_t));
198 dprintf(("trying to use addr %lx-%lx for sproc\n", addr, addr+size));
199 errno = 0;
200 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
201 perror("usconfig - CONF_ATTACHADDR (set)");
202 }
203#endif
204 if ((success = sproc(func, PR_SALL, arg)) < 0)
205 perror("sproc");
206#ifdef USE_DL
207 if (!local_initialized) {
208 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
209 perror("usconfig - CONF_ATTACHADDR (reset)");
210 local_initialized = 1;
211 }
212#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000213 if (success >= 0) {
214 nthreads++;
215 pidlist[maxpidindex++] = success;
216 }
217 }
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000218 if (usunsetlock(count_lock) < 0)
219 perror("usunsetlock (count_lock)");
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000220#endif
221#ifdef SOLARIS
222 (void) thread_create(0, 0, func, arg, THREAD_NEW_LWP);
223#endif
224#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000225 success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000226#endif
227#ifdef C_THREADS
228 (void) cthread_fork(func, arg);
229#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000230 return success < 0 ? 0 : 1;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000231}
232
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000233static void do_exit_thread _P1(no_cleanup, int no_cleanup)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000234{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000235 dprintf(("exit_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000236 if (!initialized)
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000237 if (no_cleanup)
238 _exit(0);
239 else
240 exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000241#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000242 if (ussetlock(count_lock) < 0)
243 perror("ussetlock (count_lock)");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000244 nthreads--;
245 if (getpid() == my_pid) {
246 /* main thread; wait for other threads to exit */
247 exiting = 1;
248 if (do_exit) {
249 int i;
250
251 /* notify other threads */
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000252 if (nthreads >= 0) {
253 dprintf(("kill other threads\n"));
254 for (i = 0; i < maxpidindex; i++)
255 (void) kill(pidlist[i], SIGKILL);
256 _exit(exit_status);
257 }
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000258 }
259 waiting_for_threads = 1;
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000260 if (ussetlock(wait_lock) < 0)
261 perror("ussetlock (wait_lock)");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000262 for (;;) {
263 if (nthreads < 0) {
264 dprintf(("really exit (%d)\n", exit_status));
265 if (no_cleanup)
266 _exit(exit_status);
267 else
268 exit(exit_status);
269 }
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000270 if (usunsetlock(count_lock) < 0)
271 perror("usunsetlock (count_lock)");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000272 dprintf(("waiting for other threads (%d)\n", nthreads));
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000273 if (ussetlock(wait_lock) < 0)
274 perror("ussetlock (wait_lock)");
275 if (ussetlock(count_lock) < 0)
276 perror("ussetlock (count_lock)");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000277 }
278 }
279 /* not the main thread */
280 if (waiting_for_threads) {
281 dprintf(("main thread is waiting\n"));
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000282 if (usunsetlock(wait_lock) < 0)
283 perror("usunsetlock (wait_lock)");
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000284 } else if (do_exit)
285 (void) kill(my_pid, SIGUSR1);
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000286 if (usunsetlock(count_lock) < 0)
287 perror("usunsetlock (count_lock)");
Guido van Rossumff4949e1992-08-05 19:58:53 +0000288 _exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000289#endif
290#ifdef SOLARIS
291 thread_exit();
292#endif
293#ifdef sun
294 lwp_destroy(SELF);
295#endif
296#ifdef C_THREADS
297 cthread_exit(0);
298#endif
299}
300
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000301void exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000302{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000303 do_exit_thread(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000304}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000305
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000306void _exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000307{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000308 do_exit_thread(1);
309}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000310
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000311static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
312{
313 dprintf(("exit_prog(%d) called\n", status));
314 if (!initialized)
315 if (no_cleanup)
316 _exit(status);
317 else
318 exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000319#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000320 do_exit = 1;
321 exit_status = status;
322 do_exit_thread(no_cleanup);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000323#endif
324#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000325 pod_exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000326#endif
327}
328
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000329void exit_prog _P1(status, int status)
330{
331 do_exit_prog(status, 0);
332}
333
334void _exit_prog _P1(status, int status)
335{
336 do_exit_prog(status, 1);
337}
338
339/*
340 * Lock support.
341 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000342type_lock allocate_lock _P0()
343{
344#ifdef __sgi
345 ulock_t lock;
346#endif
347#ifdef sun
348 struct lock *lock;
349 extern char *malloc();
350#endif
351
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000352 dprintf(("allocate_lock called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000353 if (!initialized)
354 init_thread();
355
356#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000357 if ((lock = usnewlock(shared_arena)) == NULL)
358 perror("usnewlock");
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000359 (void) usinitlock(lock);
360#endif
361#ifdef sun
362 lock = (struct lock *) malloc(sizeof(struct lock));
363 lock->lock_locked = 0;
364 (void) mon_create(&lock->lock_monitor);
365 (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
366#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000367 dprintf(("allocate_lock() -> %lx\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000368 return (type_lock) lock;
369}
370
371void free_lock _P1(lock, type_lock lock)
372{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000373 dprintf(("free_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000374#ifdef __sgi
375 usfreelock((ulock_t) lock, shared_arena);
376#endif
377#ifdef sun
378 mon_destroy(((struct lock *) lock)->lock_monitor);
379 free((char *) lock);
380#endif
381}
382
383int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
384{
385 int success;
386
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000387 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000388#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000389 errno = 0; /* clear it just in case */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000390 if (waitflag)
391 success = ussetlock((ulock_t) lock);
392 else
393 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000394 if (success < 0)
395 perror(waitflag ? "ussetlock" : "uscsetlock");
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000396#endif
397#ifdef sun
398 success = 0;
399
400 (void) mon_enter(((struct lock *) lock)->lock_monitor);
401 if (waitflag)
402 while (((struct lock *) lock)->lock_locked)
403 cv_wait(((struct lock *) lock)->lock_condvar);
404 if (!((struct lock *) lock)->lock_locked) {
405 success = 1;
406 ((struct lock *) lock)->lock_locked = 1;
407 }
408 cv_broadcast(((struct lock *) lock)->lock_condvar);
409 mon_exit(((struct lock *) lock)->lock_monitor);
410#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000411 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000412 return success;
413}
414
415void release_lock _P1(lock, type_lock lock)
416{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000417 dprintf(("release_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000418#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000419 if (usunsetlock((ulock_t) lock) < 0)
420 perror("usunsetlock");
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000421#endif
422#ifdef sun
423 (void) mon_enter(((struct lock *) lock)->lock_monitor);
424 ((struct lock *) lock)->lock_locked = 0;
425 cv_broadcast(((struct lock *) lock)->lock_condvar);
426 mon_exit(((struct lock *) lock)->lock_monitor);
427#endif
428}
429
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000430/*
431 * Semaphore support.
432 */
433type_sema allocate_sema _P1(value, int value)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000434{
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000435#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000436 usema_t *sema;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000437#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000438
439 dprintf(("allocate_sema called\n"));
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000440 if (!initialized)
441 init_thread();
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000442
443#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000444 if ((sema = usnewsema(shared_arena, value)) == NULL)
445 perror("usnewsema");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000446 dprintf(("allocate_sema() -> %lx\n", (long) sema));
447 return (type_sema) sema;
448#endif
449}
450
451void free_sema _P1(sema, type_sema sema)
452{
453 dprintf(("free_sema(%lx) called\n", (long) sema));
454#ifdef __sgi
455 usfreesema((usema_t *) sema, shared_arena);
456#endif
457}
458
459void down_sema _P1(sema, type_sema sema)
460{
461 dprintf(("down_sema(%lx) called\n", (long) sema));
462#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000463 if (uspsema((usema_t *) sema) < 0)
464 perror("uspsema");
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000465#endif
466 dprintf(("down_sema(%lx) return\n", (long) sema));
467}
468
469void up_sema _P1(sema, type_sema sema)
470{
471 dprintf(("up_sema(%lx)\n", (long) sema));
472#ifdef __sgi
Sjoerd Mullendere8934121993-01-13 12:08:48 +0000473 if (usvsema((usema_t *) sema) < 0)
474 perror("usvsema");
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000475#endif
476}