[igt-dev] [RFC PATCH 2/5] lib/core: make logging pthread vs. fork safe

Daniel Vetter daniel.vetter at ffwll.ch
Thu Jan 18 13:59:52 UTC 2018


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 at intel.com>
---
 lib/igt_core.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)

diff --git a/lib/igt_core.c b/lib/igt_core.c
index 558a538d35e8..8e7f0da8a44b 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:
-- 
2.14.3



More information about the igt-dev mailing list