Author: davide
Date: Mon Mar  4 16:55:16 2013
New Revision: 247804
URL: http://svnweb.freebsd.org/changeset/base/247804

Log:
  MFcalloutng:
  - Rewrite kevent() timeout implementation to allow sub-tick precision.
  - Make the interval timings for EVFILT_TIMER more accurate. This also
  removes an hack introduced in r238424.
  
  Sponsored by: Google Summer of Code 2012, iXsystems inc.
  Tested by:    flo, marius, ian, markj, Fabian Keil

Modified:
  head/sys/kern/kern_event.c

Modified: head/sys/kern/kern_event.c
==============================================================================
--- head/sys/kern/kern_event.c  Mon Mar  4 16:50:01 2013        (r247803)
+++ head/sys/kern/kern_event.c  Mon Mar  4 16:55:16 2013        (r247804)
@@ -517,39 +517,28 @@ knote_fork(struct knlist *list, int pid)
  * XXX: EVFILT_TIMER should perhaps live in kern_time.c beside the
  * interval timer support code.
  */
-static int
-timertoticks(intptr_t data)
+static __inline sbintime_t 
+timer2sbintime(intptr_t data)
 {
-       struct timeval tv;
-       int tticks;
-
-       tv.tv_sec = data / 1000;
-       tv.tv_usec = (data % 1000) * 1000;
-       tticks = tvtohz(&tv);
 
-       return tticks;
+       return (SBT_1MS * data);
 }
 
 static void
 filt_timerexpire(void *knx)
 {
-       struct knote *kn = knx;
        struct callout *calloutp;
+       struct knote *kn;
 
+       kn = knx;
        kn->kn_data++;
        KNOTE_ACTIVATE(kn, 0);  /* XXX - handle locking */
 
-       /*
-        * timertoticks() uses tvtohz() which always adds 1 to allow
-        * for the time until the next clock interrupt being strictly
-        * less than 1 clock tick.  We don't want that here since we
-        * want to appear to be in sync with the clock interrupt even
-        * when we're delayed.
-        */
        if ((kn->kn_flags & EV_ONESHOT) != EV_ONESHOT) {
                calloutp = (struct callout *)kn->kn_hook;
-               callout_reset_curcpu(calloutp, timertoticks(kn->kn_sdata) - 1,
-                   filt_timerexpire, kn);
+               callout_reset_sbt_on(calloutp,
+                   timer2sbintime(kn->kn_sdata), 0 /* 1ms? */,
+                   filt_timerexpire, kn, PCPU_GET(cpuid), 0);
        }
 }
 
@@ -573,8 +562,9 @@ filt_timerattach(struct knote *kn)
        calloutp = malloc(sizeof(*calloutp), M_KQUEUE, M_WAITOK);
        callout_init(calloutp, CALLOUT_MPSAFE);
        kn->kn_hook = calloutp;
-       callout_reset_curcpu(calloutp, timertoticks(kn->kn_sdata),
-           filt_timerexpire, kn);
+       callout_reset_sbt_on(calloutp,
+           timer2sbintime(kn->kn_sdata), 0 /* 1ms? */,
+           filt_timerexpire, kn, PCPU_GET(cpuid), 0);
 
        return (0);
 }
@@ -1319,10 +1309,9 @@ kqueue_scan(struct kqueue *kq, int maxev
     const struct timespec *tsp, struct kevent *keva, struct thread *td)
 {
        struct kevent *kevp;
-       struct timeval atv, rtv, ttv;
        struct knote *kn, *marker;
-       int count, timeout, nkev, error, influx;
-       int haskqglobal, touch;
+       sbintime_t asbt, rsbt;
+       int count, error, haskqglobal, influx, nkev, touch;
 
        count = maxevents;
        nkev = 0;
@@ -1332,24 +1321,23 @@ kqueue_scan(struct kqueue *kq, int maxev
        if (maxevents == 0)
                goto done_nl;
 
+       rsbt = 0;
        if (tsp != NULL) {
-               TIMESPEC_TO_TIMEVAL(&atv, tsp);
-               if (itimerfix(&atv)) {
+               if (tsp->tv_sec < 0 || tsp->tv_nsec < 0 ||
+                   tsp->tv_nsec > 1000000000) {
                        error = EINVAL;
                        goto done_nl;
                }
-               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;
-       }
+               if (timespecisset(tsp)) {
+                       rsbt = tstosbt(*tsp);
+                       if (TIMESEL(&asbt, rsbt))
+                               asbt += tc_tick_sbt;
+                       asbt += rsbt;
+                       rsbt >>= tc_precexp;
+               } else
+                       asbt = -1;
+       } else
+               asbt = 0;
        marker = knote_alloc(1);
        if (marker == NULL) {
                error = ENOMEM;
@@ -1357,28 +1345,16 @@ kqueue_scan(struct kqueue *kq, int maxev
        }
        marker->kn_status = KN_MARKER;
        KQ_LOCK(kq);
-       goto start;
 
 retry:
-       if (atv.tv_sec || atv.tv_usec) {
-               getmicrouptime(&rtv);
-               if (timevalcmp(&rtv, &atv, >=))
-                       goto done;
-               ttv = atv;
-               timevalsub(&ttv, &rtv);
-               timeout = ttv.tv_sec > 24 * 60 * 60 ?
-                       24 * 60 * 60 * hz : tvtohz(&ttv);
-       }
-
-start:
        kevp = keva;
        if (kq->kq_count == 0) {
-               if (timeout < 0) {
+               if (asbt == -1) {
                        error = EWOULDBLOCK;
                } else {
                        kq->kq_state |= KQ_SLEEP;
-                       error = msleep(kq, &kq->kq_lock, PSOCK | PCATCH,
-                           "kqread", timeout);
+                       error = msleep_sbt(kq, &kq->kq_lock, PSOCK | PCATCH,
+                           "kqread", asbt, rsbt, C_ABSOLUTE);
                }
                if (error == 0)
                        goto retry;
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to