160a396a4SRobert Watson /*
260a396a4SRobert Watson * Copyright (c) 2009 Mark Heily <mark@heily.com>
360a396a4SRobert Watson *
460a396a4SRobert Watson * Permission to use, copy, modify, and distribute this software for any
560a396a4SRobert Watson * purpose with or without fee is hereby granted, provided that the above
660a396a4SRobert Watson * copyright notice and this permission notice appear in all copies.
760a396a4SRobert Watson *
860a396a4SRobert Watson * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
960a396a4SRobert Watson * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1060a396a4SRobert Watson * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1160a396a4SRobert Watson * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1260a396a4SRobert Watson * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1360a396a4SRobert Watson * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1460a396a4SRobert Watson * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1560a396a4SRobert Watson */
1660a396a4SRobert Watson
1760a396a4SRobert Watson #include "common.h"
1860a396a4SRobert Watson
19c9c283bdSAlex Richardson static int sockfd[2];
2060a396a4SRobert Watson
2160a396a4SRobert Watson static void
kevent_socket_drain(void)2260a396a4SRobert Watson kevent_socket_drain(void)
2360a396a4SRobert Watson {
2460a396a4SRobert Watson char buf[1];
2560a396a4SRobert Watson
2660a396a4SRobert Watson /* Drain the read buffer, then make sure there are no more events. */
2760a396a4SRobert Watson puts("draining the read buffer");
2860a396a4SRobert Watson if (read(sockfd[0], &buf[0], 1) < 1)
2960a396a4SRobert Watson err(1, "read(2)");
3060a396a4SRobert Watson }
3160a396a4SRobert Watson
3260a396a4SRobert Watson static void
kevent_socket_fill(void)3360a396a4SRobert Watson kevent_socket_fill(void)
3460a396a4SRobert Watson {
3560a396a4SRobert Watson puts("filling the read buffer");
3660a396a4SRobert Watson if (write(sockfd[1], ".", 1) < 1)
3760a396a4SRobert Watson err(1, "write(2)");
3860a396a4SRobert Watson }
3960a396a4SRobert Watson
4060a396a4SRobert Watson
41c9c283bdSAlex Richardson static void
test_kevent_socket_add(void)4260a396a4SRobert Watson test_kevent_socket_add(void)
4360a396a4SRobert Watson {
4460a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_ADD)";
4560a396a4SRobert Watson struct kevent kev;
4660a396a4SRobert Watson
4760a396a4SRobert Watson test_begin(test_id);
4860a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
4960a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
5060a396a4SRobert Watson err(1, "%s", test_id);
5160a396a4SRobert Watson
5260a396a4SRobert Watson success();
5360a396a4SRobert Watson }
5460a396a4SRobert Watson
55c9c283bdSAlex Richardson static void
test_kevent_socket_get(void)5660a396a4SRobert Watson test_kevent_socket_get(void)
5760a396a4SRobert Watson {
5860a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ) wait";
5960a396a4SRobert Watson struct kevent kev;
6060a396a4SRobert Watson
6160a396a4SRobert Watson test_begin(test_id);
6260a396a4SRobert Watson
6360a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
6460a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
6560a396a4SRobert Watson err(1, "%s", test_id);
6660a396a4SRobert Watson
6760a396a4SRobert Watson kevent_socket_fill();
6860a396a4SRobert Watson
6960a396a4SRobert Watson kev.data = 1;
7060a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
7160a396a4SRobert Watson
7260a396a4SRobert Watson kevent_socket_drain();
7360a396a4SRobert Watson test_no_kevents();
7460a396a4SRobert Watson
7560a396a4SRobert Watson kev.flags = EV_DELETE;
7660a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
7760a396a4SRobert Watson err(1, "%s", test_id);
7860a396a4SRobert Watson
7960a396a4SRobert Watson success();
8060a396a4SRobert Watson }
8160a396a4SRobert Watson
82c9c283bdSAlex Richardson static void
test_kevent_socket_clear(void)8360a396a4SRobert Watson test_kevent_socket_clear(void)
8460a396a4SRobert Watson {
8560a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)";
8660a396a4SRobert Watson struct kevent kev;
8760a396a4SRobert Watson
8860a396a4SRobert Watson test_begin(test_id);
8960a396a4SRobert Watson
9060a396a4SRobert Watson test_no_kevents();
9160a396a4SRobert Watson
9260a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]);
9360a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
9460a396a4SRobert Watson err(1, "%s", test_id);
9560a396a4SRobert Watson
9660a396a4SRobert Watson kevent_socket_fill();
9760a396a4SRobert Watson kevent_socket_fill();
9860a396a4SRobert Watson
9960a396a4SRobert Watson kev.data = 2;
10060a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
10160a396a4SRobert Watson
10260a396a4SRobert Watson /* We filled twice, but drain once. Edge-triggered would not generate
10360a396a4SRobert Watson additional events.
10460a396a4SRobert Watson */
10560a396a4SRobert Watson kevent_socket_drain();
10660a396a4SRobert Watson test_no_kevents();
10760a396a4SRobert Watson
10860a396a4SRobert Watson kevent_socket_drain();
10960a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
11060a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
11160a396a4SRobert Watson err(1, "%s", test_id);
11260a396a4SRobert Watson
11360a396a4SRobert Watson success();
11460a396a4SRobert Watson }
11560a396a4SRobert Watson
116c9c283bdSAlex Richardson static void
test_kevent_socket_disable_and_enable(void)11760a396a4SRobert Watson test_kevent_socket_disable_and_enable(void)
11860a396a4SRobert Watson {
11960a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)";
12060a396a4SRobert Watson struct kevent kev;
12160a396a4SRobert Watson
12260a396a4SRobert Watson test_begin(test_id);
12360a396a4SRobert Watson
12488c2beacSMark Johnston /*
12588c2beacSMark Johnston * Write to the socket before adding the event. This way we can verify that
12688c2beacSMark Johnston * enabling a triggered kevent causes the event to be returned immediately.
12788c2beacSMark Johnston */
12888c2beacSMark Johnston kevent_socket_fill();
12988c2beacSMark Johnston
13088c2beacSMark Johnston /* Add a disabled event. */
13188c2beacSMark Johnston EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]);
13260a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
13360a396a4SRobert Watson err(1, "%s", test_id);
13460a396a4SRobert Watson
13560a396a4SRobert Watson test_no_kevents();
13660a396a4SRobert Watson
13760a396a4SRobert Watson /* Re-enable the knote, then see if an event is generated */
13860a396a4SRobert Watson kev.flags = EV_ENABLE;
13960a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
14060a396a4SRobert Watson err(1, "%s", test_id);
14160a396a4SRobert Watson kev.flags = EV_ADD;
14260a396a4SRobert Watson kev.data = 1;
14360a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
14460a396a4SRobert Watson
14560a396a4SRobert Watson kevent_socket_drain();
14660a396a4SRobert Watson
14760a396a4SRobert Watson kev.flags = EV_DELETE;
14860a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
14960a396a4SRobert Watson err(1, "%s", test_id);
15060a396a4SRobert Watson
15160a396a4SRobert Watson success();
15260a396a4SRobert Watson }
15360a396a4SRobert Watson
154c9c283bdSAlex Richardson static void
test_kevent_socket_del(void)15560a396a4SRobert Watson test_kevent_socket_del(void)
15660a396a4SRobert Watson {
15760a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_DELETE)";
15860a396a4SRobert Watson struct kevent kev;
15960a396a4SRobert Watson
16060a396a4SRobert Watson test_begin(test_id);
16160a396a4SRobert Watson
16260a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
16360a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
16460a396a4SRobert Watson err(1, "%s", test_id);
16560a396a4SRobert Watson
16660a396a4SRobert Watson kevent_socket_fill();
16760a396a4SRobert Watson test_no_kevents();
16860a396a4SRobert Watson kevent_socket_drain();
16960a396a4SRobert Watson
17060a396a4SRobert Watson success();
17160a396a4SRobert Watson }
17260a396a4SRobert Watson
173c9c283bdSAlex Richardson static void
test_kevent_socket_oneshot(void)17460a396a4SRobert Watson test_kevent_socket_oneshot(void)
17560a396a4SRobert Watson {
17660a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)";
17760a396a4SRobert Watson struct kevent kev;
17860a396a4SRobert Watson
17960a396a4SRobert Watson test_begin(test_id);
18060a396a4SRobert Watson
18160a396a4SRobert Watson /* Re-add the watch and make sure no events are pending */
18260a396a4SRobert Watson puts("-- re-adding knote");
18360a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]);
18460a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
18560a396a4SRobert Watson err(1, "%s", test_id);
18660a396a4SRobert Watson test_no_kevents();
18760a396a4SRobert Watson
18860a396a4SRobert Watson puts("-- getting one event");
18960a396a4SRobert Watson kevent_socket_fill();
19060a396a4SRobert Watson kev.data = 1;
19160a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
19260a396a4SRobert Watson
19360a396a4SRobert Watson puts("-- checking knote disabled");
19460a396a4SRobert Watson test_no_kevents();
19560a396a4SRobert Watson
19660a396a4SRobert Watson /* Try to delete the knote, it should already be deleted */
19760a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
19860a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0)
19960a396a4SRobert Watson err(1, "%s", test_id);
20060a396a4SRobert Watson
20160a396a4SRobert Watson kevent_socket_drain();
20260a396a4SRobert Watson
20360a396a4SRobert Watson success();
20460a396a4SRobert Watson }
20560a396a4SRobert Watson
20660a396a4SRobert Watson
20760a396a4SRobert Watson #if HAVE_EV_DISPATCH
208c9c283bdSAlex Richardson static void
test_kevent_socket_dispatch(void)20960a396a4SRobert Watson test_kevent_socket_dispatch(void)
21060a396a4SRobert Watson {
21160a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)";
21260a396a4SRobert Watson
21360a396a4SRobert Watson test_begin(test_id);
21460a396a4SRobert Watson
21560a396a4SRobert Watson struct kevent kev;
21660a396a4SRobert Watson
21760a396a4SRobert Watson /* Re-add the watch and make sure no events are pending */
21860a396a4SRobert Watson puts("-- re-adding knote");
21960a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]);
22060a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
22160a396a4SRobert Watson err(1, "%s", test_id);
22260a396a4SRobert Watson test_no_kevents();
22360a396a4SRobert Watson
22460a396a4SRobert Watson /* The event will occur only once, even though EV_CLEAR is not
22560a396a4SRobert Watson specified. */
22660a396a4SRobert Watson kevent_socket_fill();
22760a396a4SRobert Watson kev.data = 1;
22860a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
22960a396a4SRobert Watson test_no_kevents();
23060a396a4SRobert Watson
23160a396a4SRobert Watson /* Since the knote is disabled, the EV_DELETE operation succeeds. */
23260a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
23360a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
23460a396a4SRobert Watson err(1, "%s", test_id);
23560a396a4SRobert Watson
23660a396a4SRobert Watson kevent_socket_drain();
23760a396a4SRobert Watson
23860a396a4SRobert Watson success();
23960a396a4SRobert Watson }
24060a396a4SRobert Watson #endif /* HAVE_EV_DISPATCH */
24160a396a4SRobert Watson
24260a396a4SRobert Watson #if BROKEN
243c9c283bdSAlex Richardson static void
test_kevent_socket_lowat(void)24460a396a4SRobert Watson test_kevent_socket_lowat(void)
24560a396a4SRobert Watson {
24660a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)";
24760a396a4SRobert Watson struct kevent kev;
24860a396a4SRobert Watson
24960a396a4SRobert Watson test_begin(test_id);
25060a396a4SRobert Watson
25160a396a4SRobert Watson /* Re-add the watch and make sure no events are pending */
25260a396a4SRobert Watson puts("-- re-adding knote, setting low watermark to 2 bytes");
25360a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]);
25460a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
25560a396a4SRobert Watson err(1, "%s", test_id);
25660a396a4SRobert Watson test_no_kevents();
25760a396a4SRobert Watson
25860a396a4SRobert Watson puts("-- checking that one byte does not trigger an event..");
25960a396a4SRobert Watson kevent_socket_fill();
26060a396a4SRobert Watson test_no_kevents();
26160a396a4SRobert Watson
26260a396a4SRobert Watson puts("-- checking that two bytes triggers an event..");
26360a396a4SRobert Watson kevent_socket_fill();
26460a396a4SRobert Watson if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1)
26560a396a4SRobert Watson err(1, "%s", test_id);
26660a396a4SRobert Watson KEV_CMP(kev, sockfd[0], EVFILT_READ, 0);
26760a396a4SRobert Watson test_no_kevents();
26860a396a4SRobert Watson
26960a396a4SRobert Watson kevent_socket_drain();
27060a396a4SRobert Watson kevent_socket_drain();
27160a396a4SRobert Watson
27260a396a4SRobert Watson success();
27360a396a4SRobert Watson }
27460a396a4SRobert Watson #endif
27560a396a4SRobert Watson
276c9c283bdSAlex Richardson static void
test_kevent_socket_eof(void)27760a396a4SRobert Watson test_kevent_socket_eof(void)
27860a396a4SRobert Watson {
27960a396a4SRobert Watson const char *test_id = "kevent(EVFILT_READ, EV_EOF)";
28060a396a4SRobert Watson struct kevent kev;
28160a396a4SRobert Watson
28260a396a4SRobert Watson test_begin(test_id);
28360a396a4SRobert Watson
28460a396a4SRobert Watson /* Re-add the watch and make sure no events are pending */
28560a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
28660a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
28760a396a4SRobert Watson err(1, "%s", test_id);
28860a396a4SRobert Watson test_no_kevents();
28960a396a4SRobert Watson
29060a396a4SRobert Watson if (close(sockfd[1]) < 0)
29160a396a4SRobert Watson err(1, "close(2)");
29260a396a4SRobert Watson
29360a396a4SRobert Watson kev.flags |= EV_EOF;
29460a396a4SRobert Watson kevent_cmp(&kev, kevent_get(kqfd));
29560a396a4SRobert Watson
29660a396a4SRobert Watson /* Delete the watch */
29760a396a4SRobert Watson EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]);
29860a396a4SRobert Watson if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
29960a396a4SRobert Watson err(1, "%s", test_id);
30060a396a4SRobert Watson
30160a396a4SRobert Watson success();
30260a396a4SRobert Watson }
30360a396a4SRobert Watson
30460a396a4SRobert Watson void
test_evfilt_read(void)305c9c283bdSAlex Richardson test_evfilt_read(void)
30660a396a4SRobert Watson {
30760a396a4SRobert Watson /* Create a connected pair of full-duplex sockets for testing socket events */
30860a396a4SRobert Watson if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0)
30960a396a4SRobert Watson abort();
31060a396a4SRobert Watson
31160a396a4SRobert Watson kqfd = kqueue();
31260a396a4SRobert Watson test_kevent_socket_add();
31360a396a4SRobert Watson test_kevent_socket_del();
31460a396a4SRobert Watson test_kevent_socket_get();
31560a396a4SRobert Watson test_kevent_socket_disable_and_enable();
31660a396a4SRobert Watson test_kevent_socket_oneshot();
31760a396a4SRobert Watson test_kevent_socket_clear();
31860a396a4SRobert Watson #if HAVE_EV_DISPATCH
31960a396a4SRobert Watson test_kevent_socket_dispatch();
32060a396a4SRobert Watson #endif
32160a396a4SRobert Watson test_kevent_socket_eof();
32260a396a4SRobert Watson close(kqfd);
32360a396a4SRobert Watson }
324