]> granicus.if.org Git - zfs/commitdiff
Add cv_timedwait_sig_hires to allow interruptible sleep
authorChunwei Chen <david.chen@osnexus.com>
Wed, 11 May 2016 23:51:29 +0000 (16:51 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Thu, 12 May 2016 21:54:15 +0000 (14:54 -0700)
Signed-off-by: Chunwei Chen <david.chen@osnexus.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #548

include/sys/condvar.h
module/spl/spl-condvar.c

index efcf0dda2769b2c903636932bc0ca0f9b4da0c7d..9b55449ae555d2b2ece52c57730b76de78b2c9e2 100644 (file)
@@ -59,6 +59,8 @@ extern clock_t __cv_timedwait(kcondvar_t *, kmutex_t *, clock_t);
 extern clock_t __cv_timedwait_sig(kcondvar_t *, kmutex_t *, clock_t);
 extern clock_t cv_timedwait_hires(kcondvar_t *, kmutex_t *, hrtime_t,
     hrtime_t res, int flag);
+extern clock_t cv_timedwait_sig_hires(kcondvar_t *, kmutex_t *, hrtime_t,
+    hrtime_t res, int flag);
 extern void __cv_signal(kcondvar_t *);
 extern void __cv_broadcast(kcondvar_t *c);
 
index c420d18cadfe14f61cf01dec57e119bd0be401e4..1e2d0fc10d2ffd65ea19e9c870ce29054340bd36 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <sys/condvar.h>
 #include <sys/time.h>
+#include <linux/hrtimer.h>
 
 void
 __cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg)
@@ -238,7 +239,7 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
        DEFINE_WAIT(wait);
        kmutex_t *m;
        hrtime_t time_left, now;
-       unsigned long time_left_us;
+       ktime_t ktime_left;
 
        ASSERT(cvp);
        ASSERT(mp);
@@ -258,7 +259,6 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
                atomic_dec(&cvp->cv_refs);
                return (-1);
        }
-       time_left_us = time_left / NSEC_PER_USEC;
 
        prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
        atomic_inc(&cvp->cv_waiters);
@@ -273,7 +273,9 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
         * Allow a 100 us range to give kernel an opportunity to coalesce
         * interrupts
         */
-       usleep_range(time_left_us, time_left_us + 100);
+       ktime_left = ktime_set(0, time_left);
+       schedule_hrtimeout_range(&ktime_left, 100 * NSEC_PER_USEC,
+           HRTIMER_MODE_REL);
 
        /* No more waiters a different mutex could be used */
        if (atomic_dec_and_test(&cvp->cv_waiters)) {
@@ -290,15 +292,15 @@ __cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t expire_time,
 
        mutex_enter(mp);
        time_left = expire_time - gethrtime();
-       return (time_left > 0 ? time_left : -1);
+       return (time_left > 0 ? NSEC_TO_TICK(time_left) : -1);
 }
 
 /*
  * Compatibility wrapper for the cv_timedwait_hires() Illumos interface.
  */
-clock_t
-cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
-    int flag)
+static clock_t
+cv_timedwait_hires_common(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag, int state)
 {
        if (res > 1) {
                /*
@@ -309,13 +311,31 @@ cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
                tim = (tim / res) * res;
        }
 
-       if (!(flag & CALLOUT_FLAG_ABSOLUTE))
-               tim += gethrtime();
+       ASSERT(!(flag & CALLOUT_FLAG_ABSOLUTE));
+       /* get abs expire time */
+       tim += gethrtime();
+
+       return (__cv_timedwait_hires(cvp, mp, tim, state));
+}
 
-       return (__cv_timedwait_hires(cvp, mp, tim, TASK_UNINTERRUPTIBLE));
+clock_t
+cv_timedwait_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
+{
+       return (cv_timedwait_hires_common(cvp, mp, tim, res, flag,
+           TASK_UNINTERRUPTIBLE));
 }
 EXPORT_SYMBOL(cv_timedwait_hires);
 
+clock_t
+cv_timedwait_sig_hires(kcondvar_t *cvp, kmutex_t *mp, hrtime_t tim, hrtime_t res,
+    int flag)
+{
+       return (cv_timedwait_hires_common(cvp, mp, tim, res, flag,
+           TASK_INTERRUPTIBLE));
+}
+EXPORT_SYMBOL(cv_timedwait_sig_hires);
+
 void
 __cv_signal(kcondvar_t *cvp)
 {