1 /***********************************************************
2 Copyright (c) 2000, BeOpen.com.
3 Copyright (c) 1995-2000, Corporation for National Research Initiatives.
4 Copyright (c) 1990-1995, Stichting Mathematisch Centrum.
7 See the file "Misc/COPYRIGHT" for information on usage and
8 redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
9 ******************************************************************/
18 #include <sys/types.h>
20 #include <sys/prctl.h>
24 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */
25 #define MAXPROC 100 /* max # of threads that can be started */
27 static usptr_t
*shared_arena
;
28 static ulock_t count_lock
; /* protection for some variables */
29 static ulock_t wait_lock
; /* lock used to wait for other threads */
30 static int waiting_for_threads
; /* protected by count_lock */
31 static int nthreads
; /* protected by count_lock */
32 static int exit_status
;
34 static int do_exit
; /* indicates that the program is to exit */
36 static int exiting
; /* we're already exiting (for maybe_exit) */
37 static pid_t my_pid
; /* PID of main thread */
38 static struct pidlist
{
41 } pidlist
[MAXPROC
]; /* PIDs of other threads; protected by count_lock */
42 static int maxpidindex
; /* # of PIDs in pidlist */
46 * This routine is called as a signal handler when another thread
47 * exits. When that happens, we must see whether we have to exit as
48 * well (because of an PyThread_exit_prog()) or whether we should continue on.
50 static void exit_sig(void)
52 d2printf(("exit_sig called\n"));
53 if (exiting
&& getpid() == my_pid
) {
54 d2printf(("already exiting\n"));
58 d2printf(("exiting in exit_sig\n"));
60 if ((thread_debug
& 8) == 0)
61 thread_debug
&= ~1; /* don't produce debug messages */
63 PyThread_exit_thread();
68 * This routine is called when a process calls exit(). If that wasn't
69 * done from the library, we do as if an PyThread_exit_prog() was intended.
71 static void maybe_exit(void)
73 dprintf(("maybe_exit called\n"));
75 dprintf(("already exiting\n"));
78 PyThread_exit_prog(0);
80 #endif /* NO_EXIT_PROG */
85 static void PyThread__init_thread(void)
89 #endif /* NO_EXIT_PROG */
96 if ((size
= usconfig(CONF_INITSIZE
, 64*1024)) < 0)
97 perror("usconfig - CONF_INITSIZE (check)");
98 if (usconfig(CONF_INITSIZE
, size
) < 0)
99 perror("usconfig - CONF_INITSIZE (reset)");
100 addr
= (long) dl_getrange(size
+ HDR_SIZE
);
101 dprintf(("trying to use addr %p-%p for shared arena\n", addr
, addr
+size
));
103 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 && errno
!= 0)
104 perror("usconfig - CONF_ATTACHADDR (set)");
106 if (usconfig(CONF_INITUSERS
, 16) < 0)
107 perror("usconfig - CONF_INITUSERS");
108 my_pid
= getpid(); /* so that we know which is the main thread */
111 s
.sa_handler
= exit_sig
;
112 sigemptyset(&s
.sa_mask
);
113 /*sigaddset(&s.sa_mask, SIGUSR1);*/
115 sigaction(SIGUSR1
, &s
, 0);
116 if (prctl(PR_SETEXITSIG
, SIGUSR1
) < 0)
117 perror("prctl - PR_SETEXITSIG");
118 #endif /* NO_EXIT_PROG */
119 if (usconfig(CONF_ARENATYPE
, US_SHAREDONLY
) < 0)
120 perror("usconfig - CONF_ARENATYPE");
121 usconfig(CONF_LOCKTYPE
, US_DEBUG
); /* XXX */
123 if (thread_debug
& 4)
124 usconfig(CONF_LOCKTYPE
, US_DEBUGPLUS
);
125 else if (thread_debug
& 2)
126 usconfig(CONF_LOCKTYPE
, US_DEBUG
);
127 #endif /* Py_DEBUG */
128 if ((shared_arena
= usinit(tmpnam(0))) == 0)
131 if (usconfig(CONF_ATTACHADDR
, addr
) < 0) /* reset address */
132 perror("usconfig - CONF_ATTACHADDR (reset)");
134 if ((count_lock
= usnewlock(shared_arena
)) == NULL
)
135 perror("usnewlock (count_lock)");
136 (void) usinitlock(count_lock
);
137 if ((wait_lock
= usnewlock(shared_arena
)) == NULL
)
138 perror("usnewlock (wait_lock)");
139 dprintf(("arena start: %p, arena size: %ld\n", shared_arena
, (long) usconfig(CONF_GETSIZE
, shared_arena
)));
146 static void clean_threads(void)
151 /* clean up any exited threads */
154 while (i
< maxpidindex
) {
155 if (pidlist
[i
].parent
== mypid
&& (pid
= pidlist
[i
].child
) > 0) {
156 pid
= waitpid(pid
, 0, WNOHANG
);
158 /* a thread has exited */
159 pidlist
[i
] = pidlist
[--maxpidindex
];
160 /* remove references to children of dead proc */
161 for (j
= 0; j
< maxpidindex
; j
++)
162 if (pidlist
[j
].parent
== pid
)
163 pidlist
[j
].child
= -1;
164 continue; /* don't increment i */
169 /* clean up the list */
171 while (i
< maxpidindex
) {
172 if (pidlist
[i
].child
== -1) {
173 pidlist
[i
] = pidlist
[--maxpidindex
];
174 continue; /* don't increment i */
180 int PyThread_start_new_thread(void (*func
)(void *), void *arg
)
184 static int local_initialized
= 0;
186 int success
= 0; /* init not needed when SOLARIS_THREADS and */
187 /* C_THREADS implemented properly */
189 dprintf(("PyThread_start_new_thread called\n"));
191 PyThread_init_thread();
192 switch (ussetlock(count_lock
)) {
194 case -1: perror("ussetlock (count_lock)");
196 if (maxpidindex
>= MAXPROC
)
200 if (!local_initialized
) {
201 if ((size
= usconfig(CONF_INITSIZE
, 64*1024)) < 0)
202 perror("usconfig - CONF_INITSIZE (check)");
203 if (usconfig(CONF_INITSIZE
, size
) < 0)
204 perror("usconfig - CONF_INITSIZE (reset)");
205 addr
= (long) dl_getrange(size
+ HDR_SIZE
);
206 dprintf(("trying to use addr %p-%p for sproc\n",
209 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 &&
211 perror("usconfig - CONF_ATTACHADDR (set)");
215 if ((success
= sproc(func
, PR_SALL
, arg
)) < 0)
218 if (!local_initialized
) {
219 if (usconfig(CONF_ATTACHADDR
, addr
) < 0)
221 perror("usconfig - CONF_ATTACHADDR (reset)");
222 local_initialized
= 1;
227 pidlist
[maxpidindex
].parent
= getpid();
228 pidlist
[maxpidindex
++].child
= success
;
229 dprintf(("pidlist[%d] = %d\n",
230 maxpidindex
-1, success
));
233 if (usunsetlock(count_lock
) < 0)
234 perror("usunsetlock (count_lock)");
235 return success
< 0 ? 0 : 1;
238 long PyThread_get_thread_ident(void)
243 static void do_PyThread_exit_thread(int no_cleanup
)
245 dprintf(("PyThread_exit_thread called\n"));
251 if (ussetlock(count_lock
) < 0)
252 perror("ussetlock (count_lock)");
254 if (getpid() == my_pid
) {
255 /* main thread; wait for other threads to exit */
261 /* notify other threads */
264 dprintf(("kill other threads\n"));
265 for (i
= 0; i
< maxpidindex
; i
++)
266 if (pidlist
[i
].child
> 0)
267 (void) kill(pidlist
[i
].child
,
272 #endif /* NO_EXIT_PROG */
273 waiting_for_threads
= 1;
274 if (ussetlock(wait_lock
) < 0)
275 perror("ussetlock (wait_lock)");
278 dprintf(("really exit (%d)\n", exit_status
));
284 if (usunsetlock(count_lock
) < 0)
285 perror("usunsetlock (count_lock)");
286 dprintf(("waiting for other threads (%d)\n", nthreads
));
287 if (ussetlock(wait_lock
) < 0)
288 perror("ussetlock (wait_lock)");
289 if (ussetlock(count_lock
) < 0)
290 perror("ussetlock (count_lock)");
293 /* not the main thread */
294 if (waiting_for_threads
) {
295 dprintf(("main thread is waiting\n"));
296 if (usunsetlock(wait_lock
) < 0)
297 perror("usunsetlock (wait_lock)");
301 (void) kill(my_pid
, SIGUSR1
);
302 #endif /* NO_EXIT_PROG */
303 if (usunsetlock(count_lock
) < 0)
304 perror("usunsetlock (count_lock)");
308 void PyThread_exit_thread(void)
310 do_PyThread_exit_thread(0);
313 void PyThread__exit_thread(void)
315 do_PyThread_exit_thread(1);
319 static void do_PyThread_exit_prog(int status
, int no_cleanup
)
321 dprintf(("PyThread_exit_prog(%d) called\n", status
));
328 exit_status
= status
;
329 do_PyThread_exit_thread(no_cleanup
);
332 void PyThread_exit_prog(int status
)
334 do_PyThread_exit_prog(status
, 0);
337 void PyThread__exit_prog(int status
)
339 do_PyThread_exit_prog(status
, 1);
341 #endif /* NO_EXIT_PROG */
346 PyThread_type_lock
PyThread_allocate_lock(void)
350 dprintf(("PyThread_allocate_lock called\n"));
352 PyThread_init_thread();
354 if ((lock
= usnewlock(shared_arena
)) == NULL
)
356 (void) usinitlock(lock
);
357 dprintf(("PyThread_allocate_lock() -> %p\n", lock
));
358 return (PyThread_type_lock
) lock
;
361 void PyThread_free_lock(PyThread_type_lock lock
)
363 dprintf(("PyThread_free_lock(%p) called\n", lock
));
364 usfreelock((ulock_t
) lock
, shared_arena
);
367 int PyThread_acquire_lock(PyThread_type_lock lock
, int waitflag
)
371 dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock
, waitflag
));
372 errno
= 0; /* clear it just in case */
374 success
= ussetlock((ulock_t
) lock
);
376 success
= uscsetlock((ulock_t
) lock
, 1); /* Try it once */
378 perror(waitflag
? "ussetlock" : "uscsetlock");
379 dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock
, waitflag
, success
));
383 void PyThread_release_lock(PyThread_type_lock lock
)
385 dprintf(("PyThread_release_lock(%p) called\n", lock
));
386 if (usunsetlock((ulock_t
) lock
) < 0)
387 perror("usunsetlock");
393 PyThread_type_sema
PyThread_allocate_sema(int value
)
396 dprintf(("PyThread_allocate_sema called\n"));
398 PyThread_init_thread();
400 if ((sema
= usnewsema(shared_arena
, value
)) == NULL
)
402 dprintf(("PyThread_allocate_sema() -> %p\n", sema
));
403 return (PyThread_type_sema
) sema
;
406 void PyThread_free_sema(PyThread_type_sema sema
)
408 dprintf(("PyThread_free_sema(%p) called\n", sema
));
409 usfreesema((usema_t
*) sema
, shared_arena
);
412 int PyThread_down_sema(PyThread_type_sema sema
, int waitflag
)
416 dprintf(("PyThread_down_sema(%p) called\n", sema
));
418 success
= uspsema((usema_t
*) sema
);
420 success
= uscpsema((usema_t
*) sema
);
422 perror(waitflag
? "uspsema" : "uscpsema");
423 dprintf(("PyThread_down_sema(%p) return\n", sema
));
427 void PyThread_up_sema(PyThread_type_sema sema
)
429 dprintf(("PyThread_up_sema(%p)\n", sema
));
430 if (usvsema((usema_t
*) sema
) < 0)
435 * Per-thread data ("key") support.
445 static struct key
*keyhead
= NULL
;
446 static int nkeys
= 0;
447 static PyThread_type_lock keymutex
= NULL
;
449 static struct key
*find_key(int key
, void *value
)
452 long id
= PyThread_get_thread_ident();
453 for (p
= keyhead
; p
!= NULL
; p
= p
->next
) {
454 if (p
->id
== id
&& p
->key
== key
)
459 p
= (struct key
*)malloc(sizeof(struct key
));
464 PyThread_acquire_lock(keymutex
, 1);
467 PyThread_release_lock(keymutex
);
472 int PyThread_create_key(void)
474 if (keymutex
== NULL
)
475 keymutex
= PyThread_allocate_lock();
479 void PyThread_delete_key(int key
)
482 PyThread_acquire_lock(keymutex
, 1);
484 while ((p
= *q
) != NULL
) {
488 /* NB This does *not* free p->value! */
493 PyThread_release_lock(keymutex
);
496 int PyThread_set_key_value(int key
, void *value
)
498 struct key
*p
= find_key(key
, value
);
505 void *PyThread_get_key_value(int key
)
507 struct key
*p
= find_key(key
, NULL
);