igt/gem_userptr_blits: Fix forked access test
[platform/upstream/intel-gpu-tools.git] / tests / gem_reset_stats.c
index 095b14b..3f5a01f 100644 (file)
@@ -26,6 +26,7 @@
  */
 
 #define _GNU_SOURCE
+#include <stdbool.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <time.h>
 #include <signal.h>
 
-#include "i915_drm.h"
-#include "intel_bufmgr.h"
-#include "intel_batchbuffer.h"
-#include "intel_gpu_tools.h"
-#include "rendercopy.h"
+#include "ioctl_wrappers.h"
+#include "drmtest.h"
 #include "igt_debugfs.h"
+#include "intel_chipset.h"
+#include "intel_io.h"
+#include "igt_aux.h"
 
 #define RS_NO_ERROR      0
 #define RS_BATCH_ACTIVE  (1 << 0)
 #define RS_BATCH_PENDING (1 << 1)
 #define RS_UNKNOWN       (1 << 2)
 
+static uint32_t devid;
+static bool hw_contexts;
+
 struct local_drm_i915_reset_stats {
        __u32 ctx_id;
        __u32 flags;
@@ -76,7 +80,43 @@ struct local_drm_i915_gem_context_destroy {
 #define CONTEXT_DESTROY_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x2e, struct local_drm_i915_gem_context_destroy)
 #define GET_RESET_STATS_IOCTL DRM_IOWR(DRM_COMMAND_BASE + 0x32, struct local_drm_i915_reset_stats)
 
-static igt_debugfs_t dfs;
+#define LOCAL_I915_EXEC_VEBOX  (4 << 0)
+
+struct target_ring;
+
+static bool gem_has_render(int fd)
+{
+       return true;
+}
+
+static bool has_context(const struct target_ring *ring);
+
+static const struct target_ring {
+       uint32_t exec;
+       bool (*present)(int fd);
+       bool (*contexts)(const struct target_ring *ring);
+       const char *name;
+} rings[] = {
+       { I915_EXEC_RENDER, gem_has_render, has_context, "render" },
+       { I915_EXEC_BLT, gem_has_blt, has_context, "blt" },
+       { I915_EXEC_BSD, gem_has_bsd, has_context, "bsd" },
+       { LOCAL_I915_EXEC_VEBOX, gem_has_vebox, has_context, "vebox" },
+};
+
+static bool has_context(const struct target_ring *ring)
+{
+       if (!hw_contexts)
+               return false;
+
+       if(ring->exec == I915_EXEC_RENDER)
+               return true;
+
+       return false;
+}
+
+#define NUM_RINGS (sizeof(rings)/sizeof(struct target_ring))
+
+static const struct target_ring *current_ring;
 
 static uint32_t context_create(int fd)
 {
@@ -160,7 +200,7 @@ static int gem_exec(int fd, struct drm_i915_gem_execbuffer2 *execbuf)
        return 0;
 }
 
-static int exec_valid(int fd, int ctx)
+static int exec_valid_ring(int fd, int ctx, int ring)
 {
        struct drm_i915_gem_execbuffer2 execbuf;
        struct drm_i915_gem_exec_object2 exec;
@@ -186,7 +226,7 @@ static int exec_valid(int fd, int ctx)
        execbuf.num_cliprects = 0;
        execbuf.DR1 = 0;
        execbuf.DR4 = 0;
-       execbuf.flags = 0;
+       execbuf.flags = ring;
        i915_execbuffer2_set_context_id(execbuf, ctx);
        execbuf.rsvd2 = 0;
 
@@ -197,21 +237,15 @@ static int exec_valid(int fd, int ctx)
        return exec.handle;
 }
 
-static void stop_rings(void)
+static int exec_valid(int fd, int ctx)
 {
-       int fd;
-
-       fd = igt_debugfs_open(&dfs, "i915_ring_stop", O_WRONLY);
-       igt_assert(fd >= 0);
-
-       igt_assert(write(fd, "0xff", 4) == 4);
-       close(fd);
+       return exec_valid_ring(fd, ctx, current_ring->exec);
 }
 
 #define BUFSIZE (4 * 1024)
 #define ITEMS   (BUFSIZE >> 2)
 
-static int inject_hang(int fd, int ctx)
+static int inject_hang_ring(int fd, int ctx, int ring, bool ignore_ban_error)
 {
        struct drm_i915_gem_execbuffer2 execbuf;
        struct drm_i915_gem_exec_object2 exec;
@@ -219,10 +253,11 @@ static int inject_hang(int fd, int ctx)
        uint32_t *buf;
        int roff, i;
        unsigned cmd_len = 2;
+       enum stop_ring_flags flags;
 
        srandom(time(NULL));
 
-       if (intel_gen(intel_get_drm_devid(fd)) >= 8)
+       if (intel_gen(devid) >= 8)
                cmd_len = 3;
 
        buf = malloc(BUFSIZE);
@@ -249,7 +284,7 @@ static int inject_hang(int fd, int ctx)
        execbuf.num_cliprects = 0;
        execbuf.DR1 = 0;
        execbuf.DR4 = 0;
-       execbuf.flags = 0;
+       execbuf.flags = ring;
        i915_execbuffer2_set_context_id(execbuf, ctx);
        execbuf.rsvd2 = 0;
 
@@ -260,18 +295,18 @@ static int inject_hang(int fd, int ctx)
        for (i = 0; i < ITEMS; i++)
                buf[i] = MI_NOOP;
 
-       roff = random() % (ITEMS - cmd_len);
+       roff = random() % (ITEMS - cmd_len - 1);
        buf[roff] = MI_BATCH_BUFFER_START | (cmd_len - 2);
        buf[roff + 1] = (gtt_off & 0xfffffffc) + (roff << 2);
        if (cmd_len == 3)
-               buf[roff + 2] = gtt_off & 0xffffffff00000000ull;
-
-#ifdef VERBOSE
-       printf("loop injected at 0x%lx (off 0x%x, bo_start 0x%lx, bo_end 0x%lx)\n",
-              (long unsigned int)((roff << 2) + gtt_off),
-              roff << 2, (long unsigned int)gtt_off,
-              (long unsigned int)(gtt_off + BUFSIZE - 1));
-#endif
+               buf[roff + 2] = (gtt_off & 0xffffffff00000000ull) >> 32;
+
+       buf[roff + cmd_len] = MI_BATCH_BUFFER_END;
+
+       igt_debug("loop injected at 0x%lx (off 0x%x, bo_start 0x%lx, bo_end 0x%lx)\n",
+                 (long unsigned int)((roff << 2) + gtt_off),
+                 roff << 2, (long unsigned int)gtt_off,
+                 (long unsigned int)(gtt_off + BUFSIZE - 1));
        gem_write(fd, exec.handle, 0, buf, BUFSIZE);
 
        exec.relocation_count = 0;
@@ -290,7 +325,7 @@ static int inject_hang(int fd, int ctx)
        execbuf.num_cliprects = 0;
        execbuf.DR1 = 0;
        execbuf.DR4 = 0;
-       execbuf.flags = 0;
+       execbuf.flags = ring;
        i915_execbuffer2_set_context_id(execbuf, ctx);
        execbuf.rsvd2 = 0;
 
@@ -300,25 +335,42 @@ static int inject_hang(int fd, int ctx)
 
        free(buf);
 
-       stop_rings();
+       flags = igt_to_stop_ring_flag(ring);
+
+       flags |= STOP_RING_ALLOW_BAN;
+
+       if (!ignore_ban_error)
+               flags |= STOP_RING_ALLOW_ERRORS;
+
+       igt_set_stop_rings(flags);
 
        return exec.handle;
 }
 
+static int inject_hang(int fd, int ctx)
+{
+       return inject_hang_ring(fd, ctx, current_ring->exec, false);
+}
+
+static int inject_hang_no_ban_error(int fd, int ctx)
+{
+       return inject_hang_ring(fd, ctx, current_ring->exec, true);
+}
+
 static int _assert_reset_status(int fd, int ctx, int status)
 {
        int rs;
 
        rs = gem_reset_status(fd, ctx);
        if (rs < 0) {
-               printf("reset status for %d ctx %d returned %d\n",
-                      fd, ctx, rs);
+               igt_info("reset status for %d ctx %d returned %d\n",
+                        fd, ctx, rs);
                return rs;
        }
 
        if (rs != status) {
-               printf("%d:%d reset status %d differs from assumed %d\n",
-                      fd, ctx, rs, status);
+               igt_info("%d:%d reset status %d differs from assumed %d\n",
+                        fd, ctx, rs, status);
 
                return 1;
        }
@@ -462,6 +514,94 @@ static void test_rs_ctx(int num_fds, int num_ctx, int hang_index,
 static void test_ban(void)
 {
        int h1,h2,h3,h4,h5,h6,h7;
+       int fd_bad, fd_good;
+       int retry = 10;
+       int active_count = 0, pending_count = 0;
+       struct local_drm_i915_reset_stats rs_bad, rs_good;
+
+       fd_bad = drm_open_any();
+       igt_assert(fd_bad >= 0);
+
+       fd_good = drm_open_any();
+       igt_assert(fd_good >= 0);
+
+       assert_reset_status(fd_bad, 0, RS_NO_ERROR);
+       assert_reset_status(fd_good, 0, RS_NO_ERROR);
+
+       h1 = exec_valid(fd_bad, 0);
+       igt_assert(h1 >= 0);
+       h5 = exec_valid(fd_good, 0);
+       igt_assert(h5 >= 0);
+
+       assert_reset_status(fd_bad, 0, RS_NO_ERROR);
+       assert_reset_status(fd_good, 0, RS_NO_ERROR);
+
+       h2 = inject_hang_no_ban_error(fd_bad, 0);
+       igt_assert(h2 >= 0);
+       active_count++;
+       /* Second hang will be pending for this */
+       pending_count++;
+
+       h6 = exec_valid(fd_good, 0);
+       h7 = exec_valid(fd_good, 0);
+
+        while (retry--) {
+                h3 = inject_hang_no_ban_error(fd_bad, 0);
+                igt_assert(h3 >= 0);
+                gem_sync(fd_bad, h3);
+               active_count++;
+               /* This second hand will count as pending */
+                assert_reset_status(fd_bad, 0, RS_BATCH_ACTIVE);
+
+                h4 = exec_valid(fd_bad, 0);
+                if (h4 == -EIO) {
+                        gem_close(fd_bad, h3);
+                        break;
+                }
+
+                /* Should not happen often but sometimes hang is declared too slow
+                 * due to our way of faking hang using loop */
+
+                igt_assert(h4 >= 0);
+                gem_close(fd_bad, h3);
+                gem_close(fd_bad, h4);
+
+                igt_info("retrying for ban (%d)\n", retry);
+        }
+
+       igt_assert(h4 == -EIO);
+       assert_reset_status(fd_bad, 0, RS_BATCH_ACTIVE);
+
+       gem_sync(fd_good, h7);
+       assert_reset_status(fd_good, 0, RS_BATCH_PENDING);
+
+       igt_assert(gem_reset_stats(fd_good, 0, &rs_good) == 0);
+       igt_assert(gem_reset_stats(fd_bad, 0, &rs_bad) == 0);
+
+       igt_assert(rs_bad.batch_active == active_count);
+       igt_assert(rs_bad.batch_pending == pending_count);
+       igt_assert(rs_good.batch_active == 0);
+       igt_assert(rs_good.batch_pending == 2);
+
+       gem_close(fd_bad, h1);
+       gem_close(fd_bad, h2);
+       gem_close(fd_good, h6);
+       gem_close(fd_good, h7);
+
+       h1 = exec_valid(fd_good, 0);
+       igt_assert(h1 >= 0);
+       gem_close(fd_good, h1);
+
+       close(fd_bad);
+       close(fd_good);
+
+       igt_assert(gem_reset_status(fd_bad, 0) < 0);
+       igt_assert(gem_reset_status(fd_good, 0) < 0);
+}
+
+static void test_ban_ctx(void)
+{
+       int h1,h2,h3,h4,h5,h6,h7;
        int ctx_good, ctx_bad;
        int fd;
        int retry = 10;
@@ -488,7 +628,7 @@ static void test_ban(void)
        assert_reset_status(fd, ctx_good, RS_NO_ERROR);
        assert_reset_status(fd, ctx_bad, RS_NO_ERROR);
 
-       h2 = inject_hang(fd, ctx_bad);
+       h2 = inject_hang_no_ban_error(fd, ctx_bad);
        igt_assert(h2 >= 0);
        active_count++;
        /* Second hang will be pending for this */
@@ -498,7 +638,7 @@ static void test_ban(void)
        h7 = exec_valid(fd, ctx_good);
 
         while (retry--) {
-                h3 = inject_hang(fd, ctx_bad);
+                h3 = inject_hang_no_ban_error(fd, ctx_bad);
                 igt_assert(h3 >= 0);
                 gem_sync(fd, h3);
                active_count++;
@@ -518,7 +658,7 @@ static void test_ban(void)
                 gem_close(fd, h3);
                 gem_close(fd, h4);
 
-                printf("retrying for ban (%d)\n", retry);
+                igt_info("retrying for ban (%d)\n", retry);
         }
 
        igt_assert(h4 == -EIO);
@@ -554,7 +694,7 @@ static void test_ban(void)
        close(fd);
 }
 
-static void test_nonrelated_hang(void)
+static void test_unrelated_ctx(void)
 {
        int h1,h2;
        int fd1,fd2;
@@ -603,7 +743,7 @@ static int get_reset_count(int fd, int ctx)
        return rs.reset_count;
 }
 
-static void test_double_destroy_pending(void)
+static void test_close_pending_ctx(void)
 {
        int fd, h;
        uint32_t ctx;
@@ -639,7 +779,53 @@ static void test_close_pending(void)
        close(fd);
 }
 
-static void test_close_pending_fork(void)
+static void exec_noop_on_each_ring(int fd, const bool reverse)
+{
+       uint32_t batch[2] = {MI_BATCH_BUFFER_END, 0};
+       uint32_t handle;
+       struct drm_i915_gem_execbuffer2 execbuf;
+       struct drm_i915_gem_exec_object2 exec[1];
+
+       handle = gem_create(fd, 4096);
+       gem_write(fd, handle, 0, batch, sizeof(batch));
+
+       exec[0].handle = handle;
+       exec[0].relocation_count = 0;
+       exec[0].relocs_ptr = 0;
+       exec[0].alignment = 0;
+       exec[0].offset = 0;
+       exec[0].flags = 0;
+       exec[0].rsvd1 = 0;
+       exec[0].rsvd2 = 0;
+
+       execbuf.buffers_ptr = (uintptr_t)exec;
+       execbuf.buffer_count = 1;
+       execbuf.batch_start_offset = 0;
+       execbuf.batch_len = 8;
+       execbuf.cliprects_ptr = 0;
+       execbuf.num_cliprects = 0;
+       execbuf.DR1 = 0;
+       execbuf.DR4 = 0;
+       execbuf.flags = 0;
+       i915_execbuffer2_set_context_id(execbuf, 0);
+       execbuf.rsvd2 = 0;
+
+       for (unsigned i = 0; i < NUM_RINGS; i++) {
+               const struct target_ring *ring;
+
+               ring = reverse ? &rings[NUM_RINGS - 1 - i] : &rings[i];
+
+               if (ring->present(fd)) {
+                       execbuf.flags = ring->exec;
+                       do_ioctl(fd, DRM_IOCTL_I915_GEM_EXECBUFFER2, &execbuf);
+               }
+       }
+
+       gem_sync(fd, handle);
+       gem_close(fd, handle);
+}
+
+static void test_close_pending_fork(const bool reverse)
 {
        int pid;
        int fd, h;
@@ -660,15 +846,14 @@ static void test_close_pending_fork(void)
         */
        pid = fork();
        if (pid == 0) {
-               /* Not first drm_open_any() so we need to do
-                * gem_quiescent_gpu() explicitly, as it is the
-                * key component to trigger the oops
-                */
                const int fd2 = drm_open_any();
                igt_assert(fd2 >= 0);
 
-               /* This adds same batch on each ring */
-               gem_quiescent_gpu(fd2);
+               /* The crucial component is that we schedule the same noop batch
+                * on each ring. This exercises batch_obj reference counting,
+                * when gpu is reset and ring lists are cleared.
+                */
+               exec_noop_on_each_ring(fd2, reverse);
 
                close(fd2);
                return;
@@ -696,18 +881,7 @@ static void test_close_pending_fork(void)
        close(fd);
 }
 
-static void drop_root(void)
-{
-       igt_assert(getuid() == 0);
-
-       igt_assert(setgid(2) == 0);
-       igt_assert(setuid(2) == 0);
-
-       igt_assert(getgid() == 2);
-       igt_assert(getuid() == 2);
-}
-
-static void __test_count(const bool create_ctx)
+static void test_reset_count(const bool create_ctx)
 {
        int fd, h, ctx;
        long c1, c2;
@@ -734,7 +908,7 @@ static void __test_count(const bool create_ctx)
        igt_assert(c2 == (c1 + 1));
 
        igt_fork(child, 1) {
-               drop_root();
+               igt_drop_root();
 
                c2 = get_reset_count(fd, ctx);
 
@@ -754,22 +928,6 @@ static void __test_count(const bool create_ctx)
        close(fd);
 }
 
-static void test_count(void)
-{
-       return __test_count(false);
-}
-
-static void test_count_context(void)
-{
-       return __test_count(true);
-}
-
-static void test_global_reset_count(void)
-{
-       test_count();
-       test_count_context();
-}
-
 static int _test_params(int fd, int ctx, uint32_t flags, uint32_t pad)
 {
        struct local_drm_i915_reset_stats rs;
@@ -794,7 +952,7 @@ static int _test_params(int fd, int ctx, uint32_t flags, uint32_t pad)
 
 typedef enum { root = 0, user } cap_t;
 
-static void test_param_ctx(const int fd, const int ctx, const cap_t cap)
+static void _check_param_ctx(const int fd, const int ctx, const cap_t cap)
 {
        const uint32_t bad = rand() + 1;
 
@@ -815,8 +973,7 @@ static void check_params(const int fd, const int ctx, cap_t cap)
        igt_assert(ioctl(fd, GET_RESET_STATS_IOCTL, 0) == -1);
        igt_assert(_test_params(fd, 0xbadbad, 0, 0) == -ENOENT);
 
-       test_param_ctx(fd, 0, cap);
-       test_param_ctx(fd, ctx, cap);
+       _check_param_ctx(fd, ctx, cap);
 }
 
 static void _test_param(const int fd, const int ctx)
@@ -826,7 +983,7 @@ static void _test_param(const int fd, const int ctx)
        igt_fork(child, 1) {
                check_params(fd, ctx, root);
 
-               drop_root();
+               igt_drop_root();
 
                check_params(fd, ctx, user);
        }
@@ -836,7 +993,7 @@ static void _test_param(const int fd, const int ctx)
        igt_waitchildren();
 }
 
-static void test_params(void)
+static void test_params_ctx(void)
 {
        int fd, ctx;
 
@@ -849,56 +1006,158 @@ static void test_params(void)
        close(fd);
 }
 
+static void test_params(void)
+{
+       int fd;
 
-igt_main
+       fd = drm_open_any();
+       igt_assert(fd >= 0);
+
+       _test_param(fd, 0);
+
+       close(fd);
+
+}
+
+static bool gem_has_hw_contexts(int fd)
 {
        struct local_drm_i915_gem_context_create create;
-       uint32_t devid;
-       int fd;
        int ret;
 
+       memset(&create, 0, sizeof(create));
+       ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
+
+       if (ret == 0) {
+               drmIoctl(fd, CONTEXT_DESTROY_IOCTL, &create);
+               return true;
+       }
+
+       return false;
+}
+
+static bool gem_has_reset_stats(int fd)
+{
+       struct local_drm_i915_reset_stats rs;
+       int ret;
+
+       /* Carefully set flags and pad to zero, otherwise
+          we get -EINVAL
+       */
+       memset(&rs, 0, sizeof(rs));
+
+       ret = drmIoctl(fd, GET_RESET_STATS_IOCTL, &rs);
+       if (ret == 0)
+               return true;
+
+       /* If we get EPERM, we have support but did not
+          have CAP_SYSADM */
+       if (ret == -1 && errno == EPERM)
+               return true;
+
+       return false;
+}
+
+static void check_gpu_ok(void)
+{
+       int retry_count = 30;
+       enum stop_ring_flags flags;
+       int fd;
+
+       igt_debug("checking gpu state\n");
+
+       while (retry_count--) {
+               flags = igt_get_stop_rings();
+               if (flags == 0)
+                       break;
+
+               igt_debug("waiting previous hang to clear\n");
+               sleep(1);
+       }
+
+       igt_assert(flags == 0);
+
+       fd = drm_open_any();
+       gem_quiescent_gpu(fd);
+       close(fd);
+}
+
+#define RING_HAS_CONTEXTS (current_ring->contexts(current_ring))
+#define RUN_TEST(...) do { check_gpu_ok(); __VA_ARGS__; check_gpu_ok(); } while (0)
+#define RUN_CTX_TEST(...) do { igt_skip_on(RING_HAS_CONTEXTS == false); RUN_TEST(__VA_ARGS__); } while (0)
+
+igt_main
+{
        igt_skip_on_simulation();
 
        igt_fixture {
+               int fd;
+
+               bool has_reset_stats;
                fd = drm_open_any();
                devid = intel_get_drm_devid(fd);
-               igt_require_f(intel_gen(devid) >= 4,
-                             "Architecture %d too old\n", intel_gen(devid));
-
-               ret = drmIoctl(fd, CONTEXT_CREATE_IOCTL, &create);
-               igt_skip_on_f(ret != 0 && (errno == ENODEV || errno == EINVAL),
-                             "Kernel is too old, or contexts not supported: %s\n",
-                             strerror(errno));
 
-               assert(igt_debugfs_init(&dfs) == 0);
+               hw_contexts = gem_has_hw_contexts(fd);
+               has_reset_stats = gem_has_reset_stats(fd);
 
                close(fd);
+
+               igt_require_f(has_reset_stats,
+                             "No reset stats ioctl support. Too old kernel?\n");
        }
 
-       igt_subtest("basic-reset-status")
-               test_rs(4, 1, 0);
+       igt_subtest("params")
+               test_params();
 
-       igt_subtest("context-reset-status")
-               test_rs_ctx(4, 4, 1, 2);
+       for (int i = 0; i < NUM_RINGS; i++) {
+               const char *name;
 
-       igt_subtest("ban")
-               test_ban();
+               current_ring = &rings[i];
+               name = current_ring->name;
 
-       igt_subtest("ctx-unrelated")
-               test_nonrelated_hang();
+               igt_fixture {
+                       int fd = drm_open_any();
+                       gem_require_ring(fd, current_ring->exec);
+                       close(fd);
+               }
 
-       igt_subtest("global-count")
-               test_global_reset_count();
+               igt_fixture
+                       igt_require_f(intel_gen(devid) >= 4,
+                                     "gen %d doesn't support reset\n", intel_gen(devid));
 
-       igt_subtest("double-destroy-pending")
-               test_double_destroy_pending();
+               igt_subtest_f("params-ctx-%s", name)
+                       RUN_CTX_TEST(test_params_ctx());
 
-       igt_subtest("close-pending")
-               test_close_pending();
+               igt_subtest_f("reset-stats-%s", name)
+                       RUN_TEST(test_rs(4, 1, 0));
 
-       igt_subtest("close-pending-fork")
-               test_close_pending_fork();
+               igt_subtest_f("reset-stats-ctx-%s", name)
+                       RUN_CTX_TEST(test_rs_ctx(4, 4, 1, 2));
 
-       igt_subtest("params")
-               test_params();
+               igt_subtest_f("ban-%s", name)
+                       RUN_TEST(test_ban());
+
+               igt_subtest_f("ban-ctx-%s", name)
+                       RUN_CTX_TEST(test_ban_ctx());
+
+               igt_subtest_f("reset-count-%s", name)
+                       RUN_TEST(test_reset_count(false));
+
+               igt_subtest_f("reset-count-ctx-%s", name)
+                       RUN_CTX_TEST(test_reset_count(true));
+
+               igt_subtest_f("unrelated-ctx-%s", name)
+                       RUN_CTX_TEST(test_unrelated_ctx());
+
+               igt_subtest_f("close-pending-%s", name)
+                       RUN_TEST(test_close_pending());
+
+               igt_subtest_f("close-pending-ctx-%s", name)
+                       RUN_CTX_TEST(test_close_pending_ctx());
+
+               igt_subtest_f("close-pending-fork-%s", name)
+                       RUN_TEST(test_close_pending_fork(false));
+
+               igt_subtest_f("close-pending-fork-reverse-%s", name)
+                       RUN_TEST(test_close_pending_fork(true));
+       }
 }