Skip to content

Commit

Permalink
Add cv_wait_interruptible() function.
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
behlendorf committed May 14, 2010
1 parent 97f8f6d commit f752b46
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 6 deletions.
5 changes: 3 additions & 2 deletions include/sys/condvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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)
Expand Down
20 changes: 16 additions & 4 deletions module/spl/spl-condvar.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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.
*/
Expand Down

0 comments on commit f752b46

Please sign in to comment.