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