blob: 654d4aec3a6c676f949163c5b06ce6670c96c30e [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
7Permission to use, copy, modify, and distribute this software and its
8documentation for any purpose and without fee is hereby granted,
9provided that the above copyright notice appear in all copies and that
10both that copyright notice and this permission notice appear in
11supporting documentation, and that the names of Stichting Mathematisch
12Centrum or CWI not be used in advertising or publicity pertaining to
13distribution of the software without specific, written prior permission.
14
15STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
22
23******************************************************************/
24
25#ifdef WITH_SGI_DL
26#define USE_DL
27#endif
28
29#include <stdlib.h>
30#include <stdio.h>
31#include <signal.h>
32#include <sys/types.h>
33#include <sys/wait.h>
34#include <sys/prctl.h>
35#include <ulocks.h>
36#include <errno.h>
37
38#define HDR_SIZE 2680 /* sizeof(ushdr_t) */
39#define MAXPROC 100 /* max # of threads that can be started */
40
41static usptr_t *shared_arena;
42static ulock_t count_lock; /* protection for some variables */
43static ulock_t wait_lock; /* lock used to wait for other threads */
44static int waiting_for_threads; /* protected by count_lock */
45static int nthreads; /* protected by count_lock */
46static int exit_status;
47#ifndef NO_EXIT_PROG
48static int do_exit; /* indicates that the program is to exit */
49#endif
50static int exiting; /* we're already exiting (for maybe_exit) */
51static pid_t my_pid; /* PID of main thread */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +000052static struct pidlist {
53 pid_t parent;
54 pid_t child;
55} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000056static int maxpidindex; /* # of PIDs in pidlist */
57
58#ifndef NO_EXIT_PROG
59/*
60 * This routine is called as a signal handler when another thread
61 * exits. When that happens, we must see whether we have to exit as
62 * well (because of an exit_prog()) or whether we should continue on.
63 */
64static void exit_sig _P0()
65{
66 d2printf(("exit_sig called\n"));
67 if (exiting && getpid() == my_pid) {
68 d2printf(("already exiting\n"));
69 return;
70 }
71 if (do_exit) {
72 d2printf(("exiting in exit_sig\n"));
73#ifdef DEBUG
74 if ((thread_debug & 8) == 0)
75 thread_debug &= ~1; /* don't produce debug messages */
76#endif
77 exit_thread();
78 }
79}
80
81/*
82 * This routine is called when a process calls exit(). If that wasn't
83 * done from the library, we do as if an exit_prog() was intended.
84 */
85static void maybe_exit _P0()
86{
87 dprintf(("maybe_exit called\n"));
88 if (exiting) {
89 dprintf(("already exiting\n"));
90 return;
91 }
92 exit_prog(0);
93}
94#endif /* NO_EXIT_PROG */
95
96/*
97 * Initialization.
98 */
99static void _init_thread _P0()
100{
101#ifndef NO_EXIT_PROG
102 struct sigaction s;
103#endif /* NO_EXIT_PROG */
104#ifdef USE_DL
105 long addr, size;
106#endif /* USE_DL */
107
108
109#ifdef USE_DL
110 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
111 perror("usconfig - CONF_INITSIZE (check)");
112 if (usconfig(CONF_INITSIZE, size) < 0)
113 perror("usconfig - CONF_INITSIZE (reset)");
114 addr = (long) dl_getrange(size + HDR_SIZE);
115 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
116 errno = 0;
117 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
118 perror("usconfig - CONF_ATTACHADDR (set)");
119#endif /* USE_DL */
120 if (usconfig(CONF_INITUSERS, 16) < 0)
121 perror("usconfig - CONF_INITUSERS");
122 my_pid = getpid(); /* so that we know which is the main thread */
123#ifndef NO_EXIT_PROG
124 atexit(maybe_exit);
125 s.sa_handler = exit_sig;
126 sigemptyset(&s.sa_mask);
127 /*sigaddset(&s.sa_mask, SIGUSR1);*/
128 s.sa_flags = 0;
129 sigaction(SIGUSR1, &s, 0);
130 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
131 perror("prctl - PR_SETEXITSIG");
132#endif /* NO_EXIT_PROG */
133 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
134 perror("usconfig - CONF_ARENATYPE");
135 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
136#ifdef DEBUG
137 if (thread_debug & 4)
138 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
139 else if (thread_debug & 2)
140 usconfig(CONF_LOCKTYPE, US_DEBUG);
141#endif /* DEBUG */
142 if ((shared_arena = usinit(tmpnam(0))) == 0)
143 perror("usinit");
144#ifdef USE_DL
145 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
146 perror("usconfig - CONF_ATTACHADDR (reset)");
147#endif /* USE_DL */
148 if ((count_lock = usnewlock(shared_arena)) == NULL)
149 perror("usnewlock (count_lock)");
150 (void) usinitlock(count_lock);
151 if ((wait_lock = usnewlock(shared_arena)) == NULL)
152 perror("usnewlock (wait_lock)");
153 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
154}
155
156/*
157 * Thread support.
158 */
159
160static void clean_threads _P0()
161{
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000162 int i, j;
163 pid_t mypid, pid;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000164
165 /* clean up any exited threads */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000166 mypid = getpid();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000167 i = 0;
168 while (i < maxpidindex) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000169 if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000170 pid = waitpid(pid, 0, WNOHANG);
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000171 if (pid > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000172 /* a thread has exited */
173 pidlist[i] = pidlist[--maxpidindex];
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000174 /* remove references to children of dead proc */
175 for (j = 0; j < maxpidindex; j++)
176 if (pidlist[j].parent == pid)
177 pidlist[j].child = -1;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000178 continue; /* don't increment i */
179 }
180 }
181 i++;
182 }
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000183 /* clean up the list */
184 i = 0;
185 while (i < maxpidindex) {
186 if (pidlist[i].child == -1) {
187 pidlist[i] = pidlist[--maxpidindex];
188 continue; /* don't increment i */
189 }
190 i++;
191 }
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000192}
193
194int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
195{
196#ifdef USE_DL
197 long addr, size;
198 static int local_initialized = 0;
199#endif /* USE_DL */
200 int success = 0; /* init not needed when SOLARIS_THREADS and */
201 /* C_THREADS implemented properly */
202
203 dprintf(("start_new_thread called\n"));
204 if (!initialized)
205 init_thread();
206 switch (ussetlock(count_lock)) {
207 case 0: return 0;
208 case -1: perror("ussetlock (count_lock)");
209 }
210 if (maxpidindex >= MAXPROC)
211 success = -1;
212 else {
213#ifdef USE_DL
214 if (!local_initialized) {
215 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
216 perror("usconfig - CONF_INITSIZE (check)");
217 if (usconfig(CONF_INITSIZE, size) < 0)
218 perror("usconfig - CONF_INITSIZE (reset)");
219 addr = (long) dl_getrange(size + HDR_SIZE);
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000220 dprintf(("trying to use addr %lx-%lx for sproc\n",
221 addr, addr+size));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000222 errno = 0;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000223 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
224 errno != 0)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000225 perror("usconfig - CONF_ATTACHADDR (set)");
226 }
227#endif /* USE_DL */
228 clean_threads();
229 if ((success = sproc(func, PR_SALL, arg)) < 0)
230 perror("sproc");
231#ifdef USE_DL
232 if (!local_initialized) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000233 if (usconfig(CONF_ATTACHADDR, addr) < 0)
234 /* reset address */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000235 perror("usconfig - CONF_ATTACHADDR (reset)");
236 local_initialized = 1;
237 }
238#endif /* USE_DL */
239 if (success >= 0) {
240 nthreads++;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000241 pidlist[maxpidindex].parent = getpid();
242 pidlist[maxpidindex++].child = success;
243 dprintf(("pidlist[%d] = %d\n",
244 maxpidindex-1, success));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000245 }
246 }
247 if (usunsetlock(count_lock) < 0)
248 perror("usunsetlock (count_lock)");
249 return success < 0 ? 0 : 1;
250}
251
Guido van Rossume944da81994-05-23 12:43:41 +0000252long get_thread_ident _P0()
253{
254 return getpid();
255}
256
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000257static void do_exit_thread _P1(no_cleanup, int no_cleanup)
258{
259 dprintf(("exit_thread called\n"));
260 if (!initialized)
261 if (no_cleanup)
262 _exit(0);
263 else
264 exit(0);
265 if (ussetlock(count_lock) < 0)
266 perror("ussetlock (count_lock)");
267 nthreads--;
268 if (getpid() == my_pid) {
269 /* main thread; wait for other threads to exit */
270 exiting = 1;
271#ifndef NO_EXIT_PROG
272 if (do_exit) {
273 int i;
274
275 /* notify other threads */
276 clean_threads();
277 if (nthreads >= 0) {
278 dprintf(("kill other threads\n"));
279 for (i = 0; i < maxpidindex; i++)
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000280 if (pidlist[i].child > 0)
281 (void) kill(pidlist[i].child,
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000282 SIGKILL);
283 _exit(exit_status);
284 }
285 }
286#endif /* NO_EXIT_PROG */
287 waiting_for_threads = 1;
288 if (ussetlock(wait_lock) < 0)
289 perror("ussetlock (wait_lock)");
290 for (;;) {
291 if (nthreads < 0) {
292 dprintf(("really exit (%d)\n", exit_status));
293 if (no_cleanup)
294 _exit(exit_status);
295 else
296 exit(exit_status);
297 }
298 if (usunsetlock(count_lock) < 0)
299 perror("usunsetlock (count_lock)");
300 dprintf(("waiting for other threads (%d)\n", nthreads));
301 if (ussetlock(wait_lock) < 0)
302 perror("ussetlock (wait_lock)");
303 if (ussetlock(count_lock) < 0)
304 perror("ussetlock (count_lock)");
305 }
306 }
307 /* not the main thread */
308 if (waiting_for_threads) {
309 dprintf(("main thread is waiting\n"));
310 if (usunsetlock(wait_lock) < 0)
311 perror("usunsetlock (wait_lock)");
312 }
313#ifndef NO_EXIT_PROG
314 else if (do_exit)
315 (void) kill(my_pid, SIGUSR1);
316#endif /* NO_EXIT_PROG */
317 if (usunsetlock(count_lock) < 0)
318 perror("usunsetlock (count_lock)");
319 _exit(0);
320}
321
322void exit_thread _P0()
323{
324 do_exit_thread(0);
325}
326
327void _exit_thread _P0()
328{
329 do_exit_thread(1);
330}
331
332#ifndef NO_EXIT_PROG
333static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
334{
335 dprintf(("exit_prog(%d) called\n", status));
336 if (!initialized)
337 if (no_cleanup)
338 _exit(status);
339 else
340 exit(status);
341 do_exit = 1;
342 exit_status = status;
343 do_exit_thread(no_cleanup);
344}
345
346void exit_prog _P1(status, int status)
347{
348 do_exit_prog(status, 0);
349}
350
351void _exit_prog _P1(status, int status)
352{
353 do_exit_prog(status, 1);
354}
355#endif /* NO_EXIT_PROG */
356
357/*
358 * Lock support.
359 */
360type_lock allocate_lock _P0()
361{
362 ulock_t lock;
363
364 dprintf(("allocate_lock called\n"));
365 if (!initialized)
366 init_thread();
367
368 if ((lock = usnewlock(shared_arena)) == NULL)
369 perror("usnewlock");
370 (void) usinitlock(lock);
371 dprintf(("allocate_lock() -> %lx\n", (long)lock));
372 return (type_lock) lock;
373}
374
375void free_lock _P1(lock, type_lock lock)
376{
377 dprintf(("free_lock(%lx) called\n", (long)lock));
378 usfreelock((ulock_t) lock, shared_arena);
379}
380
381int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
382{
383 int success;
384
385 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
386 errno = 0; /* clear it just in case */
387 if (waitflag)
388 success = ussetlock((ulock_t) lock);
389 else
390 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
391 if (success < 0)
392 perror(waitflag ? "ussetlock" : "uscsetlock");
393 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
394 return success;
395}
396
397void release_lock _P1(lock, type_lock lock)
398{
399 dprintf(("release_lock(%lx) called\n", (long)lock));
400 if (usunsetlock((ulock_t) lock) < 0)
401 perror("usunsetlock");
402}
403
404/*
405 * Semaphore support.
406 */
407type_sema allocate_sema _P1(value, int value)
408{
409 usema_t *sema;
410 dprintf(("allocate_sema called\n"));
411 if (!initialized)
412 init_thread();
413
414 if ((sema = usnewsema(shared_arena, value)) == NULL)
415 perror("usnewsema");
416 dprintf(("allocate_sema() -> %lx\n", (long) sema));
417 return (type_sema) sema;
418}
419
420void free_sema _P1(sema, type_sema sema)
421{
422 dprintf(("free_sema(%lx) called\n", (long) sema));
423 usfreesema((usema_t *) sema, shared_arena);
424}
425
426void down_sema _P1(sema, type_sema sema)
427{
428 dprintf(("down_sema(%lx) called\n", (long) sema));
429 if (uspsema((usema_t *) sema) < 0)
430 perror("uspsema");
431 dprintf(("down_sema(%lx) return\n", (long) sema));
432}
433
434void up_sema _P1(sema, type_sema sema)
435{
436 dprintf(("up_sema(%lx)\n", (long) sema));
437 if (usvsema((usema_t *) sema) < 0)
438 perror("usvsema");
439}