This commit was manufactured by cvs2svn to create tag 'r234c1'.
[python/dscho.git] / Python / thread_sgi.h
blobe24653867955bccc799cf56d5f30932a679c6937
2 #ifdef WITH_SGI_DL
3 #define USE_DL
4 #endif
6 #include <stdlib.h>
7 #include <stdio.h>
8 #include <signal.h>
9 #include <sys/types.h>
10 #include <sys/wait.h>
11 #include <sys/prctl.h>
12 #include <ulocks.h>
13 #include <errno.h>
15 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */
16 #define MAXPROC 100 /* max # of threads that can be started */
18 static usptr_t *shared_arena;
19 static ulock_t count_lock; /* protection for some variables */
20 static ulock_t wait_lock; /* lock used to wait for other threads */
21 static int waiting_for_threads; /* protected by count_lock */
22 static int nthreads; /* protected by count_lock */
23 static int exit_status;
24 #ifndef NO_EXIT_PROG
25 static int do_exit; /* indicates that the program is to exit */
26 #endif
27 static int exiting; /* we're already exiting (for maybe_exit) */
28 static pid_t my_pid; /* PID of main thread */
29 static struct pidlist {
30 pid_t parent;
31 pid_t child;
32 } pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */
33 static int maxpidindex; /* # of PIDs in pidlist */
35 #ifndef NO_EXIT_PROG
37 * This routine is called as a signal handler when another thread
38 * exits. When that happens, we must see whether we have to exit as
39 * well (because of an PyThread_exit_prog()) or whether we should continue on.
41 static void exit_sig(void)
43 d2printf(("exit_sig called\n"));
44 if (exiting && getpid() == my_pid) {
45 d2printf(("already exiting\n"));
46 return;
48 if (do_exit) {
49 d2printf(("exiting in exit_sig\n"));
50 #ifdef Py_DEBUG
51 if ((thread_debug & 8) == 0)
52 thread_debug &= ~1; /* don't produce debug messages */
53 #endif
54 PyThread_exit_thread();
59 * This routine is called when a process calls exit(). If that wasn't
60 * done from the library, we do as if an PyThread_exit_prog() was intended.
62 static void maybe_exit(void)
64 dprintf(("maybe_exit called\n"));
65 if (exiting) {
66 dprintf(("already exiting\n"));
67 return;
69 PyThread_exit_prog(0);
71 #endif /* NO_EXIT_PROG */
74 * Initialization.
76 static void PyThread__init_thread(void)
78 #ifndef NO_EXIT_PROG
79 struct sigaction s;
80 #endif /* NO_EXIT_PROG */
81 #ifdef USE_DL
82 long addr, size;
83 #endif /* USE_DL */
86 #ifdef USE_DL
87 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
88 perror("usconfig - CONF_INITSIZE (check)");
89 if (usconfig(CONF_INITSIZE, size) < 0)
90 perror("usconfig - CONF_INITSIZE (reset)");
91 addr = (long) dl_getrange(size + HDR_SIZE);
92 dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size));
93 errno = 0;
94 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0)
95 perror("usconfig - CONF_ATTACHADDR (set)");
96 #endif /* USE_DL */
97 if (usconfig(CONF_INITUSERS, 16) < 0)
98 perror("usconfig - CONF_INITUSERS");
99 my_pid = getpid(); /* so that we know which is the main thread */
100 #ifndef NO_EXIT_PROG
101 atexit(maybe_exit);
102 s.sa_handler = exit_sig;
103 sigemptyset(&s.sa_mask);
104 /*sigaddset(&s.sa_mask, SIGUSR1);*/
105 s.sa_flags = 0;
106 sigaction(SIGUSR1, &s, 0);
107 if (prctl(PR_SETEXITSIG, SIGUSR1) < 0)
108 perror("prctl - PR_SETEXITSIG");
109 #endif /* NO_EXIT_PROG */
110 if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0)
111 perror("usconfig - CONF_ARENATYPE");
112 usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */
113 #ifdef Py_DEBUG
114 if (thread_debug & 4)
115 usconfig(CONF_LOCKTYPE, US_DEBUGPLUS);
116 else if (thread_debug & 2)
117 usconfig(CONF_LOCKTYPE, US_DEBUG);
118 #endif /* Py_DEBUG */
119 if ((shared_arena = usinit(tmpnam(0))) == 0)
120 perror("usinit");
121 #ifdef USE_DL
122 if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */
123 perror("usconfig - CONF_ATTACHADDR (reset)");
124 #endif /* USE_DL */
125 if ((count_lock = usnewlock(shared_arena)) == NULL)
126 perror("usnewlock (count_lock)");
127 (void) usinitlock(count_lock);
128 if ((wait_lock = usnewlock(shared_arena)) == NULL)
129 perror("usnewlock (wait_lock)");
130 dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena)));
134 * Thread support.
137 static void clean_threads(void)
139 int i, j;
140 pid_t mypid, pid;
142 /* clean up any exited threads */
143 mypid = getpid();
144 i = 0;
145 while (i < maxpidindex) {
146 if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) {
147 pid = waitpid(pid, 0, WNOHANG);
148 if (pid > 0) {
149 /* a thread has exited */
150 pidlist[i] = pidlist[--maxpidindex];
151 /* remove references to children of dead proc */
152 for (j = 0; j < maxpidindex; j++)
153 if (pidlist[j].parent == pid)
154 pidlist[j].child = -1;
155 continue; /* don't increment i */
158 i++;
160 /* clean up the list */
161 i = 0;
162 while (i < maxpidindex) {
163 if (pidlist[i].child == -1) {
164 pidlist[i] = pidlist[--maxpidindex];
165 continue; /* don't increment i */
167 i++;
171 long PyThread_start_new_thread(void (*func)(void *), void *arg)
173 #ifdef USE_DL
174 long addr, size;
175 static int local_initialized = 0;
176 #endif /* USE_DL */
177 int success = 0; /* init not needed when SOLARIS_THREADS and */
178 /* C_THREADS implemented properly */
180 dprintf(("PyThread_start_new_thread called\n"));
181 if (!initialized)
182 PyThread_init_thread();
183 switch (ussetlock(count_lock)) {
184 case 0: return 0;
185 case -1: perror("ussetlock (count_lock)");
187 if (maxpidindex >= MAXPROC)
188 success = -1;
189 else {
190 #ifdef USE_DL
191 if (!local_initialized) {
192 if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0)
193 perror("usconfig - CONF_INITSIZE (check)");
194 if (usconfig(CONF_INITSIZE, size) < 0)
195 perror("usconfig - CONF_INITSIZE (reset)");
196 addr = (long) dl_getrange(size + HDR_SIZE);
197 dprintf(("trying to use addr %p-%p for sproc\n",
198 addr, addr+size));
199 errno = 0;
200 if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 &&
201 errno != 0)
202 perror("usconfig - CONF_ATTACHADDR (set)");
204 #endif /* USE_DL */
205 clean_threads();
206 if ((success = sproc(func, PR_SALL, arg)) < 0)
207 perror("sproc");
208 #ifdef USE_DL
209 if (!local_initialized) {
210 if (usconfig(CONF_ATTACHADDR, addr) < 0)
211 /* reset address */
212 perror("usconfig - CONF_ATTACHADDR (reset)");
213 local_initialized = 1;
215 #endif /* USE_DL */
216 if (success >= 0) {
217 nthreads++;
218 pidlist[maxpidindex].parent = getpid();
219 pidlist[maxpidindex++].child = success;
220 dprintf(("pidlist[%d] = %d\n",
221 maxpidindex-1, success));
224 if (usunsetlock(count_lock) < 0)
225 perror("usunsetlock (count_lock)");
226 return success;
229 long PyThread_get_thread_ident(void)
231 return getpid();
234 static void do_PyThread_exit_thread(int no_cleanup)
236 dprintf(("PyThread_exit_thread called\n"));
237 if (!initialized)
238 if (no_cleanup)
239 _exit(0);
240 else
241 exit(0);
242 if (ussetlock(count_lock) < 0)
243 perror("ussetlock (count_lock)");
244 nthreads--;
245 if (getpid() == my_pid) {
246 /* main thread; wait for other threads to exit */
247 exiting = 1;
248 #ifndef NO_EXIT_PROG
249 if (do_exit) {
250 int i;
252 /* notify other threads */
253 clean_threads();
254 if (nthreads >= 0) {
255 dprintf(("kill other threads\n"));
256 for (i = 0; i < maxpidindex; i++)
257 if (pidlist[i].child > 0)
258 (void) kill(pidlist[i].child,
259 SIGKILL);
260 _exit(exit_status);
263 #endif /* NO_EXIT_PROG */
264 waiting_for_threads = 1;
265 if (ussetlock(wait_lock) < 0)
266 perror("ussetlock (wait_lock)");
267 for (;;) {
268 if (nthreads < 0) {
269 dprintf(("really exit (%d)\n", exit_status));
270 if (no_cleanup)
271 _exit(exit_status);
272 else
273 exit(exit_status);
275 if (usunsetlock(count_lock) < 0)
276 perror("usunsetlock (count_lock)");
277 dprintf(("waiting for other threads (%d)\n", nthreads));
278 if (ussetlock(wait_lock) < 0)
279 perror("ussetlock (wait_lock)");
280 if (ussetlock(count_lock) < 0)
281 perror("ussetlock (count_lock)");
284 /* not the main thread */
285 if (waiting_for_threads) {
286 dprintf(("main thread is waiting\n"));
287 if (usunsetlock(wait_lock) < 0)
288 perror("usunsetlock (wait_lock)");
290 #ifndef NO_EXIT_PROG
291 else if (do_exit)
292 (void) kill(my_pid, SIGUSR1);
293 #endif /* NO_EXIT_PROG */
294 if (usunsetlock(count_lock) < 0)
295 perror("usunsetlock (count_lock)");
296 _exit(0);
299 void PyThread_exit_thread(void)
301 do_PyThread_exit_thread(0);
304 void PyThread__exit_thread(void)
306 do_PyThread_exit_thread(1);
309 #ifndef NO_EXIT_PROG
310 static void do_PyThread_exit_prog(int status, int no_cleanup)
312 dprintf(("PyThread_exit_prog(%d) called\n", status));
313 if (!initialized)
314 if (no_cleanup)
315 _exit(status);
316 else
317 exit(status);
318 do_exit = 1;
319 exit_status = status;
320 do_PyThread_exit_thread(no_cleanup);
323 void PyThread_exit_prog(int status)
325 do_PyThread_exit_prog(status, 0);
328 void PyThread__exit_prog(int status)
330 do_PyThread_exit_prog(status, 1);
332 #endif /* NO_EXIT_PROG */
335 * Lock support.
337 PyThread_type_lock PyThread_allocate_lock(void)
339 ulock_t lock;
341 dprintf(("PyThread_allocate_lock called\n"));
342 if (!initialized)
343 PyThread_init_thread();
345 if ((lock = usnewlock(shared_arena)) == NULL)
346 perror("usnewlock");
347 (void) usinitlock(lock);
348 dprintf(("PyThread_allocate_lock() -> %p\n", lock));
349 return (PyThread_type_lock) lock;
352 void PyThread_free_lock(PyThread_type_lock lock)
354 dprintf(("PyThread_free_lock(%p) called\n", lock));
355 usfreelock((ulock_t) lock, shared_arena);
358 int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
360 int success;
362 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag));
363 errno = 0; /* clear it just in case */
364 if (waitflag)
365 success = ussetlock((ulock_t) lock);
366 else
367 success = uscsetlock((ulock_t) lock, 1); /* Try it once */
368 if (success < 0)
369 perror(waitflag ? "ussetlock" : "uscsetlock");
370 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success));
371 return success;
374 void PyThread_release_lock(PyThread_type_lock lock)
376 dprintf(("PyThread_release_lock(%p) called\n", lock));
377 if (usunsetlock((ulock_t) lock) < 0)
378 perror("usunsetlock");