diff options
Diffstat (limited to 'freebsd/sys/kern/kern_condvar.c')
-rw-r--r-- | freebsd/sys/kern/kern_condvar.c | 113 |
1 files changed, 51 insertions, 62 deletions
diff --git a/freebsd/sys/kern/kern_condvar.c b/freebsd/sys/kern/kern_condvar.c index f3be4271..239640e2 100644 --- a/freebsd/sys/kern/kern_condvar.c +++ b/freebsd/sys/kern/kern_condvar.c @@ -33,6 +33,7 @@ __FBSDID("$FreeBSD$"); #include <rtems/bsd/sys/param.h> #include <sys/systm.h> +#include <sys/limits.h> #include <rtems/bsd/sys/lock.h> #include <sys/mutex.h> #include <sys/proc.h> @@ -49,6 +50,17 @@ __FBSDID("$FreeBSD$"); #endif /* + * A bound below which cv_waiters is valid. Once cv_waiters reaches this bound, + * cv_signal must manually check the wait queue for threads. + */ +#define CV_WAITERS_BOUND INT_MAX + +#define CV_WAITERS_INC(cvp) do { \ + if ((cvp)->cv_waiters < CV_WAITERS_BOUND) \ + (cvp)->cv_waiters++; \ +} while (0) + +/* * Common sanity checks for cv_wait* functions. */ #define CV_ASSERT(cvp, lock, td) do { \ @@ -99,7 +111,7 @@ _cv_wait(struct cv *cvp, struct lock_object *lock) WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; - int lock_state; + uintptr_t lock_state; td = curthread; lock_state = 0; @@ -112,19 +124,12 @@ _cv_wait(struct cv *cvp, struct lock_object *lock) "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); - if (cold || panicstr) { - /* - * During autoconfiguration, just give interrupts - * a chance, then just return. Don't run any other - * thread or panic below, in case this is the idle - * process and already asleep. - */ + if (SCHEDULER_STOPPED()) return; - } sleepq_lock(cvp); - cvp->cv_waiters++; + CV_WAITERS_INC(cvp); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); @@ -153,7 +158,7 @@ _cv_wait(struct cv *cvp, struct lock_object *lock) /* * Wait on a condition variable. This function differs from cv_wait by - * not aquiring the mutex after condition variable was signaled. + * not acquiring the mutex after condition variable was signaled. */ void _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) @@ -173,20 +178,14 @@ _cv_wait_unlock(struct cv *cvp, struct lock_object *lock) ("cv_wait_unlock cannot be used with Giant")); class = LOCK_CLASS(lock); - if (cold || panicstr) { - /* - * During autoconfiguration, just give interrupts - * a chance, then just return. Don't run any other - * thread or panic below, in case this is the idle - * process and already asleep. - */ + if (SCHEDULER_STOPPED()) { class->lc_unlock(lock); return; } sleepq_lock(cvp); - cvp->cv_waiters++; + CV_WAITERS_INC(cvp); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); @@ -217,7 +216,8 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock) WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; struct thread *td; - int lock_state, rval; + uintptr_t lock_state; + int rval; td = curthread; lock_state = 0; @@ -230,19 +230,12 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock) "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); - if (cold || panicstr) { - /* - * After a panic, or during autoconfiguration, just give - * interrupts a chance, then just return; don't run any other - * procs or panic below, in case this is the idle process and - * already asleep. - */ + if (SCHEDULER_STOPPED()) return (0); - } sleepq_lock(cvp); - cvp->cv_waiters++; + CV_WAITERS_INC(cvp); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); @@ -278,12 +271,13 @@ _cv_wait_sig(struct cv *cvp, struct lock_object *lock) } /* - * Wait on a condition variable for at most timo/hz seconds. Returns 0 if the - * process was resumed by cv_signal or cv_broadcast, EWOULDBLOCK if the timeout - * expires. + * Wait on a condition variable for (at most) the value specified in sbt + * argument. Returns 0 if the process was resumed by cv_signal or cv_broadcast, + * EWOULDBLOCK if the timeout expires. */ int -_cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) +_cv_timedwait_sbt(struct cv *cvp, struct lock_object *lock, sbintime_t sbt, + sbintime_t pr, int flags) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; @@ -301,25 +295,18 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); - if (cold || panicstr) { - /* - * After a panic, or during autoconfiguration, just give - * interrupts a chance, then just return; don't run any other - * thread or panic below, in case this is the idle process and - * already asleep. - */ - return 0; - } + if (SCHEDULER_STOPPED()) + return (0); sleepq_lock(cvp); - cvp->cv_waiters++; + CV_WAITERS_INC(cvp); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR, 0); - sleepq_set_timeout(cvp, timo); + sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); @@ -345,13 +332,15 @@ _cv_timedwait(struct cv *cvp, struct lock_object *lock, int timo) #ifndef __rtems__ /* - * Wait on a condition variable for at most timo/hz seconds, allowing - * interruption by signals. Returns 0 if the thread was resumed by cv_signal - * or cv_broadcast, EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if - * a signal was caught. + * Wait on a condition variable for (at most) the value specified in sbt + * argument, allowing interruption by signals. + * Returns 0 if the thread was resumed by cv_signal or cv_broadcast, + * EWOULDBLOCK if the timeout expires, and EINTR or ERESTART if a signal + * was caught. */ int -_cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) +_cv_timedwait_sig_sbt(struct cv *cvp, struct lock_object *lock, + sbintime_t sbt, sbintime_t pr, int flags) { WITNESS_SAVE_DECL(lock_witness); struct lock_class *class; @@ -369,26 +358,19 @@ _cv_timedwait_sig(struct cv *cvp, struct lock_object *lock, int timo) "Waiting on \"%s\"", cvp->cv_description); class = LOCK_CLASS(lock); - if (cold || panicstr) { - /* - * After a panic, or during autoconfiguration, just give - * interrupts a chance, then just return; don't run any other - * thread or panic below, in case this is the idle process and - * already asleep. - */ - return 0; - } + if (SCHEDULER_STOPPED()) + return (0); sleepq_lock(cvp); - cvp->cv_waiters++; + CV_WAITERS_INC(cvp); if (lock == &Giant.lock_object) mtx_assert(&Giant, MA_OWNED); DROP_GIANT(); sleepq_add(cvp, lock, cvp->cv_description, SLEEPQ_CONDVAR | SLEEPQ_INTERRUPTIBLE, 0); - sleepq_set_timeout(cvp, timo); + sleepq_set_timeout_sbt(cvp, sbt, pr, flags); if (lock != &Giant.lock_object) { if (class->lc_flags & LC_SLEEPABLE) sleepq_release(cvp); @@ -428,8 +410,15 @@ cv_signal(struct cv *cvp) wakeup_swapper = 0; sleepq_lock(cvp); if (cvp->cv_waiters > 0) { - cvp->cv_waiters--; - wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, 0); + if (cvp->cv_waiters == CV_WAITERS_BOUND && + sleepq_lookup(cvp) == NULL) { + cvp->cv_waiters = 0; + } else { + if (cvp->cv_waiters < CV_WAITERS_BOUND) + cvp->cv_waiters--; + wakeup_swapper = sleepq_signal(cvp, SLEEPQ_CONDVAR, 0, + 0); + } } sleepq_release(cvp); if (wakeup_swapper) |