]> granicus.if.org Git - zfs/commitdiff
Add cv_wait_interruptible() function.
authorBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 14 May 2010 16:24:51 +0000 (09:24 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Fri, 14 May 2010 16:24:51 +0000 (09:24 -0700)
This is a minor extension to the condition variable API to allow
for reasonable signal handling on Linux.  The cv_wait() function by
definition must wait unconditionally for cv_signal()/cv_broadcast()
before waking it.  This makes it impossible to woken by a signal
such as SIGTERM.  The cv_wait_interruptible() function was added
to handle this case.  It behaves identically to cv_wait() with the
exception that it waits interruptibly allowing a signal to wake it
up.  This means you do need to be careful and check issig() after
waking.

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

index 9a2e8b5a0df46034090cfda5358f5c2764e22254..bf1347b0f104528525585bb8e68e765558d4eb47 100644 (file)
@@ -57,8 +57,8 @@ typedef enum { CV_DEFAULT=0, CV_DRIVER } kcv_type_t;
 extern void __cv_init(kcondvar_t *cvp, char *name, kcv_type_t type, void *arg);
 extern void __cv_destroy(kcondvar_t *cvp);
 extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp);
-extern clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp,
-                             clock_t expire_time);
+extern void __cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp);
+extern clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time);
 extern void __cv_signal(kcondvar_t *cvp);
 extern void __cv_broadcast(kcondvar_t *cvp);
 
@@ -71,6 +71,7 @@ extern void __cv_broadcast(kcondvar_t *cvp);
 })
 #define cv_destroy(cvp)                        __cv_destroy(cvp)
 #define cv_wait(cvp, mp)               __cv_wait(cvp, mp)
+#define cv_wait_interruptible(cvp, mp) __cv_wait_interruptible(cvp, mp)
 #define cv_timedwait(cvp, mp, t)       __cv_timedwait(cvp, mp, t)
 #define cv_signal(cvp)                 __cv_signal(cvp)
 #define cv_broadcast(cvp)              __cv_broadcast(cvp)
index 163f2a1de754f6c6c78027659d3035f700fc263a..d5b9be721fb18e209b9aedb41ca46142797df510 100644 (file)
@@ -84,8 +84,8 @@ __cv_destroy(kcondvar_t *cvp)
 }
 EXPORT_SYMBOL(__cv_destroy);
 
-void
-__cv_wait(kcondvar_t *cvp, kmutex_t *mp)
+static void
+cv_wait_common(kcondvar_t *cvp, kmutex_t *mp, int state)
 {
        DEFINE_WAIT(wait);
        ENTRY;
@@ -103,8 +103,7 @@ __cv_wait(kcondvar_t *cvp, kmutex_t *mp)
        ASSERT(cvp->cv_mutex == mp);
        spin_unlock(&cvp->cv_lock);
 
-       prepare_to_wait_exclusive(&cvp->cv_event, &wait,
-                                 TASK_UNINTERRUPTIBLE);
+       prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
        atomic_inc(&cvp->cv_waiters);
 
        /* Mutex should be dropped after prepare_to_wait() this
@@ -118,8 +117,21 @@ __cv_wait(kcondvar_t *cvp, kmutex_t *mp)
        finish_wait(&cvp->cv_event, &wait);
        EXIT;
 }
+
+void
+__cv_wait(kcondvar_t *cvp, kmutex_t *mp)
+{
+       cv_wait_common(cvp, mp, TASK_UNINTERRUPTIBLE);
+}
 EXPORT_SYMBOL(__cv_wait);
 
+void
+__cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp)
+{
+       cv_wait_common(cvp, mp, TASK_INTERRUPTIBLE);
+}
+EXPORT_SYMBOL(__cv_wait_interruptible);
+
 /* 'expire_time' argument is an absolute wall clock time in jiffies.
  * Return value is time left (expire_time - now) or -1 if timeout occurred.
  */