174 lines · cpp
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-exception6//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 functions27// really and not for the fork function. They are here along with the tests28// for fork because it is convenient to invoke and test them after forking29// 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-fork129 // 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 normally154 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([[maybe_unused]] int argc, [[maybe_unused]] char **argv,163 [[maybe_unused]] char **envp) {164 gettid_test();165 fork_and_wait_normal_exit();166 fork_and_wait4_normal_exit();167 fork_and_waitpid_normal_exit();168 fork_and_wait_signal_exit();169 fork_and_wait4_signal_exit();170 fork_and_waitpid_signal_exit();171 fork_with_atfork_callbacks();172 return 0;173}174