lib/drmtest: fix hang in quiescent_gpu_at_exit due to signal-unsafe asprintf
authorImre Deak <imre.deak@intel.com>
Wed, 5 Feb 2014 11:48:26 +0000 (13:48 +0200)
committerImre Deak <imre.deak@intel.com>
Wed, 5 Feb 2014 13:28:45 +0000 (15:28 +0200)
I got kms_flip in hung state with the backtrace below, while the parent process
waiting for the signal helper to exit. It was quite easy to reproduce the bug
by running

kms_flip --run-subtest=flip-vs-dpms-off-vs-modeset

With the change I couldn't reproduce it.

TODO: audit/fix other signal handlers with signal-unsafe functions

0  0x00007f9a1362018b in ?? () from /lib/x86_64-linux-gnu/libc.so.6
1  0x00007f9a1359df81 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
2  0x00007f9a1359b6cf in ?? () from /lib/x86_64-linux-gnu/libc.so.6
3  0x00007f9a13628eb6 in __vasprintf_chk () from /lib/x86_64-linux-gnu/libc.so.6
4  0x00007f9a13628e72 in __asprintf_chk () from /lib/x86_64-linux-gnu/libc.so.6
5  0x000000000040a4a2 in asprintf (__fmt=0x417441 "/dev/dri/card%u", __ptr=0x7fff1a972c08)
    at /usr/include/x86_64-linux-gnu/bits/stdio2.h:178
6  drm_get_card () at drmtest.c:190
7  0x000000000040a54a in __drm_open_any () at drmtest.c:229
8  0x000000000040a846 in quiescent_gpu_at_exit (sig=<optimized out>) at drmtest.c:281
9  0x0000000000408759 in call_exit_handlers (sig=3) at drmtest.c:1519
10 fatal_sig_handler (sig=3) at drmtest.c:1543
11 <signal handler called>
12 0x00007f9a13596770 in ?? () from /lib/x86_64-linux-gnu/libc.so.6
13 0x00007f9a135d8f3f in fork () from /lib/x86_64-linux-gnu/libc.so.6
14 0x000000000040b3af in __igt_fork_helper (proc=0x61d8cc <signal_helper>) at drmtest.c:1199
15 0x000000000040b4ce in igt_fork_signal_helper () at drmtest.c:751
16 0x0000000000404167 in main (argc=<optimized out>, argv=<optimized out>) at kms_flip.c:1533

v2:
- can't use snprintf as that's also signal-unsafe, so just use a dup'ed fd (Chris,Daniel)

Signed-off-by: Imre Deak <imre.deak@intel.com>
lib/drmtest.c

index f7262d7..02496c5 100644 (file)
@@ -274,26 +274,27 @@ static int __drm_open_any_render(void)
        return fd;
 }
 
+static int at_exit_drm_fd = -1;
+static int at_exit_drm_render_fd = -1;
+
 static void quiescent_gpu_at_exit(int sig)
 {
-       int fd;
+       if (at_exit_drm_fd < 0)
+               return;
 
-       fd = __drm_open_any();
-       if (fd >= 0) {
-               gem_quiescent_gpu(fd);
-               close(fd);
-       }
+       gem_quiescent_gpu(at_exit_drm_fd);
+       close(at_exit_drm_fd);
+       at_exit_drm_fd = -1;
 }
 
 static void quiescent_gpu_at_exit_render(int sig)
 {
-       int fd;
+       if (at_exit_drm_render_fd < 0)
+               return;
 
-       fd = __drm_open_any_render();
-       if (fd >= 0) {
-               gem_quiescent_gpu(fd);
-               close(fd);
-       }
+       gem_quiescent_gpu(at_exit_drm_render_fd);
+       close(at_exit_drm_render_fd);
+       at_exit_drm_render_fd = -1;
 }
 
 int drm_open_any(void)
@@ -307,6 +308,7 @@ int drm_open_any(void)
                return fd;
 
        gem_quiescent_gpu(fd);
+       at_exit_drm_fd = dup(fd);
        igt_install_exit_handler(quiescent_gpu_at_exit);
 
        return fd;
@@ -324,6 +326,7 @@ int drm_open_any_render(void)
        if (__sync_fetch_and_add(&open_count, 1))
                return fd;
 
+       at_exit_drm_render_fd = dup(fd);
        gem_quiescent_gpu(fd);
        igt_install_exit_handler(quiescent_gpu_at_exit_render);