1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
32 #include <sys/types.h>
34 #include <sys/prctl.h>
38 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */
39 #define MAXPROC 100 /* max # of threads that can be started */
41 static usptr_t
*shared_arena
;
42 static ulock_t count_lock
; /* protection for some variables */
43 static ulock_t wait_lock
; /* lock used to wait for other threads */
44 static int waiting_for_threads
; /* protected by count_lock */
45 static int nthreads
; /* protected by count_lock */
46 static int exit_status
;
48 static int do_exit
; /* indicates that the program is to exit */
50 static int exiting
; /* we're already exiting (for maybe_exit) */
51 static pid_t my_pid
; /* PID of main thread */
52 static struct pidlist
{
55 } pidlist
[MAXPROC
]; /* PIDs of other threads; protected by count_lock */
56 static int maxpidindex
; /* # of PIDs in pidlist */
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.
64 static void exit_sig
_P0()
66 d2printf(("exit_sig called\n"));
67 if (exiting
&& getpid() == my_pid
) {
68 d2printf(("already exiting\n"));
72 d2printf(("exiting in exit_sig\n"));
74 if ((thread_debug
& 8) == 0)
75 thread_debug
&= ~1; /* don't produce debug messages */
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.
85 static void maybe_exit
_P0()
87 dprintf(("maybe_exit called\n"));
89 dprintf(("already exiting\n"));
94 #endif /* NO_EXIT_PROG */
99 static void _init_thread
_P0()
103 #endif /* NO_EXIT_PROG */
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
));
117 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 && errno
!= 0)
118 perror("usconfig - CONF_ATTACHADDR (set)");
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 */
125 s
.sa_handler
= exit_sig
;
126 sigemptyset(&s
.sa_mask
);
127 /*sigaddset(&s.sa_mask, SIGUSR1);*/
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 */
137 if (thread_debug
& 4)
138 usconfig(CONF_LOCKTYPE
, US_DEBUGPLUS
);
139 else if (thread_debug
& 2)
140 usconfig(CONF_LOCKTYPE
, US_DEBUG
);
142 if ((shared_arena
= usinit(tmpnam(0))) == 0)
145 if (usconfig(CONF_ATTACHADDR
, addr
) < 0) /* reset address */
146 perror("usconfig - CONF_ATTACHADDR (reset)");
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
)));
160 static void clean_threads
_P0()
165 /* clean up any exited threads */
168 while (i
< maxpidindex
) {
169 if (pidlist
[i
].parent
== mypid
&& (pid
= pidlist
[i
].child
) > 0) {
170 pid
= waitpid(pid
, 0, WNOHANG
);
172 /* a thread has exited */
173 pidlist
[i
] = pidlist
[--maxpidindex
];
174 /* 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;
178 continue; /* don't increment i */
183 /* clean up the list */
185 while (i
< maxpidindex
) {
186 if (pidlist
[i
].child
== -1) {
187 pidlist
[i
] = pidlist
[--maxpidindex
];
188 continue; /* don't increment i */
194 int start_new_thread
_P2(func
, void (*func
) _P((void *)), arg
, void *arg
)
198 static int local_initialized
= 0;
200 int success
= 0; /* init not needed when SOLARIS_THREADS and */
201 /* C_THREADS implemented properly */
203 dprintf(("start_new_thread called\n"));
206 switch (ussetlock(count_lock
)) {
208 case -1: perror("ussetlock (count_lock)");
210 if (maxpidindex
>= MAXPROC
)
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
);
220 dprintf(("trying to use addr %lx-%lx for sproc\n",
223 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 &&
225 perror("usconfig - CONF_ATTACHADDR (set)");
229 if ((success
= sproc(func
, PR_SALL
, arg
)) < 0)
232 if (!local_initialized
) {
233 if (usconfig(CONF_ATTACHADDR
, addr
) < 0)
235 perror("usconfig - CONF_ATTACHADDR (reset)");
236 local_initialized
= 1;
241 pidlist
[maxpidindex
].parent
= getpid();
242 pidlist
[maxpidindex
++].child
= success
;
243 dprintf(("pidlist[%d] = %d\n",
244 maxpidindex
-1, success
));
247 if (usunsetlock(count_lock
) < 0)
248 perror("usunsetlock (count_lock)");
249 return success
< 0 ? 0 : 1;
252 long get_thread_ident
_P0()
257 static void do_exit_thread
_P1(no_cleanup
, int no_cleanup
)
259 dprintf(("exit_thread called\n"));
265 if (ussetlock(count_lock
) < 0)
266 perror("ussetlock (count_lock)");
268 if (getpid() == my_pid
) {
269 /* main thread; wait for other threads to exit */
275 /* notify other threads */
278 dprintf(("kill other threads\n"));
279 for (i
= 0; i
< maxpidindex
; i
++)
280 if (pidlist
[i
].child
> 0)
281 (void) kill(pidlist
[i
].child
,
286 #endif /* NO_EXIT_PROG */
287 waiting_for_threads
= 1;
288 if (ussetlock(wait_lock
) < 0)
289 perror("ussetlock (wait_lock)");
292 dprintf(("really exit (%d)\n", exit_status
));
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)");
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)");
315 (void) kill(my_pid
, SIGUSR1
);
316 #endif /* NO_EXIT_PROG */
317 if (usunsetlock(count_lock
) < 0)
318 perror("usunsetlock (count_lock)");
322 void exit_thread
_P0()
327 void _exit_thread
_P0()
333 static void do_exit_prog
_P2(status
, int status
, no_cleanup
, int no_cleanup
)
335 dprintf(("exit_prog(%d) called\n", status
));
342 exit_status
= status
;
343 do_exit_thread(no_cleanup
);
346 void exit_prog
_P1(status
, int status
)
348 do_exit_prog(status
, 0);
351 void _exit_prog
_P1(status
, int status
)
353 do_exit_prog(status
, 1);
355 #endif /* NO_EXIT_PROG */
360 type_lock allocate_lock
_P0()
364 dprintf(("allocate_lock called\n"));
368 if ((lock
= usnewlock(shared_arena
)) == NULL
)
370 (void) usinitlock(lock
);
371 dprintf(("allocate_lock() -> %lx\n", (long)lock
));
372 return (type_lock
) lock
;
375 void free_lock
_P1(lock
, type_lock lock
)
377 dprintf(("free_lock(%lx) called\n", (long)lock
));
378 usfreelock((ulock_t
) lock
, shared_arena
);
381 int acquire_lock
_P2(lock
, type_lock lock
, waitflag
, int waitflag
)
385 dprintf(("acquire_lock(%lx, %d) called\n", (long)lock
, waitflag
));
386 errno
= 0; /* clear it just in case */
388 success
= ussetlock((ulock_t
) lock
);
390 success
= uscsetlock((ulock_t
) lock
, 1); /* Try it once */
392 perror(waitflag
? "ussetlock" : "uscsetlock");
393 dprintf(("acquire_lock(%lx, %d) -> %d\n", (long)lock
, waitflag
, success
));
397 void release_lock
_P1(lock
, type_lock lock
)
399 dprintf(("release_lock(%lx) called\n", (long)lock
));
400 if (usunsetlock((ulock_t
) lock
) < 0)
401 perror("usunsetlock");
407 type_sema allocate_sema
_P1(value
, int value
)
410 dprintf(("allocate_sema called\n"));
414 if ((sema
= usnewsema(shared_arena
, value
)) == NULL
)
416 dprintf(("allocate_sema() -> %lx\n", (long) sema
));
417 return (type_sema
) sema
;
420 void free_sema
_P1(sema
, type_sema sema
)
422 dprintf(("free_sema(%lx) called\n", (long) sema
));
423 usfreesema((usema_t
*) sema
, shared_arena
);
426 void down_sema
_P1(sema
, type_sema sema
)
428 dprintf(("down_sema(%lx) called\n", (long) sema
));
429 if (uspsema((usema_t
*) sema
) < 0)
431 dprintf(("down_sema(%lx) return\n", (long) sema
));
434 void up_sema
_P1(sema
, type_sema sema
)
436 dprintf(("up_sema(%lx)\n", (long) sema
));
437 if (usvsema((usema_t
*) sema
) < 0)