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