2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
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.
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.
23 #include <sys/epoll.h>
24 #include <sys/queue.h>
25 #include <sys/socket.h>
26 #include <sys/types.h>
31 /* Linux equivalents to kqueue(2) */
32 #include <sys/timerfd.h>
34 #include "sys/event.h"
39 itimerspec_dump(struct itimerspec *ts)
41 static char __thread buf[1024];
43 snprintf(buf, sizeof(buf),
44 "itimer: [ interval=%lu s %lu ns, next expire=%lu s %lu ns ]",
45 ts->it_interval.tv_sec,
46 ts->it_interval.tv_nsec,
55 /* Convert milliseconds into seconds+nanoseconds */
57 convert_msec_to_itimerspec(struct itimerspec *dst, int src, int oneshot)
62 nsec = (src % 1000) * 1000000;
64 /* Set the interval */
66 dst->it_interval.tv_sec = 0;
67 dst->it_interval.tv_nsec = 0;
69 dst->it_interval.tv_sec = sec;
70 dst->it_interval.tv_nsec = nsec;
73 /* Set the initial expiration */
74 dst->it_value.tv_sec = sec;
75 dst->it_value.tv_nsec = nsec;
76 dbg_printf("%s", itimerspec_dump(dst));
80 ktimer_delete(struct filter *filt, struct knote *kn)
84 if (kn->data.pfd == -1)
87 dbg_printf("removing timerfd %d from %d", kn->data.pfd, filt->kf_pfd);
88 if (epoll_ctl(filt->kf_pfd, EPOLL_CTL_DEL, kn->data.pfd, NULL) < 0) {
89 dbg_printf("epoll_ctl(2): %s", strerror(errno));
92 if (close(kn->data.pfd) < 0) {
93 dbg_printf("close(2): %s", strerror(errno));
102 evfilt_timer_init(struct filter *filt)
104 filt->kf_pfd = epoll_create(1);
105 if (filt->kf_pfd < 0)
108 dbg_printf("timer epollfd = %d", filt->kf_pfd);
113 evfilt_timer_destroy(struct filter *filt)
115 close (filt->kf_pfd);//LAME
118 /* TODO: This entire function is copy+pasted from socket.c
119 with minor changes for timerfds.
120 Perhaps it could be refactored into a generic epoll_copyout()
121 that calls custom per-filter actions.
124 evfilt_timer_copyout(struct filter *filt,
128 struct epoll_event epevt[MAX_KEVENT];
129 struct epoll_event *ev;
136 nret = epoll_wait(filt->kf_pfd, &epevt[0], nevents, 0);
140 dbg_perror("epoll_wait");
147 for (i = 0, nevents = 0; i < nret; i++) {
149 /* TODO: put in generic debug.c: epoll_event_dump(ev); */
151 memcpy(dst, &kn->kev, sizeof(*dst));
152 if (ev->events & EPOLLERR)
153 dst->fflags = 1; /* FIXME: Return the actual timer error */
155 /* On return, data contains the number of times the
156 timer has been trigered.
158 n = read(kn->data.pfd, &expired, sizeof(expired));
159 if (n < 0 || n < sizeof(expired)) {
160 dbg_puts("invalid read from timerfd");
161 expired = 1; /* Fail gracefully */
165 if (kn->kev.flags & EV_DISPATCH) {
167 ktimer_delete(filt, kn);
168 } else if (kn->kev.flags & EV_ONESHOT) {
169 ktimer_delete(filt, kn);
170 knote_free(filt, kn);
181 evfilt_timer_knote_create(struct filter *filt, struct knote *kn)
183 struct epoll_event ev;
184 struct itimerspec ts;
187 kn->kev.flags |= EV_CLEAR;
189 tfd = timerfd_create(CLOCK_MONOTONIC, 0);
191 dbg_printf("timerfd_create(2): %s", strerror(errno));
194 dbg_printf("created timerfd %d", tfd);
196 convert_msec_to_itimerspec(&ts, kn->kev.data, kn->kev.flags & EV_ONESHOT);
197 if (timerfd_settime(tfd, 0, &ts, NULL) < 0) {
198 dbg_printf("timerfd_settime(2): %s", strerror(errno));
203 memset(&ev, 0, sizeof(ev));
206 if (epoll_ctl(filt->kf_pfd, EPOLL_CTL_ADD, tfd, &ev) < 0) {
207 dbg_printf("epoll_ctl(2): %d", errno);
217 evfilt_timer_knote_modify(struct filter *filt, struct knote *kn,
218 const struct kevent *kev)
220 return (0); /* STUB */
224 evfilt_timer_knote_delete(struct filter *filt, struct knote *kn)
226 return (ktimer_delete(filt,kn));
230 evfilt_timer_knote_enable(struct filter *filt, struct knote *kn)
232 return evfilt_timer_knote_create(filt, kn);
236 evfilt_timer_knote_disable(struct filter *filt, struct knote *kn)
238 return evfilt_timer_knote_delete(filt, kn);
241 const struct filter evfilt_timer = {
244 evfilt_timer_destroy,
245 evfilt_timer_copyout,
246 evfilt_timer_knote_create,
247 evfilt_timer_knote_modify,
248 evfilt_timer_knote_delete,
249 evfilt_timer_knote_enable,
250 evfilt_timer_knote_disable,