fix: handle EINTR correctly in get_cpu_mask_from_sysfs
[urcu.git] / tests / regression / test_urcu_fork.c
... / ...
CommitLineData
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
40static 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
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
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
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
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 */
90static 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
152int 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
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]);
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
194error:
195 if (!fork_generation) {
196 return exit_status();
197 } else {
198 exit(EXIT_FAILURE);
199 }
200}
This page took 0.022811 seconds and 4 git commands to generate.