comparison Python/thread.c @ 1848:b724599401ff legacy-trunk

Merge back to main trunk
author Guido van Rossum <guido@python.org>
date Tue, 30 Aug 1994 08:27:36 +0000
parents b1bb74a2b593
children d0d0a69b5ca3
comparison
equal deleted inserted replaced
1847:0d318475f9e3 1848:b724599401ff
1 /*********************************************************** 1 /***********************************************************
2 Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, 2 Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands. 3 Amsterdam, The Netherlands.
4 4
5 All Rights Reserved 5 All Rights Reserved
6 6
7 Permission to use, copy, modify, and distribute this software and its 7 Permission to use, copy, modify, and distribute this software and its
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22 22
23 ******************************************************************/ 23 ******************************************************************/
24 24
25 /* Thread package.
26 This is intended to be usable independently from Python.
27 The implementation for system foobar is in a file thread_foobar.h
28 which is included by this file dependent on config settings.
29 Stuff shared by all thread_*.h files is collected here. */
30
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34
35 #include <stdio.h>
36
37 #ifdef HAVE_STDLIB_H
38 #include <stdlib.h>
39 #else
40 extern char *getenv();
41 #endif
42
25 #include "thread.h" 43 #include "thread.h"
26 44
27 #ifdef DEBUG 45 #ifdef __ksr__
28 static int thread_debug = 0; 46 #define _POSIX_THREADS
29 #define dprintf(args) ((thread_debug & 1) && printf args)
30 #define d2printf(args) ((thread_debug & 8) && printf args)
31 #else
32 #define dprintf(args)
33 #define d2printf(args)
34 #endif 47 #endif
35 48
49 #ifndef _POSIX_THREADS
50
36 #ifdef __sgi 51 #ifdef __sgi
37 #include <stdlib.h> 52 #define SGI_THREADS
38 #include <stdio.h> 53 #endif
39 #include <signal.h>
40 #include <sys/types.h>
41 #include <sys/prctl.h>
42 #include <ulocks.h>
43 #include <errno.h>
44 54
45 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */ 55 #ifdef HAVE_THREAD_H
46 #define MAXPROC 100 /* max # of threads that can be started */ 56 #define SOLARIS_THREADS
57 #endif
47 58
48 static usptr_t *shared_arena; 59 #if defined(sun) && !defined(SOLARIS_THREADS)
49 static ulock_t count_lock; /* protection for some variables */ 60 #define SUN_LWP
50 static ulock_t wait_lock; /* lock used to wait for other threads */
51 static int waiting_for_threads; /* protected by count_lock */
52 static int nthreads; /* protected by count_lock */
53 static int exit_status;
54 static int do_exit; /* indicates that the program is to exit */
55 static int exiting; /* we're already exiting (for maybe_exit) */
56 static pid_t my_pid; /* PID of main thread */
57 static pid_t pidlist[MAXPROC]; /* PIDs of other threads */
58 static int maxpidindex; /* # of PIDs in pidlist */
59 #endif /* __sgi */
60 #ifdef SOLARIS
61 #include <stdlib.h>
62 #include <stdio.h>
63 #include <unistd.h>
64 #include </usr/include/thread.h>
65 #undef sun
66 #endif 61 #endif
67 #ifdef sun
68 #include <lwp/lwp.h>
69 #include <lwp/stackdep.h>
70 62
71 #define STACKSIZE 1000 /* stacksize for a thread */
72 #define NSTACKS 2 /* # stacks to be put in cache initialy */
73
74 struct lock {
75 int lock_locked;
76 cv_t lock_condvar;
77 mon_t lock_monitor;
78 };
79 #endif /* sun */
80 #ifdef C_THREADS
81 #include <cthreads.h>
82 #endif /* C_THREADS */
83 #ifdef _POSIX_THREADS
84 #include <pthread.h>
85 #endif /* _POSIX_THREADS */ 63 #endif /* _POSIX_THREADS */
86 64
87 #ifdef __STDC__ 65 #ifdef __STDC__
88 #define _P(args) args 66 #define _P(args) args
89 #define _P0() (void) 67 #define _P0() (void)
94 #define _P0() () 72 #define _P0() ()
95 #define _P1(v,t) (v) t; 73 #define _P1(v,t) (v) t;
96 #define _P2(v1,t1,v2,t2) (v1,v2) t1; t2; 74 #define _P2(v1,t1,v2,t2) (v1,v2) t1; t2;
97 #endif /* __STDC__ */ 75 #endif /* __STDC__ */
98 76
77 #ifdef DEBUG
78 static int thread_debug = 0;
79 #define dprintf(args) ((thread_debug & 1) && printf args)
80 #define d2printf(args) ((thread_debug & 8) && printf args)
81 #else
82 #define dprintf(args)
83 #define d2printf(args)
84 #endif
85
99 static int initialized; 86 static int initialized;
100 87
101 #ifdef __sgi 88 static void _init_thread(); /* Forward */
102 /*
103 * This routine is called as a signal handler when another thread
104 * exits. When that happens, we must see whether we have to exit as
105 * well (because of an exit_prog()) or whether we should continue on.
106 */
107 static void exit_sig _P0()
108 {
109 d2printf(("exit_sig called\n"));
110 if (exiting && getpid() == my_pid) {
111 d2printf(("already exiting\n"));
112 return;
113 }
114 if (do_exit) {
115 d2printf(("exiting in exit_sig\n"));
116 #ifdef DEBUG
117 if ((thread_debug & 8) == 0)
118 thread_debug &= ~1; /* don't produce debug messages */
119 #endif
120 exit_thread();
121 }
122 }
123 89
124 /*
125 * This routine is called when a process calls exit(). If that wasn't
126 * done from the library, we do as if an exit_prog() was intended.
127 */
128 static void maybe_exit _P0()
129 {
130 dprintf(("maybe_exit called\n"));
131 if (exiting) {
132 dprintf(("already exiting\n"));
133 return;
134 }
135 exit_prog(0);
136 }
137 #endif /* __sgi */
138
139 /*
140 * Initialization.
141 */
142 void init_thread _P0() 90 void init_thread _P0()
143 { 91 {
144 #ifdef __sgi
145 struct sigaction s;
146 #ifdef USE_DL
147 long addr, size;
148 #endif /* USE_DL */
149 #endif /* __sgi */
150
151 #ifdef DEBUG 92 #ifdef DEBUG
152 char *p = getenv("THREADDEBUG"); 93 char *p = getenv("THREADDEBUG");
153 94
154 if (p) { 95 if (p) {
155 if (*p) 96 if (*p)
160 #endif /* DEBUG */ 101 #endif /* DEBUG */
161 if (initialized) 102 if (initialized)
162 return; 103 return;
163 initialized = 1; 104 initialized = 1;
164 dprintf(("init_thread called\n")); 105 dprintf(("init_thread called\n"));
165 106 _init_thread();
166 #ifdef __sgi
167 #ifdef USE_DL
168 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
169 perror("usconfig - CONF_INITSIZE (check)");
170 if (usconfig(CONF_INITSIZE, size) < 0)
171 perror("usconfig - CONF_INITSIZE (reset)");
172 addr = (long) dl_getrange(size + HDR_SIZE);
173 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
174 errno = 0;
175 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
176 perror("usconfig - CONF_ATTACHADDR (set)");
177 #endif /* USE_DL */
178 if (usconfig(CONF_INITUSERS, 16) < 0)
179 perror("usconfig - CONF_INITUSERS");
180 my_pid = getpid(); /* so that we know which is the main thread */
181 atexit(maybe_exit);
182 s.sa_handler = exit_sig;
183 sigemptyset(&s.sa_mask);
184 /*sigaddset(&s.sa_mask, SIGUSR1);*/
185 s.sa_flags = 0;
186 sigaction(SIGUSR1, &s, 0);
187 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
188 perror("prctl - PR_SETEXITSIG");
189 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
190 perror("usconfig - CONF_ARENATYPE");
191 #ifdef DEBUG
192 if (thread_debug & 4)
193 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
194 else if (thread_debug & 2)
195 usconfig(CONF_LOCKTYPE, US_DEBUG);
196 #endif /* DEBUG */
197 if ((shared_arena = usinit(tmpnam(0))) == 0)
198 perror("usinit");
199 #ifdef USE_DL
200 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
201 perror("usconfig - CONF_ATTACHADDR (reset)");
202 #endif /* USE_DL */
203 if ((count_lock = usnewlock(shared_arena)) == NULL)
204 perror("usnewlock (count_lock)");
205 (void) usinitlock(count_lock);
206 if ((wait_lock = usnewlock(shared_arena)) == NULL)
207 perror("usnewlock (wait_lock)");
208 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
209 #endif /* __sgi */
210 #ifdef SOLARIS
211 /* nothing */
212 #endif
213 #ifdef sun
214 lwp_setstkcache(STACKSIZE, NSTACKS);
215 #endif /* sun */
216 #ifdef C_THREADS
217 cthread_init();
218 #endif /* C_THREADS */
219 } 107 }
220 108
221 /* 109 #ifdef SGI_THREADS
222 * Thread support. 110 #include "thread_sgi.h"
223 */ 111 #endif
224 #ifdef SOLARIS
225 struct func_arg {
226 void (*func) _P((void *));
227 void *arg;
228 };
229 112
230 static void *new_func _P1(funcarg, void *funcarg) 113 #ifdef SOLARIS_THREADS
231 { 114 #include "thread_solaris.h"
232 void (*func) _P((void *)); 115 #endif
233 void *arg;
234 116
235 func = ((struct func_arg *) funcarg)->func; 117 #ifdef SUN_LWP
236 arg = ((struct func_arg *) funcarg)->arg; 118 #include "thread_lwp.h"
237 free(funcarg); 119 #endif
238 (*func)(arg);
239 return 0;
240 }
241 #endif /* SOLARIS */
242 120
243 int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg) 121 #ifdef _POSIX_THREADS
244 { 122 #include "thread_pthread.h"
245 #ifdef SOLARIS
246 struct func_arg *funcarg;
247 #endif 123 #endif
248 #ifdef sun 124
249 thread_t tid; 125 #ifdef C_THREADS
250 #endif /* sun */ 126 #include "thread_cthread.h"
251 #if defined(__sgi) && defined(USE_DL)
252 long addr, size;
253 static int local_initialized = 0;
254 #endif /* __sgi and USE_DL */
255 #ifdef _POSIX_THREADS
256 pthread_t th;
257 #endif 127 #endif
258 int success = 0; /* init not needed when SOLARIS and */
259 /* C_THREADS implemented properly */
260
261 dprintf(("start_new_thread called\n"));
262 if (!initialized)
263 init_thread();
264 #ifdef __sgi
265 switch (ussetlock(count_lock)) {
266 case 0: return 0;
267 case -1: perror("ussetlock (count_lock)");
268 }
269 if (maxpidindex >= MAXPROC)
270 success = -1;
271 else {
272 #ifdef USE_DL
273 if (!local_initialized) {
274 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
275 perror("usconfig - CONF_INITSIZE (check)");
276 if (usconfig(CONF_INITSIZE, size) < 0)
277 perror("usconfig - CONF_INITSIZE (reset)");
278 addr = (long) dl_getrange(size + HDR_SIZE);
279 dprintf(("trying to use addr %lx-%lx for sproc\n", addr, addr+size));
280 errno = 0;
281 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
282 perror("usconfig - CONF_ATTACHADDR (set)");
283 }
284 #endif /* USE_DL */
285 if ((success = sproc(func, PR_SALL, arg)) < 0)
286 perror("sproc");
287 #ifdef USE_DL
288 if (!local_initialized) {
289 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
290 perror("usconfig - CONF_ATTACHADDR (reset)");
291 local_initialized = 1;
292 }
293 #endif /* USE_DL */
294 if (success >= 0) {
295 nthreads++;
296 pidlist[maxpidindex++] = success;
297 }
298 }
299 if (usunsetlock(count_lock) < 0)
300 perror("usunsetlock (count_lock)");
301 #endif /* __sgi */
302 #ifdef SOLARIS
303 funcarg = (struct func_arg *) malloc(sizeof(struct func_arg));
304 funcarg->func = func;
305 funcarg->arg = arg;
306 if (thr_create(0, 0, new_func, funcarg, THR_NEW_LWP, 0)) {
307 perror("thr_create");
308 free((void *) funcarg);
309 success = -1;
310 }
311 #endif /* SOLARIS */
312 #ifdef sun
313 success = lwp_create(&tid, func, MINPRIO, 0, lwp_newstk(), 1, arg);
314 #endif /* sun */
315 #ifdef C_THREADS
316 (void) cthread_fork(func, arg);
317 #endif /* C_THREADS */
318 #ifdef _POSIX_THREADS
319 pthread_create(&th, NULL, func, arg);
320 #endif
321 return success < 0 ? 0 : 1;
322 }
323
324 static void do_exit_thread _P1(no_cleanup, int no_cleanup)
325 {
326 dprintf(("exit_thread called\n"));
327 if (!initialized)
328 if (no_cleanup)
329 _exit(0);
330 else
331 exit(0);
332 #ifdef __sgi
333 if (ussetlock(count_lock) < 0)
334 perror("ussetlock (count_lock)");
335 nthreads--;
336 if (getpid() == my_pid) {
337 /* main thread; wait for other threads to exit */
338 exiting = 1;
339 if (do_exit) {
340 int i;
341
342 /* notify other threads */
343 if (nthreads >= 0) {
344 dprintf(("kill other threads\n"));
345 for (i = 0; i < maxpidindex; i++)
346 (void) kill(pidlist[i], SIGKILL);
347 _exit(exit_status);
348 }
349 }
350 waiting_for_threads = 1;
351 if (ussetlock(wait_lock) < 0)
352 perror("ussetlock (wait_lock)");
353 for (;;) {
354 if (nthreads < 0) {
355 dprintf(("really exit (%d)\n", exit_status));
356 if (no_cleanup)
357 _exit(exit_status);
358 else
359 exit(exit_status);
360 }
361 if (usunsetlock(count_lock) < 0)
362 perror("usunsetlock (count_lock)");
363 dprintf(("waiting for other threads (%d)\n", nthreads));
364 if (ussetlock(wait_lock) < 0)
365 perror("ussetlock (wait_lock)");
366 if (ussetlock(count_lock) < 0)
367 perror("ussetlock (count_lock)");
368 }
369 }
370 /* not the main thread */
371 if (waiting_for_threads) {
372 dprintf(("main thread is waiting\n"));
373 if (usunsetlock(wait_lock) < 0)
374 perror("usunsetlock (wait_lock)");
375 } else if (do_exit)
376 (void) kill(my_pid, SIGUSR1);
377 if (usunsetlock(count_lock) < 0)
378 perror("usunsetlock (count_lock)");
379 _exit(0);
380 #endif /* __sgi */
381 #ifdef SOLARIS
382 thr_exit(0);
383 #endif /* SOLARIS */
384 #ifdef sun
385 lwp_destroy(SELF);
386 #endif /* sun */
387 #ifdef C_THREADS
388 cthread_exit(0);
389 #endif /* C_THREADS */
390 }
391
392 void exit_thread _P0()
393 {
394 do_exit_thread(0);
395 }
396
397 void _exit_thread _P0()
398 {
399 do_exit_thread(1);
400 }
401
402 static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
403 {
404 dprintf(("exit_prog(%d) called\n", status));
405 if (!initialized)
406 if (no_cleanup)
407 _exit(status);
408 else
409 exit(status);
410 #ifdef __sgi
411 do_exit = 1;
412 exit_status = status;
413 do_exit_thread(no_cleanup);
414 #endif
415 #ifdef SOLARIS
416 if (no_cleanup)
417 _exit(status);
418 else
419 exit(status);
420 #endif
421 #ifdef sun
422 pod_exit(status);
423 #endif
424 }
425
426 void exit_prog _P1(status, int status)
427 {
428 do_exit_prog(status, 0);
429 }
430
431 void _exit_prog _P1(status, int status)
432 {
433 do_exit_prog(status, 1);
434 }
435 128
436 /* 129 /*
437 * Lock support. 130 #ifdef FOOBAR_THREADS
438 */ 131 #include "thread_foobar.h"
439 type_lock allocate_lock _P0()
440 {
441 #ifdef __sgi
442 ulock_t lock;
443 #endif 132 #endif
444 #ifdef SOLARIS 133 */
445 mutex_t *lock;
446 #endif
447 #ifdef sun
448 struct lock *lock;
449 extern char *malloc();
450 #endif
451
452 dprintf(("allocate_lock called\n"));
453 if (!initialized)
454 init_thread();
455
456 #ifdef __sgi
457 if ((lock = usnewlock(shared_arena)) == NULL)
458 perror("usnewlock");
459 (void) usinitlock(lock);
460 #endif /* __sgi */
461 #ifdef SOLARIS
462 lock = (mutex_t *) malloc(sizeof(mutex_t));
463 if (mutex_init(lock, USYNC_THREAD, 0)) {
464 perror("mutex_init");
465 free((void *) lock);
466 lock = 0;
467 }
468 #endif /* SOLARIS */
469 #ifdef sun
470 lock = (struct lock *) malloc(sizeof(struct lock));
471 lock->lock_locked = 0;
472 (void) mon_create(&lock->lock_monitor);
473 (void) cv_create(&lock->lock_condvar, lock->lock_monitor);
474 #endif /* sun */
475 dprintf(("allocate_lock() -> %lx\n", (long)lock));
476 return (type_lock) lock;
477 }
478
479 void free_lock _P1(lock, type_lock lock)
480 {
481 dprintf(("free_lock(%lx) called\n", (long)lock));
482 #ifdef __sgi
483 usfreelock((ulock_t) lock, shared_arena);
484 #endif /* __sgi */
485 #ifdef SOLARIS
486 mutex_destroy((mutex_t *) lock);
487 free((void *) lock);
488 #endif
489 #ifdef sun
490 mon_destroy(((struct lock *) lock)->lock_monitor);
491 free((char *) lock);
492 #endif /* sun */
493 }
494
495 int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
496 {
497 int success;
498
499 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
500 #ifdef __sgi
501 errno = 0; /* clear it just in case */
502 if (waitflag)
503 success = ussetlock((ulock_t) lock);
504 else
505 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
506 if (success < 0)
507 perror(waitflag ? "ussetlock" : "uscsetlock");
508 #endif /* __sgi */
509 #ifdef SOLARIS
510 if (waitflag)
511 success = mutex_lock((mutex_t *) lock);
512 else
513 success = mutex_trylock((mutex_t *) lock);
514 if (success < 0)
515 perror(waitflag ? "mutex_lock" : "mutex_trylock");
516 else
517 success = !success; /* solaris does it the other way round */
518 #endif /* SOLARIS */
519 #ifdef sun
520 success = 0;
521
522 (void) mon_enter(((struct lock *) lock)->lock_monitor);
523 if (waitflag)
524 while (((struct lock *) lock)->lock_locked)
525 cv_wait(((struct lock *) lock)->lock_condvar);
526 if (!((struct lock *) lock)->lock_locked) {
527 success = 1;
528 ((struct lock *) lock)->lock_locked = 1;
529 }
530 cv_broadcast(((struct lock *) lock)->lock_condvar);
531 mon_exit(((struct lock *) lock)->lock_monitor);
532 #endif /* sun */
533 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
534 return success;
535 }
536
537 void release_lock _P1(lock, type_lock lock)
538 {
539 dprintf(("release_lock(%lx) called\n", (long)lock));
540 #ifdef __sgi
541 if (usunsetlock((ulock_t) lock) < 0)
542 perror("usunsetlock");
543 #endif /* __sgi */
544 #ifdef SOLARIS
545 if (mutex_unlock((mutex_t *) lock))
546 perror("mutex_unlock");
547 #endif /* SOLARIS */
548 #ifdef sun
549 (void) mon_enter(((struct lock *) lock)->lock_monitor);
550 ((struct lock *) lock)->lock_locked = 0;
551 cv_broadcast(((struct lock *) lock)->lock_condvar);
552 mon_exit(((struct lock *) lock)->lock_monitor);
553 #endif /* sun */
554 }
555
556 /*
557 * Semaphore support.
558 */
559 type_sema allocate_sema _P1(value, int value)
560 {
561 #ifdef __sgi
562 usema_t *sema;
563 #endif /* __sgi */
564 #ifdef SOLARIS
565 sema_t *sema;
566 #endif
567
568 dprintf(("allocate_sema called\n"));
569 if (!initialized)
570 init_thread();
571
572 #ifdef __sgi
573 if ((sema = usnewsema(shared_arena, value)) == NULL)
574 perror("usnewsema");
575 #endif /* __sgi */
576 #ifdef SOLARIS
577 sema = (sema_t *) malloc(sizeof(sema_t));
578 if (sema_init(sema, value, USYNC_THREAD, 0)) {
579 perror("sema_init");
580 free((void *) sema);
581 sema = 0;
582 }
583 #endif /* SOLARIS */
584 dprintf(("allocate_sema() -> %lx\n", (long) sema));
585 return (type_sema) sema;
586 }
587
588 void free_sema _P1(sema, type_sema sema)
589 {
590 dprintf(("free_sema(%lx) called\n", (long) sema));
591 #ifdef __sgi
592 usfreesema((usema_t *) sema, shared_arena);
593 #endif /* __sgi */
594 #ifdef SOLARIS
595 if (sema_destroy((sema_t *) sema))
596 perror("sema_destroy");
597 free((void *) sema);
598 #endif /* SOLARIS */
599 }
600
601 void down_sema _P1(sema, type_sema sema)
602 {
603 dprintf(("down_sema(%lx) called\n", (long) sema));
604 #ifdef __sgi
605 if (uspsema((usema_t *) sema) < 0)
606 perror("uspsema");
607 #endif
608 #ifdef SOLARIS
609 if (sema_wait((sema_t *) sema))
610 perror("sema_wait");
611 #endif
612 dprintf(("down_sema(%lx) return\n", (long) sema));
613 }
614
615 void up_sema _P1(sema, type_sema sema)
616 {
617 dprintf(("up_sema(%lx)\n", (long) sema));
618 #ifdef __sgi
619 if (usvsema((usema_t *) sema) < 0)
620 perror("usvsema");
621 #endif /* __sgi */
622 #ifdef SOLARIS
623 if (sema_post((sema_t *) sema))
624 perror("sema_post");
625 #endif
626 }