• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
fork_and_wait_normal_exit()28 void 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(&status);
35   ASSERT_TRUE(cpid > 0);
36   ASSERT_EQ(cpid, pid);
37   ASSERT_TRUE(WIFEXITED(status));
38 }
39 
fork_and_wait4_normal_exit()40 void 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, &status, 0, &usage);
50   ASSERT_TRUE(cpid > 0);
51   ASSERT_EQ(cpid, pid);
52   ASSERT_TRUE(WIFEXITED(status));
53 }
54 
fork_and_waitpid_normal_exit()55 void 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, &status, 0);
62   ASSERT_TRUE(cpid > 0);
63   ASSERT_EQ(cpid, pid);
64   ASSERT_TRUE(WIFEXITED(status));
65 }
66 
fork_and_wait_signal_exit()67 void 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(&status);
74   ASSERT_TRUE(cpid > 0);
75   ASSERT_EQ(cpid, pid);
76   ASSERT_FALSE(WIFEXITED(status));
77   ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
78 }
79 
fork_and_wait4_signal_exit()80 void 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, &status, 0, &usage);
90   ASSERT_TRUE(cpid > 0);
91   ASSERT_EQ(cpid, pid);
92   ASSERT_FALSE(WIFEXITED(status));
93   ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
94 }
95 
fork_and_waitpid_signal_exit()96 void 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, &status, 0);
103   ASSERT_TRUE(cpid > 0);
104   ASSERT_EQ(cpid, pid);
105   ASSERT_FALSE(WIFEXITED(status));
106   ASSERT_TRUE(WTERMSIG(status) == SIGUSR1);
107 }
108 
109 static int prepare = 0;
110 static int parent = 0;
111 static int child = 0;
112 static constexpr int DONE = 0x600D;
113 
prepare_cb()114 static void prepare_cb() { prepare = DONE; }
115 
parent_cb()116 static void parent_cb() { parent = DONE; }
117 
child_cb()118 static void child_cb() { child = DONE; }
119 
fork_with_atfork_callbacks()120 void 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, &status, 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 
TEST_MAIN(int argc,char ** argv,char ** envp)143 TEST_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