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