1//===-- Unittests for fork ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "src/__support/OSUtil/syscall.h"
10#include "src/pthread/pthread_atfork.h"
11#include "src/signal/raise.h"
12#include "src/stdlib/exit.h"
13#include "src/sys/wait/wait.h"
14#include "src/sys/wait/wait4.h"
15#include "src/sys/wait/waitpid.h"
16#include "src/unistd/fork.h"
17#include "src/unistd/gettid.h"
18
19#include "test/IntegrationTest/test.h"
20
21#include <signal.h>
22#include <sys/syscall.h>
23#include <sys/wait.h>
24#include <unistd.h>
25
26// The tests wait4 and waitpid are present as tests for those functions
27// really and not for the fork function. They are here along with the tests
28// for fork because it is convenient to invoke and test them after forking
29// a child.
30
31void fork_and_wait_normal_exit() {
32 pid_t pid = LIBC_NAMESPACE::fork();
33 if (pid == 0)
34 return; // Just end without any thing special.
35 ASSERT_TRUE(pid > 0);
36 int status;
37 pid_t cpid = LIBC_NAMESPACE::wait(&status);
38 ASSERT_TRUE(cpid > 0);
39 ASSERT_EQ(cpid, pid);
40 ASSERT_TRUE(WIFEXITED(status));
41}
42
43void fork_and_wait4_normal_exit() {
44 pid_t pid = LIBC_NAMESPACE::fork();
45 if (pid == 0)
46 return; // Just end without any thing special.
47 ASSERT_TRUE(pid > 0);
48 int status;
49 struct rusage usage;
50 usage.ru_utime = {0, 0};
51 usage.ru_stime = {0, 0};
52 pid_t cpid = LIBC_NAMESPACE::wait4(pid, &status, 0, &usage);
53 ASSERT_TRUE(cpid > 0);
54 ASSERT_EQ(cpid, pid);
55 ASSERT_TRUE(WIFEXITED(status));
56}
57
58void fork_and_waitpid_normal_exit() {
59 pid_t pid = LIBC_NAMESPACE::fork();
60 if (pid == 0)
61 return; // Just end without any thing special.
62 ASSERT_TRUE(pid > 0);
63 int status;
64 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
65 ASSERT_TRUE(cpid > 0);
66 ASSERT_EQ(cpid, pid);
67 ASSERT_TRUE(WIFEXITED(status));
68}
69
70void fork_and_wait_signal_exit() {
71 pid_t pid = LIBC_NAMESPACE::fork();
72 if (pid == 0)
73 LIBC_NAMESPACE::raise(SIGUSR1);
74 ASSERT_TRUE(pid > 0);
75 int status;
76 pid_t cpid = LIBC_NAMESPACE::wait(&status);
77 ASSERT_TRUE(cpid > 0);
78 ASSERT_EQ(cpid, pid);
79 ASSERT_FALSE(WIFEXITED(status));
80 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
81}
82
83void fork_and_wait4_signal_exit() {
84 pid_t pid = LIBC_NAMESPACE::fork();
85 if (pid == 0)
86 LIBC_NAMESPACE::raise(SIGUSR1);
87 ASSERT_TRUE(pid > 0);
88 int status;
89 struct rusage usage;
90 usage.ru_utime = {0, 0};
91 usage.ru_stime = {0, 0};
92 pid_t cpid = LIBC_NAMESPACE::wait4(pid, &status, 0, &usage);
93 ASSERT_TRUE(cpid > 0);
94 ASSERT_EQ(cpid, pid);
95 ASSERT_FALSE(WIFEXITED(status));
96 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
97}
98
99void fork_and_waitpid_signal_exit() {
100 pid_t pid = LIBC_NAMESPACE::fork();
101 if (pid == 0)
102 LIBC_NAMESPACE::raise(SIGUSR1);
103 ASSERT_TRUE(pid > 0);
104 int status;
105 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
106 ASSERT_TRUE(cpid > 0);
107 ASSERT_EQ(cpid, pid);
108 ASSERT_FALSE(WIFEXITED(status));
109 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
110}
111
112static int prepare = 0;
113static int parent = 0;
114static int child = 0;
115static constexpr int DONE = 0x600D;
116
117static void prepare_cb() { prepare = DONE; }
118
119static void parent_cb() { parent = DONE; }
120
121static void child_cb() { child = DONE; }
122
123void fork_with_atfork_callbacks() {
124 ASSERT_EQ(LIBC_NAMESPACE::pthread_atfork(&prepare_cb, &parent_cb, &child_cb),
125 0);
126 pid_t pid = LIBC_NAMESPACE::fork();
127 if (pid == 0) {
128 // Raise a signal from the child if unexpected at-fork
129 // behavior is observed.
130 if (child != DONE || prepare != DONE || parent == DONE)
131 LIBC_NAMESPACE::raise(SIGUSR1);
132 return;
133 }
134
135 ASSERT_TRUE(pid > 0);
136 int status;
137 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
138 ASSERT_TRUE(cpid > 0);
139 ASSERT_EQ(cpid, pid);
140 ASSERT_TRUE(WIFEXITED(status));
141 ASSERT_EQ(prepare, DONE);
142 ASSERT_EQ(parent, DONE);
143 ASSERT_NE(child, DONE);
144}
145
146void gettid_test() {
147 // fork and verify tid is consistent with the syscall result.
148 int pid = LIBC_NAMESPACE::fork();
149 ASSERT_EQ(LIBC_NAMESPACE::gettid(),
150 LIBC_NAMESPACE::syscall_impl<pid_t>(SYS_gettid));
151 if (pid == 0)
152 LIBC_NAMESPACE::exit(0);
153 // make sure child process exits normally
154 int status;
155 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, &status, 0);
156 ASSERT_TRUE(cpid > 0);
157 ASSERT_EQ(cpid, pid);
158 ASSERT_TRUE(WIFEXITED(status));
159 ASSERT_EQ(WEXITSTATUS(status), 0);
160}
161
162TEST_MAIN(int argc, char **argv, char **envp) {
163 gettid_test();
164 fork_and_wait_normal_exit();
165 fork_and_wait4_normal_exit();
166 fork_and_waitpid_normal_exit();
167 fork_and_wait_signal_exit();
168 fork_and_wait4_signal_exit();
169 fork_and_waitpid_signal_exit();
170 fork_with_atfork_callbacks();
171 return 0;
172}
173

Provided by KDAB

Privacy Policy
Learn to use CMake with our Intro Training
Find out more

source code of libc/test/integration/src/unistd/fork_test.cpp