1 /*
2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17 #include "common.h"
18
19 static int sockfd[2];
20
21 static void
kevent_socket_drain(void)22 kevent_socket_drain(void)
23 {
24 char buf[1];
25
26 /* Drain the read buffer, then make sure there are no more events. */
27 puts("draining the read buffer");
28 if (read(sockfd[0], &buf[0], 1) < 1)
29 err(1, "read(2)");
30 }
31
32 static void
kevent_socket_fill(void)33 kevent_socket_fill(void)
34 {
35 puts("filling the read buffer");
36 if (write(sockfd[1], ".", 1) < 1)
37 err(1, "write(2)");
38 }
39
40
41 static void
test_kevent_socket_add(void)42 test_kevent_socket_add(void)
43 {
44 const char *test_id = "kevent(EVFILT_READ, EV_ADD)";
45 struct kevent kev;
46
47 test_begin(test_id);
48 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
49 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
50 err(1, "%s", test_id);
51
52 success();
53 }
54
55 static void
test_kevent_socket_get(void)56 test_kevent_socket_get(void)
57 {
58 const char *test_id = "kevent(EVFILT_READ) wait";
59 struct kevent kev;
60
61 test_begin(test_id);
62
63 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
64 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
65 err(1, "%s", test_id);
66
67 kevent_socket_fill();
68
69 kev.data = 1;
70 kevent_cmp(&kev, kevent_get(kqfd));
71
72 kevent_socket_drain();
73 test_no_kevents();
74
75 kev.flags = EV_DELETE;
76 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
77 err(1, "%s", test_id);
78
79 success();
80 }
81
82 static void
test_kevent_socket_clear(void)83 test_kevent_socket_clear(void)
84 {
85 const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)";
86 struct kevent kev;
87
88 test_begin(test_id);
89
90 test_no_kevents();
91
92 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
93 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
94 err(1, "%s", test_id);
95
96 kevent_socket_fill();
97 kevent_socket_fill();
98
99 kev.data = 2;
100 kevent_cmp(&kev, kevent_get(kqfd));
101
102 /* We filled twice, but drain once. Edge-triggered would not generate
103 additional events.
104 */
105 kevent_socket_drain();
106 test_no_kevents();
107
108 kevent_socket_drain();
109 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
110 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
111 err(1, "%s", test_id);
112
113 success();
114 }
115
116 static void
test_kevent_socket_disable_and_enable(void)117 test_kevent_socket_disable_and_enable(void)
118 {
119 const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)";
120 struct kevent kev;
121
122 test_begin(test_id);
123
124 /*
125 * Write to the socket before adding the event. This way we can verify that
126 * enabling a triggered kevent causes the event to be returned immediately.
127 */
128 kevent_socket_fill();
129
130 /* Add a disabled event. */
131 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]);
132 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
133 err(1, "%s", test_id);
134
135 test_no_kevents();
136
137 /* Re-enable the knote, then see if an event is generated */
138 kev.flags = EV_ENABLE;
139 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
140 err(1, "%s", test_id);
141 kev.flags = EV_ADD;
142 kev.data = 1;
143 kevent_cmp(&kev, kevent_get(kqfd));
144
145 kevent_socket_drain();
146
147 kev.flags = EV_DELETE;
148 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
149 err(1, "%s", test_id);
150
151 success();
152 }
153
154 static void
test_kevent_socket_del(void)155 test_kevent_socket_del(void)
156 {
157 const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
158 struct kevent kev;
159
160 test_begin(test_id);
161
162 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
163 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
164 err(1, "%s", test_id);
165
166 kevent_socket_fill();
167 test_no_kevents();
168 kevent_socket_drain();
169
170 success();
171 }
172
173 static void
test_kevent_socket_oneshot(void)174 test_kevent_socket_oneshot(void)
175 {
176 const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
177 struct kevent kev;
178
179 test_begin(test_id);
180
181 /* Re-add the watch and make sure no events are pending */
182 puts("-- re-adding knote");
183 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
184 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
185 err(1, "%s", test_id);
186 test_no_kevents();
187
188 puts("-- getting one event");
189 kevent_socket_fill();
190 kev.data = 1;
191 kevent_cmp(&kev, kevent_get(kqfd));
192
193 puts("-- checking knote disabled");
194 test_no_kevents();
195
196 /* Try to delete the knote, it should already be deleted */
197 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
198 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
199 err(1, "%s", test_id);
200
201 kevent_socket_drain();
202
203 success();
204 }
205
206
207 #if HAVE_EV_DISPATCH
208 static void
test_kevent_socket_dispatch(void)209 test_kevent_socket_dispatch(void)
210 {
211 const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
212
213 test_begin(test_id);
214
215 struct kevent kev;
216
217 /* Re-add the watch and make sure no events are pending */
218 puts("-- re-adding knote");
219 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
220 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
221 err(1, "%s", test_id);
222 test_no_kevents();
223
224 /* The event will occur only once, even though EV_CLEAR is not
225 specified. */
226 kevent_socket_fill();
227 kev.data = 1;
228 kevent_cmp(&kev, kevent_get(kqfd));
229 test_no_kevents();
230
231 /* Since the knote is disabled, the EV_DELETE operation succeeds. */
232 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
233 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
234 err(1, "%s", test_id);
235
236 kevent_socket_drain();
237
238 success();
239 }
240 #endif /* HAVE_EV_DISPATCH */
241
242 #if BROKEN
243 static void
test_kevent_socket_lowat(void)244 test_kevent_socket_lowat(void)
245 {
246 const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
247 struct kevent kev;
248
249 test_begin(test_id);
250
251 /* Re-add the watch and make sure no events are pending */
252 puts("-- re-adding knote, setting low watermark to 2 bytes");
253 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
254 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
255 err(1, "%s", test_id);
256 test_no_kevents();
257
258 puts("-- checking that one byte does not trigger an event..");
259 kevent_socket_fill();
260 test_no_kevents();
261
262 puts("-- checking that two bytes triggers an event..");
263 kevent_socket_fill();
264 if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
265 err(1, "%s", test_id);
266 KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
267 test_no_kevents();
268
269 kevent_socket_drain();
270 kevent_socket_drain();
271
272 success();
273 }
274 #endif
275
276 static void
test_kevent_socket_eof(void)277 test_kevent_socket_eof(void)
278 {
279 const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
280 struct kevent kev;
281
282 test_begin(test_id);
283
284 /* Re-add the watch and make sure no events are pending */
285 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
286 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
287 err(1, "%s", test_id);
288 test_no_kevents();
289
290 if (close(sockfd[1]) < 0)
291 err(1, "close(2)");
292
293 kev.flags |= EV_EOF;
294 kevent_cmp(&kev, kevent_get(kqfd));
295
296 /* Delete the watch */
297 EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
298 if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
299 err(1, "%s", test_id);
300
301 success();
302 }
303
304 void
test_evfilt_read(void)305 test_evfilt_read(void)
306 {
307 /* Create a connected pair of full-duplex sockets for testing socket events */
308 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
309 abort();
310
311 kqfd = kqueue();
312 test_kevent_socket_add();
313 test_kevent_socket_del();
314 test_kevent_socket_get();
315 test_kevent_socket_disable_and_enable();
316 test_kevent_socket_oneshot();
317 test_kevent_socket_clear();
318 #if HAVE_EV_DISPATCH
319 test_kevent_socket_dispatch();
320 #endif
321 test_kevent_socket_eof();
322 close(kqfd);
323 }
324