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