diff options
author | Daniel Vetter <daniel.vetter@ffwll.ch> | 2018-01-18 10:13:03 +0100 |
---|---|---|
committer | Daniel Vetter <daniel.vetter@ffwll.ch> | 2018-01-18 14:38:47 +0100 |
commit | 5ec8547add3edcfd3ea8da946b3783c66aee86df (patch) | |
tree | 2d571bc285bb602e4fa8718381754a671bef1edb | |
parent | 6d378ea0a17b709d86a0cbf4e30375b01c031617 (diff) |
lib/core: make logging pthread vs. fork safe
fork() is a pretty thing in a multithreaded program, it's essentially
as bad as handling signals: When we fork the memory snapshot we can
interrupts all other threads at any place, including while they're
holding mutexes and other fun stuff.
libc itself has some internal fork handlers to clear caches and make
sure locks stay in a safe place (we've had plenty of fun with e.g. the
pid/tid caches when a signal happens too fast).
I want to put dmesg capture into igt, into a separate thread (so that
dmesg capture nicely interleaves what the test is doing, +/- races),
and stuff all the dmesg output into the igt logger. Which means we
need to make sure that the log_buffer_mutex is in a predictable state.
Since we have 2 calls to fork() extract a little helper for this.
v2: Stop using fflush(NULL) - somehow this manages to hit a bug in
libc when using a FILE in a separate thread (for capturing dmesg).
Instead explicitly flush stderr and stdout only.
Signed-off-by: Daniel Vetter <daniel.vetter@intel.com>
-rw-r--r-- | lib/igt_core.c | 25 |
1 files changed, 17 insertions, 8 deletions
diff --git a/lib/igt_core.c b/lib/igt_core.c index 558a538d..8e7f0da8 100644 --- a/lib/igt_core.c +++ b/lib/igt_core.c @@ -1518,6 +1518,21 @@ static void fork_helper_exit_handler(int sig) assert(helper_process_count == 0); } +static pid_t __igt_fork_wrapper(void) +{ + pid_t ret; + + /* ensure any buffers are flushed before fork */ + fflush(stdout); + fflush(stderr); + + pthread_mutex_lock(&log_buffer_mutex); + ret = fork(); + pthread_mutex_unlock(&log_buffer_mutex); + + return ret; +} + bool __igt_fork_helper(struct igt_helper_process *proc) { pid_t pid; @@ -1540,10 +1555,7 @@ bool __igt_fork_helper(struct igt_helper_process *proc) tmp_count = exit_handler_count; exit_handler_count = 0; - /* ensure any buffers are flushed before fork */ - fflush(NULL); - - switch (pid = fork()) { + switch (pid = __igt_fork_wrapper()) { case -1: exit_handler_count = tmp_count; igt_assert(0); @@ -1642,10 +1654,7 @@ bool __igt_fork(void) igt_assert(test_children); } - /* ensure any buffers are flushed before fork */ - fflush(NULL); - - switch (test_children[num_test_children++] = fork()) { + switch (test_children[num_test_children++] = __igt_fork_wrapper()) { case -1: igt_assert(0); case 0: |