]>
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 | ||
cb323159 A |
16 | T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true)); |
17 | ||
39037602 A |
18 | #define TMP_FILE_PATH "/tmp/test_kqueue_fifo_18776047" |
19 | ||
20 | #define READ_BUFFER_LEN 256 | |
21 | ||
5ba3f43e | 22 | #if TARGET_OS_WATCH |
39037602 A |
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 | |
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) { | |
0a7de745 | 46 | if (len == 1) { |
39037602 | 47 | return count; |
0a7de745 | 48 | } else { |
39037602 | 49 | len--; |
0a7de745 | 50 | } |
39037602 A |
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 | |
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 | |
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 | |
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 | ||
813fb2f6 | 116 | T_DECL(kqueue_fifo_18776047, "Tests kqueue, kevent for watching a fifo.", T_META_LTEPHASE(LTE_POSTINIT)) |
39037602 A |
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 | } |