[Issue #82] Fixed deadlocks that were triggered when the event pipe was full and a child needed to be reaped

This commit is contained in:
Snaipe 2015-12-06 13:28:43 +01:00
parent aaa21d922c
commit 13e7928d0c
3 changed files with 49 additions and 13 deletions

View file

@ -88,6 +88,8 @@ static int get_win_status(HANDLE handle) {
}
return sig ? sig : exit_code << 8;
}
#else
# include <pthread.h>
#endif
struct worker_context g_worker_context = {.test = NULL};
@ -115,9 +117,7 @@ static struct full_context local_ctx;
# error Unsupported compiler. Use GCC or Clang under *nixes.
# endif
static void handle_sigchld(CR_UNUSED int sig) {
assert(sig == SIGCHLD);
static void handle_sigchld_pump(void) {
int fd = g_worker_pipe->fds[1];
pid_t pid;
int status;
@ -142,8 +142,49 @@ static void handle_sigchld(CR_UNUSED int sig) {
}
}
}
/*
* This child reaping logic is a dirty hack to prevent deadlocks
* when the pipe is overflowing and a child terminates.
*
* (Windows doesn't have this issue as the waitpid logic is threaded by
* RegisterWaitForSingleObject)
*
* REMOVE WHEN REFACTORING I/O LAYER
*/
static pthread_t child_pump;
static bool child_pump_running;
static void *chld_pump_thread_main(void *nil) {
child_pump_running = true;
do {
handle_sigchld_pump();
usleep(1000);
} while (child_pump_running);
return nil;
}
#endif
void init_proc_compat(void) {
#ifndef VANILLA_WIN32
pthread_attr_t attr;
int err = pthread_attr_init(&attr)
|| pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)
|| pthread_create(&child_pump, &attr, chld_pump_thread_main, NULL)
|| pthread_attr_destroy(&attr);
if (err) {
perror(0);
exit(1);
}
#endif
}
void free_proc_compat(void) {
child_pump_running = false;
}
#ifdef VANILLA_WIN32
struct wait_context {
HANDLE wait_handle;
@ -251,16 +292,6 @@ int resume_child(void) {
free(param);
return 1;
#else
# if defined(__unix__) || defined(__APPLE__)
struct sigaction sa;
sa.sa_handler = &handle_sigchld;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
if (sigaction(SIGCHLD, &sa, 0) == -1) {
perror(0);
exit(1);
}
# endif
return 0;
#endif
}

View file

@ -60,4 +60,7 @@ bool is_current_process(s_proc_handle *proc);
unsigned long long get_process_id(void);
unsigned long long get_process_id_of(s_proc_handle *proc);
void init_proc_compat(void);
void free_proc_compat(void);
#endif /* !COMPAT_PROCESS_H_ */

View file

@ -452,6 +452,7 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) {
strerror(errno));
abort();
}
init_proc_compat();
struct criterion_global_stats *stats = stats_init();
run_tests_async(set, stats);
@ -466,6 +467,7 @@ static int criterion_run_all_tests_impl(struct criterion_test_set *set) {
log(post_all, stats);
cleanup:
free_proc_compat();
sfree(g_worker_pipe);
sfree(stats);
return result;