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