1*19c3b8c2SApple OSS Distributions #ifdef T_NAMESPACE
2*19c3b8c2SApple OSS Distributions #undef T_NAMESPACE
3*19c3b8c2SApple OSS Distributions #endif /* T_NAMESPACE */
4*19c3b8c2SApple OSS Distributions
5*19c3b8c2SApple OSS Distributions #include <Block.h>
6*19c3b8c2SApple OSS Distributions #include <darwintest.h>
7*19c3b8c2SApple OSS Distributions #include <dispatch/dispatch.h>
8*19c3b8c2SApple OSS Distributions #include <err.h>
9*19c3b8c2SApple OSS Distributions #include <fcntl.h>
10*19c3b8c2SApple OSS Distributions #include <limits.h>
11*19c3b8c2SApple OSS Distributions #include <signal.h>
12*19c3b8c2SApple OSS Distributions #include <stdbool.h>
13*19c3b8c2SApple OSS Distributions #include <stdlib.h>
14*19c3b8c2SApple OSS Distributions #include <stdint.h>
15*19c3b8c2SApple OSS Distributions #include <unistd.h>
16*19c3b8c2SApple OSS Distributions #include <util.h>
17*19c3b8c2SApple OSS Distributions
18*19c3b8c2SApple OSS Distributions T_GLOBAL_META(
19*19c3b8c2SApple OSS Distributions T_META_NAMESPACE("xnu.kevent"),
20*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
21*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("kevent"),
22*19c3b8c2SApple OSS Distributions T_META_CHECK_LEAKS(false),
23*19c3b8c2SApple OSS Distributions T_META_RUN_CONCURRENTLY(true));
24*19c3b8c2SApple OSS Distributions
25*19c3b8c2SApple OSS Distributions #define TIMEOUT_SECS 10
26*19c3b8c2SApple OSS Distributions
27*19c3b8c2SApple OSS Distributions static int child_ready[2];
28*19c3b8c2SApple OSS Distributions
29*19c3b8c2SApple OSS Distributions static void
child_tty_client(void)30*19c3b8c2SApple OSS Distributions child_tty_client(void)
31*19c3b8c2SApple OSS Distributions {
32*19c3b8c2SApple OSS Distributions dispatch_source_t src;
33*19c3b8c2SApple OSS Distributions char buf[16] = "";
34*19c3b8c2SApple OSS Distributions ssize_t bytes_wr;
35*19c3b8c2SApple OSS Distributions
36*19c3b8c2SApple OSS Distributions src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
37*19c3b8c2SApple OSS Distributions (uintptr_t)STDIN_FILENO, 0, NULL);
38*19c3b8c2SApple OSS Distributions if (!src) {
39*19c3b8c2SApple OSS Distributions exit(1);
40*19c3b8c2SApple OSS Distributions }
41*19c3b8c2SApple OSS Distributions dispatch_source_set_event_handler(src, ^{});
42*19c3b8c2SApple OSS Distributions
43*19c3b8c2SApple OSS Distributions dispatch_activate(src);
44*19c3b8c2SApple OSS Distributions
45*19c3b8c2SApple OSS Distributions close(child_ready[0]);
46*19c3b8c2SApple OSS Distributions snprintf(buf, sizeof(buf), "%ds", getpid());
47*19c3b8c2SApple OSS Distributions bytes_wr = write(child_ready[1], buf, strlen(buf));
48*19c3b8c2SApple OSS Distributions if (bytes_wr < 0) {
49*19c3b8c2SApple OSS Distributions err(1, "failed to write on child ready pipe");
50*19c3b8c2SApple OSS Distributions }
51*19c3b8c2SApple OSS Distributions
52*19c3b8c2SApple OSS Distributions dispatch_main();
53*19c3b8c2SApple OSS Distributions }
54*19c3b8c2SApple OSS Distributions
55*19c3b8c2SApple OSS Distributions static void
pty_master(void)56*19c3b8c2SApple OSS Distributions pty_master(void)
57*19c3b8c2SApple OSS Distributions {
58*19c3b8c2SApple OSS Distributions pid_t child_pid;
59*19c3b8c2SApple OSS Distributions int ret;
60*19c3b8c2SApple OSS Distributions
61*19c3b8c2SApple OSS Distributions child_pid = fork();
62*19c3b8c2SApple OSS Distributions if (child_pid == 0) {
63*19c3b8c2SApple OSS Distributions child_tty_client();
64*19c3b8c2SApple OSS Distributions }
65*19c3b8c2SApple OSS Distributions ret = setpgid(child_pid, child_pid);
66*19c3b8c2SApple OSS Distributions if (ret < 0) {
67*19c3b8c2SApple OSS Distributions exit(1);
68*19c3b8c2SApple OSS Distributions }
69*19c3b8c2SApple OSS Distributions ret = tcsetpgrp(STDIN_FILENO, child_pid);
70*19c3b8c2SApple OSS Distributions if (ret < 0) {
71*19c3b8c2SApple OSS Distributions exit(1);
72*19c3b8c2SApple OSS Distributions }
73*19c3b8c2SApple OSS Distributions
74*19c3b8c2SApple OSS Distributions sleep(TIMEOUT_SECS);
75*19c3b8c2SApple OSS Distributions exit(1);
76*19c3b8c2SApple OSS Distributions }
77*19c3b8c2SApple OSS Distributions
78*19c3b8c2SApple OSS Distributions T_DECL(pty_master_teardown,
79*19c3b8c2SApple OSS Distributions "try removing a TTY master out from under a PTY slave holding a kevent",
80*19c3b8c2SApple OSS Distributions T_META_ASROOT(true))
81*19c3b8c2SApple OSS Distributions {
82*19c3b8c2SApple OSS Distributions __block pid_t master_pid;
83*19c3b8c2SApple OSS Distributions char buf[16] = "";
84*19c3b8c2SApple OSS Distributions char *end;
85*19c3b8c2SApple OSS Distributions ssize_t bytes_rd;
86*19c3b8c2SApple OSS Distributions size_t buf_len = 0;
87*19c3b8c2SApple OSS Distributions unsigned long slave_pid;
88*19c3b8c2SApple OSS Distributions int master_fd;
89*19c3b8c2SApple OSS Distributions char pty_filename[PATH_MAX];
90*19c3b8c2SApple OSS Distributions int status;
91*19c3b8c2SApple OSS Distributions
92*19c3b8c2SApple OSS Distributions T_SETUPBEGIN;
93*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(pipe(child_ready), NULL);
94*19c3b8c2SApple OSS Distributions
95*19c3b8c2SApple OSS Distributions master_pid = forkpty(&master_fd, pty_filename, NULL, NULL);
96*19c3b8c2SApple OSS Distributions if (master_pid == 0) {
97*19c3b8c2SApple OSS Distributions pty_master();
98*19c3b8c2SApple OSS Distributions __builtin_unreachable();
99*19c3b8c2SApple OSS Distributions }
100*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(master_pid,
101*19c3b8c2SApple OSS Distributions "forked child master PTY with pid %d, at pty %s", master_pid,
102*19c3b8c2SApple OSS Distributions pty_filename);
103*19c3b8c2SApple OSS Distributions
104*19c3b8c2SApple OSS Distributions close(child_ready[1]);
105*19c3b8c2SApple OSS Distributions
106*19c3b8c2SApple OSS Distributions end = buf;
107*19c3b8c2SApple OSS Distributions do {
108*19c3b8c2SApple OSS Distributions bytes_rd = read(child_ready[0], end, sizeof(buf) - buf_len);
109*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(bytes_rd, "read on pipe between master and runner");
110*19c3b8c2SApple OSS Distributions buf_len += (size_t)bytes_rd;
111*19c3b8c2SApple OSS Distributions T_LOG("runner read %zd bytes", bytes_rd);
112*19c3b8c2SApple OSS Distributions end += bytes_rd;
113*19c3b8c2SApple OSS Distributions } while (bytes_rd != 0 && *(end - 1) != 's');
114*19c3b8c2SApple OSS Distributions
115*19c3b8c2SApple OSS Distributions slave_pid = strtoul(buf, &end, 0);
116*19c3b8c2SApple OSS Distributions if (buf == end) {
117*19c3b8c2SApple OSS Distributions T_ASSERT_FAIL("could not parse child PID from master pipe");
118*19c3b8c2SApple OSS Distributions }
119*19c3b8c2SApple OSS Distributions
120*19c3b8c2SApple OSS Distributions T_LOG("got pid %lu for slave process from master", slave_pid);
121*19c3b8c2SApple OSS Distributions T_SETUPEND;
122*19c3b8c2SApple OSS Distributions
123*19c3b8c2SApple OSS Distributions T_LOG("sending fatal signal to master");
124*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(kill(master_pid, SIGKILL), NULL);
125*19c3b8c2SApple OSS Distributions
126*19c3b8c2SApple OSS Distributions T_LOG("sending fatal signal to slave");
127*19c3b8c2SApple OSS Distributions (void)kill((int)slave_pid, SIGKILL);
128*19c3b8c2SApple OSS Distributions
129*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(waitpid(master_pid, &status, 0), NULL);
130*19c3b8c2SApple OSS Distributions T_ASSERT_TRUE(WIFSIGNALED(status), "master PID was signaled");
131*19c3b8c2SApple OSS Distributions (void)waitpid((int)slave_pid, &status, 0);
132*19c3b8c2SApple OSS Distributions }
133*19c3b8c2SApple OSS Distributions
134*19c3b8c2SApple OSS Distributions volatile static bool writing = true;
135*19c3b8c2SApple OSS Distributions
136*19c3b8c2SApple OSS Distributions static void *
reader_thread(void * arg)137*19c3b8c2SApple OSS Distributions reader_thread(void *arg)
138*19c3b8c2SApple OSS Distributions {
139*19c3b8c2SApple OSS Distributions int fd = (int)arg;
140*19c3b8c2SApple OSS Distributions char c;
141*19c3b8c2SApple OSS Distributions
142*19c3b8c2SApple OSS Distributions T_SETUPBEGIN;
143*19c3b8c2SApple OSS Distributions T_QUIET;
144*19c3b8c2SApple OSS Distributions T_ASSERT_GT(fd, 0, "reader thread received valid fd");
145*19c3b8c2SApple OSS Distributions T_SETUPEND;
146*19c3b8c2SApple OSS Distributions
147*19c3b8c2SApple OSS Distributions for (;;) {
148*19c3b8c2SApple OSS Distributions ssize_t rdsize = read(fd, &c, sizeof(c));
149*19c3b8c2SApple OSS Distributions if (rdsize == -1) {
150*19c3b8c2SApple OSS Distributions if (errno == EINTR) {
151*19c3b8c2SApple OSS Distributions continue;
152*19c3b8c2SApple OSS Distributions } else if (errno == EBADF) {
153*19c3b8c2SApple OSS Distributions T_LOG("reader got an error (%s), shutting down",
154*19c3b8c2SApple OSS Distributions strerror(errno));
155*19c3b8c2SApple OSS Distributions return NULL;
156*19c3b8c2SApple OSS Distributions } else {
157*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(rdsize, "read on PTY");
158*19c3b8c2SApple OSS Distributions }
159*19c3b8c2SApple OSS Distributions } else if (rdsize == 0) {
160*19c3b8c2SApple OSS Distributions return NULL;
161*19c3b8c2SApple OSS Distributions }
162*19c3b8c2SApple OSS Distributions }
163*19c3b8c2SApple OSS Distributions
164*19c3b8c2SApple OSS Distributions return NULL;
165*19c3b8c2SApple OSS Distributions }
166*19c3b8c2SApple OSS Distributions
167*19c3b8c2SApple OSS Distributions static void *
writer_thread(void * arg)168*19c3b8c2SApple OSS Distributions writer_thread(void *arg)
169*19c3b8c2SApple OSS Distributions {
170*19c3b8c2SApple OSS Distributions int fd = (int)arg;
171*19c3b8c2SApple OSS Distributions char c[4096];
172*19c3b8c2SApple OSS Distributions memset(c, 'a', sizeof(c));
173*19c3b8c2SApple OSS Distributions
174*19c3b8c2SApple OSS Distributions T_SETUPBEGIN;
175*19c3b8c2SApple OSS Distributions T_QUIET;
176*19c3b8c2SApple OSS Distributions T_ASSERT_GT(fd, 0, "writer thread received valid fd");
177*19c3b8c2SApple OSS Distributions T_SETUPEND;
178*19c3b8c2SApple OSS Distributions
179*19c3b8c2SApple OSS Distributions while (writing) {
180*19c3b8c2SApple OSS Distributions ssize_t wrsize = write(fd, c, sizeof(c));
181*19c3b8c2SApple OSS Distributions if (wrsize == -1) {
182*19c3b8c2SApple OSS Distributions if (errno == EINTR) {
183*19c3b8c2SApple OSS Distributions continue;
184*19c3b8c2SApple OSS Distributions } else {
185*19c3b8c2SApple OSS Distributions T_LOG("writer got an error (%s), shutting down",
186*19c3b8c2SApple OSS Distributions strerror(errno));
187*19c3b8c2SApple OSS Distributions return NULL;
188*19c3b8c2SApple OSS Distributions }
189*19c3b8c2SApple OSS Distributions }
190*19c3b8c2SApple OSS Distributions }
191*19c3b8c2SApple OSS Distributions
192*19c3b8c2SApple OSS Distributions return NULL;
193*19c3b8c2SApple OSS Distributions }
194*19c3b8c2SApple OSS Distributions
195*19c3b8c2SApple OSS Distributions #define ATTACH_ITERATIONS 10000
196*19c3b8c2SApple OSS Distributions
197*19c3b8c2SApple OSS Distributions static int attach_master, attach_slave;
198*19c3b8c2SApple OSS Distributions static pthread_t reader, writer;
199*19c3b8c2SApple OSS Distributions
200*19c3b8c2SApple OSS Distributions static void
redispatch(dispatch_group_t grp,dispatch_source_type_t type,int fd)201*19c3b8c2SApple OSS Distributions redispatch(dispatch_group_t grp, dispatch_source_type_t type, int fd)
202*19c3b8c2SApple OSS Distributions {
203*19c3b8c2SApple OSS Distributions __block int iters = 0;
204*19c3b8c2SApple OSS Distributions
205*19c3b8c2SApple OSS Distributions __block void (^redispatch_blk)(void) = Block_copy(^{
206*19c3b8c2SApple OSS Distributions if (iters++ > ATTACH_ITERATIONS) {
207*19c3b8c2SApple OSS Distributions return;
208*19c3b8c2SApple OSS Distributions } else if (iters == ATTACH_ITERATIONS) {
209*19c3b8c2SApple OSS Distributions dispatch_group_leave(grp);
210*19c3b8c2SApple OSS Distributions T_PASS("created %d %s sources on busy PTY", iters,
211*19c3b8c2SApple OSS Distributions type == DISPATCH_SOURCE_TYPE_READ ? "read" : "write");
212*19c3b8c2SApple OSS Distributions }
213*19c3b8c2SApple OSS Distributions
214*19c3b8c2SApple OSS Distributions dispatch_source_t src = dispatch_source_create(
215*19c3b8c2SApple OSS Distributions type, (uintptr_t)fd, 0,
216*19c3b8c2SApple OSS Distributions dispatch_get_main_queue());
217*19c3b8c2SApple OSS Distributions
218*19c3b8c2SApple OSS Distributions dispatch_source_set_event_handler(src, ^{
219*19c3b8c2SApple OSS Distributions dispatch_cancel(src);
220*19c3b8c2SApple OSS Distributions });
221*19c3b8c2SApple OSS Distributions
222*19c3b8c2SApple OSS Distributions dispatch_source_set_cancel_handler(src, redispatch_blk);
223*19c3b8c2SApple OSS Distributions
224*19c3b8c2SApple OSS Distributions dispatch_activate(src);
225*19c3b8c2SApple OSS Distributions });
226*19c3b8c2SApple OSS Distributions
227*19c3b8c2SApple OSS Distributions dispatch_group_enter(grp);
228*19c3b8c2SApple OSS Distributions dispatch_async(dispatch_get_main_queue(), redispatch_blk);
229*19c3b8c2SApple OSS Distributions }
230*19c3b8c2SApple OSS Distributions
231*19c3b8c2SApple OSS Distributions T_DECL(attach_while_tty_wakeups,
232*19c3b8c2SApple OSS Distributions "try to attach knotes while a TTY is getting wakeups")
233*19c3b8c2SApple OSS Distributions {
234*19c3b8c2SApple OSS Distributions dispatch_group_t grp = dispatch_group_create();
235*19c3b8c2SApple OSS Distributions
236*19c3b8c2SApple OSS Distributions T_SETUPBEGIN;
237*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(openpty(&attach_master, &attach_slave, NULL, NULL,
238*19c3b8c2SApple OSS Distributions NULL), NULL);
239*19c3b8c2SApple OSS Distributions
240*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&reader, NULL, reader_thread,
241*19c3b8c2SApple OSS Distributions (void *)(uintptr_t)attach_master), NULL);
242*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&writer, NULL, writer_thread,
243*19c3b8c2SApple OSS Distributions (void *)(uintptr_t)attach_slave), NULL);
244*19c3b8c2SApple OSS Distributions T_SETUPEND;
245*19c3b8c2SApple OSS Distributions
246*19c3b8c2SApple OSS Distributions redispatch(grp, DISPATCH_SOURCE_TYPE_READ, attach_master);
247*19c3b8c2SApple OSS Distributions redispatch(grp, DISPATCH_SOURCE_TYPE_WRITE, attach_slave);
248*19c3b8c2SApple OSS Distributions
249*19c3b8c2SApple OSS Distributions dispatch_group_notify(grp, dispatch_get_main_queue(), ^{
250*19c3b8c2SApple OSS Distributions T_LOG("both reader and writer sources cleaned up");
251*19c3b8c2SApple OSS Distributions T_END;
252*19c3b8c2SApple OSS Distributions });
253*19c3b8c2SApple OSS Distributions
254*19c3b8c2SApple OSS Distributions dispatch_main();
255*19c3b8c2SApple OSS Distributions }
256*19c3b8c2SApple OSS Distributions
257*19c3b8c2SApple OSS Distributions T_DECL(master_read_data_set,
258*19c3b8c2SApple OSS Distributions "check that the data is set on read sources of master fds")
259*19c3b8c2SApple OSS Distributions {
260*19c3b8c2SApple OSS Distributions int master = -1, slave = -1;
261*19c3b8c2SApple OSS Distributions
262*19c3b8c2SApple OSS Distributions T_SETUPBEGIN;
263*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(openpty(&master, &slave, NULL, NULL, NULL), NULL);
264*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_GE(master, 0, "master fd is valid");
265*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_GE(slave, 0, "slave fd is valid");
266*19c3b8c2SApple OSS Distributions
267*19c3b8c2SApple OSS Distributions dispatch_source_t src = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
268*19c3b8c2SApple OSS Distributions (uintptr_t)master, 0, dispatch_get_main_queue());
269*19c3b8c2SApple OSS Distributions
270*19c3b8c2SApple OSS Distributions dispatch_source_set_event_handler(src, ^{
271*19c3b8c2SApple OSS Distributions unsigned long len = dispatch_source_get_data(src);
272*19c3b8c2SApple OSS Distributions T_EXPECT_GT(len, (unsigned long)0,
273*19c3b8c2SApple OSS Distributions "the amount of data to read was set for the master source");
274*19c3b8c2SApple OSS Distributions dispatch_cancel(src);
275*19c3b8c2SApple OSS Distributions });
276*19c3b8c2SApple OSS Distributions
277*19c3b8c2SApple OSS Distributions dispatch_source_set_cancel_handler(src, ^{
278*19c3b8c2SApple OSS Distributions dispatch_release(src);
279*19c3b8c2SApple OSS Distributions T_END;
280*19c3b8c2SApple OSS Distributions });
281*19c3b8c2SApple OSS Distributions
282*19c3b8c2SApple OSS Distributions dispatch_activate(src);
283*19c3b8c2SApple OSS Distributions T_SETUPEND;
284*19c3b8c2SApple OSS Distributions
285*19c3b8c2SApple OSS Distributions // Let's not fill up the TTY's buffer, otherwise write(2) will block.
286*19c3b8c2SApple OSS Distributions char buf[512] = "";
287*19c3b8c2SApple OSS Distributions
288*19c3b8c2SApple OSS Distributions int ret = 0;
289*19c3b8c2SApple OSS Distributions while ((ret = write(slave, buf, sizeof(buf)) == -1 && errno == EAGAIN)) {
290*19c3b8c2SApple OSS Distributions ;
291*19c3b8c2SApple OSS Distributions }
292*19c3b8c2SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "slave wrote data");
293*19c3b8c2SApple OSS Distributions
294*19c3b8c2SApple OSS Distributions dispatch_main();
295*19c3b8c2SApple OSS Distributions }
296