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 ev.data.ptr = fd; 56 57 return epoll_ctl(poll_fd, op, fd->fd, &ev); 58 } 59 60 static struct epoll_event events[ULOOP_MAX_EVENTS]; 61 62 static int __uloop_fd_delete(struct uloop_fd *sock) 63 { 64 sock->flags = 0; 65 return epoll_ctl(poll_fd, EPOLL_CTL_DEL, sock->fd, 0); 66 } 67 68 static int uloop_fetch_events(int timeout) 69 { 70 int n, nfds; 71 72 nfds = epoll_wait(poll_fd, events, ARRAY_SIZE(events), timeout); 73 for (n = 0; n < nfds; ++n) { 74 struct uloop_fd_event *cur = &cur_fds[n]; 75 struct uloop_fd *u = events[n].data.ptr; 76 unsigned int ev = 0; 77 78 cur->fd = u; 79 if (!u) 80 continue; 81 82 if (events[n].events & (EPOLLERR|EPOLLHUP)) { 83 u->error = true; 84 if (!(u->flags & ULOOP_ERROR_CB)) 85 uloop_fd_delete(u); 86 } 87 88 if(!(events[n].events & (EPOLLRDHUP|EPOLLIN|EPOLLOUT|EPOLLERR|EPOLLHUP))) { 89 cur->fd = NULL; 90 continue; 91 } 92 93 if(events[n].events & EPOLLRDHUP) 94 u->eof = true; 95 96 if(events[n].events & EPOLLIN) 97 ev |= ULOOP_READ; 98 99 if(events[n].events & EPOLLOUT) 100 ev |= ULOOP_WRITE; 101 102 cur->events = ev; 103 } 104 105 return nfds; 106 } 107 108 static void dispatch_timer(struct uloop_fd *u, unsigned int events) 109 { 110 if (!(events & ULOOP_READ)) 111 return; 112 113 uint64_t fired; 114 115 if (read(u->fd, &fired, sizeof(fired)) != sizeof(fired)) 116 return; 117 118 struct uloop_interval *tm = container_of(u, struct uloop_interval, priv.ufd); 119 120 tm->expirations += fired; 121 tm->cb(tm); 122 } 123 124 static int timer_register(struct uloop_interval *tm, unsigned int msecs) 125 { 126 if (!tm->priv.ufd.registered) { 127 int fd = timerfd_create(CLOCK_MONOTONIC, TFD_CLOEXEC|TFD_NONBLOCK); 128 129 if (fd == -1) 130 return -1; 131 132 tm->priv.ufd.fd = fd; 133 tm->priv.ufd.cb = dispatch_timer; 134 } 135 136 struct itimerspec spec = { 137 .it_value = { 138 .tv_sec = msecs / 1000, 139 .tv_nsec = (msecs % 1000) * 1000000 140 }, 141 .it_interval = { 142 .tv_sec = msecs / 1000, 143 .tv_nsec = (msecs % 1000) * 1000000 144 } 145 }; 146 147 if (timerfd_settime(tm->priv.ufd.fd, 0, &spec, NULL) == -1) 148 goto err; 149 150 if (uloop_fd_add(&tm->priv.ufd, ULOOP_READ) == -1) 151 goto err; 152 153 return 0; 154 155 err: 156 uloop_fd_delete(&tm->priv.ufd); 157 close(tm->priv.ufd.fd); 158 memset(&tm->priv.ufd, 0, sizeof(tm->priv.ufd)); 159 160 return -1; 161 } 162 163 static int timer_remove(struct uloop_interval *tm) 164 { 165 int ret = __uloop_fd_delete(&tm->priv.ufd); 166 167 if (ret == 0) { 168 close(tm->priv.ufd.fd); 169 memset(&tm->priv.ufd, 0, sizeof(tm->priv.ufd)); 170 } 171 172 return ret; 173 } 174 175 static int64_t timer_next(struct uloop_interval *tm) 176 { 177 struct itimerspec spec; 178 179 if (!tm->priv.ufd.registered) 180 return -1; 181 182 if (timerfd_gettime(tm->priv.ufd.fd, &spec) == -1) 183 return -1; 184 185 return spec.it_value.tv_sec * 1000 + spec.it_value.tv_nsec / 1000000; 186 } 187
This page was automatically generated by LXR 0.3.1. • OpenWrt