axeld + bonefish:

Changed condition variables so that it is allowed to block (e.g. lock
mutexes etc.) between Add() and Wait(). This fixes #2059, since the
block writer used them this way and could thusly fail to wait for a
condition variable, causing a temporary stack object to be used past its
lifetime.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25525 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2008-05-17 10:21:37 +00:00
parent a93840a2f4
commit fbe0c27a94
5 changed files with 43 additions and 22 deletions
+3 -3
View File
@@ -27,9 +27,8 @@ public:
inline ~ConditionVariableEntry(); inline ~ConditionVariableEntry();
#endif #endif
bool Add(const void* object, uint32 flags = 0); bool Add(const void* object);
status_t Wait(uint32 timeoutFlags = 0, status_t Wait(uint32 flags = 0, bigtime_t timeout = 0);
bigtime_t timeout = 0);
status_t Wait(const void* object, uint32 flags = 0, status_t Wait(const void* object, uint32 flags = 0,
bigtime_t timeout = 0); bigtime_t timeout = 0);
@@ -42,6 +41,7 @@ private:
private: private:
ConditionVariable* fVariable; ConditionVariable* fVariable;
struct thread* fThread; struct thread* fThread;
status_t fWaitStatus;
friend class ConditionVariable; friend class ConditionVariable;
}; };
+4 -2
View File
@@ -414,14 +414,16 @@ RequestOwner::Wait(bool interruptable, bigtime_t timeout)
// add an entry to wait on // add an entry to wait on
ConditionVariableEntry entry; ConditionVariableEntry entry;
entry.Add(this, interruptable ? B_CAN_INTERRUPT : 0); entry.Add(this);
locker.Unlock(); locker.Unlock();
// wait // wait
TRACE(("%p->RequestOwner::Wait(): waiting for condition...\n", this)); TRACE(("%p->RequestOwner::Wait(): waiting for condition...\n", this));
error = entry.Wait(B_RELATIVE_TIMEOUT, timeout); error = entry.Wait(
(interruptable ? B_CAN_INTERRUPT : 0) | B_RELATIVE_TIMEOUT,
timeout);
TRACE(("%p->RequestOwner::Wait(): condition occurred: %lx\n", this, TRACE(("%p->RequestOwner::Wait(): condition occurred: %lx\n", this,
error)); error));
+32 -13
View File
@@ -17,6 +17,10 @@
#include <util/AutoLock.h> #include <util/AutoLock.h>
#define STATUS_ADDED 1
#define STATUS_WAITING 2
static const int kConditionVariableHashSize = 512; static const int kConditionVariableHashSize = 512;
@@ -90,7 +94,7 @@ dump_condition_variable(int argc, char** argv)
bool bool
ConditionVariableEntry::Add(const void* object, uint32 flags) ConditionVariableEntry::Add(const void* object)
{ {
ASSERT(object != NULL); ASSERT(object != NULL);
@@ -100,16 +104,12 @@ ConditionVariableEntry::Add(const void* object, uint32 flags)
fVariable = sConditionVariableHash.Lookup(object); fVariable = sConditionVariableHash.Lookup(object);
thread_prepare_to_block(fThread, flags,
THREAD_BLOCK_TYPE_CONDITION_VARIABLE, fVariable);
if (fVariable == NULL) { if (fVariable == NULL) {
SpinLocker threadLocker(thread_spinlock); fWaitStatus = B_ENTRY_NOT_FOUND;
thread_unblock_locked(fThread, B_ENTRY_NOT_FOUND);
return false; return false;
} }
// add to the queue for the variable fWaitStatus = STATUS_ADDED;
fVariable->fEntries.Add(this); fVariable->fEntries.Add(this);
return true; return true;
@@ -117,7 +117,7 @@ ConditionVariableEntry::Add(const void* object, uint32 flags)
status_t status_t
ConditionVariableEntry::Wait(uint32 timeoutFlags, bigtime_t timeout) ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
{ {
if (!are_interrupts_enabled()) { if (!are_interrupts_enabled()) {
panic("wait_for_condition_variable_entry() called with interrupts " panic("wait_for_condition_variable_entry() called with interrupts "
@@ -127,15 +127,28 @@ ConditionVariableEntry::Wait(uint32 timeoutFlags, bigtime_t timeout)
InterruptsLocker _; InterruptsLocker _;
SpinLocker conditionLocker(sConditionVariablesLock);
if (fVariable == NULL)
return fWaitStatus;
thread_prepare_to_block(fThread, flags,
THREAD_BLOCK_TYPE_CONDITION_VARIABLE, fVariable);
fWaitStatus = STATUS_WAITING;
conditionLocker.Unlock();
SpinLocker threadLocker(thread_spinlock); SpinLocker threadLocker(thread_spinlock);
status_t error; status_t error;
if ((timeoutFlags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0) if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0)
error = thread_block_with_timeout_locked(timeoutFlags, timeout); error = thread_block_with_timeout_locked(flags, timeout);
else else
error = thread_block_locked(thread_get_current_thread()); error = thread_block_locked(thread_get_current_thread());
threadLocker.Unlock(); threadLocker.Unlock();
SpinLocker locker(sConditionVariablesLock); conditionLocker.Lock();
// remove entry from variable, if not done yet // remove entry from variable, if not done yet
if (fVariable != NULL) { if (fVariable != NULL) {
@@ -151,7 +164,7 @@ status_t
ConditionVariableEntry::Wait(const void* object, uint32 flags, ConditionVariableEntry::Wait(const void* object, uint32 flags,
bigtime_t timeout) bigtime_t timeout)
{ {
if (Add(object, flags)) if (Add(object))
return Wait(flags, timeout); return Wait(flags, timeout);
return B_ENTRY_NOT_FOUND; return B_ENTRY_NOT_FOUND;
} }
@@ -294,7 +307,13 @@ ConditionVariable::_NotifyChecked(bool all, status_t result)
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) { while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
entry->fVariable = NULL; entry->fVariable = NULL;
thread_unblock_locked(entry->fThread, B_OK); if (entry->fWaitStatus <= 0)
continue;
if (entry->fWaitStatus == STATUS_WAITING)
thread_unblock_locked(entry->fThread, result);
entry->fWaitStatus = result;
if (!all) if (!all)
break; break;
+2 -2
View File
@@ -358,13 +358,13 @@ Inode::WriteDataToBuffer(const void *_data, size_t *_length, bool nonBlocking)
return B_WOULD_BLOCK; return B_WOULD_BLOCK;
ConditionVariableEntry entry; ConditionVariableEntry entry;
entry.Add(this, B_CAN_INTERRUPT); entry.Add(this);
WriteRequest request(minToWrite); WriteRequest request(minToWrite);
fWriteRequests.Add(&request); fWriteRequests.Add(&request);
mutex_unlock(&fRequestLock); mutex_unlock(&fRequestLock);
status_t status = entry.Wait(); status_t status = entry.Wait(B_CAN_INTERRUPT);
mutex_lock(&fRequestLock); mutex_lock(&fRequestLock);
fWriteRequests.Remove(&request); fWriteRequests.Remove(&request);
+2 -2
View File
@@ -1867,7 +1867,7 @@ wait_for_child(pid_t child, uint32 flags, int32 *_reason,
ConditionVariableEntry deadWaitEntry; ConditionVariableEntry deadWaitEntry;
if (status == B_WOULD_BLOCK && (flags & WNOHANG) == 0) if (status == B_WOULD_BLOCK && (flags & WNOHANG) == 0)
deadWaitEntry.Add(team->dead_children, B_CAN_INTERRUPT); deadWaitEntry.Add(team->dead_children);
locker.Unlock(); locker.Unlock();
@@ -1888,7 +1888,7 @@ wait_for_child(pid_t child, uint32 flags, int32 *_reason,
return status; return status;
} }
status = deadWaitEntry.Wait(); status = deadWaitEntry.Wait(B_CAN_INTERRUPT);
if (status == B_INTERRUPTED) { if (status == B_INTERRUPTED) {
T(WaitForChildDone(status)); T(WaitForChildDone(status));
return status; return status;