1 /*-
2 * Copyright (c) 2023 Klara, Inc.
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7 #include <sys/wait.h>
8
9 #include <pthread.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <unistd.h>
13
14 #include <atf-c.h>
15
16 static void
func_a(void)17 func_a(void)
18 {
19 if (write(STDOUT_FILENO, "a", 1) != 1)
20 _Exit(1);
21 }
22
23 static void
func_b(void)24 func_b(void)
25 {
26 if (write(STDOUT_FILENO, "b", 1) != 1)
27 _Exit(1);
28 }
29
30 static void
func_c(void)31 func_c(void)
32 {
33 if (write(STDOUT_FILENO, "c", 1) != 1)
34 _Exit(1);
35 }
36
37 static void
child(void)38 child(void)
39 {
40 /* this will be received by the parent */
41 printf("hello, ");
42 fflush(stdout);
43 /* this won't, because quick_exit() does not flush */
44 printf("world");
45 /* these will be called in reverse order, producing "abc" */
46 if (at_quick_exit(func_c) != 0 ||
47 at_quick_exit(func_b) != 0 ||
48 at_quick_exit(func_a) != 0)
49 _Exit(1);
50 quick_exit(0);
51 }
52
53 ATF_TC_WITHOUT_HEAD(quick_exit);
ATF_TC_BODY(quick_exit,tc)54 ATF_TC_BODY(quick_exit, tc)
55 {
56 char buf[100] = "";
57 ssize_t len;
58 int p[2], wstatus = 0;
59 pid_t pid;
60
61 ATF_REQUIRE(pipe(p) == 0);
62 pid = fork();
63 if (pid == 0) {
64 if (dup2(p[1], STDOUT_FILENO) < 0)
65 _Exit(1);
66 (void)close(p[1]);
67 (void)close(p[0]);
68 child();
69 _Exit(1);
70 }
71 ATF_REQUIRE_MSG(pid > 0,
72 "expect fork() to succeed");
73 ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
74 "expect to collect child process");
75 ATF_CHECK_EQ_MSG(0, wstatus,
76 "expect child to exit cleanly");
77 ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0,
78 "expect to receive output from child");
79 ATF_CHECK_STREQ("hello, abc", buf);
80 }
81
82 static void
myatexit1(void)83 myatexit1(void)
84 {
85 exit(12);
86 }
87
88 ATF_TC_WITHOUT_HEAD(recursive_exit1);
ATF_TC_BODY(recursive_exit1,tc)89 ATF_TC_BODY(recursive_exit1, tc)
90 {
91 pid_t pid;
92 int wstatus;
93
94 pid = fork();
95 if (pid == 0) {
96 atexit(myatexit1);
97 exit(1);
98 }
99 ATF_REQUIRE_MSG(pid > 0,
100 "expect fork() to succeed");
101 ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
102 "expect to collect child process");
103 ATF_CHECK(WIFEXITED(wstatus));
104 ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12);
105 }
106
107 static pthread_barrier_t barrier;
108
109 static void
myatexit2(void)110 myatexit2(void)
111 {
112 pthread_barrier_wait(&barrier);
113 exit(12);
114 }
115
116 static void *
mythreadexit(void * arg)117 mythreadexit(void *arg)
118 {
119 pthread_barrier_wait(&barrier);
120 exit(15);
121 }
122
123 ATF_TC_WITHOUT_HEAD(recursive_exit2);
ATF_TC_BODY(recursive_exit2,tc)124 ATF_TC_BODY(recursive_exit2, tc)
125 {
126 pid_t pid;
127 int wstatus;
128
129 pid = fork();
130 if (pid == 0) {
131 pthread_t thr;
132
133 atexit(myatexit2);
134
135 pthread_barrier_init(&barrier, NULL, 2);
136 pthread_create(&thr, NULL, mythreadexit, NULL);
137
138 exit(1);
139 }
140 ATF_REQUIRE_MSG(pid > 0,
141 "expect fork() to succeed");
142 ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
143 "expect to collect child process");
144 ATF_CHECK(WIFEXITED(wstatus));
145 ATF_CHECK_EQ(WEXITSTATUS(wstatus), 12);
146 }
147
ATF_TP_ADD_TCS(tp)148 ATF_TP_ADD_TCS(tp)
149 {
150 ATF_TP_ADD_TC(tp, quick_exit);
151 ATF_TP_ADD_TC(tp, recursive_exit1);
152 ATF_TP_ADD_TC(tp, recursive_exit2);
153 return (atf_no_error());
154 }
155