blob: 234665848b7f9b4db162e3763e05abbf1bf3a286 [file] [log] [blame]
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00001
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +00002#include <stdlib.h>
3#include <stdio.h>
4#include <signal.h>
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <sys/prctl.h>
8#include <ulocks.h>
9#include <errno.h>
10
11#define HDR_SIZE 2680 /* sizeof(ushdr_t) */
12#define MAXPROC 100 /* max # of threads that can be started */
13
14static usptr_t *shared_arena;
15static ulock_t count_lock; /* protection for some variables */
16static ulock_t wait_lock; /* lock used to wait for other threads */
17static int waiting_for_threads; /* protected by count_lock */
18static int nthreads; /* protected by count_lock */
19static int exit_status;
20#ifndef NO_EXIT_PROG
21static int do_exit; /* indicates that the program is to exit */
22#endif
23static int exiting; /* we're already exiting (for maybe_exit) */
24static pid_t my_pid; /* PID of main thread */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +000025static struct pidlist {
26 pid_t parent;
27 pid_t child;
28} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000029static int maxpidindex; /* # of PIDs in pidlist */
30
31#ifndef NO_EXIT_PROG
32/*
33 * This routine is called as a signal handler when another thread
34 * exits. When that happens, we must see whether we have to exit as
Guido van Rossum65d5b571998-12-21 19:32:43 +000035 * well (because of an PyThread_exit_prog()) or whether we should continue on.
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000036 */
Thomas Woutersf70ef4f2000-07-22 18:47:25 +000037static void exit_sig(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000038{
39 d2printf(("exit_sig called\n"));
40 if (exiting && getpid() == my_pid) {
41 d2printf(("already exiting\n"));
42 return;
43 }
44 if (do_exit) {
45 d2printf(("exiting in exit_sig\n"));
Guido van Rossum408027e1996-12-30 16:17:54 +000046#ifdef Py_DEBUG
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000047 if ((thread_debug & 8) == 0)
48 thread_debug &= ~1; /* don't produce debug messages */
49#endif
Guido van Rossum65d5b571998-12-21 19:32:43 +000050 PyThread_exit_thread();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000051 }
52}
53
54/*
55 * This routine is called when a process calls exit(). If that wasn't
Guido van Rossum65d5b571998-12-21 19:32:43 +000056 * done from the library, we do as if an PyThread_exit_prog() was intended.
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000057 */
Thomas Woutersf70ef4f2000-07-22 18:47:25 +000058static void maybe_exit(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000059{
60 dprintf(("maybe_exit called\n"));
61 if (exiting) {
62 dprintf(("already exiting\n"));
63 return;
64 }
Guido van Rossum65d5b571998-12-21 19:32:43 +000065 PyThread_exit_prog(0);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000066}
67#endif /* NO_EXIT_PROG */
68
69/*
70 * Initialization.
71 */
Thomas Woutersf70ef4f2000-07-22 18:47:25 +000072static void PyThread__init_thread(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000073{
74#ifndef NO_EXIT_PROG
75 struct sigaction s;
76#endif /* NO_EXIT_PROG */
77#ifdef USE_DL
78 long addr, size;
79#endif /* USE_DL */
80
81
82#ifdef USE_DL
83 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
84 perror("usconfig - CONF_INITSIZE (check)");
85 if (usconfig(CONF_INITSIZE, size) < 0)
86 perror("usconfig - CONF_INITSIZE (reset)");
87 addr = (long) dl_getrange(size + HDR_SIZE);
Fred Drakea44d3532000-06-30 15:01:00 +000088 dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +000089 errno = 0;
90 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
91 perror("usconfig - CONF_ATTACHADDR (set)");
92#endif /* USE_DL */
93 if (usconfig(CONF_INITUSERS, 16) < 0)
94 perror("usconfig - CONF_INITUSERS");
95 my_pid = getpid(); /* so that we know which is the main thread */
96#ifndef NO_EXIT_PROG
97 atexit(maybe_exit);
98 s.sa_handler = exit_sig;
99 sigemptyset(&s.sa_mask);
100 /*sigaddset(&s.sa_mask, SIGUSR1);*/
101 s.sa_flags = 0;
102 sigaction(SIGUSR1, &s, 0);
103 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
104 perror("prctl - PR_SETEXITSIG");
105#endif /* NO_EXIT_PROG */
106 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
107 perror("usconfig - CONF_ARENATYPE");
108 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
Guido van Rossum408027e1996-12-30 16:17:54 +0000109#ifdef Py_DEBUG
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000110 if (thread_debug & 4)
111 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
112 else if (thread_debug & 2)
113 usconfig(CONF_LOCKTYPE, US_DEBUG);
Guido van Rossum408027e1996-12-30 16:17:54 +0000114#endif /* Py_DEBUG */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000115 if ((shared_arena = usinit(tmpnam(0))) == 0)
116 perror("usinit");
117#ifdef USE_DL
118 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
119 perror("usconfig - CONF_ATTACHADDR (reset)");
120#endif /* USE_DL */
121 if ((count_lock = usnewlock(shared_arena)) == NULL)
122 perror("usnewlock (count_lock)");
123 (void) usinitlock(count_lock);
124 if ((wait_lock = usnewlock(shared_arena)) == NULL)
125 perror("usnewlock (wait_lock)");
Fred Drakea44d3532000-06-30 15:01:00 +0000126 dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000127}
128
129/*
130 * Thread support.
131 */
132
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000133static void clean_threads(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000134{
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000135 int i, j;
136 pid_t mypid, pid;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000137
138 /* clean up any exited threads */
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000139 mypid = getpid();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000140 i = 0;
141 while (i < maxpidindex) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000142 if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000143 pid = waitpid(pid, 0, WNOHANG);
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000144 if (pid > 0) {
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000145 /* a thread has exited */
146 pidlist[i] = pidlist[--maxpidindex];
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000147 /* remove references to children of dead proc */
148 for (j = 0; j < maxpidindex; j++)
149 if (pidlist[j].parent == pid)
150 pidlist[j].child = -1;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000151 continue; /* don't increment i */
152 }
153 }
154 i++;
155 }
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000156 /* clean up the list */
157 i = 0;
158 while (i < maxpidindex) {
159 if (pidlist[i].child == -1) {
160 pidlist[i] = pidlist[--maxpidindex];
161 continue; /* don't increment i */
162 }
163 i++;
164 }
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000165}
166
Guido van Rossum3c288632001-10-16 21:13:49 +0000167long PyThread_start_new_thread(void (*func)(void *), void *arg)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000168{
169#ifdef USE_DL
170 long addr, size;
171 static int local_initialized = 0;
172#endif /* USE_DL */
173 int success = 0; /* init not needed when SOLARIS_THREADS and */
174 /* C_THREADS implemented properly */
175
Guido van Rossum65d5b571998-12-21 19:32:43 +0000176 dprintf(("PyThread_start_new_thread called\n"));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000177 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000178 PyThread_init_thread();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000179 switch (ussetlock(count_lock)) {
180 case 0: return 0;
181 case -1: perror("ussetlock (count_lock)");
182 }
183 if (maxpidindex >= MAXPROC)
184 success = -1;
185 else {
186#ifdef USE_DL
187 if (!local_initialized) {
188 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
189 perror("usconfig - CONF_INITSIZE (check)");
190 if (usconfig(CONF_INITSIZE, size) < 0)
191 perror("usconfig - CONF_INITSIZE (reset)");
192 addr = (long) dl_getrange(size + HDR_SIZE);
Fred Drakea44d3532000-06-30 15:01:00 +0000193 dprintf(("trying to use addr %p-%p for sproc\n",
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000194 addr, addr+size));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000195 errno = 0;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000196 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
197 errno != 0)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000198 perror("usconfig - CONF_ATTACHADDR (set)");
199 }
200#endif /* USE_DL */
201 clean_threads();
202 if ((success = sproc(func, PR_SALL, arg)) < 0)
203 perror("sproc");
204#ifdef USE_DL
205 if (!local_initialized) {
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000206 if (usconfig(CONF_ATTACHADDR, addr) < 0)
207 /* reset address */
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000208 perror("usconfig - CONF_ATTACHADDR (reset)");
209 local_initialized = 1;
210 }
211#endif /* USE_DL */
212 if (success >= 0) {
213 nthreads++;
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000214 pidlist[maxpidindex].parent = getpid();
215 pidlist[maxpidindex++].child = success;
216 dprintf(("pidlist[%d] = %d\n",
217 maxpidindex-1, success));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000218 }
219 }
220 if (usunsetlock(count_lock) < 0)
221 perror("usunsetlock (count_lock)");
Guido van Rossum3c288632001-10-16 21:13:49 +0000222 return success;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000223}
224
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000225long PyThread_get_thread_ident(void)
Guido van Rossume944da81994-05-23 12:43:41 +0000226{
227 return getpid();
228}
229
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000230static void do_PyThread_exit_thread(int no_cleanup)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000231{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000232 dprintf(("PyThread_exit_thread called\n"));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000233 if (!initialized)
234 if (no_cleanup)
235 _exit(0);
236 else
237 exit(0);
238 if (ussetlock(count_lock) < 0)
239 perror("ussetlock (count_lock)");
240 nthreads--;
241 if (getpid() == my_pid) {
242 /* main thread; wait for other threads to exit */
243 exiting = 1;
244#ifndef NO_EXIT_PROG
245 if (do_exit) {
246 int i;
247
248 /* notify other threads */
249 clean_threads();
250 if (nthreads >= 0) {
251 dprintf(("kill other threads\n"));
252 for (i = 0; i < maxpidindex; i++)
Guido van Rossum6f5f8dd1994-05-30 13:39:05 +0000253 if (pidlist[i].child > 0)
254 (void) kill(pidlist[i].child,
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000255 SIGKILL);
256 _exit(exit_status);
257 }
258 }
259#endif /* NO_EXIT_PROG */
260 waiting_for_threads = 1;
261 if (ussetlock(wait_lock) < 0)
262 perror("ussetlock (wait_lock)");
263 for (;;) {
264 if (nthreads < 0) {
265 dprintf(("really exit (%d)\n", exit_status));
266 if (no_cleanup)
267 _exit(exit_status);
268 else
269 exit(exit_status);
270 }
271 if (usunsetlock(count_lock) < 0)
272 perror("usunsetlock (count_lock)");
273 dprintf(("waiting for other threads (%d)\n", nthreads));
274 if (ussetlock(wait_lock) < 0)
275 perror("ussetlock (wait_lock)");
276 if (ussetlock(count_lock) < 0)
277 perror("ussetlock (count_lock)");
278 }
279 }
280 /* not the main thread */
281 if (waiting_for_threads) {
282 dprintf(("main thread is waiting\n"));
283 if (usunsetlock(wait_lock) < 0)
284 perror("usunsetlock (wait_lock)");
285 }
286#ifndef NO_EXIT_PROG
287 else if (do_exit)
288 (void) kill(my_pid, SIGUSR1);
289#endif /* NO_EXIT_PROG */
290 if (usunsetlock(count_lock) < 0)
291 perror("usunsetlock (count_lock)");
292 _exit(0);
293}
294
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000295void PyThread_exit_thread(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000296{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000297 do_PyThread_exit_thread(0);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000298}
299
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000300void PyThread__exit_thread(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000301{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000302 do_PyThread_exit_thread(1);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000303}
304
305#ifndef NO_EXIT_PROG
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000306static void do_PyThread_exit_prog(int status, int no_cleanup)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000307{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000308 dprintf(("PyThread_exit_prog(%d) called\n", status));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000309 if (!initialized)
310 if (no_cleanup)
311 _exit(status);
312 else
313 exit(status);
314 do_exit = 1;
315 exit_status = status;
Guido van Rossum65d5b571998-12-21 19:32:43 +0000316 do_PyThread_exit_thread(no_cleanup);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000317}
318
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000319void PyThread_exit_prog(int status)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000320{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000321 do_PyThread_exit_prog(status, 0);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000322}
323
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000324void PyThread__exit_prog(int status)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000325{
Guido van Rossum65d5b571998-12-21 19:32:43 +0000326 do_PyThread_exit_prog(status, 1);
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000327}
328#endif /* NO_EXIT_PROG */
329
330/*
331 * Lock support.
332 */
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000333PyThread_type_lock PyThread_allocate_lock(void)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000334{
335 ulock_t lock;
336
Guido van Rossum65d5b571998-12-21 19:32:43 +0000337 dprintf(("PyThread_allocate_lock called\n"));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000338 if (!initialized)
Guido van Rossum65d5b571998-12-21 19:32:43 +0000339 PyThread_init_thread();
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000340
341 if ((lock = usnewlock(shared_arena)) == NULL)
342 perror("usnewlock");
343 (void) usinitlock(lock);
Fred Drakea44d3532000-06-30 15:01:00 +0000344 dprintf(("PyThread_allocate_lock() -> %p\n", lock));
Guido van Rossum65d5b571998-12-21 19:32:43 +0000345 return (PyThread_type_lock) lock;
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000346}
347
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000348void PyThread_free_lock(PyThread_type_lock lock)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000349{
Fred Drakea44d3532000-06-30 15:01:00 +0000350 dprintf(("PyThread_free_lock(%p) called\n", lock));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000351 usfreelock((ulock_t) lock, shared_arena);
352}
353
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000354int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000355{
356 int success;
357
Fred Drakea44d3532000-06-30 15:01:00 +0000358 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000359 errno = 0; /* clear it just in case */
360 if (waitflag)
361 success = ussetlock((ulock_t) lock);
362 else
363 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
364 if (success < 0)
365 perror(waitflag ? "ussetlock" : "uscsetlock");
Fred Drakea44d3532000-06-30 15:01:00 +0000366 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000367 return success;
368}
369
Thomas Woutersf70ef4f2000-07-22 18:47:25 +0000370void PyThread_release_lock(PyThread_type_lock lock)
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000371{
Fred Drakea44d3532000-06-30 15:01:00 +0000372 dprintf(("PyThread_release_lock(%p) called\n", lock));
Guido van Rossum2c8cb9f1994-05-09 15:12:46 +0000373 if (usunsetlock((ulock_t) lock) < 0)
374 perror("usunsetlock");
375}