1/* 2 * Copyright (c) 2009 Mark Heily <mark@heily.com> 3 * 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. 7 * 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. 15 */ 16 17#include <errno.h> 18#include <fcntl.h> 19#include <pthread.h> 20#include <signal.h> 21#include <stdlib.h> 22#include <stdio.h> 23#include <sys/queue.h> 24#include <sys/socket.h> 25#include <sys/types.h> 26#include <string.h> 27#include <time.h> 28#include <unistd.h> 29 30#include "sys/event.h" 31#include "private.h" 32 33/* A request to sleep for a certain time */ 34struct sleepreq { 35 int pfd; /* fd to poll for ACKs */ 36 int wfd; /* fd to wake up when sleep is over */ 37 uintptr_t ident; /* from kevent */ 38 intptr_t interval; /* sleep time, in milliseconds */ 39 struct sleepstat *stat; 40}; 41 42/* Information about a successful sleep operation */ 43struct sleepinfo { 44 uintptr_t ident; /* from kevent */ 45 uintptr_t counter; /* number of times the timer expired */ 46}; 47 48static void * 49sleeper_thread(void *arg) 50{ 51 struct sleepreq sr; 52 struct sleepinfo si; 53 struct timespec req, rem; 54 sigset_t mask; 55 ssize_t cnt; 56 bool cts = true; /* Clear To Send */ 57 char buf[1]; 58 59 pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL); 60 61 /* Copyin the request */ 62 memcpy(&sr, arg, sizeof(sr)); 63 free(arg); 64 65 /* Initialize the response */ 66 si.ident = sr.ident; 67 si.counter = 0; 68 69 /* Convert milliseconds into seconds+nanoseconds */ 70 req.tv_sec = sr.interval / 1000; 71 req.tv_nsec = (sr.interval % 1000) * 1000000; 72 73 /* Block all signals */ 74 sigfillset(&mask); 75 (void) pthread_sigmask(SIG_BLOCK, &mask, NULL); 76 77 for (;;) { 78 79 /* Sleep */ 80 if (nanosleep(&req, &rem) < 0) { 81 //TODO: handle eintr, spurious wakeups 82 dbg_perror("nanosleep(2)"); 83 } 84 si.counter++; 85 dbg_printf(" -------- sleep over (CTS=%d)----------", cts); 86 87 /* Test if the previous wakeup has been acknowledged */ 88 if (!cts) { 89 cnt = read(sr.wfd, &buf, 1); 90 if (cnt < 0) { 91 if (errno == EAGAIN || errno == EWOULDBLOCK) { 92 ; 93 } else { 94 dbg_perror("read(2)"); 95 break; 96 } 97 } else if (cnt == 0) { 98 dbg_perror("short read(2)"); 99 break; 100 } else { 101 cts = true; 102 } 103 } 104 105 /* Wake up kevent waiters if they are ready */ 106 if (cts) { 107 cnt = write(sr.wfd, &si, sizeof(si)); 108 if (cnt < 0) { 109 /* FIXME: handle EAGAIN and EINTR */ 110 dbg_perror("write(2)"); 111 } else if (cnt < sizeof(si)) { 112 dbg_puts("FIXME: handle short write"); 113 } 114 cts = false; 115 si.counter = 0; 116 } 117 } 118 119 return (NULL); 120} 121 122static int 123_timer_create(struct filter *filt, struct knote *kn) 124{ 125 pthread_attr_t attr; 126 struct sleepreq *req; 127 kn->kev.flags |= EV_CLEAR; 128 129 req = malloc(sizeof(*req)); 130 if (req == NULL) { 131 dbg_perror("malloc"); 132 return (-1); 133 } 134 req->pfd = filt->kf_pfd; 135 req->wfd = filt->kf_wfd; 136 req->ident = kn->kev.ident; 137 req->interval = kn->kev.data; 138 139 pthread_attr_init(&attr); 140 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 141 if (pthread_create(&kn->data.tid, &attr, sleeper_thread, req) != 0) { 142 dbg_perror("pthread_create"); 143 pthread_attr_destroy(&attr); 144 free(req); 145 return (-1); 146 } 147 pthread_attr_destroy(&attr); 148 149 return (0); 150} 151 152static int 153_timer_delete(struct knote *kn) 154{ 155 if (pthread_cancel(kn->data.tid) != 0) { 156 /* Race condition: sleeper_thread exits before it is cancelled */ 157 if (errno == ENOENT) 158 return (0); 159 dbg_perror("pthread_cancel(3)"); 160 return (-1); 161 } 162 return (0); 163} 164 165int 166evfilt_timer_init(struct filter *filt) 167{ 168 int fd[2]; 169 170 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0) { 171 dbg_perror("socketpair(3)"); 172 return (-1); 173 } 174 if (fcntl(fd[0], F_SETFL, O_NONBLOCK) < 0 175 || fcntl(fd[1], F_SETFL, O_NONBLOCK) < 0) { 176 dbg_perror("fcntl(2)"); 177 close(fd[0]); 178 close(fd[1]); 179 return (-1); 180 } 181 182 filt->kf_wfd = fd[0]; 183 filt->kf_pfd = fd[1]; 184 185 return (0); 186} 187 188void 189evfilt_timer_destroy(struct filter *filt) 190{ 191 (void) close(filt->kf_wfd); 192 (void) close(filt->kf_pfd); 193} 194 195int 196evfilt_timer_copyout(struct filter *filt, 197 struct kevent *dst, 198 int nevents) 199{ 200 struct sleepinfo si; 201 ssize_t cnt; 202 struct knote *kn; 203 204 /* Read the ident */ 205 cnt = read(filt->kf_pfd, &si, sizeof(si)); 206 if (cnt < 0) { 207 /* FIXME: handle EAGAIN and EINTR */ 208 dbg_printf("read(2): %s", strerror(errno)); 209 return (-1); 210 } else if (cnt < sizeof(si)) { 211 dbg_puts("error: short read"); 212 return (-1); 213 } 214 215 /* Acknowlege receipt */ 216 cnt = write(filt->kf_pfd, ".", 1); 217 if (cnt < 0) { 218 /* FIXME: handle EAGAIN and EINTR */ 219 dbg_printf("write(2): %s", strerror(errno)); 220 return (-1); 221 } else if (cnt < 1) { 222 dbg_puts("error: short write"); 223 return (-1); 224 } 225 226 kn = knote_lookup(filt, si.ident); 227 228 /* Race condition: timer events remain queued even after 229 the knote is deleted. Ignore these events */ 230 if (kn == NULL) 231 return (0); 232 233 dbg_printf("knote=%p", kn); 234 memcpy(dst, &kn->kev, sizeof(*dst)); 235 236 dst->data = si.counter; 237 238 if (kn->kev.flags & EV_DISPATCH) { 239 KNOTE_DISABLE(kn); 240 _timer_delete(kn); 241 } else if (kn->kev.flags & EV_ONESHOT) { 242 _timer_delete(kn); 243 knote_free(filt, kn); 244 } 245 246 return (1); 247} 248 249int 250evfilt_timer_knote_create(struct filter *filt, struct knote *kn) 251{ 252 return _timer_create(filt, kn); 253} 254 255int 256evfilt_timer_knote_modify(struct filter *filt, struct knote *kn, 257 const struct kevent *kev) 258{ 259 return (-1); /* STUB */ 260} 261 262int 263evfilt_timer_knote_delete(struct filter *filt, struct knote *kn) 264{ 265 if (kn->kev.flags & EV_DISABLE) 266 return (0); 267 268 dbg_printf("deleting timer # %d", (int) kn->kev.ident); 269 return _timer_delete(kn); 270} 271 272int 273evfilt_timer_knote_enable(struct filter *filt, struct knote *kn) 274{ 275 return evfilt_timer_knote_create(filt, kn); 276} 277 278int 279evfilt_timer_knote_disable(struct filter *filt, struct knote *kn) 280{ 281 return evfilt_timer_knote_delete(filt, kn); 282} 283 284const struct filter evfilt_timer = { 285 EVFILT_TIMER, 286 evfilt_timer_init, 287 evfilt_timer_destroy, 288 evfilt_timer_copyout, 289 evfilt_timer_knote_create, 290 evfilt_timer_knote_modify, 291 evfilt_timer_knote_delete, 292 evfilt_timer_knote_enable, 293 evfilt_timer_knote_disable, 294}; 295