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 or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
39 #include <sys/types.h>
41 #include <sys/prctl.h>
45 #define HDR_SIZE 2680 /* sizeof(ushdr_t) */
46 #define MAXPROC 100 /* max # of threads that can be started */
48 static usptr_t
*shared_arena
;
49 static ulock_t count_lock
; /* protection for some variables */
50 static ulock_t wait_lock
; /* lock used to wait for other threads */
51 static int waiting_for_threads
; /* protected by count_lock */
52 static int nthreads
; /* protected by count_lock */
53 static int exit_status
;
55 static int do_exit
; /* indicates that the program is to exit */
57 static int exiting
; /* we're already exiting (for maybe_exit) */
58 static pid_t my_pid
; /* PID of main thread */
59 static struct pidlist
{
62 } pidlist
[MAXPROC
]; /* PIDs of other threads; protected by count_lock */
63 static int maxpidindex
; /* # of PIDs in pidlist */
67 * This routine is called as a signal handler when another thread
68 * exits. When that happens, we must see whether we have to exit as
69 * well (because of an PyThread_exit_prog()) or whether we should continue on.
71 static void exit_sig
_P0()
73 d2printf(("exit_sig called\n"));
74 if (exiting
&& getpid() == my_pid
) {
75 d2printf(("already exiting\n"));
79 d2printf(("exiting in exit_sig\n"));
81 if ((thread_debug
& 8) == 0)
82 thread_debug
&= ~1; /* don't produce debug messages */
84 PyThread_exit_thread();
89 * This routine is called when a process calls exit(). If that wasn't
90 * done from the library, we do as if an PyThread_exit_prog() was intended.
92 static void maybe_exit
_P0()
94 dprintf(("maybe_exit called\n"));
96 dprintf(("already exiting\n"));
99 PyThread_exit_prog(0);
101 #endif /* NO_EXIT_PROG */
106 static void PyThread__init_thread
_P0()
110 #endif /* NO_EXIT_PROG */
117 if ((size
= usconfig(CONF_INITSIZE
, 64*1024)) < 0)
118 perror("usconfig - CONF_INITSIZE (check)");
119 if (usconfig(CONF_INITSIZE
, size
) < 0)
120 perror("usconfig - CONF_INITSIZE (reset)");
121 addr
= (long) dl_getrange(size
+ HDR_SIZE
);
122 dprintf(("trying to use addr %lx-%lx for shared arena\n", addr
, addr
+size
));
124 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 && errno
!= 0)
125 perror("usconfig - CONF_ATTACHADDR (set)");
127 if (usconfig(CONF_INITUSERS
, 16) < 0)
128 perror("usconfig - CONF_INITUSERS");
129 my_pid
= getpid(); /* so that we know which is the main thread */
132 s
.sa_handler
= exit_sig
;
133 sigemptyset(&s
.sa_mask
);
134 /*sigaddset(&s.sa_mask, SIGUSR1);*/
136 sigaction(SIGUSR1
, &s
, 0);
137 if (prctl(PR_SETEXITSIG
, SIGUSR1
) < 0)
138 perror("prctl - PR_SETEXITSIG");
139 #endif /* NO_EXIT_PROG */
140 if (usconfig(CONF_ARENATYPE
, US_SHAREDONLY
) < 0)
141 perror("usconfig - CONF_ARENATYPE");
142 usconfig(CONF_LOCKTYPE
, US_DEBUG
); /* XXX */
144 if (thread_debug
& 4)
145 usconfig(CONF_LOCKTYPE
, US_DEBUGPLUS
);
146 else if (thread_debug
& 2)
147 usconfig(CONF_LOCKTYPE
, US_DEBUG
);
148 #endif /* Py_DEBUG */
149 if ((shared_arena
= usinit(tmpnam(0))) == 0)
152 if (usconfig(CONF_ATTACHADDR
, addr
) < 0) /* reset address */
153 perror("usconfig - CONF_ATTACHADDR (reset)");
155 if ((count_lock
= usnewlock(shared_arena
)) == NULL
)
156 perror("usnewlock (count_lock)");
157 (void) usinitlock(count_lock
);
158 if ((wait_lock
= usnewlock(shared_arena
)) == NULL
)
159 perror("usnewlock (wait_lock)");
160 dprintf(("arena start: %lx, arena size: %ld\n", (long) shared_arena
, (long) usconfig(CONF_GETSIZE
, shared_arena
)));
167 static void clean_threads
_P0()
172 /* clean up any exited threads */
175 while (i
< maxpidindex
) {
176 if (pidlist
[i
].parent
== mypid
&& (pid
= pidlist
[i
].child
) > 0) {
177 pid
= waitpid(pid
, 0, WNOHANG
);
179 /* a thread has exited */
180 pidlist
[i
] = pidlist
[--maxpidindex
];
181 /* remove references to children of dead proc */
182 for (j
= 0; j
< maxpidindex
; j
++)
183 if (pidlist
[j
].parent
== pid
)
184 pidlist
[j
].child
= -1;
185 continue; /* don't increment i */
190 /* clean up the list */
192 while (i
< maxpidindex
) {
193 if (pidlist
[i
].child
== -1) {
194 pidlist
[i
] = pidlist
[--maxpidindex
];
195 continue; /* don't increment i */
201 int PyThread_start_new_thread
_P2(func
, void (*func
) _P((void *)), arg
, void *arg
)
205 static int local_initialized
= 0;
207 int success
= 0; /* init not needed when SOLARIS_THREADS and */
208 /* C_THREADS implemented properly */
210 dprintf(("PyThread_start_new_thread called\n"));
212 PyThread_init_thread();
213 switch (ussetlock(count_lock
)) {
215 case -1: perror("ussetlock (count_lock)");
217 if (maxpidindex
>= MAXPROC
)
221 if (!local_initialized
) {
222 if ((size
= usconfig(CONF_INITSIZE
, 64*1024)) < 0)
223 perror("usconfig - CONF_INITSIZE (check)");
224 if (usconfig(CONF_INITSIZE
, size
) < 0)
225 perror("usconfig - CONF_INITSIZE (reset)");
226 addr
= (long) dl_getrange(size
+ HDR_SIZE
);
227 dprintf(("trying to use addr %lx-%lx for sproc\n",
230 if ((addr
= usconfig(CONF_ATTACHADDR
, addr
)) < 0 &&
232 perror("usconfig - CONF_ATTACHADDR (set)");
236 if ((success
= sproc(func
, PR_SALL
, arg
)) < 0)
239 if (!local_initialized
) {
240 if (usconfig(CONF_ATTACHADDR
, addr
) < 0)
242 perror("usconfig - CONF_ATTACHADDR (reset)");
243 local_initialized
= 1;
248 pidlist
[maxpidindex
].parent
= getpid();
249 pidlist
[maxpidindex
++].child
= success
;
250 dprintf(("pidlist[%d] = %d\n",
251 maxpidindex
-1, success
));
254 if (usunsetlock(count_lock
) < 0)
255 perror("usunsetlock (count_lock)");
256 return success
< 0 ? 0 : 1;
259 long PyThread_get_thread_ident
_P0()
264 static void do_PyThread_exit_thread
_P1(no_cleanup
, int no_cleanup
)
266 dprintf(("PyThread_exit_thread called\n"));
272 if (ussetlock(count_lock
) < 0)
273 perror("ussetlock (count_lock)");
275 if (getpid() == my_pid
) {
276 /* main thread; wait for other threads to exit */
282 /* notify other threads */
285 dprintf(("kill other threads\n"));
286 for (i
= 0; i
< maxpidindex
; i
++)
287 if (pidlist
[i
].child
> 0)
288 (void) kill(pidlist
[i
].child
,
293 #endif /* NO_EXIT_PROG */
294 waiting_for_threads
= 1;
295 if (ussetlock(wait_lock
) < 0)
296 perror("ussetlock (wait_lock)");
299 dprintf(("really exit (%d)\n", exit_status
));
305 if (usunsetlock(count_lock
) < 0)
306 perror("usunsetlock (count_lock)");
307 dprintf(("waiting for other threads (%d)\n", nthreads
));
308 if (ussetlock(wait_lock
) < 0)
309 perror("ussetlock (wait_lock)");
310 if (ussetlock(count_lock
) < 0)
311 perror("ussetlock (count_lock)");
314 /* not the main thread */
315 if (waiting_for_threads
) {
316 dprintf(("main thread is waiting\n"));
317 if (usunsetlock(wait_lock
) < 0)
318 perror("usunsetlock (wait_lock)");
322 (void) kill(my_pid
, SIGUSR1
);
323 #endif /* NO_EXIT_PROG */
324 if (usunsetlock(count_lock
) < 0)
325 perror("usunsetlock (count_lock)");
329 void PyThread_exit_thread
_P0()
331 do_PyThread_exit_thread(0);
334 void PyThread__exit_thread
_P0()
336 do_PyThread_exit_thread(1);
340 static void do_PyThread_exit_prog
_P2(status
, int status
, no_cleanup
, int no_cleanup
)
342 dprintf(("PyThread_exit_prog(%d) called\n", status
));
349 exit_status
= status
;
350 do_PyThread_exit_thread(no_cleanup
);
353 void PyThread_exit_prog
_P1(status
, int status
)
355 do_PyThread_exit_prog(status
, 0);
358 void PyThread__exit_prog
_P1(status
, int status
)
360 do_PyThread_exit_prog(status
, 1);
362 #endif /* NO_EXIT_PROG */
367 PyThread_type_lock PyThread_allocate_lock
_P0()
371 dprintf(("PyThread_allocate_lock called\n"));
373 PyThread_init_thread();
375 if ((lock
= usnewlock(shared_arena
)) == NULL
)
377 (void) usinitlock(lock
);
378 dprintf(("PyThread_allocate_lock() -> %lx\n", (long)lock
));
379 return (PyThread_type_lock
) lock
;
382 void PyThread_free_lock
_P1(lock
, PyThread_type_lock lock
)
384 dprintf(("PyThread_free_lock(%lx) called\n", (long)lock
));
385 usfreelock((ulock_t
) lock
, shared_arena
);
388 int PyThread_acquire_lock
_P2(lock
, PyThread_type_lock lock
, waitflag
, int waitflag
)
392 dprintf(("PyThread_acquire_lock(%lx, %d) called\n", (long)lock
, waitflag
));
393 errno
= 0; /* clear it just in case */
395 success
= ussetlock((ulock_t
) lock
);
397 success
= uscsetlock((ulock_t
) lock
, 1); /* Try it once */
399 perror(waitflag
? "ussetlock" : "uscsetlock");
400 dprintf(("PyThread_acquire_lock(%lx, %d) -> %d\n", (long)lock
, waitflag
, success
));
404 void PyThread_release_lock
_P1(lock
, PyThread_type_lock lock
)
406 dprintf(("PyThread_release_lock(%lx) called\n", (long)lock
));
407 if (usunsetlock((ulock_t
) lock
) < 0)
408 perror("usunsetlock");
414 PyThread_type_sema PyThread_allocate_sema
_P1(value
, int value
)
417 dprintf(("PyThread_allocate_sema called\n"));
419 PyThread_init_thread();
421 if ((sema
= usnewsema(shared_arena
, value
)) == NULL
)
423 dprintf(("PyThread_allocate_sema() -> %lx\n", (long) sema
));
424 return (PyThread_type_sema
) sema
;
427 void PyThread_free_sema
_P1(sema
, PyThread_type_sema sema
)
429 dprintf(("PyThread_free_sema(%lx) called\n", (long) sema
));
430 usfreesema((usema_t
*) sema
, shared_arena
);
433 int PyThread_down_sema
_P2(sema
, PyThread_type_sema sema
, waitflag
, int waitflag
)
437 dprintf(("PyThread_down_sema(%lx) called\n", (long) sema
));
439 success
= uspsema((usema_t
*) sema
);
441 success
= uscpsema((usema_t
*) sema
);
443 perror(waitflag
? "uspsema" : "uscpsema");
444 dprintf(("PyThread_down_sema(%lx) return\n", (long) sema
));
448 void PyThread_up_sema
_P1(sema
, PyThread_type_sema sema
)
450 dprintf(("PyThread_up_sema(%lx)\n", (long) sema
));
451 if (usvsema((usema_t
*) sema
) < 0)
456 * Per-thread data ("key") support.
466 static struct key
*keyhead
= NULL
;
467 static int nkeys
= 0;
468 static PyThread_type_lock keymutex
= NULL
;
470 static struct key
*find_key
_P2(key
, int key
, value
, void *value
)
473 long id
= PyThread_get_thread_ident();
474 for (p
= keyhead
; p
!= NULL
; p
= p
->next
) {
475 if (p
->id
== id
&& p
->key
== key
)
480 p
= (struct key
*)malloc(sizeof(struct key
));
485 PyThread_acquire_lock(keymutex
, 1);
488 PyThread_release_lock(keymutex
);
493 int PyThread_create_key
_P0()
495 if (keymutex
== NULL
)
496 keymutex
= PyThread_allocate_lock();
500 void PyThread_delete_key
_P1(key
, int key
)
503 PyThread_acquire_lock(keymutex
, 1);
505 while ((p
= *q
) != NULL
) {
509 /* NB This does *not* free p->value! */
514 PyThread_release_lock(keymutex
);
517 int PyThread_set_key_value
_P2(key
, int key
, value
, void *value
)
519 struct key
*p
= find_key(key
, value
);
526 void *PyThread_get_key_value
_P1(key
, int key
)
528 struct key
*p
= find_key(key
, NULL
);