summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Vetter <daniel.vetter@ffwll.ch>2018-01-18 10:13:03 +0100
committerDaniel Vetter <daniel.vetter@ffwll.ch>2018-01-18 14:38:47 +0100
commit5ec8547add3edcfd3ea8da946b3783c66aee86df (patch)
tree2d571bc285bb602e4fa8718381754a671bef1edb
parent6d378ea0a17b709d86a0cbf4e30375b01c031617 (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.c25
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: