* Fix a race condition in kevent_wait() by holding the kqueue lock

for the duration of the kevent() function call. To avoid going to
    sleep with the lock, it is dropped temporarily before calling 
    pselect() or similar system calls.

    Thanks to Eric Wong for reporting this bug.



git-svn-id: svn://svn.code.sf.net/p/libkqueue/code/branches/stable@541 fb4e3144-bc1c-4b72-a658-5bcd248dd7f7
This commit is contained in:
mheily 2012-04-22 21:46:51 +00:00
parent d409012e4c
commit 993be36cda
5 changed files with 25 additions and 18 deletions

View File

@ -1,3 +1,11 @@
2012-04-22 v1.0.7 r541
------------------------------------------------------------------------
* Fix a race condition in kevent_wait() by holding the kqueue lock
for the duration of the kevent() function call. To avoid going to
sleep with the lock, it is dropped temporarily before calling
pselect() or similar system calls.
Thanks to Eric Wong for reporting this bug.
2012-04-19 v1.0.6 r539
------------------------------------------------------------------------

View File

@ -1,5 +1,5 @@
program="libkqueue"
version="1.0.6"
version="1.0.7"
abi_major="0"
abi_minor="0"
abi_version="$abi_major.$abi_minor"

View File

@ -248,21 +248,21 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
return (-1);
}
kqueue_lock(kq);
rv = kqueue_validate(kq);
if (rv < 0) {
return (-1);
goto errout;
} else if (rv == 0) {
errno = EBADF;
return (-1);
goto errout;
}
/*
* Process each kevent on the changelist.
*/
if (nchanges) {
kqueue_lock(kq);
rv = kevent_copyin(kq, changelist, nchanges, eventlist, nevents);
kqueue_unlock(kq);
dbg_printf("changelist: rv=%d", rv);
if (rv < 0)
goto errout;
@ -291,9 +291,7 @@ kevent(int kqfd, const struct kevent *changelist, int nchanges,
goto out; /* Timeout */
/* Copy the events to the caller */
kqueue_lock(kq);
nret = kevent_copyout(kq, n, eventlist, nevents);
kqueue_unlock(kq);
}
if (KQUEUE_DEBUG) {
@ -309,6 +307,7 @@ errout:
nret = -1;
out:
kqueue_unlock(kq);
kqueue_put(kq);
return (nret);
}

View File

@ -28,15 +28,12 @@ kevent_wait(struct kqueue *kq, const struct timespec *timeout)
dbg_puts("waiting for events");
kq->kq_rfds = kq->kq_fds;
kqueue_unlock(kq);
n = pselect(kq->kq_nfds, &kq->kq_rfds, NULL , NULL, timeout, NULL);
if (n < 0) {
if (errno == EINTR) {
dbg_puts("signal caught");
return (-1);
}
if (n < 0)
dbg_perror("pselect(2)");
return (-1);
}
kqueue_lock(kq);
return (n);
}

View File

@ -90,23 +90,26 @@ kevent_wait(struct kqueue *kq, const struct timespec *timeout)
reset_errno();
dbg_printf("waiting for events (timeout=%p)", timeout);
kqueue_unlock(kq);
rv = port_getn(kq->kq_port, pe, 1, &nget, (struct timespec *) timeout);
dbg_printf("rv=%d errno=%d (%s) nget=%d",
rv, errno, strerror(errno), nget);
if (rv < 0) {
if (errno == ETIME) {
dbg_puts("no events within the given timeout");
return (0);
rv = 0;
}
if (errno == EINTR) {
dbg_puts("signal caught");
return (-1);
rv = -1;
}
dbg_perror("port_get(2)");
return (-1);
} else {
rv = nget;
}
return (nget);
kqueue_lock(kq);
return (rv);
}
int