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 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 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 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 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 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 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 117 static void prepare_cb() { prepare = DONE; } 118 119 static void parent_cb() { parent = DONE; } 120 121 static void child_cb() { child = DONE; } 122 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 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 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