Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/lib/libc/tests/stdlib/libc_exit_test.c
39530 views
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
156