blob: a53c8dc65db488aa81bc0497a44b32218634ff99 [file] [log] [blame]
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00001/***********************************************************
Guido van Rossum6d023c91995-01-04 19:12:13 +00002Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3The Netherlands.
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00004
5 All Rights Reserved
6
Guido van Rossumd266eb41996-10-25 14:44:06 +00007Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00009provided that the above copyright notice appear in all copies and that
Guido van Rossumd266eb41996-10-25 14:44:06 +000010both that copyright notice and this permission notice appear in
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000011supporting documentation, and that the names of Stichting Mathematisch
Guido van Rossumd266eb41996-10-25 14:44:06 +000012Centrum or CWI or Corporation for National Research Initiatives or
13CNRI not be used in advertising or publicity pertaining to
14distribution of the software without specific, written prior
15permission.
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000016
Guido van Rossumd266eb41996-10-25 14:44:06 +000017While CWI is the initial source for this software, a modified version
18is made available by the Corporation for National Research Initiatives
19(CNRI) at the Internet address ftp://ftp.python.org.
20
21STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28PERFORMANCE OF THIS SOFTWARE.
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000029
30******************************************************************/
31
32#ifdef WITH_SGI_DL
33#define USE_DL
34#endif
35
36#include <stdlib.h>
37#include <stdio.h>
38#include <signal.h>
39#include <sys/types.h>
40#include <sys/wait.h>
41#include <sys/prctl.h>
42#include <ulocks.h>
43#include <errno.h>
44
45#define HDR_SIZE 2680 /* sizeof(ushdr_t) */
46#define MAXPROC 100 /* max # of threads that can be started */
47
48static usptr_t *shared_arena;
49static ulock_t count_lock; /* protection for some variables */
50static ulock_t wait_lock; /* lock used to wait for other threads */
51static int waiting_for_threads; /* protected by count_lock */
52static int nthreads; /* protected by count_lock */
53static int exit_status;
54#ifndef NO_EXIT_PROG
55static int do_exit; /* indicates that the program is to exit */
56#endif
57static int exiting; /* we're already exiting (for maybe_exit) */
58static pid_t my_pid; /* PID of main thread */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +000059static struct pidlist {
60 pid_t parent;
61 pid_t child;
62} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000063static int maxpidindex; /* # of PIDs in pidlist */
64
65#ifndef NO_EXIT_PROG
66/*
67 * This routine is called as a signal handler when another thread
68 * exits. When that happens, we must see whether we have to exit as
69 * well (because of an exit_prog()) or whether we should continue on.
70 */
71static void exit_sig _P0()
72{
73 d2printf(("exit_sig called\n"));
74 if (exiting && getpid() == my_pid) {
75 d2printf(("already exiting\n"));
76 return;
77 }
78 if (do_exit) {
79 d2printf(("exiting in exit_sig\n"));
Guido van Rossum408027e1996-12-30 16:17:54 +000080#ifdef Py_DEBUG
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000081 if ((thread_debug & 8) == 0)
82 thread_debug &= ~1; /* don't produce debug messages */
83#endif
84 exit_thread();
85 }
86}
87
88/*
89 * This routine is called when a process calls exit(). If that wasn't
90 * done from the library, we do as if an exit_prog() was intended.
91 */
92static void maybe_exit _P0()
93{
94 dprintf(("maybe_exit called\n"));
95 if (exiting) {
96 dprintf(("already exiting\n"));
97 return;
98 }
99 exit_prog(0);
100}
101#endif /* NO_EXIT_PROG */
102
103/*
104 * Initialization.
105 */
106static void _init_thread _P0()
107{
108#ifndef NO_EXIT_PROG
109 struct sigaction s;
110#endif /* NO_EXIT_PROG */
111#ifdef USE_DL
112 long addr, size;
113#endif /* USE_DL */
114
115
116#ifdef USE_DL
117 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
118 perror("usconfig - CONF_INITSIZE (check)");
119 if (usconfig(CONF_INITSIZE, size) < 0)
120 perror("usconfig - CONF_INITSIZE (reset)");
121 addr = (long) dl_getrange(size + HDR_SIZE);
122 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
123 errno = 0;
124 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
125 perror("usconfig - CONF_ATTACHADDR (set)");
126#endif /* USE_DL */
127 if (usconfig(CONF_INITUSERS, 16) < 0)
128 perror("usconfig - CONF_INITUSERS");
129 my_pid = getpid(); /* so that we know which is the main thread */
130#ifndef NO_EXIT_PROG
131 atexit(maybe_exit);
132 s.sa_handler = exit_sig;
133 sigemptyset(&s.sa_mask);
134 /*sigaddset(&s.sa_mask, SIGUSR1);*/
135 s.sa_flags = 0;
136 sigaction(SIGUSR1, &s, 0);
137 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
138 perror("prctl - PR_SETEXITSIG");
139#endif /* NO_EXIT_PROG */
140 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
141 perror("usconfig - CONF_ARENATYPE");
142 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
Guido van Rossum408027e1996-12-30 16:17:54 +0000143#ifdef Py_DEBUG
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000144 if (thread_debug & 4)
145 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
146 else if (thread_debug & 2)
147 usconfig(CONF_LOCKTYPE, US_DEBUG);
Guido van Rossum408027e1996-12-30 16:17:54 +0000148#endif /* Py_DEBUG */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000149 if ((shared_arena = usinit(tmpnam(0))) == 0)
150 perror("usinit");
151#ifdef USE_DL
152 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
153 perror("usconfig - CONF_ATTACHADDR (reset)");
154#endif /* USE_DL */
155 if ((count_lock = usnewlock(shared_arena)) == NULL)
156 perror("usnewlock (count_lock)");
157 (void) usinitlock(count_lock);
158 if ((wait_lock = usnewlock(shared_arena)) == NULL)
159 perror("usnewlock (wait_lock)");
160 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
161}
162
163/*
164 * Thread support.
165 */
166
167static void clean_threads _P0()
168{
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000169 int i, j;
170 pid_t mypid, pid;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000171
172 /* clean up any exited threads */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000173 mypid = getpid();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000174 i = 0;
175 while (i < maxpidindex) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000176 if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000177 pid = waitpid(pid, 0, WNOHANG);
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000178 if (pid > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000179 /* a thread has exited */
180 pidlist[i] = pidlist[--maxpidindex];
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000181 /* remove references to children of dead proc */
182 for (j = 0; j < maxpidindex; j++)
183 if (pidlist[j].parent == pid)
184 pidlist[j].child = -1;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000185 continue; /* don't increment i */
186 }
187 }
188 i++;
189 }
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000190 /* clean up the list */
191 i = 0;
192 while (i < maxpidindex) {
193 if (pidlist[i].child == -1) {
194 pidlist[i] = pidlist[--maxpidindex];
195 continue; /* don't increment i */
196 }
197 i++;
198 }
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000199}
200
201int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
202{
203#ifdef USE_DL
204 long addr, size;
205 static int local_initialized = 0;
206#endif /* USE_DL */
207 int success = 0; /* init not needed when SOLARIS_THREADS and */
208 /* C_THREADS implemented properly */
209
210 dprintf(("start_new_thread called\n"));
211 if (!initialized)
212 init_thread();
213 switch (ussetlock(count_lock)) {
214 case 0: return 0;
215 case -1: perror("ussetlock (count_lock)");
216 }
217 if (maxpidindex >= MAXPROC)
218 success = -1;
219 else {
220#ifdef USE_DL
221 if (!local_initialized) {
222 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
223 perror("usconfig - CONF_INITSIZE (check)");
224 if (usconfig(CONF_INITSIZE, size) < 0)
225 perror("usconfig - CONF_INITSIZE (reset)");
226 addr = (long) dl_getrange(size + HDR_SIZE);
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000227 dprintf(("trying to use addr %lx-%lx for sproc\n",
228 addr, addr+size));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000229 errno = 0;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000230 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
231 errno != 0)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000232 perror("usconfig - CONF_ATTACHADDR (set)");
233 }
234#endif /* USE_DL */
235 clean_threads();
236 if ((success = sproc(func, PR_SALL, arg)) < 0)
237 perror("sproc");
238#ifdef USE_DL
239 if (!local_initialized) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000240 if (usconfig(CONF_ATTACHADDR, addr) < 0)
241 /* reset address */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000242 perror("usconfig - CONF_ATTACHADDR (reset)");
243 local_initialized = 1;
244 }
245#endif /* USE_DL */
246 if (success >= 0) {
247 nthreads++;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000248 pidlist[maxpidindex].parent = getpid();
249 pidlist[maxpidindex++].child = success;
250 dprintf(("pidlist[%d] = %d\n",
251 maxpidindex-1, success));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000252 }
253 }
254 if (usunsetlock(count_lock) < 0)
255 perror("usunsetlock (count_lock)");
256 return success < 0 ? 0 : 1;
257}
258
Guido van Rossume944da81994-05-23 12:43:41 +0000259long get_thread_ident _P0()
260{
261 return getpid();
262}
263
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000264static void do_exit_thread _P1(no_cleanup, int no_cleanup)
265{
266 dprintf(("exit_thread called\n"));
267 if (!initialized)
268 if (no_cleanup)
269 _exit(0);
270 else
271 exit(0);
272 if (ussetlock(count_lock) < 0)
273 perror("ussetlock (count_lock)");
274 nthreads--;
275 if (getpid() == my_pid) {
276 /* main thread; wait for other threads to exit */
277 exiting = 1;
278#ifndef NO_EXIT_PROG
279 if (do_exit) {
280 int i;
281
282 /* notify other threads */
283 clean_threads();
284 if (nthreads >= 0) {
285 dprintf(("kill other threads\n"));
286 for (i = 0; i < maxpidindex; i++)
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000287 if (pidlist[i].child > 0)
288 (void) kill(pidlist[i].child,
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000289 SIGKILL);
290 _exit(exit_status);
291 }
292 }
293#endif /* NO_EXIT_PROG */
294 waiting_for_threads = 1;
295 if (ussetlock(wait_lock) < 0)
296 perror("ussetlock (wait_lock)");
297 for (;;) {
298 if (nthreads < 0) {
299 dprintf(("really exit (%d)\n", exit_status));
300 if (no_cleanup)
301 _exit(exit_status);
302 else
303 exit(exit_status);
304 }
305 if (usunsetlock(count_lock) < 0)
306 perror("usunsetlock (count_lock)");
307 dprintf(("waiting for other threads (%d)\n", nthreads));
308 if (ussetlock(wait_lock) < 0)
309 perror("ussetlock (wait_lock)");
310 if (ussetlock(count_lock) < 0)
311 perror("ussetlock (count_lock)");
312 }
313 }
314 /* not the main thread */
315 if (waiting_for_threads) {
316 dprintf(("main thread is waiting\n"));
317 if (usunsetlock(wait_lock) < 0)
318 perror("usunsetlock (wait_lock)");
319 }
320#ifndef NO_EXIT_PROG
321 else if (do_exit)
322 (void) kill(my_pid, SIGUSR1);
323#endif /* NO_EXIT_PROG */
324 if (usunsetlock(count_lock) < 0)
325 perror("usunsetlock (count_lock)");
326 _exit(0);
327}
328
329void exit_thread _P0()
330{
331 do_exit_thread(0);
332}
333
334void _exit_thread _P0()
335{
336 do_exit_thread(1);
337}
338
339#ifndef NO_EXIT_PROG
340static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
341{
342 dprintf(("exit_prog(%d) called\n", status));
343 if (!initialized)
344 if (no_cleanup)
345 _exit(status);
346 else
347 exit(status);
348 do_exit = 1;
349 exit_status = status;
350 do_exit_thread(no_cleanup);
351}
352
353void exit_prog _P1(status, int status)
354{
355 do_exit_prog(status, 0);
356}
357
358void _exit_prog _P1(status, int status)
359{
360 do_exit_prog(status, 1);
361}
362#endif /* NO_EXIT_PROG */
363
364/*
365 * Lock support.
366 */
367type_lock allocate_lock _P0()
368{
369 ulock_t lock;
370
371 dprintf(("allocate_lock called\n"));
372 if (!initialized)
373 init_thread();
374
375 if ((lock = usnewlock(shared_arena)) == NULL)
376 perror("usnewlock");
377 (void) usinitlock(lock);
378 dprintf(("allocate_lock() -> %lx\n", (long)lock));
379 return (type_lock) lock;
380}
381
382void free_lock _P1(lock, type_lock lock)
383{
384 dprintf(("free_lock(%lx) called\n", (long)lock));
385 usfreelock((ulock_t) lock, shared_arena);
386}
387
388int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
389{
390 int success;
391
392 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
393 errno = 0; /* clear it just in case */
394 if (waitflag)
395 success = ussetlock((ulock_t) lock);
396 else
397 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
398 if (success < 0)
399 perror(waitflag ? "ussetlock" : "uscsetlock");
400 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
401 return success;
402}
403
404void release_lock _P1(lock, type_lock lock)
405{
406 dprintf(("release_lock(%lx) called\n", (long)lock));
407 if (usunsetlock((ulock_t) lock) < 0)
408 perror("usunsetlock");
409}
410
411/*
412 * Semaphore support.
413 */
414type_sema allocate_sema _P1(value, int value)
415{
416 usema_t *sema;
417 dprintf(("allocate_sema called\n"));
418 if (!initialized)
419 init_thread();
420
421 if ((sema = usnewsema(shared_arena, value)) == NULL)
422 perror("usnewsema");
423 dprintf(("allocate_sema() -> %lx\n", (long) sema));
424 return (type_sema) sema;
425}
426
427void free_sema _P1(sema, type_sema sema)
428{
429 dprintf(("free_sema(%lx) called\n", (long) sema));
430 usfreesema((usema_t *) sema, shared_arena);
431}
432
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000433int down_sema _P2(sema, type_sema sema, waitflag, int waitflag)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000434{
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000435 int success;
436
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000437 dprintf(("down_sema(%lx) called\n", (long) sema));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000438 if (waitflag)
439 success = uspsema((usema_t *) sema);
440 else
441 success = uscpsema((usema_t *) sema);
442 if (success < 0)
443 perror(waitflag ? "uspsema" : "uscpsema");
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000444 dprintf(("down_sema(%lx) return\n", (long) sema));
Guido van Rossumcf1474b1996-10-08 14:17:53 +0000445 return success;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000446}
447
448void up_sema _P1(sema, type_sema sema)
449{
450 dprintf(("up_sema(%lx)\n", (long) sema));
451 if (usvsema((usema_t *) sema) < 0)
452 perror("usvsema");
453}
Guido van Rossuma027efa1997-05-05 20:56:21 +0000454
455/*
456 * Per-thread data ("key") support.
457 */
458
459struct key {
460 struct key *next;
461 long id;
462 int key;
463 void *value;
464};
465
466static struct key *keyhead = NULL;
467static int nkeys = 0;
468static type_lock keymutex = NULL;
469
470static struct key *find_key _P2(key, int key, value, void *value)
471{
472 struct key *p;
473 long id = get_thread_ident();
474 for (p = keyhead; p != NULL; p = p->next) {
475 if (p->id == id && p->key == key)
476 return p;
477 }
478 if (value == NULL)
479 return NULL;
480 p = (struct key *)malloc(sizeof(struct key));
481 if (p != NULL) {
482 p->id = id;
483 p->key = key;
484 p->value = value;
485 acquire_lock(keymutex, 1);
486 p->next = keyhead;
487 keyhead = p;
488 release_lock(keymutex);
489 }
490 return p;
491}
492
493int create_key _P0()
494{
495 if (keymutex == NULL)
496 keymutex = allocate_lock();
497 return ++nkeys;
498}
499
500void delete_key _P1(key, int key)
501{
502 struct key *p, **q;
503 acquire_lock(keymutex, 1);
504 q = &keyhead;
505 while ((p = *q) != NULL) {
506 if (p->key == key) {
507 *q = p->next;
508 free((void *)p);
509 /* NB This does *not* free p->value! */
510 }
511 else
512 q = &p->next;
513 }
514 release_lock(keymutex);
515}
516
517int set_key_value _P2(key, int key, value, void *value)
518{
519 struct key *p = find_key(key, value);
520 if (p == NULL)
521 return -1;
522 else
523 return 0;
524}
525
526void *get_key_value _P1(key, int key)
527{
528 struct key *p = find_key(key, NULL);
529 if (p == NULL)
530 return NULL;
531 else
532 return p->value;
533}