1 #include <unistd.h>
2 #include <errno.h>
3 #include <sys/event.h>
4 #include <sys/select.h>
5 #include <Block.h>
6 #include <darwintest.h>
7
8 T_GLOBAL_META(
9 T_META_NAMESPACE("xnu.kevent"),
10 T_META_RADAR_COMPONENT_NAME("xnu"),
11 T_META_RADAR_COMPONENT_VERSION("kevent"),
12 T_META_RUN_CONCURRENTLY(true)
13 );
14
15 #define TV(s) (struct timeval){ .tv_sec = s }
16
17 static void *
pthread_async_do(void * arg)18 pthread_async_do(void *arg)
19 {
20 void (^block)(void) = arg;
21 block();
22 Block_release(block);
23 pthread_detach(pthread_self());
24 return NULL;
25 }
26
27 static void
28 pthread_async(void (^block)(void))
29 {
30 pthread_t th;
31 int rc;
32
33 rc = pthread_create(&th, NULL, pthread_async_do, Block_copy(block));
34 T_QUIET; T_ASSERT_POSIX_SUCCESS(rc, "pthread_create");
35 }
36
37 T_DECL(kqueue_in_select, "make sure kqueue in select works", T_META_TAG_VM_PREFERRED)
38 {
39 fd_set rd_set;
40 int kq_fd, ret, nfd;
41 struct kevent ret_kev;
42 const struct kevent kev = {
43 .ident = 1,
44 .filter = EVFILT_USER,
45 .flags = EV_ADD | EV_CLEAR,
46 };
47
48 T_ASSERT_POSIX_SUCCESS((kq_fd = kqueue()), NULL);
49 ret = kevent(kq_fd, &kev, 1, NULL, 0, NULL);
50 T_ASSERT_POSIX_SUCCESS(ret, "kevent");
51
52 FD_ZERO(&rd_set);
53 FD_SET(kq_fd, &rd_set);
54 nfd = select(kq_fd + 1, &rd_set, NULL, NULL, &TV(1));
55 T_EXPECT_EQ(nfd, 0, "no trigger");
56
57 pthread_async(^{
58 sleep(1);
59 const struct kevent k = {
60 .ident = 1,
61 .filter = EVFILT_USER,
62 .flags = EV_ADD | EV_CLEAR,
63 .fflags = NOTE_TRIGGER,
64 };
65
66 T_ASSERT_POSIX_SUCCESS(kevent(kq_fd, &k, 1, NULL, 0, NULL), "trigger");
67 });
68
69 FD_ZERO(&rd_set);
70 FD_SET(kq_fd, &rd_set);
71 nfd = select(kq_fd + 1, &rd_set, NULL, NULL, &TV(5));
72 T_EXPECT_EQ(nfd, 1, "kqueue triggered");
73
74 FD_ZERO(&rd_set);
75 FD_SET(kq_fd, &rd_set);
76 nfd = select(kq_fd + 1, &rd_set, NULL, NULL, &TV(1));
77 T_EXPECT_EQ(nfd, 1, "kqueue is still triggered");
78
79 T_EXPECT_EQ(kevent(kq_fd, NULL, 0, &ret_kev, 1, NULL), 1, "pump event");
80
81 FD_ZERO(&rd_set);
82 FD_SET(kq_fd, &rd_set);
83 nfd = select(kq_fd + 1, &rd_set, NULL, NULL, &TV(1));
84 T_EXPECT_EQ(nfd, 0, "no trigger");
85 }
86