Ensure that we test the event condition when a disabled kevent is enabled.

r274560 modified kqueue_register() to only test the event condition if the
corresponding knote is not disabled. However, this check takes place before
the EV_ENABLE flag is used to clear the KN_DISABLED flag on the knote, so
enabling a previously-disabled kevent would not result in a notification for
a triggered event. This change fixes the problem by testing for EV_ENABLED
before possibly checking the event condition.

This change also updates a kqueue regression test to exercise this case.

PR:		206368
Reviewed by:	kib
Sponsored by:	EMC / Isilon Storage Division
Differential Revision:	https://reviews.freebsd.org/D5307
This commit is contained in:
markj 2016-02-19 01:49:33 +00:00
parent 1945f66461
commit 32d1c3375a
2 changed files with 16 additions and 17 deletions

View File

@ -1323,27 +1323,24 @@ kqueue_register(struct kqueue *kq, struct kevent *kev, struct thread *td, int wa
* kn_knlist.
*/
done_ev_add:
if ((kev->flags & EV_DISABLE) &&
((kn->kn_status & KN_DISABLED) == 0)) {
if ((kev->flags & EV_ENABLE) != 0)
kn->kn_status &= ~KN_DISABLED;
else if ((kev->flags & EV_DISABLE) != 0)
kn->kn_status |= KN_DISABLED;
}
if ((kn->kn_status & KN_DISABLED) == 0)
event = kn->kn_fop->f_event(kn, 0);
else
event = 0;
KQ_LOCK(kq);
if (event)
KNOTE_ACTIVATE(kn, 1);
kn->kn_status |= KN_ACTIVE;
if ((kn->kn_status & (KN_ACTIVE | KN_DISABLED | KN_QUEUED)) ==
KN_ACTIVE)
knote_enqueue(kn);
kn->kn_status &= ~(KN_INFLUX | KN_SCAN);
KN_LIST_UNLOCK(kn);
if ((kev->flags & EV_ENABLE) && (kn->kn_status & KN_DISABLED)) {
kn->kn_status &= ~KN_DISABLED;
if ((kn->kn_status & KN_ACTIVE) &&
((kn->kn_status & KN_QUEUED) == 0))
knote_enqueue(kn);
}
KQ_UNLOCK_FLUX(kq);
done:

View File

@ -124,15 +124,17 @@ test_kevent_socket_disable_and_enable(void)
test_begin(test_id);
/* Add an event, then disable it. */
EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DISABLE, 0, 0, &sockfd[0]);
/*
* Write to the socket before adding the event. This way we can verify that
* enabling a triggered kevent causes the event to be returned immediately.
*/
kevent_socket_fill();
/* Add a disabled event. */
EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]);
if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
err(1, "%s", test_id);
kevent_socket_fill();
test_no_kevents();
/* Re-enable the knote, then see if an event is generated */