Author: markj
Date: Fri Feb 19 01:49:33 2016
New Revision: 295786
URL: https://svnweb.freebsd.org/changeset/base/295786

Log:
  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

Modified:
  head/sys/kern/kern_event.c
  head/tests/sys/kqueue/read.c

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c  Fri Feb 19 01:35:01 2016        (r295785)
+++ head/sys/kern/kern_event.c  Fri Feb 19 01:49:33 2016        (r295786)
@@ -1323,27 +1323,24 @@ findkn:
         * 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:

Modified: head/tests/sys/kqueue/read.c
==============================================================================
--- head/tests/sys/kqueue/read.c        Fri Feb 19 01:35:01 2016        
(r295785)
+++ head/tests/sys/kqueue/read.c        Fri Feb 19 01:49:33 2016        
(r295786)
@@ -124,15 +124,17 @@ test_kevent_socket_disable_and_enable(vo
 
     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 */
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to