diff options
author | jlemon <jlemon@FreeBSD.org> | 2000-08-07 16:45:42 +0000 |
---|---|---|
committer | jlemon <jlemon@FreeBSD.org> | 2000-08-07 16:45:42 +0000 |
commit | 8713fbd9e3d63370b8594130e7ee8ea2213d142d (patch) | |
tree | 62e7957c86190da051ce2b26d3e886fd4deffa5f /sys/kern/kern_event.c | |
parent | e35ff24b97251716934363c568b0a7c1e8e064f5 (diff) | |
download | FreeBSD-src-8713fbd9e3d63370b8594130e7ee8ea2213d142d.zip FreeBSD-src-8713fbd9e3d63370b8594130e7ee8ea2213d142d.tar.gz |
Fix bug with timeout; previously, when attempting to poll the kqueue by
passing a zero-valued timeout, the code would always sleep for one tick.
Change code to avoid calling tsleep if we have no intention of sleeping.
Bring in bugfix from sys_select.c, r1.60 which also applies here.
Modify error handling slightly; passing in an invalid fd will now result
in EBADF returned in the eventlist, while an attempt to change a knote
which does not exist will result in ENOENT being returned. Previously
such attempts would fail silently without notification.
Pointed out by: nicolas.leonard@animaths.com
Rick Reed (rr@yahoo-inc.com)
Diffstat (limited to 'sys/kern/kern_event.c')
-rw-r--r-- | sys/kern/kern_event.c | 36 |
1 files changed, 22 insertions, 14 deletions
diff --git a/sys/kern/kern_event.c b/sys/kern/kern_event.c index 2db8524..74d5fa7 100644 --- a/sys/kern/kern_event.c +++ b/sys/kern/kern_event.c @@ -413,10 +413,10 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p) } if (fops->f_isfd) { - /* validate descriptor; ignore invalid descriptors */ + /* validate descriptor */ if ((u_int)kev->ident >= fdp->fd_nfiles || (fp = fdp->fd_ofiles[kev->ident]) == NULL) - return (0); + return (EBADF); if (kev->ident < fdp->fd_knlistsize) { SLIST_FOREACH(kn, &fdp->fd_knlist[kev->ident], kn_link) @@ -439,7 +439,7 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct proc *p) } if (kn == NULL && ((kev->flags & EV_ADD) == 0)) - goto done; + return (ENOENT); /* * kn now contains the matching knote, or NULL if no match @@ -523,24 +523,28 @@ kqueue_scan(struct file *fp, int maxevents, struct kevent *ulistp, if (count == 0) goto done; - if (tsp != NULL) { + if (tsp != NULL) { TIMESPEC_TO_TIMEVAL(&atv, tsp); - if (itimerfix(&atv)) { + if (itimerfix(&atv)) { error = EINVAL; goto done; } - timeout = atv.tv_sec > 24 * 60 * 60 ? - 24 * 60 * 60 * hz : tvtohz(&atv); - getmicrouptime(&rtv); - timevaladd(&atv, &rtv); - } else { - atv.tv_sec = 0; + if (tsp->tv_sec == 0 && tsp->tv_nsec == 0) + timeout = -1; + else + timeout = atv.tv_sec > 24 * 60 * 60 ? + 24 * 60 * 60 * hz : tvtohz(&atv); + getmicrouptime(&rtv); + timevaladd(&atv, &rtv); + } else { + atv.tv_sec = 0; + atv.tv_usec = 0; timeout = 0; } goto start; retry: - if (atv.tv_sec) { + if (atv.tv_sec || atv.tv_usec) { getmicrouptime(&rtv); if (timevalcmp(&rtv, &atv, >=)) goto done; @@ -554,8 +558,12 @@ start: kevp = kq->kq_kev; s = splhigh(); if (kq->kq_count == 0) { - kq->kq_state |= KQ_SLEEP; - error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout); + if (timeout < 0) { + error = EWOULDBLOCK; + } else { + kq->kq_state |= KQ_SLEEP; + error = tsleep(kq, PSOCK | PCATCH, "kqread", timeout); + } splx(s); if (error == 0) goto retry; |