diff --git a/src/libs/compat/freebsd_network/Condvar.cpp b/src/libs/compat/freebsd_network/Condvar.cpp index 652be6009d..6d583eb430 100644 --- a/src/libs/compat/freebsd_network/Condvar.cpp +++ b/src/libs/compat/freebsd_network/Condvar.cpp @@ -11,9 +11,11 @@ extern "C" { #include } -#include +#include +#include #include +#include #include "device.h" @@ -21,53 +23,83 @@ extern "C" { #define ticks_to_usecs(t) (1000000*(t) / hz) -extern "C" { -static object_cache* sConditionVariableCache; +static const int kConditionVariableHashSize = 32; +struct ConditionVariableHashDefinition { + typedef const void* KeyType; + typedef ConditionVariable ValueType; + + size_t HashKey(const void* key) const + { return (size_t)key; } + size_t Hash(ConditionVariable* variable) const + { return (size_t)variable->fObject; } + bool Compare(const void* key, ConditionVariable* variable) const + { return key == variable->fObject; } + ConditionVariable*& GetLink(ConditionVariable* variable) const + { return variable->fNext; } +}; + +typedef BOpenHashTable ConditionVariableHash; +static ConditionVariableHash sConditionVariableHash; +static spinlock sConditionVariablesLock; + +extern "C" { + status_t init_condition_variables() { - sConditionVariableCache = create_object_cache("condition variables", - sizeof (ConditionVariable), 0, NULL, NULL, NULL); - if (sConditionVariableCache == NULL) - return B_NO_MEMORY; - - return B_OK; + return sConditionVariableHash.Init(kConditionVariableHashSize); } void uninit_condition_variables() { - delete_object_cache(sConditionVariableCache); + InterruptsSpinLocker _(sConditionVariablesLock); + ConditionVariableHash::Iterator it = sConditionVariableHash.GetIterator(); + while (ConditionVariable* variable = it.Next()) { + variable->Unpublish(); + free(variable); + } } } /* extern "C" */ void -_cv_init(struct cv* conditionVariable, const char* description) +_cv_init(struct cv* conditionVariablePointer, const char* description) { - conditionVariable->condVar - = (ConditionVariable*)object_cache_alloc(sConditionVariableCache, 0); - conditionVariable->condVar->Init(NULL, description); + ConditionVariable* conditionVariable + = new(std::nothrow) ConditionVariable(); + if (conditionVariable == NULL) + panic("No memory left."); + conditionVariablePointer->cv_waiters = 0; + conditionVariable->Init(conditionVariablePointer, description); + InterruptsSpinLocker _(sConditionVariablesLock); + sConditionVariableHash.Insert(conditionVariable); } void -_cv_wait_unlocked(struct cv* conditionVariable) +_cv_wait_unlocked(struct cv* conditionVariablePointer) { - conditionVariable->condVar->Wait(); + InterruptsSpinLocker _(sConditionVariablesLock); + ConditionVariable* conditionVariable + = sConditionVariableHash.Lookup(conditionVariablePointer); + conditionVariablePointer->cv_waiters++; + conditionVariable->Wait(); } int -_cv_timedwait_unlocked(struct cv* conditionVariable, int timeout) +_cv_timedwait_unlocked(struct cv* conditionVariablePointer, int timeout) { - status_t status; - - status = conditionVariable->condVar->Wait(B_ABSOLUTE_TIMEOUT, + InterruptsSpinLocker _(sConditionVariablesLock); + ConditionVariable* conditionVariable + = sConditionVariableHash.Lookup(conditionVariablePointer); + conditionVariablePointer->cv_waiters++; + status_t status = conditionVariable->Wait(B_ABSOLUTE_TIMEOUT, ticks_to_usecs(timeout)); if (status == B_OK) @@ -78,7 +110,12 @@ _cv_timedwait_unlocked(struct cv* conditionVariable, int timeout) void -_cv_signal(struct cv* conditionVariable) +_cv_signal(struct cv* conditionVariablePointer) { - conditionVariable->condVar->NotifyOne(); + InterruptsSpinLocker _(sConditionVariablesLock); + ConditionVariable* conditionVariable + = sConditionVariableHash.Lookup(conditionVariablePointer); + if (conditionVariablePointer->cv_waiters > 0) + conditionVariablePointer->cv_waiters--; + conditionVariable->NotifyOne(); } diff --git a/src/libs/compat/freebsd_network/compat/sys/condvar.h b/src/libs/compat/freebsd_network/compat/sys/condvar.h index d407acbc60..aa9abb3f91 100644 --- a/src/libs/compat/freebsd_network/compat/sys/condvar.h +++ b/src/libs/compat/freebsd_network/compat/sys/condvar.h @@ -8,13 +8,15 @@ #include + struct cv { - struct ConditionVariable* condVar; + int cv_waiters; }; + void cv_init(struct cv*, const char*); void cv_wait(struct cv*, struct mtx*); -int cv_timedwait(struct cv*, struct mtx*, int); +int cv_timedwait(struct cv*, struct mtx*, int); void cv_signal(struct cv*); #endif /* _FBSD_COMPAT_SYS_CONDVAR_H_ */