blob: 76a67af97f9c70b3f25e101973907436b5a0c3f9 [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;
Sjoerd Mullendered59d201993-01-06 13:36:38 +000026static int do_exit; /* indicates that the program is to 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 if (initialized)
110 return;
111 initialized = 1;
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000112 dprintf(("init_thread called\n"));
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000113
114#ifdef __sgi
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000115 if (usconfig(CONF_INITUSERS, 16) < 0)
116 perror("usconfig - CONF_INITUSERS");
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000117 my_pid = getpid(); /* so that we know which is the main thread */
118 atexit(maybe_exit);
119 s.sa_handler = exit_sig;
120 sigemptyset(&s.sa_mask);
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000121 /*sigaddset(&s.sa_mask, SIGUSR1);*/
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000122 s.sa_flags = 0;
123 sigaction(SIGUSR1, &s, 0);
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000124 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
125 perror("prctl - PR_SETEXITSIG");
126 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
127 perror("usconfig - CONF_ARENATYPE");
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000128 /*usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);*/
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000129 if ((shared_arena = usinit(tmpnam(0))) == 0)
130 perror("usinit");
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000131 count_lock = usnewlock(shared_arena);
132 (void) usinitlock(count_lock);
133 wait_lock = usnewlock(shared_arena);
Sjoerd Mullendered59d201993-01-06 13:36:38 +0000134 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
135#ifdef USE_DL /* for python */
136 dl_setrange((long) shared_arena, (long) shared_arena + 64 * 1024);
137#endif
Sjoerd Mullenderaee8bc11992-09-02 11:25:37 +0000138#endif
139#ifdef sun
140 lwp_setstkcache(STACKSIZE, NSTACKS);
141#endif
142#ifdef C_THREADS
143 cthread_init();
144#endif
145}
146
147/*
148 * Thread support.
149 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000150int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
151{
152#ifdef sun
153 thread_t tid;
154#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000155 int success = 0; /* init not needed when SOLARIS and */
156 /* C_THREADS implemented properly */
157
158 dprintf(("start_new_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000159 if (!initialized)
160 init_thread();
161#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000162 if (ussetlock(count_lock) == 0)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000163 return 0;
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000164 if (maxpidindex >= MAXPROC)
165 success = -1;
166 else {
167 success = sproc(func, PR_SALL, arg);
168 if (success >= 0) {
169 nthreads++;
170 pidlist[maxpidindex++] = success;
171 }
172 }
173 (void) usunsetlock(count_lock);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000174#endif
175#ifdef SOLARIS
176 (void) thread_create(0, 0, func, arg, THREAD_NEW_LWP);
177#endif
178#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000179 success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000180#endif
181#ifdef C_THREADS
182 (void) cthread_fork(func, arg);
183#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000184 return success < 0 ? 0 : 1;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000185}
186
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000187static void do_exit_thread _P1(no_cleanup, int no_cleanup)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000188{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000189 dprintf(("exit_thread called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000190 if (!initialized)
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000191 if (no_cleanup)
192 _exit(0);
193 else
194 exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000195#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000196 (void) ussetlock(count_lock);
197 nthreads--;
198 if (getpid() == my_pid) {
199 /* main thread; wait for other threads to exit */
200 exiting = 1;
201 if (do_exit) {
202 int i;
203
204 /* notify other threads */
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000205 if (nthreads >= 0) {
206 dprintf(("kill other threads\n"));
207 for (i = 0; i < maxpidindex; i++)
208 (void) kill(pidlist[i], SIGKILL);
209 _exit(exit_status);
210 }
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000211 }
212 waiting_for_threads = 1;
213 ussetlock(wait_lock);
214 for (;;) {
215 if (nthreads < 0) {
216 dprintf(("really exit (%d)\n", exit_status));
217 if (no_cleanup)
218 _exit(exit_status);
219 else
220 exit(exit_status);
221 }
222 usunsetlock(count_lock);
223 dprintf(("waiting for other threads (%d)\n", nthreads));
224 ussetlock(wait_lock);
225 ussetlock(count_lock);
226 }
227 }
228 /* not the main thread */
229 if (waiting_for_threads) {
230 dprintf(("main thread is waiting\n"));
231 usunsetlock(wait_lock);
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000232 } else if (do_exit)
233 (void) kill(my_pid, SIGUSR1);
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000234 (void) usunsetlock(count_lock);
Guido van Rossumff4949e1992-08-05 19:58:53 +0000235 _exit(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000236#endif
237#ifdef SOLARIS
238 thread_exit();
239#endif
240#ifdef sun
241 lwp_destroy(SELF);
242#endif
243#ifdef C_THREADS
244 cthread_exit(0);
245#endif
246}
247
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000248void exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000249{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000250 do_exit_thread(0);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000251}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000252
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000253void _exit_thread _P0()
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000254{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000255 do_exit_thread(1);
256}
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000257
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000258static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
259{
260 dprintf(("exit_prog(%d) called\n", status));
261 if (!initialized)
262 if (no_cleanup)
263 _exit(status);
264 else
265 exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000266#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000267 do_exit = 1;
268 exit_status = status;
269 do_exit_thread(no_cleanup);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000270#endif
271#ifdef sun
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000272 pod_exit(status);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000273#endif
274}
275
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000276void exit_prog _P1(status, int status)
277{
278 do_exit_prog(status, 0);
279}
280
281void _exit_prog _P1(status, int status)
282{
283 do_exit_prog(status, 1);
284}
285
286/*
287 * Lock support.
288 */
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000289type_lock allocate_lock _P0()
290{
291#ifdef __sgi
292 ulock_t lock;
293#endif
294#ifdef sun
295 struct lock *lock;
296 extern char *malloc();
297#endif
298
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000299 dprintf(("allocate_lock called\n"));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000300 if (!initialized)
301 init_thread();
302
303#ifdef __sgi
304 lock = usnewlock(shared_arena);
305 (void) usinitlock(lock);
306#endif
307#ifdef sun
308 lock = (struct lock *) malloc(sizeof(struct lock));
309 lock->lock_locked = 0;
310 (void) mon_create(&lock->lock_monitor);
311 (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
312#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000313 dprintf(("allocate_lock() -> %lx\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000314 return (type_lock) lock;
315}
316
317void free_lock _P1(lock, type_lock lock)
318{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000319 dprintf(("free_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000320#ifdef __sgi
321 usfreelock((ulock_t) lock, shared_arena);
322#endif
323#ifdef sun
324 mon_destroy(((struct lock *) lock)->lock_monitor);
325 free((char *) lock);
326#endif
327}
328
329int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
330{
331 int success;
332
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000333 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000334#ifdef __sgi
335 if (waitflag)
336 success = ussetlock((ulock_t) lock);
337 else
338 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
339#endif
340#ifdef sun
341 success = 0;
342
343 (void) mon_enter(((struct lock *) lock)->lock_monitor);
344 if (waitflag)
345 while (((struct lock *) lock)->lock_locked)
346 cv_wait(((struct lock *) lock)->lock_condvar);
347 if (!((struct lock *) lock)->lock_locked) {
348 success = 1;
349 ((struct lock *) lock)->lock_locked = 1;
350 }
351 cv_broadcast(((struct lock *) lock)->lock_condvar);
352 mon_exit(((struct lock *) lock)->lock_monitor);
353#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000354 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000355 return success;
356}
357
358void release_lock _P1(lock, type_lock lock)
359{
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000360 dprintf(("release_lock(%lx) called\n", (long)lock));
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000361#ifdef __sgi
362 (void) usunsetlock((ulock_t) lock);
363#endif
364#ifdef sun
365 (void) mon_enter(((struct lock *) lock)->lock_monitor);
366 ((struct lock *) lock)->lock_locked = 0;
367 cv_broadcast(((struct lock *) lock)->lock_condvar);
368 mon_exit(((struct lock *) lock)->lock_monitor);
369#endif
370}
371
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000372/*
373 * Semaphore support.
374 */
375type_sema allocate_sema _P1(value, int value)
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000376{
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000377#ifdef __sgi
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000378 usema_t *sema;
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000379#endif
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000380
381 dprintf(("allocate_sema called\n"));
Sjoerd Mullenderd10d8291992-09-11 15:19:27 +0000382 if (!initialized)
383 init_thread();
Guido van Rossumf9f2e821992-08-17 08:59:08 +0000384
385#ifdef __sgi
386 sema = usnewsema(shared_arena, value);
387 dprintf(("allocate_sema() -> %lx\n", (long) sema));
388 return (type_sema) sema;
389#endif
390}
391
392void free_sema _P1(sema, type_sema sema)
393{
394 dprintf(("free_sema(%lx) called\n", (long) sema));
395#ifdef __sgi
396 usfreesema((usema_t *) sema, shared_arena);
397#endif
398}
399
400void down_sema _P1(sema, type_sema sema)
401{
402 dprintf(("down_sema(%lx) called\n", (long) sema));
403#ifdef __sgi
404 (void) uspsema((usema_t *) sema);
405#endif
406 dprintf(("down_sema(%lx) return\n", (long) sema));
407}
408
409void up_sema _P1(sema, type_sema sema)
410{
411 dprintf(("up_sema(%lx)\n", (long) sema));
412#ifdef __sgi
413 (void) usvsema((usema_t *) sema);
Guido van Rossum1984f1e1992-08-04 12:41:02 +0000414#endif
415}