xref: /xnu-8796.121.2/tests/kqueue_fifo_18776047.c (revision c54f35ca767986246321eb901baf8f5ff7923f6a)
1 /*
2  * testname: kqueue_fifo
3  */
4 
5 #include <darwintest.h>
6 #include <fcntl.h>
7 #include <sys/event.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <unistd.h>
11 #include <stdlib.h>
12 #include <errno.h>
13 
14 #include <TargetConditionals.h>
15 
16 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(false));  // rdar://79464597
17 
18 #define TMP_FILE_PATH "/tmp/test_kqueue_fifo_18776047"
19 
20 #define READ_BUFFER_LEN 256
21 
22 #if TARGET_OS_WATCH
23 #define TOTAL_ITERATIONS 5000
24 #else
25 #define TOTAL_ITERATIONS 10000
26 #endif
27 
28 /* prototypes */
29 int write_some_data(int fd);
30 int read_data(int fd);
31 void create_fifo(const char * filepath);
32 void kevent_one_shot(int kq, int fd, int filter);
33 
34 int
write_some_data(int fd)35 write_some_data(int fd)
36 {
37 	int retval  = 0;
38 	int count   = 0;
39 	int len     = 5;
40 	char * data = "ABCDE";
41 	while (true) {
42 		errno  = 0;
43 		retval = (int)write(fd, data, (size_t)len);
44 		if (retval < 0) {
45 			if (errno == EAGAIN) {
46 				if (len == 1) {
47 					return count;
48 				} else {
49 					len--;
50 				}
51 			} else {
52 				T_ASSERT_FAIL("write to fd %d of %s of len %d failed.", fd, data, len);
53 				abort();
54 			}
55 		} else {
56 			count += retval;
57 		}
58 	}
59 }
60 
61 int
read_data(int fd)62 read_data(int fd)
63 {
64 	int retval, count = 0;
65 	char databuffer[READ_BUFFER_LEN];
66 	while (true) {
67 		errno  = 0;
68 		retval = (int)read(fd, databuffer, READ_BUFFER_LEN);
69 		if (retval < 0) {
70 			if (errno == EAGAIN) {
71 				return count;
72 			} else {
73 				T_ASSERT_FAIL("read from fd %d failed.", fd);
74 				abort();
75 			}
76 		}
77 		count += retval;
78 	}
79 }
80 
81 void
create_fifo(const char * filepath)82 create_fifo(const char * filepath)
83 {
84 	struct stat f_stat;
85 	int ret = 0;
86 	errno   = 0;
87 	ret = stat(filepath, &f_stat);
88 	if (ret == 0) {
89 		/* if file exists, make sure its a fifo */
90 		T_ASSERT_TRUE(S_ISFIFO(f_stat.st_mode), "ensure %s is a fifo", filepath);
91 	} else if (errno == ENOENT) {
92 		ret = mkfifo(filepath, 0777);
93 		T_ASSERT_POSIX_ZERO(ret, "creating a fifo at path %s", filepath);
94 	} else {
95 		T_ASSERT_FAIL("stat operation on %s", filepath);
96 	}
97 }
98 
99 void
kevent_one_shot(int kq,int fd,int filter)100 kevent_one_shot(int kq, int fd, int filter)
101 {
102 	int retval             = 0;
103 	struct timespec t_zero = {0, 0};
104 	struct kevent kev[1];
105 
106 	T_QUIET;
107 	T_ASSERT_GE(kq, 0, "ensure kq is valid");
108 	T_LOG("kevent doing ONESHOT %s", filter == EVFILT_READ ? "read" : "write");
109 
110 	EV_SET(kev, fd, filter, EV_ADD | EV_ONESHOT, 0, 0, NULL);
111 	retval = kevent(kq, kev, 1, NULL, 0, &t_zero);
112 	T_QUIET;
113 	T_ASSERT_POSIX_ZERO(retval, "ONESHOT kevent for fd %d, filter %d", fd, filter);
114 }
115 
116 T_DECL(kqueue_fifo_18776047, "Tests kqueue, kevent for watching a fifo.", T_META_LTEPHASE(LTE_POSTINIT))
117 {
118 	struct kevent kev[1];
119 	int read_fd, write_fd, kq;
120 	int retval         = 0;
121 	int iter           = 0;
122 	const char * fpath = TMP_FILE_PATH;
123 	T_SETUPBEGIN;
124 	create_fifo(fpath);
125 
126 	kq = kqueue();
127 	T_ASSERT_GE(kq, 0, "create a kqueue");
128 
129 	read_fd = open(fpath, O_RDONLY | O_APPEND | O_NONBLOCK);
130 	T_ASSERT_POSIX_SUCCESS(read_fd, "opening read fd on fifo.");
131 
132 	write_fd = open(fpath, O_WRONLY | O_APPEND | O_NONBLOCK);
133 	T_ASSERT_POSIX_SUCCESS(write_fd, "opening write fd on fifo.");
134 
135 	T_SETUPEND;
136 
137 	kevent_one_shot(kq, write_fd, EVFILT_WRITE);
138 	kevent_one_shot(kq, read_fd, EVFILT_READ);
139 
140 	while (iter++ < TOTAL_ITERATIONS) {
141 		retval = kevent(kq, NULL, 0, kev, 1, NULL);
142 		T_QUIET;
143 		T_ASSERT_GE(retval, 0, "kevent on kq %d", kq);
144 
145 		if (kev[0].ident == (uintptr_t)write_fd) {
146 			retval = write_some_data(write_fd);
147 			T_LOG("writer ready iter: %d wrote %d bytes", iter, retval);
148 			kevent_one_shot(kq, write_fd, EVFILT_WRITE);
149 		} else if (kev[0].ident == (uintptr_t)read_fd) {
150 			retval = read_data(read_fd);
151 			T_LOG("reader ready iter: %d read %d bytes", iter, retval);
152 			kevent_one_shot(kq, read_fd, EVFILT_READ);
153 		}
154 	}
155 	T_PASS("kqueue_fifo_18776047 PASSED");
156 }
157