blob: 40f28a04681a9295a793e3def4a81b74d6a54d13 [file] [log] [blame]
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00001/***********************************************************
2Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3Amsterdam, The Netherlands.
4
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 */
52static pid_t pidlist[MAXPROC]; /* PIDs of other threads */
53static int maxpidindex; /* # of PIDs in pidlist */
54
55#ifndef NO_EXIT_PROG
56/*
57 * This routine is called as a signal handler when another thread
58 * exits. When that happens, we must see whether we have to exit as
59 * well (because of an exit_prog()) or whether we should continue on.
60 */
61static void exit_sig _P0()
62{
63 d2printf(("exit_sig called\n"));
64 if (exiting && getpid() == my_pid) {
65 d2printf(("already exiting\n"));
66 return;
67 }
68 if (do_exit) {
69 d2printf(("exiting in exit_sig\n"));
70#ifdef DEBUG
71 if ((thread_debug & 8) == 0)
72 thread_debug &= ~1; /* don't produce debug messages */
73#endif
74 exit_thread();
75 }
76}
77
78/*
79 * This routine is called when a process calls exit(). If that wasn't
80 * done from the library, we do as if an exit_prog() was intended.
81 */
82static void maybe_exit _P0()
83{
84 dprintf(("maybe_exit called\n"));
85 if (exiting) {
86 dprintf(("already exiting\n"));
87 return;
88 }
89 exit_prog(0);
90}
91#endif /* NO_EXIT_PROG */
92
93/*
94 * Initialization.
95 */
96static void _init_thread _P0()
97{
98#ifndef NO_EXIT_PROG
99 struct sigaction s;
100#endif /* NO_EXIT_PROG */
101#ifdef USE_DL
102 long addr, size;
103#endif /* USE_DL */
104
105
106#ifdef USE_DL
107 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
108 perror("usconfig - CONF_INITSIZE (check)");
109 if (usconfig(CONF_INITSIZE, size) < 0)
110 perror("usconfig - CONF_INITSIZE (reset)");
111 addr = (long) dl_getrange(size + HDR_SIZE);
112 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr, addr+size));
113 errno = 0;
114 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
115 perror("usconfig - CONF_ATTACHADDR (set)");
116#endif /* USE_DL */
117 if (usconfig(CONF_INITUSERS, 16) < 0)
118 perror("usconfig - CONF_INITUSERS");
119 my_pid = getpid(); /* so that we know which is the main thread */
120#ifndef NO_EXIT_PROG
121 atexit(maybe_exit);
122 s.sa_handler = exit_sig;
123 sigemptyset(&s.sa_mask);
124 /*sigaddset(&s.sa_mask, SIGUSR1);*/
125 s.sa_flags = 0;
126 sigaction(SIGUSR1, &s, 0);
127 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
128 perror("prctl - PR_SETEXITSIG");
129#endif /* NO_EXIT_PROG */
130 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
131 perror("usconfig - CONF_ARENATYPE");
132 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
133#ifdef DEBUG
134 if (thread_debug & 4)
135 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
136 else if (thread_debug & 2)
137 usconfig(CONF_LOCKTYPE, US_DEBUG);
138#endif /* DEBUG */
139 if ((shared_arena = usinit(tmpnam(0))) == 0)
140 perror("usinit");
141#ifdef USE_DL
142 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
143 perror("usconfig - CONF_ATTACHADDR (reset)");
144#endif /* USE_DL */
145 if ((count_lock = usnewlock(shared_arena)) == NULL)
146 perror("usnewlock (count_lock)");
147 (void) usinitlock(count_lock);
148 if ((wait_lock = usnewlock(shared_arena)) == NULL)
149 perror("usnewlock (wait_lock)");
150 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
151}
152
153/*
154 * Thread support.
155 */
156
157static void clean_threads _P0()
158{
159 int i;
160 pid_t pid;
161
162 /* clean up any exited threads */
163 i = 0;
164 while (i < maxpidindex) {
165 if ((pid = pidlist[i]) > 0) {
166 pid = waitpid(pid, 0, WNOHANG);
167 if (pid < 0)
168 return;
169 if (pid != 0) {
170 /* a thread has exited */
171 pidlist[i] = pidlist[--maxpidindex];
172 continue; /* don't increment i */
173 }
174 }
175 i++;
176 }
177}
178
179int start_new_thread _P2(func, void (*func) _P((void *)), arg, void *arg)
180{
181#ifdef USE_DL
182 long addr, size;
183 static int local_initialized = 0;
184#endif /* USE_DL */
185 int success = 0; /* init not needed when SOLARIS_THREADS and */
186 /* C_THREADS implemented properly */
187
188 dprintf(("start_new_thread called\n"));
189 if (!initialized)
190 init_thread();
191 switch (ussetlock(count_lock)) {
192 case 0: return 0;
193 case -1: perror("ussetlock (count_lock)");
194 }
195 if (maxpidindex >= MAXPROC)
196 success = -1;
197 else {
198#ifdef USE_DL
199 if (!local_initialized) {
200 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
201 perror("usconfig - CONF_INITSIZE (check)");
202 if (usconfig(CONF_INITSIZE, size) < 0)
203 perror("usconfig - CONF_INITSIZE (reset)");
204 addr = (long) dl_getrange(size + HDR_SIZE);
205 dprintf(("trying to use addr %lx-%lx for sproc\n", addr, addr+size));
206 errno = 0;
207 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
208 perror("usconfig - CONF_ATTACHADDR (set)");
209 }
210#endif /* USE_DL */
211 clean_threads();
212 if ((success = sproc(func, PR_SALL, arg)) < 0)
213 perror("sproc");
214#ifdef USE_DL
215 if (!local_initialized) {
216 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
217 perror("usconfig - CONF_ATTACHADDR (reset)");
218 local_initialized = 1;
219 }
220#endif /* USE_DL */
221 if (success >= 0) {
222 nthreads++;
223 pidlist[maxpidindex++] = success;
224 dprintf(("pidlist[%d] = %d\n", maxpidindex-1, success));
225 }
226 }
227 if (usunsetlock(count_lock) < 0)
228 perror("usunsetlock (count_lock)");
229 return success < 0 ? 0 : 1;
230}
231
Guido van Rossume944da81994-05-23 12:43:41 +0000232long get_thread_ident _P0()
233{
234 return getpid();
235}
236
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000237static void do_exit_thread _P1(no_cleanup, int no_cleanup)
238{
239 dprintf(("exit_thread called\n"));
240 if (!initialized)
241 if (no_cleanup)
242 _exit(0);
243 else
244 exit(0);
245 if (ussetlock(count_lock) < 0)
246 perror("ussetlock (count_lock)");
247 nthreads--;
248 if (getpid() == my_pid) {
249 /* main thread; wait for other threads to exit */
250 exiting = 1;
251#ifndef NO_EXIT_PROG
252 if (do_exit) {
253 int i;
254
255 /* notify other threads */
256 clean_threads();
257 if (nthreads >= 0) {
258 dprintf(("kill other threads\n"));
259 for (i = 0; i < maxpidindex; i++)
260 if (pidlist[i] > 0)
261 (void) kill(pidlist[i],
262 SIGKILL);
263 _exit(exit_status);
264 }
265 }
266#endif /* NO_EXIT_PROG */
267 waiting_for_threads = 1;
268 if (ussetlock(wait_lock) < 0)
269 perror("ussetlock (wait_lock)");
270 for (;;) {
271 if (nthreads < 0) {
272 dprintf(("really exit (%d)\n", exit_status));
273 if (no_cleanup)
274 _exit(exit_status);
275 else
276 exit(exit_status);
277 }
278 if (usunsetlock(count_lock) < 0)
279 perror("usunsetlock (count_lock)");
280 dprintf(("waiting for other threads (%d)\n", nthreads));
281 if (ussetlock(wait_lock) < 0)
282 perror("ussetlock (wait_lock)");
283 if (ussetlock(count_lock) < 0)
284 perror("ussetlock (count_lock)");
285 }
286 }
287 /* not the main thread */
288 if (waiting_for_threads) {
289 dprintf(("main thread is waiting\n"));
290 if (usunsetlock(wait_lock) < 0)
291 perror("usunsetlock (wait_lock)");
292 }
293#ifndef NO_EXIT_PROG
294 else if (do_exit)
295 (void) kill(my_pid, SIGUSR1);
296#endif /* NO_EXIT_PROG */
297 if (usunsetlock(count_lock) < 0)
298 perror("usunsetlock (count_lock)");
299 _exit(0);
300}
301
302void exit_thread _P0()
303{
304 do_exit_thread(0);
305}
306
307void _exit_thread _P0()
308{
309 do_exit_thread(1);
310}
311
312#ifndef NO_EXIT_PROG
313static void do_exit_prog _P2(status, int status, no_cleanup, int no_cleanup)
314{
315 dprintf(("exit_prog(%d) called\n", status));
316 if (!initialized)
317 if (no_cleanup)
318 _exit(status);
319 else
320 exit(status);
321 do_exit = 1;
322 exit_status = status;
323 do_exit_thread(no_cleanup);
324}
325
326void exit_prog _P1(status, int status)
327{
328 do_exit_prog(status, 0);
329}
330
331void _exit_prog _P1(status, int status)
332{
333 do_exit_prog(status, 1);
334}
335#endif /* NO_EXIT_PROG */
336
337/*
338 * Lock support.
339 */
340type_lock allocate_lock _P0()
341{
342 ulock_t lock;
343
344 dprintf(("allocate_lock called\n"));
345 if (!initialized)
346 init_thread();
347
348 if ((lock = usnewlock(shared_arena)) == NULL)
349 perror("usnewlock");
350 (void) usinitlock(lock);
351 dprintf(("allocate_lock() -> %lx\n", (long)lock));
352 return (type_lock) lock;
353}
354
355void free_lock _P1(lock, type_lock lock)
356{
357 dprintf(("free_lock(%lx) called\n", (long)lock));
358 usfreelock((ulock_t) lock, shared_arena);
359}
360
361int acquire_lock _P2(lock, type_lock lock, waitflag, int waitflag)
362{
363 int success;
364
365 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock, waitflag));
366 errno = 0; /* clear it just in case */
367 if (waitflag)
368 success = ussetlock((ulock_t) lock);
369 else
370 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
371 if (success < 0)
372 perror(waitflag ? "ussetlock" : "uscsetlock");
373 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock, waitflag, success));
374 return success;
375}
376
377void release_lock _P1(lock, type_lock lock)
378{
379 dprintf(("release_lock(%lx) called\n", (long)lock));
380 if (usunsetlock((ulock_t) lock) < 0)
381 perror("usunsetlock");
382}
383
384/*
385 * Semaphore support.
386 */
387type_sema allocate_sema _P1(value, int value)
388{
389 usema_t *sema;
390 dprintf(("allocate_sema called\n"));
391 if (!initialized)
392 init_thread();
393
394 if ((sema = usnewsema(shared_arena, value)) == NULL)
395 perror("usnewsema");
396 dprintf(("allocate_sema() -> %lx\n", (long) sema));
397 return (type_sema) sema;
398}
399
400void free_sema _P1(sema, type_sema sema)
401{
402 dprintf(("free_sema(%lx) called\n", (long) sema));
403 usfreesema((usema_t *) sema, shared_arena);
404}
405
406void down_sema _P1(sema, type_sema sema)
407{
408 dprintf(("down_sema(%lx) called\n", (long) sema));
409 if (uspsema((usema_t *) sema) < 0)
410 perror("uspsema");
411 dprintf(("down_sema(%lx) return\n", (long) sema));
412}
413
414void up_sema _P1(sema, type_sema sema)
415{
416 dprintf(("up_sema(%lx)\n", (long) sema));
417 if (usvsema((usema_t *) sema) < 0)
418 perror("usvsema");
419}