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 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 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 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 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); 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 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); 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 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 * 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); 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 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