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