xref: /freebsd/tests/sys/kqueue/libkqueue/read.c (revision b3e76948)
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