static void *mz_proc_thread_signal_worker(void *data) { int status; int pid, check_pid, is_group; sigset_t set; Child_Status *unused_status, *prev_unused, *next; sigemptyset(&set); sigaddset(&set, SIGCHLD); while (1) { int rc; int signalid; do { rc = sigwait(&set, &signalid); if (rc == -1) { if (errno != EINTR) { fprintf(stderr, "unexpected error from sigwait(): %d\n", errno); } } } while (rc == -1 && errno == EINTR); mzrt_mutex_lock(child_status_lock); do_group_signal_fds(); mzrt_mutex_unlock(child_status_lock); mzrt_mutex_lock(child_wait_lock); unused_status = unused_pid_statuses; prev_unused = NULL; do { if (unused_status) { /* See unused_pid_statuses above */ check_pid = unused_status->pid; is_group = 1; } else { /* We wait only on processes in the same group as Racket, because detecting the termination of a group's main process disables our ability to terminate all processes in the group. */ check_pid = 0; /* => processes in the same group as Racket */ is_group = 0; } pid = waitpid(check_pid, &status, WNOHANG); if (pid == -1) { if (errno == EINTR) { /* try again */ pid = 1; } else if (!is_group && (errno == ECHILD)) { /* no more to check */ } else { fprintf(stderr, "unexpected error from waitpid(%d[%d]): %d\n", check_pid, is_group, errno); if (is_group) { prev_unused = unused_status; unused_status = unused_status->next; } } } else if (pid > 0) { /* printf("SIGCHILD pid %i with status %i %i\n", pid, status, WEXITSTATUS(status)); */ if (is_group) { next = unused_status->next; if (prev_unused) prev_unused->next_unused = next; else unused_pid_statuses = next; free(unused_status); unused_status = next; } else add_child_status(pid, status); } else { if (is_group) { prev_unused = unused_status; unused_status = unused_status->next; } } } while ((pid > 0) || is_group); mzrt_mutex_unlock(child_wait_lock); } return NULL; }
static void *thread_signal_worker(void *data) { int status; int pid, check_pid, in_group; sigset_t set; Child_Status *unused_status, *prev_unused, *next; sigemptyset(&set); sigaddset(&set, SIGCHLD); while (1) { int rc; int signalid; do { rc = sigwait(&set, &signalid); if (rc == -1) { if (errno != EINTR) { fprintf(stderr, "unexpected error from sigwait(): %d\n", errno); } } } while (rc == -1 && errno == EINTR); pthread_mutex_lock(&child_status_lock); do_group_signal_fds(); pthread_mutex_unlock(&child_status_lock); pthread_mutex_lock(&child_wait_lock); unused_status = unused_pid_statuses; prev_unused = NULL; do { if (unused_status) { /* See unused_pid_statuses above */ check_pid = unused_status->pid; in_group = 1; } else { /* We wait only on processes in the same group as the current process, because detecting the termination of a group's main process disables our ability to terminate all processes in the group. */ if (pending_children) check_pid = 0; /* => processes in the same group as the current process */ else check_pid = -1; /* don't check */ in_group = 0; } if (check_pid == -1) { pid = -1; errno = ECHILD; } else pid = waitpid(check_pid, &status, WNOHANG); if (pid == -1) { if (errno == EINTR) { /* try again */ pid = 1; } else if (!in_group && (errno == ECHILD)) { /* no more to check */ } else { fprintf(stderr, "unexpected error from waitpid(%d[%d]): %d\n", check_pid, in_group, errno); if (in_group) { prev_unused = unused_status; unused_status = unused_status->next; } } } else if (pid > 0) { /* printf("SIGCHILD pid %i with status %i %i\n", pid, status, WEXITSTATUS(status)); */ if (in_group) { next = unused_status->next_unused; if (prev_unused) prev_unused->next_unused = next; else unused_pid_statuses = next; free(unused_status); unused_status = next; } else { /* Double-check for pid in unused_pid_statuses, since it may have completed between the pid-specific waitpid and the non-group waitpid: */ prev_unused = NULL; for (unused_status = unused_pid_statuses; unused_status; unused_status = unused_status->next_unused) { if (unused_status->pid == pid) break; prev_unused = unused_status; } if (!unused_status) { /* not in unused_pid_statuses: */ add_child_status(pid, extract_child_status(status)); } else { if (prev_unused) prev_unused->next_unused = unused_status->next_unused; else unused_pid_statuses = unused_status->next_unused; free(unused_status); unused_status = NULL; } } } else { if (in_group) { prev_unused = unused_status; unused_status = unused_status->next_unused; } } } while ((pid > 0) || in_group); pthread_mutex_unlock(&child_wait_lock); } return NULL; }
static void *mz_proc_thread_signal_worker(void *data) { int status; int pid, check_pid, is_group; sigset_t set; Child_Status *group_status, *prev_group, *next; sigemptyset(&set); sigaddset(&set, SIGCHLD); while (1) { int rc; int signalid; do { rc = sigwait(&set, &signalid); if (rc == -1) { if (errno != EINTR) { fprintf(stderr, "unexpected error from sigwait(): %d\n", errno); } } } while (rc == -1 && errno == EINTR); mzrt_mutex_lock(child_status_lock); do_group_signal_fds(); mzrt_mutex_unlock(child_status_lock); mzrt_mutex_lock(child_wait_lock); group_status = child_group_statuses; prev_group = NULL; do { if (group_status) { check_pid = group_status->pid; is_group = 1; } else { check_pid = 0; /* => processes in the same group as Racket */ is_group = 0; } pid = waitpid(check_pid, &status, WNOHANG); if (pid == -1) { if (errno == EINTR) { /* try again */ pid = 1; } else if (!is_group && (errno == ECHILD)) { /* no more to check */ } else { fprintf(stderr, "unexpected error from waitpid(%d[%d]): %d\n", check_pid, is_group, errno); if (is_group) { prev_group = group_status; group_status = group_status->next; } } } else if (pid > 0) { /* printf("SIGCHILD pid %i with status %i %i\n", pid, status, WEXITSTATUS(status)); */ if (is_group) { next = group_status->next; if (prev_group) prev_group->next_group = next; else child_group_statuses = next; free(group_status); group_status = next; } else add_child_status(pid, status); } else { if (is_group) { prev_group = group_status; group_status = group_status->next; } } } while ((pid > 0) || is_group); mzrt_mutex_unlock(child_wait_lock); } return NULL; }