1 // SPDX-FileCopyrightText: 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
3 // SPDX-License-Identifier: GPL-2.0-or-later
6 * Userspace RCU library - test program (fork)
13 #include <sys/types.h>
20 #include <urcu/assert.h>
21 #include <urcu/arch.h>
22 #include <urcu/tls-compat.h>
24 #ifndef DYNAMIC_LINK_TEST
27 #define rcu_debug_yield_read()
33 /* We generate children 3 levels deep */
35 /* Each generation spawns 10 children */
38 #define NR_TESTS NR_FORK
40 static int fork_generation
;
43 * Only print diagnostic for top level parent process, else the console
44 * has trouble formatting the tap output.
46 #define diag_gen0(...) \
48 if (!fork_generation) \
57 static void cb(struct rcu_head
*head
)
59 struct test_node
*node
;
61 diag_gen0("rcu callback invoked in pid: %d", (int) getpid());
62 node
= caa_container_of(head
, struct test_node
, head
);
66 static void test_rcu(void)
68 struct test_node
*node
;
70 rcu_register_thread();
77 node
= (struct test_node
*) malloc(sizeof(*node
));
78 urcu_posix_assert(node
);
80 call_rcu(&node
->head
, cb
);
84 rcu_unregister_thread();
88 * Return 0 if child, > 0 if parent, < 0 on error.
90 static int do_fork(const char *execname
)
94 diag_gen0("%s parent pid: %d, before fork",
95 execname
, (int) getpid());
97 call_rcu_before_fork();
104 call_rcu_after_fork_child();
105 diag_gen0("%s child pid: %d, after fork",
106 execname
, (int) getpid());
108 diag_gen0("%s child pid: %d, after rcu test",
109 execname
, (int) getpid());
110 if (fork_generation
>= FORK_DEPTH
)
113 } else if (pid
> 0) {
117 call_rcu_after_fork_parent();
118 diag_gen0("%s parent pid: %d, after fork",
119 execname
, (int) getpid());
121 diag_gen0("%s parent pid: %d, after rcu test",
122 execname
, (int) getpid());
126 if (!fork_generation
)
130 if (WIFEXITED(status
)) {
131 diag_gen0("child %u exited normally with status %u",
132 pid
, WEXITSTATUS(status
));
133 if (WEXITSTATUS(status
))
136 } else if (WIFSIGNALED(status
)) {
137 diag_gen0("child %u was terminated by signal %u",
138 pid
, WTERMSIG(status
));
146 if (!fork_generation
)
152 int main(int argc
__attribute__((unused
)), char **argv
)
156 plan_tests(NR_TESTS
);
159 /* pthread_atfork does not work with malloc/free in callbacks */
160 ret
= pthread_atfork(call_rcu_before_fork
,
161 call_rcu_after_fork_parent
,
162 call_rcu_after_fork_child
);
165 perror("pthread_atfork");
171 for (i
= 0; i
< NR_FORK
; i
++) {
176 ret
= do_fork(argv
[0]);
177 if (!fork_generation
) {
178 ok(ret
>= 0, "child status %d", ret
);
180 if (ret
== 0) { /* child */
182 } else if (ret
< 0) {
185 /* else parent, continue. */
188 if (!fork_generation
) {
189 return exit_status();
195 if (!fork_generation
) {
196 return exit_status();