From 023bf5fcda8c37eb8e295784608ce818384a0ca5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 22 Apr 2008 21:46:23 +0000 Subject: [PATCH] * Added support for timeouts. * Added support for non-published condition variables. One has to call Init() on those, and add entries directly with the ConditionVariable::Add() method. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25110 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/condition_variable.h | 17 +++++- src/system/kernel/condition_variable.cpp | 65 +++++++++++++++------ 2 files changed, 62 insertions(+), 20 deletions(-) diff --git a/headers/private/kernel/condition_variable.h b/headers/private/kernel/condition_variable.h index ffd76f1e6f..7f22e41f7f 100644 --- a/headers/private/kernel/condition_variable.h +++ b/headers/private/kernel/condition_variable.h @@ -28,11 +28,17 @@ public: #endif bool Add(const void* object, uint32 flags = 0); - status_t Wait(); - status_t Wait(const void* object, uint32 flags = 0); + status_t Wait(uint32 timeoutFlags = 0, + bigtime_t timeout = 0); + status_t Wait(const void* object, uint32 flags = 0, + bigtime_t timeout = 0); inline ConditionVariable* Variable() const { return fVariable; } +private: + inline void AddToVariable(ConditionVariable* variable, + uint32 flags); + private: ConditionVariable* fVariable; struct thread* fThread; @@ -43,6 +49,10 @@ private: class ConditionVariable : protected HashTableLink { public: + void Init(const void* object, + const char* objectType); + // for anonymous (unpublished) cvars + void Publish(const void* object, const char* objectType); void Unpublish(bool threadsLocked = false); @@ -50,6 +60,9 @@ public: inline void NotifyOne(bool threadsLocked = false); inline void NotifyAll(bool threadsLocked = false); + void Add(ConditionVariableEntry* entry, + uint32 flags = 0); + const void* Object() const { return fObject; } static void ListAll(); diff --git a/src/system/kernel/condition_variable.cpp b/src/system/kernel/condition_variable.cpp index af03e0b4ca..6e95aea18e 100644 --- a/src/system/kernel/condition_variable.cpp +++ b/src/system/kernel/condition_variable.cpp @@ -96,18 +96,16 @@ ConditionVariableEntry::Add(const void* object, uint32 flags) fThread = thread_get_current_thread(); - InterruptsLocker _; - SpinLocker locker(sConditionVariablesLock); + InterruptsSpinLocker _(sConditionVariablesLock); fVariable = sConditionVariableHash.Lookup(object); - struct thread* thread = thread_get_current_thread(); - thread_prepare_to_block(thread, flags, THREAD_BLOCK_TYPE_CONDITION_VARIABLE, - fVariable); + thread_prepare_to_block(fThread, flags, + THREAD_BLOCK_TYPE_CONDITION_VARIABLE, fVariable); if (fVariable == NULL) { SpinLocker threadLocker(thread_spinlock); - thread_unblock_locked(thread, B_ENTRY_NOT_FOUND); + thread_unblock_locked(fThread, B_ENTRY_NOT_FOUND); return false; } @@ -119,7 +117,7 @@ ConditionVariableEntry::Add(const void* object, uint32 flags) status_t -ConditionVariableEntry::Wait() +ConditionVariableEntry::Wait(uint32 timeoutFlags, bigtime_t timeout) { if (!are_interrupts_enabled()) { panic("wait_for_condition_variable_entry() called with interrupts " @@ -130,7 +128,11 @@ ConditionVariableEntry::Wait() InterruptsLocker _; SpinLocker threadLocker(thread_spinlock); - status_t error = thread_block_locked(thread_get_current_thread()); + status_t error; + if ((timeoutFlags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) + error = thread_block_with_timeout_locked(timeoutFlags, timeout); + else + error = thread_block_locked(thread_get_current_thread()); threadLocker.Unlock(); SpinLocker locker(sConditionVariablesLock); @@ -146,17 +148,45 @@ ConditionVariableEntry::Wait() status_t -ConditionVariableEntry::Wait(const void* object, uint32 flags) +ConditionVariableEntry::Wait(const void* object, uint32 flags, + bigtime_t timeout) { if (Add(object, flags)) - return Wait(); + return Wait(flags, timeout); return B_ENTRY_NOT_FOUND; } +inline void +ConditionVariableEntry::AddToVariable(ConditionVariable* variable, uint32 flags) +{ + fThread = thread_get_current_thread(); + + thread_prepare_to_block(fThread, flags, + THREAD_BLOCK_TYPE_CONDITION_VARIABLE, fVariable); + + // add to the variable + InterruptsSpinLocker _(sConditionVariablesLock); + + fVariable = variable; + fVariable->fEntries.Add(this); +} + + // #pragma mark - ConditionVariable +/*! Initialization method for anonymous (unpublished) condition variables. +*/ +void +ConditionVariable::Init(const void* object, const char* objectType) +{ + fObject = object; + fObjectType = objectType; + new(&fEntries) EntryList; +} + + void ConditionVariable::Publish(const void* object, const char* objectType) { @@ -202,6 +232,13 @@ ConditionVariable::Unpublish(bool threadsLocked) } +void +ConditionVariable::Add(ConditionVariableEntry* entry, uint32 flags) +{ + entry->AddToVariable(this, flags); +} + + /*static*/ void ConditionVariable::ListAll() { @@ -242,14 +279,6 @@ ConditionVariable::_Notify(bool all, bool threadsLocked) SpinLocker threadLocker(threadsLocked ? NULL : &thread_spinlock); SpinLocker locker(sConditionVariablesLock); -#if KDEBUG - ConditionVariable* variable = sConditionVariableHash.Lookup(fObject); - if (variable != this) { - panic("Condition variable %p not published, found: %p", this, variable); - return; - } -#endif - if (!fEntries.IsEmpty()) _NotifyChecked(all, B_OK); }