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 19 /** 20 * FIXME: uClibc < 0.9.30.3 does not define EPOLLRDHUP for Linux >= 2.6.17 21 */ 22 #ifndef EPOLLRDHUP 23 #define EPOLLRDHUP 0x2000 24 #endif 25 26 static int uloop_init_pollfd(void) 27 { 28 if (poll_fd >= 0) 29 return 0; 30 31 poll_fd = epoll_create(32); 32 if (poll_fd < 0) 33 return -1; 34 35 fcntl(poll_fd, F_SETFD, fcntl(poll_fd, F_GETFD) | FD_CLOEXEC); 36 return 0; 37 } 38 39 static int register_poll(struct uloop_fd *fd, unsigned int flags) 40 { 41 struct epoll_event ev; 42 int op = fd->registered ? EPOLL_CTL_MOD : EPOLL_CTL_ADD; 43 44 memset(&ev, 0, sizeof(struct epoll_event)); 45 46 if (flags & ULOOP_READ) 47 ev.events |= EPOLLIN | EPOLLRDHUP; 48 49 if (flags & ULOOP_WRITE) 50 ev.events |= EPOLLOUT; 51 52 if (flags & ULOOP_EDGE_TRIGGER) 53 ev.events |= EPOLLET; 54 55 if (flags & ULOOP_PRIORITY) 56 ev.events |= EPOLLPRI; 57 58 ev.data.ptr = fd; 59 60 return epoll_ctl(poll_fd, op, fd->fd, &ev); 61 } 62 63 static struct epoll_event events[ULOOP_MAX_EVENTS]; 64 65 static int __uloop_fd_delete(struct uloop_fd *sock) 66 { 67 sock->flags = 0; 68 return epoll_ctl(poll_fd, EPOLL_CTL_DEL, sock->fd, 0); 69 } 70 71 static int uloop_fetch_events(int timeout) 72 { 73 int n, nfds; 74 75 nfds = epoll_wait(poll_fd, events, ARRAY_SIZE(events), timeout); 76 for (n = 0; n < nfds; ++n) { 77 struct uloop_fd_event *cur = &cur_fds[n]; 78 struct uloop_fd *u = events[n].data.ptr; 79 unsigned int ev = 0; 80 81 cur->fd = u; 82 if (!u) 83 continue; 84 85 if (events[n].events & (EPOLLERR|EPOLLHUP)) { 86 u->error = true; 87 if (!(u->flags & ULOOP_ERROR_CB)) 88 uloop_fd_delete(u); 89 } 90 91 if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP|EPOLLPRI))) { 92 cur->fd = NULL; 93 continue; 94 } 95 96 if(events[n].events & EPOLLRDHUP) 97 u->eof = true; 98 99 if(events[n].events & EPOLLIN) 100 ev |= ULOOP_READ; 101 102 if(events[n].events & EPOLLOUT) 103 ev |= ULOOP_WRITE; 104 105 if(events[n].events & EPOLLPRI) 106 ev |= ULOOP_PRIORITY; 107 108 cur->events = ev; 109 } 110 111 return nfds; 112 } 113 114 static void dispatch_timer(struct uloop_fd *u, unsigned int events) 115 { 116 if (!(events & ULOOP_READ)) 117 return; 118 119 uint64_t fired; 120 121 if (read(u->fd, &fired, sizeof(fired)) != sizeof(fired)) 122 return; 123 124 struct uloop_interval *tm = container_of(u, struct uloop_interval, priv.ufd); 125 126 tm->expirations += fired; 127 tm->cb(tm); 128 } 129 130 static int timer_register(struct uloop_interval *tm, unsigned int msecs) 131 { 132 if (!tm->priv.ufd.registered) { 133 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC|TFD_NONBLOCK); 134 135 if (fd == -1) 136 return -1; 137 138 tm->priv.ufd.fd = fd; 139 tm->priv.ufd.cb = dispatch_timer; 140 } 141 142 struct itimerspec spec = { 143 .it_value = { 144 .tv_sec = msecs / 1000, 145 .tv_nsec = (msecs % 1000) * 1000000 146 }, 147 .it_interval = { 148 .tv_sec = msecs / 1000, 149 .tv_nsec = (msecs % 1000) * 1000000 150 } 151 }; 152 153 if (timerfd_settime(tm->priv.ufd.fd, 0, &spec, NULL) == -1) 154 goto err; 155 156 if (uloop_fd_add(&tm->priv.ufd, ULOOP_READ) == -1) 157 goto err; 158 159 return 0; 160 161 err: 162 uloop_fd_delete(&tm->priv.ufd); 163 close(tm->priv.ufd.fd); 164 memset(&tm->priv.ufd, 0, sizeof(tm->priv.ufd)); 165 166 return -1; 167 } 168 169 static int timer_remove(struct uloop_interval *tm) 170 { 171 if (!tm->priv.ufd.registered) 172 return -1; 173 174 uloop_fd_delete(&tm->priv.ufd); 175 close(tm->priv.ufd.fd); 176 memset(&tm->priv.ufd, 0, sizeof(tm->priv.ufd)); 177 178 return 0; 179 } 180 181 static int64_t timer_next(struct uloop_interval *tm) 182 { 183 struct itimerspec spec; 184 185 if (!tm->priv.ufd.registered) 186 return -1; 187 188 if (timerfd_gettime(tm->priv.ufd.fd, &spec) == -1) 189 return -1; 190 191 return spec.it_value.tv_sec * 1000 + spec.it_value.tv_nsec / 1000000; 192 } 193
This page was automatically generated by LXR 0.3.1. • OpenWrt