15132e16eSMark Johnston /*-
25132e16eSMark Johnston * Copyright (c) 2023 Klara, Inc.
35132e16eSMark Johnston *
45132e16eSMark Johnston * SPDX-License-Identifier: BSD-2-Clause
55132e16eSMark Johnston */
65132e16eSMark Johnston
75132e16eSMark Johnston #include <sys/wait.h>
85132e16eSMark Johnston
9*c0946aeeSMark Johnston #include <pthread.h>
105132e16eSMark Johnston #include <stdio.h>
115132e16eSMark Johnston #include <stdlib.h>
125132e16eSMark Johnston #include <unistd.h>
135132e16eSMark Johnston
145132e16eSMark Johnston #include <atf-c.h>
155132e16eSMark Johnston
165132e16eSMark Johnston static void
func_a(void)175132e16eSMark Johnston func_a(void)
185132e16eSMark Johnston {
195132e16eSMark Johnston if (write(STDOUT_FILENO, "a", 1) != 1)
205132e16eSMark Johnston _Exit(1);
215132e16eSMark Johnston }
225132e16eSMark Johnston
235132e16eSMark Johnston static void
func_b(void)245132e16eSMark Johnston func_b(void)
255132e16eSMark Johnston {
265132e16eSMark Johnston if (write(STDOUT_FILENO, "b", 1) != 1)
275132e16eSMark Johnston _Exit(1);
285132e16eSMark Johnston }
295132e16eSMark Johnston
305132e16eSMark Johnston static void
func_c(void)315132e16eSMark Johnston func_c(void)
325132e16eSMark Johnston {
335132e16eSMark Johnston if (write(STDOUT_FILENO, "c", 1) != 1)
345132e16eSMark Johnston _Exit(1);
355132e16eSMark Johnston }
365132e16eSMark Johnston
375132e16eSMark Johnston static void
child(void)385132e16eSMark Johnston child(void)
395132e16eSMark Johnston {
405132e16eSMark Johnston /* this will be received by the parent */
415132e16eSMark Johnston printf("hello, ");
425132e16eSMark Johnston fflush(stdout);
435132e16eSMark Johnston /* this won't, because quick_exit() does not flush */
445132e16eSMark Johnston printf("world");
455132e16eSMark Johnston /* these will be called in reverse order, producing "abc" */
465132e16eSMark Johnston if (at_quick_exit(func_c) != 0 ||
475132e16eSMark Johnston at_quick_exit(func_b) != 0 ||
485132e16eSMark Johnston at_quick_exit(func_a) != 0)
495132e16eSMark Johnston _Exit(1);
505132e16eSMark Johnston quick_exit(0);
515132e16eSMark Johnston }
525132e16eSMark Johnston
535132e16eSMark Johnston ATF_TC_WITHOUT_HEAD(quick_exit);
ATF_TC_BODY(quick_exit,tc)545132e16eSMark Johnston ATF_TC_BODY(quick_exit, tc)
555132e16eSMark Johnston {
565132e16eSMark Johnston char buf[100] = "";
575132e16eSMark Johnston ssize_t len;
585132e16eSMark Johnston int p[2], wstatus = 0;
595132e16eSMark Johnston pid_t pid;
605132e16eSMark Johnston
615132e16eSMark Johnston ATF_REQUIRE(pipe(p) == 0);
625132e16eSMark Johnston pid = fork();
635132e16eSMark Johnston if (pid == 0) {
645132e16eSMark Johnston if (dup2(p[1], STDOUT_FILENO) < 0)
655132e16eSMark Johnston _Exit(1);
665132e16eSMark Johnston (void)close(p[1]);
675132e16eSMark Johnston (void)close(p[0]);
685132e16eSMark Johnston child();
695132e16eSMark Johnston _Exit(1);
705132e16eSMark Johnston }
715132e16eSMark Johnston ATF_REQUIRE_MSG(pid > 0,
725132e16eSMark Johnston "expect fork() to succeed");
735132e16eSMark Johnston ATF_CHECK_EQ_MSG(pid, waitpid(pid, &wstatus, 0),
745132e16eSMark Johnston "expect to collect child process");
755132e16eSMark Johnston ATF_CHECK_EQ_MSG(0, wstatus,
765132e16eSMark Johnston "expect child to exit cleanly");
775132e16eSMark Johnston ATF_CHECK_MSG((len = read(p[0], buf, sizeof(buf))) > 0,
785132e16eSMark Johnston "expect to receive output from child");
795132e16eSMark Johnston ATF_CHECK_STREQ("hello, abc", buf);
805132e16eSMark Johnston }
815132e16eSMark Johnston
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)1485132e16eSMark Johnston ATF_TP_ADD_TCS(tp)
1495132e16eSMark Johnston {
1505132e16eSMark Johnston 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);
1535132e16eSMark Johnston return (atf_no_error());
1545132e16eSMark Johnston }
155