xref: /freebsd/tests/sys/kqueue/libkqueue/read.c (revision 193d9e768ba63fcfb187cfd17f461f7d41345048)
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 int kqfd;
22 int sockfd[2];
23 
24 static 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
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
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
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
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
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
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
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
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
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
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
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