uatomic/x86: Remove redundant memory barriers
[urcu.git] / tests / regression / test_urcu_fork.c
1 // SPDX-FileCopyrightText: 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2 //
3 // SPDX-License-Identifier: GPL-2.0-or-later
4
5 /*
6 * Userspace RCU library - test program (fork)
7 */
8
9 #include <stdio.h>
10 #include <pthread.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/wait.h>
15 #include <unistd.h>
16 #include <stdio.h>
17 #include <sched.h>
18 #include <errno.h>
19
20 #include <urcu/assert.h>
21 #include <urcu/arch.h>
22 #include <urcu/tls-compat.h>
23
24 #ifndef DYNAMIC_LINK_TEST
25 #define _LGPL_SOURCE
26 #else
27 #define rcu_debug_yield_read()
28 #endif
29 #include <urcu.h>
30
31 #include "tap.h"
32
33 /* We generate children 3 levels deep */
34 #define FORK_DEPTH 3
35 /* Each generation spawns 10 children */
36 #define NR_FORK 10
37
38 #define NR_TESTS NR_FORK
39
40 static int fork_generation;
41
42 /*
43 * Only print diagnostic for top level parent process, else the console
44 * has trouble formatting the tap output.
45 */
46 #define diag_gen0(...) \
47 do { \
48 if (!fork_generation) \
49 diag(__VA_ARGS__); \
50 } while (0)
51
52 struct test_node {
53 int somedata;
54 struct rcu_head head;
55 };
56
57 static void cb(struct rcu_head *head)
58 {
59 struct test_node *node;
60
61 diag_gen0("rcu callback invoked in pid: %d", (int) getpid());
62 node = caa_container_of(head, struct test_node, head);
63 free(node);
64 }
65
66 static void test_rcu(void)
67 {
68 struct test_node *node;
69
70 rcu_register_thread();
71
72 synchronize_rcu();
73
74 rcu_read_lock();
75 rcu_read_unlock();
76
77 node = (struct test_node *) malloc(sizeof(*node));
78 urcu_posix_assert(node);
79
80 call_rcu(&node->head, cb);
81
82 synchronize_rcu();
83
84 rcu_unregister_thread();
85 }
86
87 /*
88 * Return 0 if child, > 0 if parent, < 0 on error.
89 */
90 static int do_fork(const char *execname)
91 {
92 pid_t pid;
93
94 diag_gen0("%s parent pid: %d, before fork",
95 execname, (int) getpid());
96
97 call_rcu_before_fork();
98 pid = fork();
99 if (pid == 0) {
100 /* child */
101 fork_generation++;
102 tap_disable();
103
104 call_rcu_after_fork_child();
105 diag_gen0("%s child pid: %d, after fork",
106 execname, (int) getpid());
107 test_rcu();
108 diag_gen0("%s child pid: %d, after rcu test",
109 execname, (int) getpid());
110 if (fork_generation >= FORK_DEPTH)
111 exit(EXIT_SUCCESS);
112 return 0;
113 } else if (pid > 0) {
114 int status;
115
116 /* parent */
117 call_rcu_after_fork_parent();
118 diag_gen0("%s parent pid: %d, after fork",
119 execname, (int) getpid());
120 test_rcu();
121 diag_gen0("%s parent pid: %d, after rcu test",
122 execname, (int) getpid());
123 for (;;) {
124 pid = wait(&status);
125 if (pid < 0) {
126 if (!fork_generation)
127 perror("wait");
128 return -1;
129 }
130 if (WIFEXITED(status)) {
131 diag_gen0("child %u exited normally with status %u",
132 pid, WEXITSTATUS(status));
133 if (WEXITSTATUS(status))
134 return -1;
135 break;
136 } else if (WIFSIGNALED(status)) {
137 diag_gen0("child %u was terminated by signal %u",
138 pid, WTERMSIG(status));
139 return -1;
140 } else {
141 continue;
142 }
143 }
144 return 1;
145 } else {
146 if (!fork_generation)
147 perror("fork");
148 return -1;
149 }
150 }
151
152 int main(int argc __attribute__((unused)), char **argv)
153 {
154 unsigned int i;
155
156 plan_tests(NR_TESTS);
157
158 #if 0
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);
163 if (ret) {
164 errno = ret;
165 perror("pthread_atfork");
166 exit(EXIT_FAILURE);
167 }
168 #endif
169
170 restart:
171 for (i = 0; i < NR_FORK; i++) {
172 int ret;
173
174 test_rcu();
175 synchronize_rcu();
176 ret = do_fork(argv[0]);
177 if (!fork_generation) {
178 ok(ret >= 0, "child status %d", ret);
179 }
180 if (ret == 0) { /* child */
181 goto restart;
182 } else if (ret < 0) {
183 goto error;
184 } else {
185 /* else parent, continue. */
186 }
187 }
188 if (!fork_generation) {
189 return exit_status();
190 } else {
191 exit(EXIT_SUCCESS);
192 }
193
194 error:
195 if (!fork_generation) {
196 return exit_status();
197 } else {
198 exit(EXIT_FAILURE);
199 }
200 }
This page took 0.034229 seconds and 5 git commands to generate.