uatomic/x86: Remove redundant memory barriers
[urcu.git] / tests / regression / test_urcu_fork.c
CommitLineData
ce29b371
MJ
1// SPDX-FileCopyrightText: 2012 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
2//
3// SPDX-License-Identifier: GPL-2.0-or-later
4
390f0a26 5/*
390f0a26 6 * Userspace RCU library - test program (fork)
390f0a26
MD
7 */
8
390f0a26
MD
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>
390f0a26
MD
17#include <sched.h>
18#include <errno.h>
19
01477510 20#include <urcu/assert.h>
390f0a26
MD
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
ad460058
MD
31#include "tap.h"
32
d6aefcd1
MD
33/* We generate children 3 levels deep */
34#define FORK_DEPTH 3
35/* Each generation spawns 10 children */
36#define NR_FORK 10
37
ad460058
MD
38#define NR_TESTS NR_FORK
39
d6aefcd1
MD
40static int fork_generation;
41
ad460058
MD
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
390f0a26
MD
52struct test_node {
53 int somedata;
54 struct rcu_head head;
55};
56
57static void cb(struct rcu_head *head)
58{
59 struct test_node *node;
60
ad460058 61 diag_gen0("rcu callback invoked in pid: %d", (int) getpid());
390f0a26
MD
62 node = caa_container_of(head, struct test_node, head);
63 free(node);
64}
65
66static 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
153b081a 77 node = (struct test_node *) malloc(sizeof(*node));
01477510 78 urcu_posix_assert(node);
390f0a26
MD
79
80 call_rcu(&node->head, cb);
81
82 synchronize_rcu();
83
84 rcu_unregister_thread();
85}
86
d6aefcd1
MD
87/*
88 * Return 0 if child, > 0 if parent, < 0 on error.
89 */
90static int do_fork(const char *execname)
390f0a26
MD
91{
92 pid_t pid;
390f0a26 93
ad460058 94 diag_gen0("%s parent pid: %d, before fork",
d6aefcd1 95 execname, (int) getpid());
390f0a26
MD
96
97 call_rcu_before_fork();
98 pid = fork();
390f0a26
MD
99 if (pid == 0) {
100 /* child */
d6aefcd1 101 fork_generation++;
ad460058 102 tap_disable();
d6aefcd1 103
390f0a26 104 call_rcu_after_fork_child();
ad460058 105 diag_gen0("%s child pid: %d, after fork",
d6aefcd1 106 execname, (int) getpid());
390f0a26 107 test_rcu();
ad460058 108 diag_gen0("%s child pid: %d, after rcu test",
d6aefcd1
MD
109 execname, (int) getpid());
110 if (fork_generation >= FORK_DEPTH)
111 exit(EXIT_SUCCESS);
112 return 0;
390f0a26
MD
113 } else if (pid > 0) {
114 int status;
115
116 /* parent */
117 call_rcu_after_fork_parent();
ad460058 118 diag_gen0("%s parent pid: %d, after fork",
d6aefcd1 119 execname, (int) getpid());
390f0a26 120 test_rcu();
ad460058 121 diag_gen0("%s parent pid: %d, after rcu test",
d6aefcd1 122 execname, (int) getpid());
390f0a26
MD
123 for (;;) {
124 pid = wait(&status);
d6aefcd1 125 if (pid < 0) {
ad460058
MD
126 if (!fork_generation)
127 perror("wait");
d6aefcd1
MD
128 return -1;
129 }
390f0a26 130 if (WIFEXITED(status)) {
ad460058 131 diag_gen0("child %u exited normally with status %u",
390f0a26 132 pid, WEXITSTATUS(status));
d6aefcd1
MD
133 if (WEXITSTATUS(status))
134 return -1;
390f0a26
MD
135 break;
136 } else if (WIFSIGNALED(status)) {
ad460058 137 diag_gen0("child %u was terminated by signal %u",
390f0a26 138 pid, WTERMSIG(status));
d6aefcd1 139 return -1;
390f0a26
MD
140 } else {
141 continue;
142 }
143 }
d6aefcd1 144 return 1;
390f0a26 145 } else {
ad460058
MD
146 if (!fork_generation)
147 perror("fork");
d6aefcd1
MD
148 return -1;
149 }
150}
151
70469b43 152int main(int argc __attribute__((unused)), char **argv)
d6aefcd1
MD
153{
154 unsigned int i;
155
ad460058
MD
156 plan_tests(NR_TESTS);
157
d6aefcd1
MD
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");
390f0a26
MD
166 exit(EXIT_FAILURE);
167 }
d6aefcd1
MD
168#endif
169
170restart:
171 for (i = 0; i < NR_FORK; i++) {
172 int ret;
173
174 test_rcu();
175 synchronize_rcu();
176 ret = do_fork(argv[0]);
ad460058
MD
177 if (!fork_generation) {
178 ok(ret >= 0, "child status %d", ret);
179 }
180 if (ret == 0) { /* child */
d6aefcd1 181 goto restart;
ad460058 182 } else if (ret < 0) {
d6aefcd1 183 goto error;
ad460058
MD
184 } else {
185 /* else parent, continue. */
186 }
187 }
188 if (!fork_generation) {
189 return exit_status();
190 } else {
191 exit(EXIT_SUCCESS);
d6aefcd1 192 }
d6aefcd1
MD
193
194error:
ad460058
MD
195 if (!fork_generation) {
196 return exit_status();
197 } else {
198 exit(EXIT_FAILURE);
199 }
390f0a26 200}
This page took 0.048101 seconds and 4 git commands to generate.