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/pthread/pthread_atfork.h"
10#include "src/signal/raise.h"
11#include "src/sys/wait/wait.h"
12#include "src/sys/wait/wait4.h"
13#include "src/sys/wait/waitpid.h"
14#include "src/unistd/fork.h"
15
16#include "test/IntegrationTest/test.h"
17
18#include <errno.h>
19#include <signal.h>
20#include <sys/wait.h>
21#include <unistd.h>
22
23// The tests wait4 and waitpid are present as tests for those functions
24// really and not for the fork function. They are here along with the tests
25// for fork because it is convenient to invoke and test them after forking
26// a child.
27
28void fork_and_wait_normal_exit() {
29 pid_t pid = LIBC_NAMESPACE::fork();
30 if (pid == 0)
31 return; // Just end without any thing special.
32 ASSERT_TRUE(pid > 0);
33 int status;
34 pid_t cpid = LIBC_NAMESPACE::wait(waitstatus: &status);
35 ASSERT_TRUE(cpid > 0);
36 ASSERT_EQ(cpid, pid);
37 ASSERT_TRUE(WIFEXITED(status));
38}
39
40void fork_and_wait4_normal_exit() {
41 pid_t pid = LIBC_NAMESPACE::fork();
42 if (pid == 0)
43 return; // Just end without any thing special.
44 ASSERT_TRUE(pid > 0);
45 int status;
46 struct rusage usage;
47 usage.ru_utime = {0, 0};
48 usage.ru_stime = {0, 0};
49 pid_t cpid = LIBC_NAMESPACE::wait4(pid, waitstatus: &status, options: 0, usage: &usage);
50 ASSERT_TRUE(cpid > 0);
51 ASSERT_EQ(cpid, pid);
52 ASSERT_TRUE(WIFEXITED(status));
53}
54
55void fork_and_waitpid_normal_exit() {
56 pid_t pid = LIBC_NAMESPACE::fork();
57 if (pid == 0)
58 return; // Just end without any thing special.
59 ASSERT_TRUE(pid > 0);
60 int status;
61 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, waitstatus: &status, options: 0);
62 ASSERT_TRUE(cpid > 0);
63 ASSERT_EQ(cpid, pid);
64 ASSERT_TRUE(WIFEXITED(status));
65}
66
67void fork_and_wait_signal_exit() {
68 pid_t pid = LIBC_NAMESPACE::fork();
69 if (pid == 0)
70 LIBC_NAMESPACE::raise(SIGUSR1);
71 ASSERT_TRUE(pid > 0);
72 int status;
73 pid_t cpid = LIBC_NAMESPACE::wait(waitstatus: &status);
74 ASSERT_TRUE(cpid > 0);
75 ASSERT_EQ(cpid, pid);
76 ASSERT_FALSE(WIFEXITED(status));
77 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
78}
79
80void fork_and_wait4_signal_exit() {
81 pid_t pid = LIBC_NAMESPACE::fork();
82 if (pid == 0)
83 LIBC_NAMESPACE::raise(SIGUSR1);
84 ASSERT_TRUE(pid > 0);
85 int status;
86 struct rusage usage;
87 usage.ru_utime = {0, 0};
88 usage.ru_stime = {0, 0};
89 pid_t cpid = LIBC_NAMESPACE::wait4(pid, waitstatus: &status, options: 0, usage: &usage);
90 ASSERT_TRUE(cpid > 0);
91 ASSERT_EQ(cpid, pid);
92 ASSERT_FALSE(WIFEXITED(status));
93 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
94}
95
96void fork_and_waitpid_signal_exit() {
97 pid_t pid = LIBC_NAMESPACE::fork();
98 if (pid == 0)
99 LIBC_NAMESPACE::raise(SIGUSR1);
100 ASSERT_TRUE(pid > 0);
101 int status;
102 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, waitstatus: &status, options: 0);
103 ASSERT_TRUE(cpid > 0);
104 ASSERT_EQ(cpid, pid);
105 ASSERT_FALSE(WIFEXITED(status));
106 ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
107}
108
109static int prepare = 0;
110static int parent = 0;
111static int child = 0;
112static constexpr int DONE = 0x600D;
113
114static void prepare_cb() { prepare = DONE; }
115
116static void parent_cb() { parent = DONE; }
117
118static void child_cb() { child = DONE; }
119
120void fork_with_atfork_callbacks() {
121 ASSERT_EQ(LIBC_NAMESPACE::pthread_atfork(&prepare_cb, &parent_cb, &child_cb),
122 0);
123 pid_t pid = LIBC_NAMESPACE::fork();
124 if (pid == 0) {
125 // Raise a signal from the child if unexpected at-fork
126 // behavior is observed.
127 if (child != DONE || prepare != DONE || parent == DONE)
128 LIBC_NAMESPACE::raise(SIGUSR1);
129 return;
130 }
131
132 ASSERT_TRUE(pid > 0);
133 int status;
134 pid_t cpid = LIBC_NAMESPACE::waitpid(pid, waitstatus: &status, options: 0);
135 ASSERT_TRUE(cpid > 0);
136 ASSERT_EQ(cpid, pid);
137 ASSERT_TRUE(WIFEXITED(status));
138 ASSERT_EQ(prepare, DONE);
139 ASSERT_EQ(parent, DONE);
140 ASSERT_NE(child, DONE);
141}
142
143TEST_MAIN(int argc, char **argv, char **envp) {
144 fork_and_wait_normal_exit();
145 fork_and_wait4_normal_exit();
146 fork_and_waitpid_normal_exit();
147 fork_and_wait_signal_exit();
148 fork_and_wait4_signal_exit();
149 fork_and_waitpid_signal_exit();
150 fork_with_atfork_callbacks();
151 return 0;
152}
153

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