/tests/basic_percpu_ops_mm_cid_test_cxx.tap
/tests/basic_test.tap
/tests/basic_test_cxx.tap
+/tests/fork_test.tap
+/tests/fork_test_cxx.tap
/tests/mempool_cow_race_test.tap
/tests/mempool_cow_race_test_cxx.tap
/tests/mempool_test.tap
basic_percpu_ops_mm_cid_test_cxx.tap \
basic_test.tap \
basic_test_cxx.tap \
+ fork_test.tap \
+ fork_test_cxx.tap \
mempool_test.tap \
mempool_test_cxx.tap \
mempool_cow_race_test.tap \
unregistered_test.tap
dist_noinst_SCRIPTS = \
+ run_fork_test_cxx.tap \
+ run_fork_test.tap \
run_no_syscall_test_cxx.tap \
run_no_syscall_test.tap \
run_param_test_cxx.tap \
basic_test_cxx_tap_SOURCES = basic_test_cxx.cpp
basic_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
+fork_test_tap_SOURCES = fork_test.c
+fork_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
+
+fork_test_cxx_tap_SOURCES = fork_test_cxx.cpp
+fork_test_cxx_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
+
mempool_test_tap_SOURCES = mempool_test.c
mempool_test_tap_LDADD = $(top_builddir)/src/librseq.la $(top_builddir)/tests/utils/libtap.la $(DL_LIBS)
TESTS = \
basic_test.tap \
basic_test_cxx.tap \
+ run_fork_test.tap \
+ run_fork_test_cxx.tap \
run_unregistered_test.tap \
run_unregistered_test_cxx.tap \
run_syscall_errors_test.tap \
--- /dev/null
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2024 Michael Jeanson <mjeanson@efficios.com>
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/wait.h>
+#include <syscall.h>
+#include <unistd.h>
+
+#include <rseq/rseq.h>
+
+#include "tap.h"
+
+#define NR_TESTS 4
+
+/*
+ * Check that a registration from a parent is still active in the child.
+ */
+
+static int sys_rseq(void *rseq_abi, uint32_t rseq_len,
+ int flags, uint32_t sig)
+{
+ return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig);
+}
+
+static
+int test_child(void)
+{
+ int ret, errno_copy;
+ struct rseq_abi *global_rseq = rseq_get_abi();
+
+ /* The registration from the parent should survive in the child. */
+
+ ret = sys_rseq(global_rseq, 32, 0, RSEQ_SIG);
+ errno_copy = errno;
+ ok(ret != 0 && errno_copy == EBUSY, "Registration is still active in the child");
+
+ ok((int32_t) global_rseq->cpu_id >= 0,
+ "rseq->cpu_id after registration is 0 or greater (%d)",
+ (int32_t) global_rseq->cpu_id);
+
+ return exit_status();
+}
+
+int main(void)
+{
+ pid_t pid;
+ int ret, wstatus;
+ struct rseq_abi *global_rseq = rseq_get_abi();
+
+ /*
+ * Skip all tests if the rseq syscall is unavailable
+ */
+ if (!rseq_available(RSEQ_AVAILABLE_QUERY_KERNEL)) {
+ plan_skip_all("The rseq syscall is unavailable");
+ }
+
+ plan_tests(NR_TESTS);
+
+ ret = rseq_register_current_thread();
+ ok(ret == 0, "Registered rseq in the parent");
+
+ ok((int32_t) global_rseq->cpu_id >= 0,
+ "rseq->cpu_id after registration is 0 or greater (%d)",
+ (int32_t) global_rseq->cpu_id);
+
+ pid = fork();
+ switch (pid) {
+ case -1:
+ perror("fork");
+ ret = EXIT_FAILURE;
+ break;
+ case 0:
+ /* Child */
+ ret = test_child();
+ break;
+ default:
+ /* Parent */
+ ret = waitpid(pid, &wstatus, 0);
+ if (ret < 0) {
+ ret = EXIT_FAILURE;
+ } else {
+ /* Let the child handle the tap cleanup. */
+ disable_cleanup();
+
+ ret = WEXITSTATUS(wstatus);
+ }
+ break;
+ }
+
+ return ret;
+}
--- /dev/null
+// SPDX-License-Identifier: MIT
+// SPDX-FileCopyrightText: 2024 EfficiOS Inc.
+
+#include "fork_test.c"
--- /dev/null
+#!/bin/bash
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2024 Michael Jeanson <mjeanson@efficios.com>
+
+SH_TAP=0
+
+if [ "x${RSEQ_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$RSEQ_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/utils/utils.sh"
+fi
+
+# shellcheck source=./utils/utils.sh
+source "$UTILSSH"
+
+GLIBC_TUNABLES="${GLIBC_TUNABLES:-}:glibc.pthread.rseq=0" "${RSEQ_TESTS_BUILDDIR}/fork_test.tap"
--- /dev/null
+#!/bin/bash
+# SPDX-License-Identifier: MIT
+# SPDX-FileCopyrightText: 2024 Michael Jeanson <mjeanson@efficios.com>
+
+SH_TAP=0
+
+if [ "x${RSEQ_TESTS_SRCDIR:-}" != "x" ]; then
+ UTILSSH="$RSEQ_TESTS_SRCDIR/utils/utils.sh"
+else
+ UTILSSH="$(dirname "$0")/utils/utils.sh"
+fi
+
+# shellcheck source=./utils/utils.sh
+source "$UTILSSH"
+
+GLIBC_TUNABLES="${GLIBC_TUNABLES:-}:glibc.pthread.rseq=0" "${RSEQ_TESTS_BUILDDIR}/fork_test_cxx.tap"
#include "tap.h"
+static int no_cleanup = 0;
static int no_plan = 0;
static int skip_all = 0;
static int have_plan = 0;
return r;
}
+void
+disable_cleanup(void)
+{
+ LOCK;
+
+ no_cleanup = 1;
+
+ UNLOCK;
+}
+
/*
* Cleanup at the end of the run, produce any final output that might be
* required.
LOCK;
+ if(no_cleanup) {
+ UNLOCK;
+ return;
+ }
+
/* If plan_no_plan() wasn't called, and we don't have a plan,
and we're not skipping everything, then something happened
before we could produce any output */
int exit_status(void);
+void disable_cleanup(void);
+
#ifdef __cplusplus
}
#endif