kernel: Rework ConditionVariableEntry destruction.
It is no longer an error to destroy a ConditionVariableEntry that is still attached to a ConditionVariable; it will now be implicitly detached in that case. This makes ConditionVariableEntrys much eaiser to use from an API standpoint. Change-Id: I03c676d3a198aa885de733d3e1729b15f80de031 Reviewed-on: https://review.haiku-os.org/c/haiku/+/2301 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
1c9c772967
commit
1728b8c777
@@ -23,10 +23,8 @@ struct ConditionVariable;
|
|||||||
struct ConditionVariableEntry
|
struct ConditionVariableEntry
|
||||||
: DoublyLinkedListLinkImpl<ConditionVariableEntry> {
|
: DoublyLinkedListLinkImpl<ConditionVariableEntry> {
|
||||||
public:
|
public:
|
||||||
#if KDEBUG
|
ConditionVariableEntry();
|
||||||
inline ConditionVariableEntry();
|
~ConditionVariableEntry();
|
||||||
inline ~ConditionVariableEntry();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool Add(const void* object);
|
bool Add(const void* object);
|
||||||
status_t Wait(uint32 flags = 0, bigtime_t timeout = 0);
|
status_t Wait(uint32 flags = 0, bigtime_t timeout = 0);
|
||||||
@@ -38,7 +36,8 @@ public:
|
|||||||
inline ConditionVariable* Variable() const { return fVariable; }
|
inline ConditionVariable* Variable() const { return fVariable; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
inline void AddToLockedVariable(ConditionVariable* variable);
|
inline void _AddToLockedVariable(ConditionVariable* variable);
|
||||||
|
void _RemoveFromVariable();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
spinlock fLock;
|
spinlock fLock;
|
||||||
@@ -100,26 +99,6 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#if KDEBUG
|
|
||||||
|
|
||||||
inline
|
|
||||||
ConditionVariableEntry::ConditionVariableEntry()
|
|
||||||
: fVariable(NULL)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
ConditionVariableEntry::~ConditionVariableEntry()
|
|
||||||
{
|
|
||||||
if (fVariable != NULL) {
|
|
||||||
panic("Destroying condition variable entry %p, but it's still "
|
|
||||||
"attached to variable %p\n", this, fVariable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ConditionVariable::NotifyOne(status_t result)
|
ConditionVariable::NotifyOne(status_t result)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -90,6 +90,19 @@ dump_condition_variable(int argc, char** argv)
|
|||||||
// #pragma mark - ConditionVariableEntry
|
// #pragma mark - ConditionVariableEntry
|
||||||
|
|
||||||
|
|
||||||
|
ConditionVariableEntry::ConditionVariableEntry()
|
||||||
|
: fVariable(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConditionVariableEntry::~ConditionVariableEntry()
|
||||||
|
{
|
||||||
|
if (fVariable != NULL)
|
||||||
|
_RemoveFromVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ConditionVariableEntry::Add(const void* object)
|
ConditionVariableEntry::Add(const void* object)
|
||||||
{
|
{
|
||||||
@@ -108,14 +121,14 @@ ConditionVariableEntry::Add(const void* object)
|
|||||||
SpinLocker variableLocker(variable->fLock);
|
SpinLocker variableLocker(variable->fLock);
|
||||||
hashLocker.Unlock();
|
hashLocker.Unlock();
|
||||||
|
|
||||||
AddToLockedVariable(variable);
|
_AddToLockedVariable(variable);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ConditionVariableEntry::AddToLockedVariable(ConditionVariable* variable)
|
ConditionVariableEntry::_AddToLockedVariable(ConditionVariable* variable)
|
||||||
{
|
{
|
||||||
ASSERT(fVariable == NULL);
|
ASSERT(fVariable == NULL);
|
||||||
|
|
||||||
@@ -127,6 +140,32 @@ ConditionVariableEntry::AddToLockedVariable(ConditionVariable* variable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ConditionVariableEntry::_RemoveFromVariable()
|
||||||
|
{
|
||||||
|
InterruptsLocker _;
|
||||||
|
SpinLocker entryLocker(fLock);
|
||||||
|
|
||||||
|
if (fVariable != NULL) {
|
||||||
|
SpinLocker conditionLocker(fVariable->fLock);
|
||||||
|
if (fVariable->fEntries.Contains(this)) {
|
||||||
|
fVariable->fEntries.Remove(this);
|
||||||
|
} else {
|
||||||
|
entryLocker.Unlock();
|
||||||
|
// The variable's fEntries did not contain us, but we currently
|
||||||
|
// have the variable's lock acquired. This must mean we are in
|
||||||
|
// a race with the variable's Notify. It is possible we will be
|
||||||
|
// destroyed immediately upon returning here, so we need to
|
||||||
|
// spin until our fVariable member is unset by the Notify thread
|
||||||
|
// and then re-acquire our own lock to avoid a use-after-free.
|
||||||
|
while (atomic_pointer_get(&fVariable) != NULL) {}
|
||||||
|
entryLocker.Lock();
|
||||||
|
}
|
||||||
|
fVariable = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
||||||
{
|
{
|
||||||
@@ -157,27 +196,7 @@ ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
|||||||
else
|
else
|
||||||
error = thread_block();
|
error = thread_block();
|
||||||
|
|
||||||
entryLocker.Lock();
|
_RemoveFromVariable();
|
||||||
|
|
||||||
// Remove entry from variable, if not done yet.
|
|
||||||
if (fVariable != NULL) {
|
|
||||||
SpinLocker conditionLocker(fVariable->fLock);
|
|
||||||
if (fVariable->fEntries.Contains(this)) {
|
|
||||||
fVariable->fEntries.Remove(this);
|
|
||||||
} else {
|
|
||||||
entryLocker.Unlock();
|
|
||||||
// The variable's fEntries did not contain us, but we currently
|
|
||||||
// have the variable's lock acquired. This must mean we are in
|
|
||||||
// a race with the variable's Notify. It is possible we will be
|
|
||||||
// destroyed immediately upon returning here, so we need to
|
|
||||||
// spin until our fVariable member is unset by the Notify thread
|
|
||||||
// and then re-acquire our own lock to avoid a use-after-free.
|
|
||||||
while (atomic_pointer_get(&fVariable) != NULL) {}
|
|
||||||
entryLocker.Lock();
|
|
||||||
}
|
|
||||||
fVariable = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +285,7 @@ void
|
|||||||
ConditionVariable::Add(ConditionVariableEntry* entry)
|
ConditionVariable::Add(ConditionVariableEntry* entry)
|
||||||
{
|
{
|
||||||
InterruptsSpinLocker _(fLock);
|
InterruptsSpinLocker _(fLock);
|
||||||
entry->AddToLockedVariable(this);
|
entry->_AddToLockedVariable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -53,6 +53,19 @@ static mutex sConditionVariablesLock = MUTEX_INITIALIZER("condition variables");
|
|||||||
// #pragma mark - ConditionVariableEntry
|
// #pragma mark - ConditionVariableEntry
|
||||||
|
|
||||||
|
|
||||||
|
ConditionVariableEntry::ConditionVariableEntry()
|
||||||
|
: fVariable(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ConditionVariableEntry::~ConditionVariableEntry()
|
||||||
|
{
|
||||||
|
if (fVariable != NULL)
|
||||||
|
_RemoveFromVariable();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ConditionVariableEntry::Add(const void* object)
|
ConditionVariableEntry::Add(const void* object)
|
||||||
{
|
{
|
||||||
@@ -95,14 +108,7 @@ ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
|||||||
while ((error = _kern_block_thread(flags, timeout)) == B_INTERRUPTED) {
|
while ((error = _kern_block_thread(flags, timeout)) == B_INTERRUPTED) {
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionLocker.Lock();
|
_RemoveFromVariable();
|
||||||
|
|
||||||
// remove entry from variable, if not done yet
|
|
||||||
if (fVariable != NULL) {
|
|
||||||
fVariable->fEntries.Remove(this);
|
|
||||||
fVariable = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +124,7 @@ ConditionVariableEntry::Wait(const void* object, uint32 flags,
|
|||||||
|
|
||||||
|
|
||||||
inline void
|
inline void
|
||||||
ConditionVariableEntry::AddToLockedVariable(ConditionVariable* variable)
|
ConditionVariableEntry::_AddToLockedVariable(ConditionVariable* variable)
|
||||||
{
|
{
|
||||||
fThread = get_current_thread();
|
fThread = get_current_thread();
|
||||||
fVariable = variable;
|
fVariable = variable;
|
||||||
@@ -127,6 +133,17 @@ ConditionVariableEntry::AddToLockedVariable(ConditionVariable* variable)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ConditionVariableEntry::_RemoveFromVariable()
|
||||||
|
{
|
||||||
|
MutexLocker _(sConditionVariablesLock);
|
||||||
|
if (fVariable != NULL) {
|
||||||
|
fVariable->fEntries.Remove(this);
|
||||||
|
fVariable = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - ConditionVariable
|
// #pragma mark - ConditionVariable
|
||||||
|
|
||||||
|
|
||||||
@@ -178,7 +195,7 @@ void
|
|||||||
ConditionVariable::Add(ConditionVariableEntry* entry)
|
ConditionVariable::Add(ConditionVariableEntry* entry)
|
||||||
{
|
{
|
||||||
MutexLocker _(sConditionVariablesLock);
|
MutexLocker _(sConditionVariablesLock);
|
||||||
entry->AddToLockedVariable(this);
|
entry->_AddToLockedVariable(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user