You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
379 lines
9.8 KiB
379 lines
9.8 KiB
|
|
#ifdef WITH_SGI_DL |
|
#define USE_DL |
|
#endif |
|
|
|
#include <stdlib.h> |
|
#include <stdio.h> |
|
#include <signal.h> |
|
#include <sys/types.h> |
|
#include <sys/wait.h> |
|
#include <sys/prctl.h> |
|
#include <ulocks.h> |
|
#include <errno.h> |
|
|
|
#define HDR_SIZE 2680 /* sizeof(ushdr_t) */ |
|
#define MAXPROC 100 /* max # of threads that can be started */ |
|
|
|
static usptr_t *shared_arena; |
|
static ulock_t count_lock; /* protection for some variables */ |
|
static ulock_t wait_lock; /* lock used to wait for other threads */ |
|
static int waiting_for_threads; /* protected by count_lock */ |
|
static int nthreads; /* protected by count_lock */ |
|
static int exit_status; |
|
#ifndef NO_EXIT_PROG |
|
static int do_exit; /* indicates that the program is to exit */ |
|
#endif |
|
static int exiting; /* we're already exiting (for maybe_exit) */ |
|
static pid_t my_pid; /* PID of main thread */ |
|
static struct pidlist { |
|
pid_t parent; |
|
pid_t child; |
|
} pidlist[MAXPROC]; /* PIDs of other threads; protected by count_lock */ |
|
static int maxpidindex; /* # of PIDs in pidlist */ |
|
|
|
#ifndef NO_EXIT_PROG |
|
/* |
|
* This routine is called as a signal handler when another thread |
|
* exits. When that happens, we must see whether we have to exit as |
|
* well (because of an PyThread_exit_prog()) or whether we should continue on. |
|
*/ |
|
static void exit_sig(void) |
|
{ |
|
d2printf(("exit_sig called\n")); |
|
if (exiting && getpid() == my_pid) { |
|
d2printf(("already exiting\n")); |
|
return; |
|
} |
|
if (do_exit) { |
|
d2printf(("exiting in exit_sig\n")); |
|
#ifdef Py_DEBUG |
|
if ((thread_debug & 8) == 0) |
|
thread_debug &= ~1; /* don't produce debug messages */ |
|
#endif |
|
PyThread_exit_thread(); |
|
} |
|
} |
|
|
|
/* |
|
* This routine is called when a process calls exit(). If that wasn't |
|
* done from the library, we do as if an PyThread_exit_prog() was intended. |
|
*/ |
|
static void maybe_exit(void) |
|
{ |
|
dprintf(("maybe_exit called\n")); |
|
if (exiting) { |
|
dprintf(("already exiting\n")); |
|
return; |
|
} |
|
PyThread_exit_prog(0); |
|
} |
|
#endif /* NO_EXIT_PROG */ |
|
|
|
/* |
|
* Initialization. |
|
*/ |
|
static void PyThread__init_thread(void) |
|
{ |
|
#ifndef NO_EXIT_PROG |
|
struct sigaction s; |
|
#endif /* NO_EXIT_PROG */ |
|
#ifdef USE_DL |
|
long addr, size; |
|
#endif /* USE_DL */ |
|
|
|
|
|
#ifdef USE_DL |
|
if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) |
|
perror("usconfig - CONF_INITSIZE (check)"); |
|
if (usconfig(CONF_INITSIZE, size) < 0) |
|
perror("usconfig - CONF_INITSIZE (reset)"); |
|
addr = (long) dl_getrange(size + HDR_SIZE); |
|
dprintf(("trying to use addr %p-%p for shared arena\n", addr, addr+size)); |
|
errno = 0; |
|
if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && errno != 0) |
|
perror("usconfig - CONF_ATTACHADDR (set)"); |
|
#endif /* USE_DL */ |
|
if (usconfig(CONF_INITUSERS, 16) < 0) |
|
perror("usconfig - CONF_INITUSERS"); |
|
my_pid = getpid(); /* so that we know which is the main thread */ |
|
#ifndef NO_EXIT_PROG |
|
atexit(maybe_exit); |
|
s.sa_handler = exit_sig; |
|
sigemptyset(&s.sa_mask); |
|
/*sigaddset(&s.sa_mask, SIGUSR1);*/ |
|
s.sa_flags = 0; |
|
sigaction(SIGUSR1, &s, 0); |
|
if (prctl(PR_SETEXITSIG, SIGUSR1) < 0) |
|
perror("prctl - PR_SETEXITSIG"); |
|
#endif /* NO_EXIT_PROG */ |
|
if (usconfig(CONF_ARENATYPE, US_SHAREDONLY) < 0) |
|
perror("usconfig - CONF_ARENATYPE"); |
|
usconfig(CONF_LOCKTYPE, US_DEBUG); /* XXX */ |
|
#ifdef Py_DEBUG |
|
if (thread_debug & 4) |
|
usconfig(CONF_LOCKTYPE, US_DEBUGPLUS); |
|
else if (thread_debug & 2) |
|
usconfig(CONF_LOCKTYPE, US_DEBUG); |
|
#endif /* Py_DEBUG */ |
|
if ((shared_arena = usinit(tmpnam(0))) == 0) |
|
perror("usinit"); |
|
#ifdef USE_DL |
|
if (usconfig(CONF_ATTACHADDR, addr) < 0) /* reset address */ |
|
perror("usconfig - CONF_ATTACHADDR (reset)"); |
|
#endif /* USE_DL */ |
|
if ((count_lock = usnewlock(shared_arena)) == NULL) |
|
perror("usnewlock (count_lock)"); |
|
(void) usinitlock(count_lock); |
|
if ((wait_lock = usnewlock(shared_arena)) == NULL) |
|
perror("usnewlock (wait_lock)"); |
|
dprintf(("arena start: %p, arena size: %ld\n", shared_arena, (long) usconfig(CONF_GETSIZE, shared_arena))); |
|
} |
|
|
|
/* |
|
* Thread support. |
|
*/ |
|
|
|
static void clean_threads(void) |
|
{ |
|
int i, j; |
|
pid_t mypid, pid; |
|
|
|
/* clean up any exited threads */ |
|
mypid = getpid(); |
|
i = 0; |
|
while (i < maxpidindex) { |
|
if (pidlist[i].parent == mypid && (pid = pidlist[i].child) > 0) { |
|
pid = waitpid(pid, 0, WNOHANG); |
|
if (pid > 0) { |
|
/* a thread has exited */ |
|
pidlist[i] = pidlist[--maxpidindex]; |
|
/* remove references to children of dead proc */ |
|
for (j = 0; j < maxpidindex; j++) |
|
if (pidlist[j].parent == pid) |
|
pidlist[j].child = -1; |
|
continue; /* don't increment i */ |
|
} |
|
} |
|
i++; |
|
} |
|
/* clean up the list */ |
|
i = 0; |
|
while (i < maxpidindex) { |
|
if (pidlist[i].child == -1) { |
|
pidlist[i] = pidlist[--maxpidindex]; |
|
continue; /* don't increment i */ |
|
} |
|
i++; |
|
} |
|
} |
|
|
|
long PyThread_start_new_thread(void (*func)(void *), void *arg) |
|
{ |
|
#ifdef USE_DL |
|
long addr, size; |
|
static int local_initialized = 0; |
|
#endif /* USE_DL */ |
|
int success = 0; /* init not needed when SOLARIS_THREADS and */ |
|
/* C_THREADS implemented properly */ |
|
|
|
dprintf(("PyThread_start_new_thread called\n")); |
|
if (!initialized) |
|
PyThread_init_thread(); |
|
switch (ussetlock(count_lock)) { |
|
case 0: return 0; |
|
case -1: perror("ussetlock (count_lock)"); |
|
} |
|
if (maxpidindex >= MAXPROC) |
|
success = -1; |
|
else { |
|
#ifdef USE_DL |
|
if (!local_initialized) { |
|
if ((size = usconfig(CONF_INITSIZE, 64*1024)) < 0) |
|
perror("usconfig - CONF_INITSIZE (check)"); |
|
if (usconfig(CONF_INITSIZE, size) < 0) |
|
perror("usconfig - CONF_INITSIZE (reset)"); |
|
addr = (long) dl_getrange(size + HDR_SIZE); |
|
dprintf(("trying to use addr %p-%p for sproc\n", |
|
addr, addr+size)); |
|
errno = 0; |
|
if ((addr = usconfig(CONF_ATTACHADDR, addr)) < 0 && |
|
errno != 0) |
|
perror("usconfig - CONF_ATTACHADDR (set)"); |
|
} |
|
#endif /* USE_DL */ |
|
clean_threads(); |
|
if ((success = sproc(func, PR_SALL, arg)) < 0) |
|
perror("sproc"); |
|
#ifdef USE_DL |
|
if (!local_initialized) { |
|
if (usconfig(CONF_ATTACHADDR, addr) < 0) |
|
/* reset address */ |
|
perror("usconfig - CONF_ATTACHADDR (reset)"); |
|
local_initialized = 1; |
|
} |
|
#endif /* USE_DL */ |
|
if (success >= 0) { |
|
nthreads++; |
|
pidlist[maxpidindex].parent = getpid(); |
|
pidlist[maxpidindex++].child = success; |
|
dprintf(("pidlist[%d] = %d\n", |
|
maxpidindex-1, success)); |
|
} |
|
} |
|
if (usunsetlock(count_lock) < 0) |
|
perror("usunsetlock (count_lock)"); |
|
return success; |
|
} |
|
|
|
long PyThread_get_thread_ident(void) |
|
{ |
|
return getpid(); |
|
} |
|
|
|
static void do_PyThread_exit_thread(int no_cleanup) |
|
{ |
|
dprintf(("PyThread_exit_thread called\n")); |
|
if (!initialized) |
|
if (no_cleanup) |
|
_exit(0); |
|
else |
|
exit(0); |
|
if (ussetlock(count_lock) < 0) |
|
perror("ussetlock (count_lock)"); |
|
nthreads--; |
|
if (getpid() == my_pid) { |
|
/* main thread; wait for other threads to exit */ |
|
exiting = 1; |
|
#ifndef NO_EXIT_PROG |
|
if (do_exit) { |
|
int i; |
|
|
|
/* notify other threads */ |
|
clean_threads(); |
|
if (nthreads >= 0) { |
|
dprintf(("kill other threads\n")); |
|
for (i = 0; i < maxpidindex; i++) |
|
if (pidlist[i].child > 0) |
|
(void) kill(pidlist[i].child, |
|
SIGKILL); |
|
_exit(exit_status); |
|
} |
|
} |
|
#endif /* NO_EXIT_PROG */ |
|
waiting_for_threads = 1; |
|
if (ussetlock(wait_lock) < 0) |
|
perror("ussetlock (wait_lock)"); |
|
for (;;) { |
|
if (nthreads < 0) { |
|
dprintf(("really exit (%d)\n", exit_status)); |
|
if (no_cleanup) |
|
_exit(exit_status); |
|
else |
|
exit(exit_status); |
|
} |
|
if (usunsetlock(count_lock) < 0) |
|
perror("usunsetlock (count_lock)"); |
|
dprintf(("waiting for other threads (%d)\n", nthreads)); |
|
if (ussetlock(wait_lock) < 0) |
|
perror("ussetlock (wait_lock)"); |
|
if (ussetlock(count_lock) < 0) |
|
perror("ussetlock (count_lock)"); |
|
} |
|
} |
|
/* not the main thread */ |
|
if (waiting_for_threads) { |
|
dprintf(("main thread is waiting\n")); |
|
if (usunsetlock(wait_lock) < 0) |
|
perror("usunsetlock (wait_lock)"); |
|
} |
|
#ifndef NO_EXIT_PROG |
|
else if (do_exit) |
|
(void) kill(my_pid, SIGUSR1); |
|
#endif /* NO_EXIT_PROG */ |
|
if (usunsetlock(count_lock) < 0) |
|
perror("usunsetlock (count_lock)"); |
|
_exit(0); |
|
} |
|
|
|
void PyThread_exit_thread(void) |
|
{ |
|
do_PyThread_exit_thread(0); |
|
} |
|
|
|
void PyThread__exit_thread(void) |
|
{ |
|
do_PyThread_exit_thread(1); |
|
} |
|
|
|
#ifndef NO_EXIT_PROG |
|
static void do_PyThread_exit_prog(int status, int no_cleanup) |
|
{ |
|
dprintf(("PyThread_exit_prog(%d) called\n", status)); |
|
if (!initialized) |
|
if (no_cleanup) |
|
_exit(status); |
|
else |
|
exit(status); |
|
do_exit = 1; |
|
exit_status = status; |
|
do_PyThread_exit_thread(no_cleanup); |
|
} |
|
|
|
void PyThread_exit_prog(int status) |
|
{ |
|
do_PyThread_exit_prog(status, 0); |
|
} |
|
|
|
void PyThread__exit_prog(int status) |
|
{ |
|
do_PyThread_exit_prog(status, 1); |
|
} |
|
#endif /* NO_EXIT_PROG */ |
|
|
|
/* |
|
* Lock support. |
|
*/ |
|
PyThread_type_lock PyThread_allocate_lock(void) |
|
{ |
|
ulock_t lock; |
|
|
|
dprintf(("PyThread_allocate_lock called\n")); |
|
if (!initialized) |
|
PyThread_init_thread(); |
|
|
|
if ((lock = usnewlock(shared_arena)) == NULL) |
|
perror("usnewlock"); |
|
(void) usinitlock(lock); |
|
dprintf(("PyThread_allocate_lock() -> %p\n", lock)); |
|
return (PyThread_type_lock) lock; |
|
} |
|
|
|
void PyThread_free_lock(PyThread_type_lock lock) |
|
{ |
|
dprintf(("PyThread_free_lock(%p) called\n", lock)); |
|
usfreelock((ulock_t) lock, shared_arena); |
|
} |
|
|
|
int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag) |
|
{ |
|
int success; |
|
|
|
dprintf(("PyThread_acquire_lock(%p, %d) called\n", lock, waitflag)); |
|
errno = 0; /* clear it just in case */ |
|
if (waitflag) |
|
success = ussetlock((ulock_t) lock); |
|
else |
|
success = uscsetlock((ulock_t) lock, 1); /* Try it once */ |
|
if (success < 0) |
|
perror(waitflag ? "ussetlock" : "uscsetlock"); |
|
dprintf(("PyThread_acquire_lock(%p, %d) -> %d\n", lock, waitflag, success)); |
|
return success; |
|
} |
|
|
|
void PyThread_release_lock(PyThread_type_lock lock) |
|
{ |
|
dprintf(("PyThread_release_lock(%p) called\n", lock)); |
|
if (usunsetlock((ulock_t) lock) < 0) |
|
perror("usunsetlock"); |
|
}
|
|
|