[Places] Fix SIGCHLD

svn: r17140
This commit is contained in:
Kevin Tew 2009-12-01 17:26:54 +00:00
parent 788d913bba
commit 93488dfe1e
8 changed files with 287 additions and 54 deletions

View File

@ -356,8 +356,10 @@ Scheme_Env *scheme_engine_instance_init() {
#endif
#if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
scheme_places_block_child_signal();
GC_switch_out_master_gc();
spawn_master_scheme_place();
scheme_spawn_master_place();
#endif
place_instance_init_pre_kernel(stack_base);
@ -367,7 +369,7 @@ Scheme_Env *scheme_engine_instance_init() {
#if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
{
int signal_fd;
int *signal_fd;
signal_fd = scheme_get_signal_handle();
GC_set_put_external_event_fd(signal_fd);
}
@ -508,7 +510,7 @@ static Scheme_Env *place_instance_init_post_kernel(int initial_main_os_thread) {
Scheme_Env *scheme_place_instance_init(void *stack_base) {
Scheme_Env *env;
#if defined(MZ_PRECISE_GC) && defined(MZ_USE_PLACES)
int signal_fd;
int *signal_fd;
GC_construct_child_gc();
#endif
place_instance_init_pre_kernel(stack_base);

View File

@ -3582,7 +3582,7 @@ static int mark_input_fd_FIXUP(void *p) {
#endif
#if defined(UNIX_PROCESSES)
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
static int mark_system_child_SIZE(void *p) {
return
gcBYTES_TO_WORDS(sizeof(System_Child));

View File

@ -72,7 +72,8 @@ static void rungdb() {
case 'd':
snprintf(outbuffer, 100, "xterm -e gdb ./mzscheme3m %d &", pid);
fprintf(stderr, "%s\n", outbuffer);
system(outbuffer);
if(system(outbuffer))
fprintf(stderr, "system failed\n");
break;
case 'e':
default:

View File

@ -39,6 +39,7 @@ static Scheme_Object *not_implemented(int argc, Scheme_Object **argv)
# ifdef MZ_PRECISE_GC
static void register_traversers(void) { }
# endif
#endif
@ -133,10 +134,151 @@ Scheme_Object *scheme_place(int argc, Scheme_Object *args[]) {
}
#ifdef MZ_PRECISE_GC
/*============= SIGNAL HANDLER =============*/
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
static void error_info() {
char *erstr;
erstr = strerror(errno);
printf("errno %i %s\n", errno, erstr);
}
typedef struct Child_Status {
int pid;
int status;
void *signal_fd;
struct Child_Status *next;
} Child_Status;
static Child_Status *child_statuses = NULL;
static mzrt_mutex* child_status_lock = NULL;
static void add_child_status(int pid, int status) {
Child_Status *st;
st = malloc(sizeof(Child_Status));
st->pid = pid;
st->signal_fd = NULL;
st->status = status;
mzrt_mutex_lock(child_status_lock);
st->next = child_statuses;
child_statuses = st;
mzrt_mutex_unlock(child_status_lock);
}
static int raw_get_child_status(int pid, int *status) {
Child_Status *st;
Child_Status *prev;
int found = 0;
for (st = child_statuses, prev = NULL; st; prev = st, st = st->next) {
if (st->pid == pid) {
*status = st->status;
found = 1;
if (prev) {
prev->next = st->next;
}
else {
child_statuses = st->next;
}
free(st);
break;
}
}
return found;
}
int scheme_get_child_status(int pid, int *status) {
int found = 0;
mzrt_mutex_lock(child_status_lock);
found = raw_get_child_status(pid, status);
mzrt_mutex_unlock(child_status_lock);
/* printf("scheme_get_child_status found %i pid %i status %i\n", found, pid, *status); */
return found;
}
int scheme_places_register_child(int pid, void *signal_fd, int *status) {
int found = 0;
mzrt_mutex_lock(child_status_lock);
found = raw_get_child_status(pid, status);
if (!found) {
Child_Status *st;
st = malloc(sizeof(Child_Status));
st->pid = pid;
st->signal_fd = signal_fd;
st->status = 0;
st->next = child_statuses;
child_statuses = st;
}
mzrt_mutex_unlock(child_status_lock);
return found;
}
static void *mz_proc_thread_signal_worker(void *data) {
int status;
int pid;
sigset_t set;
//GC_CAN_IGNORE siginfo_t info;
{
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
pthread_sigmask(SIG_UNBLOCK, &set, NULL);
}
while(1) {
int rc;
int signalid;
do {
rc = sigwait(&set, &signalid);
if (rc == -1) {
if (errno != EINTR ) {
error_info();
}
}
} while (rc == -1 && errno == EINTR);
pid = waitpid((pid_t)-1, &status, WNOHANG);
if (pid == -1) {
char *erstr;
erstr = strerror(errno);
/* printf("errno %i %s\n", errno, erstr); */
}
else {
/* printf("SIGCHILD pid %i with status %i %i\n", pid, status, WEXITSTATUS(status)); */
add_child_status(pid, status);
}
};
return NULL;
}
void scheme_places_block_child_signal() {
{
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGCHLD);
pthread_sigmask(SIG_BLOCK, &set, NULL);
}
{
mz_proc_thread *signal_thread;
mzrt_mutex_create(&child_status_lock);
signal_thread = mz_proc_thread_create(mz_proc_thread_signal_worker, NULL);
mz_proc_thread_detach(signal_thread);
}
}
/*============= THREAD JOIN HANDLER =============*/
typedef struct {
mz_proc_thread *proc_thread;
Scheme_Place *waiting_place;
int wake_fd;
int *wake_fd;
int ready;
long rc;
} proc_thread_wait_data;
@ -149,7 +291,7 @@ static void *mz_proc_thread_wait_worker(void *data) {
rc = mz_proc_thread_wait(wd->proc_thread);
wd->rc = (long) rc;
wd->ready = 1;
scheme_signal_received_at(&wd->wake_fd);
scheme_signal_received_at(wd->wake_fd);
return NULL;
}
@ -171,7 +313,7 @@ static Scheme_Object *scheme_place_wait(int argc, Scheme_Object *args[]) {
Scheme_Object *rc;
mz_proc_thread *worker_thread;
Scheme_Place *waiting_place;
int wake_fd;
int *wake_fd;
proc_thread_wait_data *wd;
wd = (proc_thread_wait_data*) malloc(sizeof(proc_thread_wait_data));
@ -285,7 +427,7 @@ static void *place_start_proc(void *data_arg) {
stack_base = PROMPT_STACK(stack_base);
place_data = (Place_Start_Data *) data_arg;
printf("Startin place: proc thread id%u\n", ptid);
/* printf("Startin place: proc thread id%u\n", ptid); */
/* create pristine THREAD_LOCAL variables*/
null_out_runtime_globals();
@ -328,6 +470,8 @@ Scheme_Object *scheme_places_deep_copy_in_master(Scheme_Object *so) {
#ifdef MZ_PRECISE_GC
static void* scheme_master_place_handlemsg(int msg_type, void *msg_payload);
#if 0
static void *master_scheme_place(void *data) {
mz_proc_thread *myself;
myself = proc_thread_self;
@ -345,6 +489,7 @@ static void *master_scheme_place(void *data) {
}
return NULL;
}
#endif
static void* scheme_master_place_handlemsg(int msg_type, void *msg_payload)
{
@ -390,7 +535,7 @@ void* scheme_master_fast_path(int msg_type, void *msg_payload) {
}
void spawn_master_scheme_place() {
void scheme_spawn_master_place() {
mzrt_proc_first_thread_init();

View File

@ -169,7 +169,7 @@ int scheme_stupid_windows_machine;
/******************** Unix Subprocesses ********************/
#if defined(UNIX_PROCESSES)
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
/* For process & system: */
typedef struct System_Child {
MZTAG_IF_REQUIRED
@ -186,6 +186,10 @@ typedef struct Scheme_Subprocess {
Scheme_Object so;
void *handle;
int pid;
#if defined(UNIX_PROCESSES) && defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
short done;
int status;
#endif
} Scheme_Subprocess;
#ifdef USE_FD_PORTS
@ -486,7 +490,7 @@ scheme_init_port (Scheme_Env *env)
REGISTER_SO(scheme_null_output_port_type);
REGISTER_SO(scheme_redirect_output_port_type);
#if defined(UNIX_PROCESSES)
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
REGISTER_SO(scheme_system_children);
#endif
@ -6787,7 +6791,7 @@ static int MyPipe(int *ph, int near_index) {
/**************** Unix: signal stuff ******************/
#if defined(UNIX_PROCESSES)
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
# define WAITANY(s) waitpid((pid_t)-1, s, WNOHANG)
@ -6800,6 +6804,7 @@ static int need_to_check_children;
void scheme_block_child_signals(int block)
XFORM_SKIP_PROC
{
#if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
sigset_t sigs;
sigemptyset(&sigs);
@ -6808,6 +6813,7 @@ void scheme_block_child_signals(int block)
sigaddset(&sigs, SIGPROF);
#endif
sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL);
#endif
}
static void child_done(int ingored)
@ -6825,6 +6831,7 @@ static int sigchld_installed = 0;
static void init_sigchld(void)
{
#if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
if (!sigchld_installed) {
/* Catch child-done signals */
START_XFORM_SKIP;
@ -6833,6 +6840,7 @@ static void init_sigchld(void)
sigchld_installed = 1;
}
#endif
}
static void check_child_done()
@ -7073,24 +7081,47 @@ scheme_make_redirect_output_port(Scheme_Object *port)
#if defined(UNIX_PROCESSES) || defined(WINDOWS_PROCESSES)
static int subp_done(Scheme_Object *sp)
static int subp_done(Scheme_Object *so)
{
void *sci = ((Scheme_Subprocess *)sp)->handle;
Scheme_Subprocess *sp;
sp = (Scheme_Subprocess*) so;
#if defined(UNIX_PROCESSES)
System_Child *sc = (System_Child *)sci;
check_child_done();
return sc->done;
#endif
#ifdef WINDOWS_PROCESSES
DWORD w;
if (sci) {
if (GetExitCodeProcess((HANDLE)sci, &w))
return w != STILL_ACTIVE;
# if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
{
int status;
if(! sp->done) {
if(scheme_get_child_status(((Scheme_Subprocess *)sp)->pid, &status)) {
sp->done = 1;
sp->status = status;
return 1;
}
return 0;
}
else
return 1;
} else
return 1;
}
# else
{
System_Child *sc;
sc = ((System_Child *) ((Scheme_Subprocess *)sp)->handle);
check_child_done();
return sc->done;
}
# endif
#endif
#ifdef WINDOWS_PROCESSES
{
HANDLE sci = (HANDLE) ((Scheme_Subprocess *)sp)->handle;
DWORD w;
if (sci) {
if (GetExitCodeProcess(sci, &w))
return w != STILL_ACTIVE;
else
return 1;
} else
return 1;
}
#endif
}
@ -7116,14 +7147,23 @@ static Scheme_Object *subprocess_status(int argc, Scheme_Object **argv)
int going = 0, status = MZ_FAILURE_STATUS;
#if defined(UNIX_PROCESSES)
System_Child *sc = (System_Child *)sp->handle;
check_child_done();
if (sc->done)
status = sc->status;
else
# if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
if (sp->done)
status = sp->status;
else {
if(!scheme_get_child_status(((Scheme_Subprocess *)sp)->pid, &status)) {
going = 1;
}
}
# else
System_Child *sc = (System_Child *)sp->handle;
check_child_done();
if (sc->done)
status = sc->status;
else
going = 1;
# endif
#else
# ifdef WINDOWS_PROCESSES
DWORD w;
@ -7189,23 +7229,34 @@ static Scheme_Object *subprocess_kill(int argc, Scheme_Object **argv)
Scheme_Subprocess *sp = (Scheme_Subprocess *)argv[0];
#if defined(UNIX_PROCESSES)
{
System_Child *sc = (System_Child *)sp->handle;
check_child_done();
while (1) {
if (sc->done)
return scheme_void;
if (!kill(sp->pid, SCHEME_TRUEP(argv[1]) ? SIGKILL : SIGINT))
return scheme_void;
if (errno != EINTR)
break;
/* Otherwise we were interrupted. Try `kill' again. */
}
# if defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC)
{
int status;
if (sp->done)
return scheme_void;
if(scheme_get_child_status(sp->pid, &status)) {
return scheme_void;
}
}
# else
{
System_Child *sc = (System_Child *)sp->handle;
check_child_done();
if (sc->done)
return scheme_void;
}
# endif
while (1) {
if (!kill(sp->pid, SCHEME_TRUEP(argv[1]) ? SIGKILL : SIGINT))
return scheme_void;
if (errno != EINTR)
break;
/* Otherwise we were interrupted. Try `kill' again. */
}
#else
if (SCHEME_TRUEP(argv[1])) {
DWORD w;
@ -7369,6 +7420,16 @@ static long mz_spawnv(char *command, const char * const *argv,
static void close_subprocess_handle(void *sp, void *ignored)
{
Scheme_Subprocess *subproc = (Scheme_Subprocess *)sp;
#if defined(MZ_USE_PLACES) && defined (MZ_PRECISE_GC)
{
int status;
int pid = ((Scheme_Subprocess *)sp)->pid;
scheme_get_child_status(pid, &status)
/* printf("close_subprocess_handle pid %i status %i\n", pid status); */
}
#endif
CloseHandle(subproc->handle);
}
@ -7387,7 +7448,9 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
char **argv;
Scheme_Object *in, *out, *err;
#if defined(UNIX_PROCESSES)
# if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
System_Child *sc;
# endif
int fork_errno = 0;
#else
void *sc = 0;
@ -7609,6 +7672,7 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
/*--------------------------------------*/
{
#if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
init_sigchld();
sc = MALLOC_ONE_RT(System_Child);
@ -7619,13 +7683,25 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
sc->done = 0;
scheme_block_child_signals(1);
#endif
pid = fork();
if (pid > 0) {
#if defined(MZ_USE_PLACES) && defined (MZ_PRECISE_GC)
{
int *signal_fd;
int status;
signal_fd = scheme_get_signal_handle();
scheme_places_register_child(pid, signal_fd, &status);
/* printf("SUBPROCESS %i\n", pid); */
}
#else
sc->next = scheme_system_children;
scheme_system_children = sc;
sc->id = pid;
#endif
} else if (!pid) {
#ifdef USE_ITIMER
/* Turn off the timer. */
@ -7659,7 +7735,9 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
fork_errno = errno;
}
#if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
scheme_block_child_signals(0);
#endif
}
switch (pid)
@ -7807,7 +7885,9 @@ static Scheme_Object *subprocess(int c, Scheme_Object *args[])
subproc = MALLOC_ONE_TAGGED(Scheme_Subprocess);
subproc->so.type = scheme_subprocess_type;
#if !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
subproc->handle = (void *)sc;
#endif
subproc->pid = pid;
# if defined(WINDOWS_PROCESSES)
scheme_add_finalizer(subproc, close_subprocess_handle, NULL);
@ -8781,7 +8861,7 @@ static void register_traversers(void)
GC_REG_TRAV(scheme_rt_input_fd, mark_input_fd);
#endif
#if defined(UNIX_PROCESSES)
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined (MZ_PRECISE_GC))
GC_REG_TRAV(scheme_rt_system_child, mark_system_child);
#endif

View File

@ -539,6 +539,7 @@ static int check_cycles(Scheme_Object *obj, int for_write, Scheme_Hash_Table *ht
version takes to long, we back out to the general case. (We don't
even check for stack overflow, so keep the max limit low.) */
#if !defined(MZ_USE_PLACES)
static int check_cycles_fast(Scheme_Object *obj, PrintParams *pp, int *fast_checker_counter)
XFORM_SKIP_PROC
{
@ -614,6 +615,7 @@ static int check_cycles_fast(Scheme_Object *obj, PrintParams *pp, int *fast_chec
return cycle;
}
#endif
#ifdef DO_STACK_CHECK
static void setup_graph_table(Scheme_Object *obj, int for_write, Scheme_Hash_Table *ht, int *counter, PrintParams *pp);

View File

@ -3250,8 +3250,11 @@ typedef struct Scheme_Symbol_Parts {
const char *name;
} Scheme_Symbol_Parts;
void spawn_master_scheme_place();
void scheme_spawn_master_place();
void *scheme_master_fast_path(int msg_type, void *msg_payload);
void scheme_places_block_child_signal();
int scheme_get_child_status(int pid, int *status);
int scheme_places_register_child(int pid, void *signal_fd, int *status);
# endif
Scheme_Object *scheme_places_deep_copy(Scheme_Object *so);
#endif

View File

@ -4057,7 +4057,7 @@ void scheme_thread_block(float sleep_time)
/* Check scheduled_kills early and often. */
check_scheduled_kills();
#ifdef UNIX_PROCESSES
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
/* Reap zombie processes: */
scheme_check_child_done();
#endif
@ -7371,7 +7371,7 @@ static void get_ready_for_GC()
#ifdef WINDOWS_PROCESSES
scheme_suspend_remembered_threads();
#endif
#ifdef UNIX_PROCESSES
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
scheme_block_child_signals(1);
#endif
@ -7402,7 +7402,7 @@ static void done_with_GC()
#ifdef WINDOWS_PROCESSES
scheme_resume_remembered_threads();
#endif
#ifdef UNIX_PROCESSES
#if defined(UNIX_PROCESSES) && !(defined(MZ_USE_PLACES) && defined(MZ_PRECISE_GC))
scheme_block_child_signals(0);
#endif