libubox
C utility functions for OpenWrt.
uloop-kqueue.c
Go to the documentation of this file.
1 /*
2  * uloop - event loop implementation
3  *
4  * Copyright (C) 2010-2016 Felix Fietkau <nbd@openwrt.org>
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 static int uloop_init_pollfd(void)
19 {
20  struct timespec timeout = { 0, 0 };
21  struct kevent ev = {};
22 
23  if (poll_fd >= 0)
24  return 0;
25 
26  poll_fd = kqueue();
27  if (poll_fd < 0)
28  return -1;
29 
30  EV_SET(&ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
31  kevent(poll_fd, &ev, 1, NULL, 0, &timeout);
32 
33  return 0;
34 }
35 
36 
37 static uint16_t get_flags(unsigned int flags, unsigned int mask)
38 {
39  uint16_t kflags = 0;
40 
41  if (!(flags & mask))
42  return EV_DELETE;
43 
44  kflags = EV_ADD;
45  if (flags & ULOOP_EDGE_TRIGGER)
46  kflags |= EV_CLEAR;
47 
48  return kflags;
49 }
50 
51 static struct kevent events[ULOOP_MAX_EVENTS];
52 
53 static int register_kevent(struct uloop_fd *fd, unsigned int flags)
54 {
55  struct timespec timeout = { 0, 0 };
56  struct kevent ev[2];
57  int nev = 0;
58  unsigned int fl = 0;
59  unsigned int changed;
60  uint16_t kflags;
61 
62  if (flags & ULOOP_EDGE_DEFER)
63  flags &= ~ULOOP_EDGE_TRIGGER;
64 
65  changed = flags ^ fd->flags;
66  if (changed & ULOOP_EDGE_TRIGGER)
67  changed |= flags;
68 
69  if (!changed)
70  return 0;
71 
72  if (changed & ULOOP_READ) {
73  kflags = get_flags(flags, ULOOP_READ);
74  EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd);
75  }
76 
77  if (changed & ULOOP_WRITE) {
78  kflags = get_flags(flags, ULOOP_WRITE);
79  EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd);
80  }
81 
82  if (!flags)
83  fl |= EV_DELETE;
84 
85  if (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)
86  return -1;
87 
88  return 0;
89 }
90 
91 static int register_poll(struct uloop_fd *fd, unsigned int flags)
92 {
93  if (flags & ULOOP_EDGE_TRIGGER)
94  flags |= ULOOP_EDGE_DEFER;
95  else
96  flags &= ~ULOOP_EDGE_DEFER;
97 
98  return register_kevent(fd, flags);
99 }
100 
101 static int __uloop_fd_delete(struct uloop_fd *fd)
102 {
103  return register_poll(fd, 0);
104 }
105 
106 static int64_t get_timestamp_us(void)
107 {
108 #ifdef CLOCK_MONOTONIC
109  struct timespec ts = { 0, 0 };
110 
111  clock_gettime(CLOCK_MONOTONIC, &ts);
112 
113  return ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
114 #else
115  struct timeval tv = { 0, 0 };
116 
117  gettimeofday(&tv, NULL);
118 
119  return tv.tv_sec * 1000000 + tv.tv_usec;
120 #endif
121 }
122 
123 static int uloop_fetch_events(int timeout)
124 {
125  struct timespec ts;
126  int nfds, n;
127 
128  if (timeout >= 0) {
129  ts.tv_sec = timeout / 1000;
130  ts.tv_nsec = (timeout % 1000) * 1000000;
131  }
132 
133  nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL);
134  for (n = 0; n < nfds; n++) {
135  if (events[n].filter == EVFILT_TIMER) {
136  struct uloop_interval *tm = events[n].udata;
137 
138  tm->priv.time.fired = get_timestamp_us();
139  tm->expirations += events[n].data;
140  tm->cb(tm);
141 
142  continue;
143  }
144 
145  struct uloop_fd_event *cur = &cur_fds[n];
146  struct uloop_fd *u = events[n].udata;
147  unsigned int ev = 0;
148 
149  cur->fd = u;
150  if (!u)
151  continue;
152 
153  if (events[n].flags & EV_ERROR) {
154  u->error = true;
155  if (!(u->flags & ULOOP_ERROR_CB))
156  uloop_fd_delete(u);
157  }
158 
159  if(events[n].filter == EVFILT_READ)
160  ev |= ULOOP_READ;
161  else if (events[n].filter == EVFILT_WRITE)
162  ev |= ULOOP_WRITE;
163 
164  if (events[n].flags & EV_EOF)
165  u->eof = true;
166  else if (!ev)
167  cur->fd = NULL;
168 
169  cur->events = ev;
170  if (u->flags & ULOOP_EDGE_DEFER) {
171  u->flags &= ~ULOOP_EDGE_DEFER;
173  register_kevent(u, u->flags);
174  }
175  }
176  return nfds;
177 }
178 
179 static int timer_register(struct uloop_interval *tm, unsigned int msecs)
180 {
181  struct kevent ev;
182 
183  tm->priv.time.msecs = msecs;
184  tm->priv.time.fired = get_timestamp_us();
185 
186  EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_ADD, NOTE_USECONDS, msecs * 1000, tm);
187 
188  return kevent(poll_fd, &ev, 1, NULL, 0, NULL);
189 }
190 
191 static int timer_remove(struct uloop_interval *tm)
192 {
193  struct kevent ev;
194 
195  EV_SET(&ev, (uintptr_t)tm, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
196 
197  return kevent(poll_fd, &ev, 1, NULL, 0, NULL);
198 }
199 
200 static int64_t timer_next(struct uloop_interval *tm)
201 {
202  int64_t t1 = tm->priv.time.fired;
203  int64_t t2 = get_timestamp_us();
204 
205  while (t1 < t2)
206  t1 += tm->priv.time.msecs * 1000;
207 
208  return (t1 - t2) / 1000;
209 }
struct uloop_fd * fd
Definition: uloop.c:44
unsigned int events
Definition: uloop.c:45
Definition: uloop.h:63
bool eof
Definition: uloop.h:66
uint8_t flags
Definition: uloop.h:69
bool error
Definition: uloop.h:67
uint64_t expirations
Definition: uloop.h:93
union uloop_interval::@15 priv
uloop_interval_handler cb
Definition: uloop.h:92
struct uloop_interval::@15::@16 time
#define ARRAY_SIZE(x)
int fd
Definition: udebug-priv.h:27
static uint16_t get_flags(unsigned int flags, unsigned int mask)
Definition: uloop-kqueue.c:37
static int register_poll(struct uloop_fd *fd, unsigned int flags)
Definition: uloop-kqueue.c:91
static int uloop_fetch_events(int timeout)
Definition: uloop-kqueue.c:123
static int uloop_init_pollfd(void)
Definition: uloop-kqueue.c:18
static int timer_register(struct uloop_interval *tm, unsigned int msecs)
Definition: uloop-kqueue.c:179
static int timer_remove(struct uloop_interval *tm)
Definition: uloop-kqueue.c:191
static struct kevent events[ULOOP_MAX_EVENTS]
Definition: uloop-kqueue.c:51
static int register_kevent(struct uloop_fd *fd, unsigned int flags)
Definition: uloop-kqueue.c:53
static int64_t get_timestamp_us(void)
Definition: uloop-kqueue.c:106
static int __uloop_fd_delete(struct uloop_fd *fd)
Definition: uloop-kqueue.c:101
static int64_t timer_next(struct uloop_interval *tm)
Definition: uloop-kqueue.c:200
#define ULOOP_MAX_EVENTS
Definition: uloop.c:56
int uloop_fd_delete(struct uloop_fd *fd)
Definition: uloop.c:265
static struct uloop_fd_event cur_fds[10]
Definition: uloop.c:68
static int poll_fd
Definition: uloop.c:62
#define ULOOP_ERROR_CB
Definition: uloop.h:60
#define ULOOP_WRITE
Definition: uloop.h:48
#define ULOOP_READ
Definition: uloop.h:47
#define ULOOP_EDGE_TRIGGER
Definition: uloop.h:49