Add cv_timedwait_interruptible() function

The cv_timedwait() function by definition must wait unconditionally
for cv_signal()/cv_broadcast() before waking.  This causes processes
to go in the D state which increases the load average.  The load
average is the summation of processes in D state and run queue.

To avoid this it can be desirable to sleep interruptibly.  These
processes do not count against the load average but may be woken by
a signal.  It is up to the caller to determine why the process
was woken it may be for one of three reasons.

  1) cv_signal()/cv_broadcast()
  2) the timeout expired
  3) a signal was received

Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
This commit is contained in:
Neependra Khare 2010-12-06 17:05:58 +05:30 committed by Brian Behlendorf
parent 6bf4d76f47
commit 3f688a8c38
2 changed files with 33 additions and 16 deletions

View File

@ -53,21 +53,25 @@ extern void __cv_destroy(kcondvar_t *cvp);
extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp); extern void __cv_wait(kcondvar_t *cvp, kmutex_t *mp);
extern void __cv_wait_interruptible(kcondvar_t *cvp, kmutex_t *mp); 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 clock_t __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time);
extern clock_t __cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp,
clock_t exp_time);
extern void __cv_signal(kcondvar_t *cvp); extern void __cv_signal(kcondvar_t *cvp);
extern void __cv_broadcast(kcondvar_t *cvp); extern void __cv_broadcast(kcondvar_t *cvp);
#define cv_init(cvp, name, type, arg) \ #define cv_init(cvp, name, type, arg) \
({ \ ({ \
if ((name) == NULL) \ if ((name) == NULL) \
__cv_init(cvp, #cvp, type, arg); \ __cv_init(cvp, #cvp, type, arg); \
else \ else \
__cv_init(cvp, name, type, arg); \ __cv_init(cvp, name, type, arg); \
}) })
#define cv_destroy(cvp) __cv_destroy(cvp) #define cv_destroy(cvp) __cv_destroy(cvp)
#define cv_wait(cvp, mp) __cv_wait(cvp, mp) #define cv_wait(cvp, mp) __cv_wait(cvp, mp)
#define cv_wait_interruptible(cvp, mp) __cv_wait_interruptible(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_timedwait(cvp, mp, t) __cv_timedwait(cvp, mp, t)
#define cv_signal(cvp) __cv_signal(cvp) #define cv_timedwait_interruptible(cvp, mp, t) \
#define cv_broadcast(cvp) __cv_broadcast(cvp) __cv_timedwait_interruptible(cvp, mp, t)
#define cv_signal(cvp) __cv_signal(cvp)
#define cv_broadcast(cvp) __cv_broadcast(cvp)
#endif /* _SPL_CONDVAR_H */ #endif /* _SPL_CONDVAR_H */

View File

@ -135,8 +135,9 @@ EXPORT_SYMBOL(__cv_wait_interruptible);
/* 'expire_time' argument is an absolute wall clock time in jiffies. /* 'expire_time' argument is an absolute wall clock time in jiffies.
* Return value is time left (expire_time - now) or -1 if timeout occurred. * Return value is time left (expire_time - now) or -1 if timeout occurred.
*/ */
clock_t static clock_t
__cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time) __cv_timedwait_common(kcondvar_t *cvp, kmutex_t *mp,
clock_t expire_time, int state)
{ {
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
clock_t time_left; clock_t time_left;
@ -158,8 +159,7 @@ __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time)
if (time_left <= 0) if (time_left <= 0)
SRETURN(-1); SRETURN(-1);
prepare_to_wait_exclusive(&cvp->cv_event, &wait, prepare_to_wait_exclusive(&cvp->cv_event, &wait, state);
TASK_UNINTERRUPTIBLE);
atomic_inc(&cvp->cv_waiters); atomic_inc(&cvp->cv_waiters);
/* Mutex should be dropped after prepare_to_wait() this /* Mutex should be dropped after prepare_to_wait() this
@ -177,8 +177,21 @@ __cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t expire_time)
SRETURN(time_left > 0 ? time_left : -1); SRETURN(time_left > 0 ? time_left : -1);
} }
clock_t
__cv_timedwait(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
{
return __cv_timedwait_common(cvp, mp, exp_time, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(__cv_timedwait); EXPORT_SYMBOL(__cv_timedwait);
clock_t
__cv_timedwait_interruptible(kcondvar_t *cvp, kmutex_t *mp, clock_t exp_time)
{
return __cv_timedwait_common(cvp, mp, exp_time, TASK_INTERRUPTIBLE);
}
EXPORT_SYMBOL(__cv_timedwait_interruptible);
void void
__cv_signal(kcondvar_t *cvp) __cv_signal(kcondvar_t *cvp)
{ {