haiku/headers/private/kernel/condition_variable.h
Ingo Weinhold addece2001 * Fixed incorrect check in condition_variable_interrupt_thread().
Condition variables would never be interrupted.
* ConditionVariableEntry::Add() did not correctly insert the entry into
  the per-thread list of entries (the next link of the previous entry
  was not adjusted), which could leave the entry unnotified when the
  previous entry was notified, thus leaving it in the respective
  condition variable's list after the end of its life time. This should
  fix a crashing bug I rarely encountered.
* Added debug checks in the PrivateConditionVariableEntry
  constructor/destructor that should have helped me to find
  forementioned bug hours earlier, had I been bright enough to realize
  that I didn't include <debug.h> and those KDEBUG guarded checks were
  never executed. :-/


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22151 a95241bf-73f2-0310-859d-f6bbb57e9c96
2007-09-02 22:21:26 +00:00

192 lines
4.1 KiB
C++

/*
* Copyright 2007, Ingo Weinhold, bonefish@cs.tu-berlin.de.
* Distributed under the terms of the MIT License.
*/
#ifndef _KERNEL_CONDITION_VARIABLE_H
#define _KERNEL_CONDITION_VARIABLE_H
#include <OS.h>
#include <debug.h>
#ifdef __cplusplus
#include <util/OpenHashTable.h>
class PrivateConditionVariable;
struct PrivateConditionVariableEntry {
public:
#if KDEBUG
inline PrivateConditionVariableEntry()
: fVariable(NULL)
{
}
inline ~PrivateConditionVariableEntry()
{
if (fVariable != NULL) {
panic("Destroying condition variable entry %p, but it's still "
"attached to variable %p\n", this, fVariable);
}
}
#endif
inline PrivateConditionVariable* Variable() const
{ return fVariable; }
inline PrivateConditionVariableEntry* ThreadNext() const
{ return fThreadNext; }
inline PrivateConditionVariableEntry* ThreadPrevious() const
{ return fThreadPrevious; }
class Private;
protected:
bool Add(const void* object,
PrivateConditionVariableEntry* threadNext);
status_t Wait(uint32 flags);
status_t Wait(const void* object, uint32 flags);
private:
void _Remove();
protected:
PrivateConditionVariableEntry* fVariableNext;
PrivateConditionVariable* fVariable;
struct thread* fThread;
uint32 fFlags;
status_t fResult;
PrivateConditionVariableEntry* fThreadPrevious;
PrivateConditionVariableEntry* fThreadNext;
friend class PrivateConditionVariable;
friend class Private;
};
class PrivateConditionVariable
: protected HashTableLink<PrivateConditionVariable> {
public:
static void ListAll();
void Dump();
protected:
void Publish(const void* object,
const char* objectType);
void Unpublish(bool threadsLocked);
void Notify(bool all, bool threadsLocked);
private:
void _Notify(bool all, bool threadsLocked,
status_t result);
protected:
const void* fObject;
const char* fObjectType;
PrivateConditionVariableEntry* fEntries;
friend class PrivateConditionVariableEntry;
friend class ConditionVariableHashDefinition;
};
template<typename Type>
class ConditionVariable : private PrivateConditionVariable {
public:
inline void Publish(const Type* object,
const char* objectType);
inline void Unpublish(bool threadsLocked = false);
inline void NotifyOne(bool threadsLocked = false);
inline void NotifyAll(bool threadsLocked = false);
};
template<typename Type>
class ConditionVariableEntry : public PrivateConditionVariableEntry {
public:
inline bool Add(const Type* object,
PrivateConditionVariableEntry* threadNext
= NULL);
inline status_t Wait(uint32 flags = 0);
inline status_t Wait(const Type* object, uint32 flags = 0);
};
template<typename Type>
inline void
ConditionVariable<Type>::Publish(const Type* object, const char* objectType)
{
PrivateConditionVariable::Publish(object, objectType);
}
template<typename Type>
inline void
ConditionVariable<Type>::Unpublish(bool threadsLocked)
{
PrivateConditionVariable::Unpublish(threadsLocked);
}
template<typename Type>
inline void
ConditionVariable<Type>::NotifyOne(bool threadsLocked)
{
PrivateConditionVariable::Notify(false, threadsLocked);
}
template<typename Type>
inline void
ConditionVariable<Type>::NotifyAll(bool threadsLocked)
{
PrivateConditionVariable::Notify(true, threadsLocked);
}
template<typename Type>
inline bool
ConditionVariableEntry<Type>::Add(const Type* object,
PrivateConditionVariableEntry* threadNext)
{
return PrivateConditionVariableEntry::Add(object, threadNext);
}
template<typename Type>
inline status_t
ConditionVariableEntry<Type>::Wait(uint32 flags)
{
return PrivateConditionVariableEntry::Wait(flags);
}
template<typename Type>
inline status_t
ConditionVariableEntry<Type>::Wait(const Type* object, uint32 flags)
{
return PrivateConditionVariableEntry::Wait(object, flags);
}
extern "C" {
#endif // __cplusplus
struct thread;
extern status_t condition_variable_interrupt_thread(struct thread* thread);
extern void condition_variable_init();
#ifdef __cplusplus
} // extern "C"
#endif
#endif /* _KERNEL_CONDITION_VARIABLE_H */