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