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 17 func_a(void) 18 { 19 if (write(STDOUT_FILENO, "a", 1) != 1) 20 _Exit(1); 21 } 22 23 static void 24 func_b(void) 25 { 26 if (write(STDOUT_FILENO, "b", 1) != 1) 27 _Exit(1); 28 } 29 30 static void 31 func_c(void) 32 { 33 if (write(STDOUT_FILENO, "c", 1) != 1) 34 _Exit(1); 35 } 36 37 static 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); 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 83 myatexit1(void) 84 { 85 exit(12); 86 } 87 88 ATF_TC_WITHOUT_HEAD(recursive_exit1); 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 110 myatexit2(void) 111 { 112 pthread_barrier_wait(&barrier); 113 exit(12); 114 } 115 116 static void * 117 mythreadexit(void *arg) 118 { 119 pthread_barrier_wait(&barrier); 120 exit(15); 121 } 122 123 ATF_TC_WITHOUT_HEAD(recursive_exit2); 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 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