From d0805bf47eff05d78cd40127bc7d1d6f04e99b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20G=C3=BCnther?= Date: Mon, 30 Nov 2009 13:17:04 +0000 Subject: [PATCH] * Basically reimplemented the conditional variable support, so that it is now easier to a) cleanup on driver unloading and b) to implement the msleep and wakeup functions. This is facilitated by keeping track of used conditional variables in a hash table. Also this table can be used to get the conditional variable belonging to a hash, which isn't supported by Haiku's conditional variable support at the moment. All network drivers are compiling and linking but it needs to be tested, whether executing rises any issues. * Minor coding style cleanup in condvar.h regarding intersection spacing. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@34375 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- src/libs/compat/freebsd_network/Condvar.cpp | 81 ++++++++++++++----- .../freebsd_network/compat/sys/condvar.h | 6 +- 2 files changed, 63 insertions(+), 24 deletions(-) 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_ */