xref: /aosp_15_r20/external/llvm-libc/test/integration/src/unistd/fork_test.cpp (revision 71db0c75aadcf003ffe3238005f61d7618a3fead)
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 
fork_and_wait_normal_exit()31 void 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 
fork_and_wait4_normal_exit()43 void 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 
fork_and_waitpid_normal_exit()58 void 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 
fork_and_wait_signal_exit()70 void 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 
fork_and_wait4_signal_exit()83 void 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 
fork_and_waitpid_signal_exit()99 void 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 
112 static int prepare = 0;
113 static int parent = 0;
114 static int child = 0;
115 static constexpr int DONE = 0x600D;
116 
prepare_cb()117 static void prepare_cb() { prepare = DONE; }
118 
parent_cb()119 static void parent_cb() { parent = DONE; }
120 
child_cb()121 static void child_cb() { child = DONE; }
122 
fork_with_atfork_callbacks()123 void 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 
gettid_test()146 void 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 
TEST_MAIN(int argc,char ** argv,char ** envp)162 TEST_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