diff mbox

[RFC,2/5] lib/core: make logging pthread vs. fork safe

Message ID 20180118135955.10739-2-daniel.vetter@ffwll.ch (mailing list archive)
State New, archived
Headers show

Commit Message

Daniel Vetter Jan. 18, 2018, 1:59 p.m. UTC
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>
---
 lib/igt_core.c | 25 +++++++++++++++++--------
 1 file changed, 17 insertions(+), 8 deletions(-)
diff mbox

Patch

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: