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