X-Git-Url: http://git.archive.openwrt.org/?p=project%2Flibubox.git;a=blobdiff_plain;f=uloop.c;h=f0ccb0c2e6344400853bd8548355328f19feb06f;hp=88e9c814fce0d329a0a6afbef72edeae9e3b2f74;hb=e5a40544ecfa87583bbac014faae7e217e4e64b9;hpb=9c8ab5d64cb1bfc6f8a235af5913ed3537c38e2a diff --git a/uloop.c b/uloop.c index 88e9c81..f0ccb0c 100644 --- a/uloop.c +++ b/uloop.c @@ -1,24 +1,20 @@ /* - * Copyright (C) 2010 Felix Fietkau - * Copyright (C) 2010 John Crispin - * Copyright (C) 2010 Steven Barth + * uloop - event loop implementation * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. + * Copyright (C) 2010-2013 Felix Fietkau * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - #include #include @@ -57,6 +53,9 @@ static int cur_fd, cur_nfds; int uloop_init(void) { + struct timespec timeout = { 0, 0 }; + struct kevent ev = {}; + if (poll_fd >= 0) return 0; @@ -64,6 +63,9 @@ int uloop_init(void) if (poll_fd < 0) return -1; + EV_SET(&ev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0); + kevent(poll_fd, &ev, 1, NULL, 0, &timeout); + return 0; } @@ -84,38 +86,52 @@ static uint16_t get_flags(unsigned int flags, unsigned int mask) static struct kevent events[ULOOP_MAX_EVENTS]; -static int register_poll(struct uloop_fd *fd, unsigned int flags) +static int register_kevent(struct uloop_fd *fd, unsigned int flags) { struct timespec timeout = { 0, 0 }; struct kevent ev[2]; - unsigned int changed; int nev = 0; unsigned int fl = 0; + unsigned int changed; + uint16_t kflags; - changed = fd->kqflags ^ flags; + if (flags & ULOOP_EDGE_DEFER) + flags &= ~ULOOP_EDGE_TRIGGER; + + changed = flags ^ fd->flags; if (changed & ULOOP_EDGE_TRIGGER) changed |= flags; if (changed & ULOOP_READ) { - uint16_t kflags = get_flags(flags, ULOOP_READ); + kflags = get_flags(flags, ULOOP_READ); EV_SET(&ev[nev++], fd->fd, EVFILT_READ, kflags, 0, 0, fd); } if (changed & ULOOP_WRITE) { - uint16_t kflags = get_flags(flags, ULOOP_WRITE); + kflags = get_flags(flags, ULOOP_WRITE); EV_SET(&ev[nev++], fd->fd, EVFILT_WRITE, kflags, 0, 0, fd); } if (!flags) fl |= EV_DELETE; - if (nev && (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1)) + fd->flags = flags; + if (kevent(poll_fd, ev, nev, NULL, fl, &timeout) == -1) return -1; - fd->kqflags = flags; return 0; } +static int register_poll(struct uloop_fd *fd, unsigned int flags) +{ + if (flags & ULOOP_EDGE_TRIGGER) + flags |= ULOOP_EDGE_DEFER; + else + flags &= ~ULOOP_EDGE_DEFER; + + return register_kevent(fd, flags); +} + int uloop_fd_delete(struct uloop_fd *sock) { int i; @@ -136,12 +152,12 @@ static void uloop_run_events(int timeout) struct timespec ts; int nfds, n; - if (timeout > 0) { + if (timeout >= 0) { ts.tv_sec = timeout / 1000; ts.tv_nsec = (timeout % 1000) * 1000000; } - nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout > 0 ? &ts : NULL); + nfds = kevent(poll_fd, NULL, 0, events, ARRAY_SIZE(events), timeout >= 0 ? &ts : NULL); for(n = 0; n < nfds; ++n) { struct uloop_fd *u = events[n].udata; @@ -169,6 +185,10 @@ static void uloop_run_events(int timeout) cur_fd = n; cur_nfds = nfds; u->cb(u, ev); + if (u->flags & ULOOP_EDGE_DEFER) { + u->flags &= ~ULOOP_EDGE_DEFER; + register_kevent(u, u->flags); + } } } cur_nfds = 0; @@ -226,6 +246,9 @@ int uloop_fd_delete(struct uloop_fd *sock) { int i; + if (!sock->registered) + return 0; + for (i = cur_fd + 1; i < cur_nfds; i++) { if (events[i].data.ptr != sock) continue; @@ -282,6 +305,9 @@ int uloop_fd_add(struct uloop_fd *sock, unsigned int flags) unsigned int fl; int ret; + if (!(flags & (ULOOP_READ | ULOOP_WRITE))) + return uloop_fd_delete(sock); + if (!sock->registered && !(flags & ULOOP_BLOCKING)) { fl = fcntl(sock->fd, F_GETFL, 0); fl |= O_NONBLOCK; @@ -327,6 +353,15 @@ int uloop_timeout_add(struct uloop_timeout *timeout) return 0; } +static void uloop_gettime(struct timeval *tv) +{ + struct timespec ts; + + clock_gettime(CLOCK_MONOTONIC, &ts); + tv->tv_sec = ts.tv_sec; + tv->tv_usec = ts.tv_nsec / 1000; +} + int uloop_timeout_set(struct uloop_timeout *timeout, int msecs) { struct timeval *time = &timeout->time; @@ -334,7 +369,7 @@ int uloop_timeout_set(struct uloop_timeout *timeout, int msecs) if (timeout->pending) uloop_timeout_cancel(timeout); - gettimeofday(&timeout->time, NULL); + uloop_gettime(&timeout->time); time->tv_sec += msecs / 1000; time->tv_usec += (msecs % 1000) * 1000; @@ -358,6 +393,18 @@ int uloop_timeout_cancel(struct uloop_timeout *timeout) return 0; } +int uloop_timeout_remaining(struct uloop_timeout *timeout) +{ + struct timeval now; + + if (!timeout->pending) + return -1; + + uloop_gettime(&now); + + return tv_diff(&timeout->time, &now); +} + int uloop_process_add(struct uloop_process *p) { struct uloop_process *tmp; @@ -497,7 +544,7 @@ void uloop_run(void) uloop_setup_signals(); while(!uloop_cancelled) { - gettimeofday(&tv, NULL); + uloop_gettime(&tv); uloop_process_timeouts(&tv); if (uloop_cancelled) break;