1 #include "kqueue_event.h"
2
3 #include <sys/param.h>
4
5 #include <assert.h>
6
7 #include <fcntl.h>
8 #include <time.h>
9 #include <unistd.h>
10
11 errno_t
kqueue_event_init(KQueueEvent * kqueue_event,struct kevent * kevs,int * kevs_length,bool should_trigger)12 kqueue_event_init(KQueueEvent *kqueue_event, struct kevent *kevs,
13 int *kevs_length, bool should_trigger)
14 {
15 *kqueue_event = (KQueueEvent) { .self_pipe_ = { -1, -1 } };
16
17 #ifdef EVFILT_USER
18 EV_SET(&kevs[(*kevs_length)++], 0, /**/
19 EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, 0);
20
21 if (should_trigger) {
22 EV_SET(&kevs[(*kevs_length)++], 0, /**/
23 EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
24 kqueue_event->is_triggered_ = true;
25 }
26
27 return 0;
28 #else
29 errno_t ec;
30
31 if (pipe2(kqueue_event->self_pipe_, O_NONBLOCK | O_CLOEXEC) < 0) {
32 return errno;
33 }
34
35 EV_SET(&kevs[(*kevs_length)++], kqueue_event->self_pipe_[0], /**/
36 EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, 0);
37 if (should_trigger) {
38 if ((ec = kqueue_event_trigger(kqueue_event, -1)) != 0) {
39 goto out;
40 }
41 assert(kqueue_event->is_triggered_);
42 }
43
44 return 0;
45
46 out:
47 (void)kqueue_event_terminate(kqueue_event);
48 return ec;
49 #endif
50 }
51
52 errno_t
kqueue_event_terminate(KQueueEvent * kqueue_event)53 kqueue_event_terminate(KQueueEvent *kqueue_event)
54 {
55 #ifdef EVFILT_USER
56 (void)kqueue_event;
57 return 0;
58 #else
59 errno_t ec = 0;
60 if (close(kqueue_event->self_pipe_[0]) < 0) {
61 ec = ec != 0 ? ec : errno;
62 }
63 if (close(kqueue_event->self_pipe_[1]) < 0) {
64 ec = ec != 0 ? ec : errno;
65 }
66 return ec;
67 #endif
68 }
69
70 bool
kqueue_event_is_triggered(KQueueEvent * kqueue_event)71 kqueue_event_is_triggered(KQueueEvent *kqueue_event)
72 {
73 return kqueue_event->is_triggered_;
74 }
75
76 errno_t
kqueue_event_trigger(KQueueEvent * kqueue_event,int kq)77 kqueue_event_trigger(KQueueEvent *kqueue_event, int kq)
78 {
79 if (kqueue_event->is_triggered_) {
80 return 0;
81 }
82
83 #ifdef EVFILT_USER
84 struct kevent kevs[1];
85 EV_SET(&kevs[0], 0, EVFILT_USER, 0, NOTE_TRIGGER, 0, 0);
86
87 if (kevent(kq, kevs, 1, NULL, 0, NULL) < 0) {
88 return errno;
89 }
90 #else
91 char c = 0;
92 if (write(kqueue_event->self_pipe_[1], &c, 1) < 0) {
93 if (errno != EAGAIN && errno != EWOULDBLOCK) {
94 return errno;
95 }
96 }
97 #endif
98
99 kqueue_event->is_triggered_ = true;
100 return 0;
101 }
102
103 void
kqueue_event_clear(KQueueEvent * kqueue_event,int kq)104 kqueue_event_clear(KQueueEvent *kqueue_event, int kq)
105 {
106 #ifndef EVFILT_USER
107 char c[32];
108 while (read(kqueue_event->self_pipe_[0], c, sizeof(c)) >= 0) {
109 }
110 #endif
111
112 struct kevent kevs[32];
113 int n;
114
115 while ((n = kevent(kq, NULL, 0, kevs, 32,
116 &(struct timespec) { 0, 0 })) > 0) {
117 }
118
119 kqueue_event->is_triggered_ = false;
120 }
121