* Detemplatized ConditionVariable{Entry}. Merged them with their
respective Private* base class. * Changed sigwait() and sigsuspend() to use thread_block() instead of a condition variable. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25100 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -16,152 +16,98 @@
|
|||||||
#include <util/OpenHashTable.h>
|
#include <util/OpenHashTable.h>
|
||||||
|
|
||||||
|
|
||||||
class PrivateConditionVariable;
|
class ConditionVariable;
|
||||||
|
|
||||||
|
|
||||||
struct PrivateConditionVariableEntry
|
struct ConditionVariableEntry
|
||||||
: DoublyLinkedListLinkImpl<PrivateConditionVariableEntry> {
|
: DoublyLinkedListLinkImpl<ConditionVariableEntry> {
|
||||||
public:
|
public:
|
||||||
#if KDEBUG
|
#if KDEBUG
|
||||||
inline PrivateConditionVariableEntry()
|
inline ConditionVariableEntry();
|
||||||
: fVariable(NULL)
|
inline ~ConditionVariableEntry();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
inline ~PrivateConditionVariableEntry()
|
|
||||||
{
|
|
||||||
if (fVariable != NULL) {
|
|
||||||
panic("Destroying condition variable entry %p, but it's still "
|
|
||||||
"attached to variable %p\n", this, fVariable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline PrivateConditionVariable* Variable() const
|
bool Add(const void* object, uint32 flags = 0);
|
||||||
{ return fVariable; }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
bool Add(const void* object, uint32 flags);
|
|
||||||
status_t Wait();
|
status_t Wait();
|
||||||
status_t Wait(const void* object, uint32 flags);
|
status_t Wait(const void* object, uint32 flags = 0);
|
||||||
|
|
||||||
protected:
|
inline ConditionVariable* Variable() const { return fVariable; }
|
||||||
PrivateConditionVariable* fVariable;
|
|
||||||
|
private:
|
||||||
|
ConditionVariable* fVariable;
|
||||||
struct thread* fThread;
|
struct thread* fThread;
|
||||||
|
|
||||||
friend class PrivateConditionVariable;
|
friend class ConditionVariable;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class PrivateConditionVariable
|
class ConditionVariable : protected HashTableLink<ConditionVariable> {
|
||||||
: protected HashTableLink<PrivateConditionVariable> {
|
|
||||||
public:
|
public:
|
||||||
static void ListAll();
|
|
||||||
void Dump() const;
|
|
||||||
const void* Object() const { return fObject; }
|
|
||||||
protected:
|
|
||||||
void Publish(const void* object,
|
void Publish(const void* object,
|
||||||
const char* objectType);
|
const char* objectType);
|
||||||
void Unpublish(bool threadsLocked);
|
void Unpublish(bool threadsLocked = false);
|
||||||
void Notify(bool all, bool threadsLocked);
|
|
||||||
|
inline void NotifyOne(bool threadsLocked = false);
|
||||||
|
inline void NotifyAll(bool threadsLocked = false);
|
||||||
|
|
||||||
|
const void* Object() const { return fObject; }
|
||||||
|
|
||||||
|
static void ListAll();
|
||||||
|
void Dump() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void _Notify(bool all, status_t result);
|
void _Notify(bool all, bool threadsLocked);
|
||||||
|
void _NotifyChecked(bool all, status_t result);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
typedef DoublyLinkedList<PrivateConditionVariableEntry> EntryList;
|
typedef DoublyLinkedList<ConditionVariableEntry> EntryList;
|
||||||
|
|
||||||
const void* fObject;
|
const void* fObject;
|
||||||
const char* fObjectType;
|
const char* fObjectType;
|
||||||
EntryList fEntries;
|
EntryList fEntries;
|
||||||
|
|
||||||
friend class PrivateConditionVariableEntry;
|
friend class ConditionVariableEntry;
|
||||||
friend class ConditionVariableHashDefinition;
|
friend class ConditionVariableHashDefinition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename Type = void>
|
#if KDEBUG
|
||||||
class ConditionVariable : private PrivateConditionVariable {
|
|
||||||
public:
|
|
||||||
inline void Publish(const Type* object,
|
|
||||||
const char* objectType);
|
|
||||||
|
|
||||||
inline void Unpublish(bool threadsLocked = false);
|
inline
|
||||||
inline void NotifyOne(bool threadsLocked = false);
|
ConditionVariableEntry::ConditionVariableEntry()
|
||||||
inline void NotifyAll(bool threadsLocked = false);
|
: 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
|
||||||
|
|
||||||
|
|
||||||
template<typename Type = void>
|
|
||||||
class ConditionVariableEntry : public PrivateConditionVariableEntry {
|
|
||||||
public:
|
|
||||||
inline bool Add(const Type* object, uint32 flags = 0);
|
|
||||||
inline status_t Wait();
|
|
||||||
inline status_t Wait(const Type* object, uint32 flags = 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
inline void
|
inline void
|
||||||
ConditionVariable<Type>::Publish(const Type* object, const char* objectType)
|
ConditionVariable::NotifyOne(bool threadsLocked)
|
||||||
{
|
{
|
||||||
PrivateConditionVariable::Publish(object, objectType);
|
_Notify(false, threadsLocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
inline void
|
inline void
|
||||||
ConditionVariable<Type>::Unpublish(bool threadsLocked)
|
ConditionVariable::NotifyAll(bool threadsLocked)
|
||||||
{
|
{
|
||||||
PrivateConditionVariable::Unpublish(threadsLocked);
|
_Notify(true, 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, uint32 flags)
|
|
||||||
{
|
|
||||||
return PrivateConditionVariableEntry::Add(object, flags);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
inline status_t
|
|
||||||
ConditionVariableEntry<Type>::Wait()
|
|
||||||
{
|
|
||||||
return PrivateConditionVariableEntry::Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
template<typename Type>
|
|
||||||
inline status_t
|
|
||||||
ConditionVariableEntry<Type>::Wait(const Type* object, uint32 flags)
|
|
||||||
{
|
|
||||||
return PrivateConditionVariableEntry::Wait(object, flags);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|
||||||
struct thread;
|
|
||||||
|
|
||||||
extern void condition_variable_init();
|
extern void condition_variable_init();
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ enum {
|
|||||||
THREAD_BLOCK_TYPE_SEMAPHORE = 0,
|
THREAD_BLOCK_TYPE_SEMAPHORE = 0,
|
||||||
THREAD_BLOCK_TYPE_CONDITION_VARIABLE = 1,
|
THREAD_BLOCK_TYPE_CONDITION_VARIABLE = 1,
|
||||||
THREAD_BLOCK_TYPE_SNOOZE = 2,
|
THREAD_BLOCK_TYPE_SNOOZE = 2,
|
||||||
|
THREAD_BLOCK_TYPE_SIGNAL = 3,
|
||||||
THREAD_BLOCK_TYPE_USER_BASE = 10000
|
THREAD_BLOCK_TYPE_USER_BASE = 10000
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -151,10 +152,10 @@ struct team_job_control_children {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct team_dead_children : team_job_control_children {
|
struct team_dead_children : team_job_control_children {
|
||||||
ConditionVariable<team_dead_children> condition_variable;
|
ConditionVariable condition_variable;
|
||||||
uint32 count;
|
uint32 count;
|
||||||
bigtime_t kernel_time;
|
bigtime_t kernel_time;
|
||||||
bigtime_t user_time;
|
bigtime_t user_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct vm_dummy_page : vm_page {
|
struct vm_dummy_page : vm_page {
|
||||||
ConditionVariable<vm_page> busy_condition;
|
ConditionVariable busy_condition;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct vm_cache {
|
struct vm_cache {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2007, Ingo Weinhold, [email protected]. All rights reserved.
|
* Copyright 2007-2008, Ingo Weinhold, [email protected].
|
||||||
* Copyright 2004-2006, Axel Dörfler, [email protected]. All rights reserved.
|
* Copyright 2004-2006, Axel Dörfler, [email protected]. All rights reserved.
|
||||||
* Distributed under the terms of the MIT License.
|
* Distributed under the terms of the MIT License.
|
||||||
*/
|
*/
|
||||||
@@ -402,12 +402,12 @@ RequestOwner::Wait(bool interruptable)
|
|||||||
// not yet done
|
// not yet done
|
||||||
|
|
||||||
// publish the condition variable
|
// publish the condition variable
|
||||||
ConditionVariable<> conditionVariable;
|
ConditionVariable conditionVariable;
|
||||||
conditionVariable.Publish(this, "tty request");
|
conditionVariable.Publish(this, "tty request");
|
||||||
fConditionVariable = &conditionVariable;
|
fConditionVariable = &conditionVariable;
|
||||||
|
|
||||||
// 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, interruptable ? B_CAN_INTERRUPT : 0);
|
||||||
|
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ class RequestOwner {
|
|||||||
status_t Error() const { return fError; }
|
status_t Error() const { return fError; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConditionVariable<>* fConditionVariable;
|
ConditionVariable* fConditionVariable;
|
||||||
tty_cookie* fCookie;
|
tty_cookie* fCookie;
|
||||||
status_t fError;
|
status_t fError;
|
||||||
RequestQueue* fRequestQueues[2];
|
RequestQueue* fRequestQueues[2];
|
||||||
|
|||||||
+2
-2
@@ -114,7 +114,7 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
|
|||||||
bool read_only;
|
bool read_only;
|
||||||
|
|
||||||
NotificationList pending_notifications;
|
NotificationList pending_notifications;
|
||||||
ConditionVariable<block_cache> condition_variable;
|
ConditionVariable condition_variable;
|
||||||
bool deleting;
|
bool deleting;
|
||||||
|
|
||||||
block_cache(int fd, off_t numBlocks, size_t blockSize, bool readOnly);
|
block_cache(int fd, off_t numBlocks, size_t blockSize, bool readOnly);
|
||||||
@@ -1611,7 +1611,7 @@ wait_for_notifications(block_cache *cache)
|
|||||||
set_notification(NULL, notification, TRANSACTION_WRITTEN, notify_sync,
|
set_notification(NULL, notification, TRANSACTION_WRITTEN, notify_sync,
|
||||||
cache);
|
cache);
|
||||||
|
|
||||||
ConditionVariableEntry<block_cache> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(cache);
|
entry.Add(cache);
|
||||||
|
|
||||||
add_notification(cache, ¬ification, TRANSACTION_WRITTEN, false);
|
add_notification(cache, ¬ification, TRANSACTION_WRITTEN, false);
|
||||||
|
|||||||
+4
-4
@@ -184,7 +184,7 @@ read_into_cache(file_cache_ref *ref, void *cookie, off_t offset,
|
|||||||
|
|
||||||
size_t numBytes = PAGE_ALIGN(pageOffset + bufferSize);
|
size_t numBytes = PAGE_ALIGN(pageOffset + bufferSize);
|
||||||
vm_page *pages[MAX_IO_VECS];
|
vm_page *pages[MAX_IO_VECS];
|
||||||
ConditionVariable<vm_page> busyConditions[MAX_IO_VECS];
|
ConditionVariable busyConditions[MAX_IO_VECS];
|
||||||
int32 pageIndex = 0;
|
int32 pageIndex = 0;
|
||||||
|
|
||||||
// allocate pages for the cache and mark them busy
|
// allocate pages for the cache and mark them busy
|
||||||
@@ -324,7 +324,7 @@ write_to_cache(file_cache_ref *ref, void *cookie, off_t offset,
|
|||||||
vm_page *pages[MAX_IO_VECS];
|
vm_page *pages[MAX_IO_VECS];
|
||||||
int32 pageIndex = 0;
|
int32 pageIndex = 0;
|
||||||
status_t status = B_OK;
|
status_t status = B_OK;
|
||||||
ConditionVariable<vm_page> busyConditions[MAX_IO_VECS];
|
ConditionVariable busyConditions[MAX_IO_VECS];
|
||||||
|
|
||||||
// ToDo: this should be settable somewhere
|
// ToDo: this should be settable somewhere
|
||||||
bool writeThrough = false;
|
bool writeThrough = false;
|
||||||
@@ -622,7 +622,7 @@ cache_io(void *_cacheRef, void *cookie, off_t offset, addr_t buffer,
|
|||||||
return status;
|
return status;
|
||||||
|
|
||||||
if (page->state == PAGE_STATE_BUSY) {
|
if (page->state == PAGE_STATE_BUSY) {
|
||||||
ConditionVariableEntry<vm_page> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(page);
|
entry.Add(page);
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
@@ -790,7 +790,7 @@ cache_prefetch_vnode(struct vnode *vnode, off_t offset, size_t size)
|
|||||||
if (page != NULL) {
|
if (page != NULL) {
|
||||||
if (page->state == PAGE_STATE_BUSY) {
|
if (page->state == PAGE_STATE_BUSY) {
|
||||||
// if busy retry again later
|
// if busy retry again later
|
||||||
ConditionVariableEntry<vm_page> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(page);
|
entry.Add(page);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
|
|||||||
@@ -22,16 +22,15 @@ static const int kConditionVariableHashSize = 512;
|
|||||||
|
|
||||||
struct ConditionVariableHashDefinition {
|
struct ConditionVariableHashDefinition {
|
||||||
typedef const void* KeyType;
|
typedef const void* KeyType;
|
||||||
typedef PrivateConditionVariable ValueType;
|
typedef ConditionVariable ValueType;
|
||||||
|
|
||||||
size_t HashKey(const void* key) const
|
size_t HashKey(const void* key) const
|
||||||
{ return (size_t)key; }
|
{ return (size_t)key; }
|
||||||
size_t Hash(PrivateConditionVariable* variable) const
|
size_t Hash(ConditionVariable* variable) const
|
||||||
{ return (size_t)variable->fObject; }
|
{ return (size_t)variable->fObject; }
|
||||||
bool Compare(const void* key, PrivateConditionVariable* variable) const
|
bool Compare(const void* key, ConditionVariable* variable) const
|
||||||
{ return key == variable->fObject; }
|
{ return key == variable->fObject; }
|
||||||
HashTableLink<PrivateConditionVariable>* GetLink(
|
HashTableLink<ConditionVariable>* GetLink(ConditionVariable* variable) const
|
||||||
PrivateConditionVariable* variable) const
|
|
||||||
{ return variable; }
|
{ return variable; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -43,7 +42,7 @@ static spinlock sConditionVariablesLock;
|
|||||||
static int
|
static int
|
||||||
list_condition_variables(int argc, char** argv)
|
list_condition_variables(int argc, char** argv)
|
||||||
{
|
{
|
||||||
PrivateConditionVariable::ListAll();
|
ConditionVariable::ListAll();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -60,14 +59,13 @@ dump_condition_variable(int argc, char** argv)
|
|||||||
if (address == 0)
|
if (address == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
PrivateConditionVariable* variable = sConditionVariableHash.Lookup(
|
ConditionVariable* variable = sConditionVariableHash.Lookup((void*)address);
|
||||||
(void*)address);
|
|
||||||
|
|
||||||
if (variable == NULL) {
|
if (variable == NULL) {
|
||||||
// It might be a direct pointer to a condition variable. Search the
|
// It might be a direct pointer to a condition variable. Search the
|
||||||
// hash.
|
// hash.
|
||||||
ConditionVariableHash::Iterator it(&sConditionVariableHash);
|
ConditionVariableHash::Iterator it(&sConditionVariableHash);
|
||||||
while (PrivateConditionVariable* hashVariable = it.Next()) {
|
while (ConditionVariable* hashVariable = it.Next()) {
|
||||||
if (hashVariable == (void*)address) {
|
if (hashVariable == (void*)address) {
|
||||||
variable = hashVariable;
|
variable = hashVariable;
|
||||||
break;
|
break;
|
||||||
@@ -88,11 +86,11 @@ dump_condition_variable(int argc, char** argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - PrivateConditionVariableEntry
|
// #pragma mark - ConditionVariableEntry
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
PrivateConditionVariableEntry::Add(const void* object, uint32 flags)
|
ConditionVariableEntry::Add(const void* object, uint32 flags)
|
||||||
{
|
{
|
||||||
ASSERT(object != NULL);
|
ASSERT(object != NULL);
|
||||||
|
|
||||||
@@ -121,7 +119,7 @@ PrivateConditionVariableEntry::Add(const void* object, uint32 flags)
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PrivateConditionVariableEntry::Wait()
|
ConditionVariableEntry::Wait()
|
||||||
{
|
{
|
||||||
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 "
|
||||||
@@ -148,7 +146,7 @@ PrivateConditionVariableEntry::Wait()
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
PrivateConditionVariableEntry::Wait(const void* object, uint32 flags)
|
ConditionVariableEntry::Wait(const void* object, uint32 flags)
|
||||||
{
|
{
|
||||||
if (Add(object, flags))
|
if (Add(object, flags))
|
||||||
return Wait();
|
return Wait();
|
||||||
@@ -156,42 +154,11 @@ PrivateConditionVariableEntry::Wait(const void* object, uint32 flags)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - PrivateConditionVariable
|
// #pragma mark - ConditionVariable
|
||||||
|
|
||||||
|
|
||||||
/*static*/ void
|
|
||||||
PrivateConditionVariable::ListAll()
|
|
||||||
{
|
|
||||||
kprintf(" variable object (type) waiting threads\n");
|
|
||||||
kprintf("------------------------------------------------------------\n");
|
|
||||||
ConditionVariableHash::Iterator it(&sConditionVariableHash);
|
|
||||||
while (PrivateConditionVariable* variable = it.Next()) {
|
|
||||||
// count waiting threads
|
|
||||||
int count = variable->fEntries.Size();
|
|
||||||
|
|
||||||
kprintf("%p %p %-20s %15d\n", variable, variable->fObject,
|
|
||||||
variable->fObjectType, count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PrivateConditionVariable::Dump() const
|
ConditionVariable::Publish(const void* object, const char* objectType)
|
||||||
{
|
|
||||||
kprintf("condition variable %p\n", this);
|
|
||||||
kprintf(" object: %p (%s)\n", fObject, fObjectType);
|
|
||||||
kprintf(" threads:");
|
|
||||||
|
|
||||||
for (EntryList::ConstIterator it = fEntries.GetIterator();
|
|
||||||
PrivateConditionVariableEntry* entry = it.Next();) {
|
|
||||||
kprintf(" %ld", entry->fThread->id);
|
|
||||||
}
|
|
||||||
kprintf("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
PrivateConditionVariable::Publish(const void* object, const char* objectType)
|
|
||||||
{
|
{
|
||||||
ASSERT(object != NULL);
|
ASSERT(object != NULL);
|
||||||
|
|
||||||
@@ -210,7 +177,7 @@ PrivateConditionVariable::Publish(const void* object, const char* objectType)
|
|||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PrivateConditionVariable::Unpublish(bool threadsLocked)
|
ConditionVariable::Unpublish(bool threadsLocked)
|
||||||
{
|
{
|
||||||
ASSERT(fObject != NULL);
|
ASSERT(fObject != NULL);
|
||||||
|
|
||||||
@@ -219,7 +186,7 @@ PrivateConditionVariable::Unpublish(bool threadsLocked)
|
|||||||
SpinLocker locker(sConditionVariablesLock);
|
SpinLocker locker(sConditionVariablesLock);
|
||||||
|
|
||||||
#if KDEBUG
|
#if KDEBUG
|
||||||
PrivateConditionVariable* variable = sConditionVariableHash.Lookup(fObject);
|
ConditionVariable* variable = sConditionVariableHash.Lookup(fObject);
|
||||||
if (variable != this) {
|
if (variable != this) {
|
||||||
panic("Condition variable %p not published, found: %p", this, variable);
|
panic("Condition variable %p not published, found: %p", this, variable);
|
||||||
return;
|
return;
|
||||||
@@ -231,12 +198,43 @@ PrivateConditionVariable::Unpublish(bool threadsLocked)
|
|||||||
fObjectType = NULL;
|
fObjectType = NULL;
|
||||||
|
|
||||||
if (!fEntries.IsEmpty())
|
if (!fEntries.IsEmpty())
|
||||||
_Notify(true, B_ENTRY_NOT_FOUND);
|
_NotifyChecked(true, B_ENTRY_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*static*/ void
|
||||||
|
ConditionVariable::ListAll()
|
||||||
|
{
|
||||||
|
kprintf(" variable object (type) waiting threads\n");
|
||||||
|
kprintf("------------------------------------------------------------\n");
|
||||||
|
ConditionVariableHash::Iterator it(&sConditionVariableHash);
|
||||||
|
while (ConditionVariable* variable = it.Next()) {
|
||||||
|
// count waiting threads
|
||||||
|
int count = variable->fEntries.Size();
|
||||||
|
|
||||||
|
kprintf("%p %p %-20s %15d\n", variable, variable->fObject,
|
||||||
|
variable->fObjectType, count);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
PrivateConditionVariable::Notify(bool all, bool threadsLocked)
|
ConditionVariable::Dump() const
|
||||||
|
{
|
||||||
|
kprintf("condition variable %p\n", this);
|
||||||
|
kprintf(" object: %p (%s)\n", fObject, fObjectType);
|
||||||
|
kprintf(" threads:");
|
||||||
|
|
||||||
|
for (EntryList::ConstIterator it = fEntries.GetIterator();
|
||||||
|
ConditionVariableEntry* entry = it.Next();) {
|
||||||
|
kprintf(" %ld", entry->fThread->id);
|
||||||
|
}
|
||||||
|
kprintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
ConditionVariable::_Notify(bool all, bool threadsLocked)
|
||||||
{
|
{
|
||||||
ASSERT(fObject != NULL);
|
ASSERT(fObject != NULL);
|
||||||
|
|
||||||
@@ -245,7 +243,7 @@ PrivateConditionVariable::Notify(bool all, bool threadsLocked)
|
|||||||
SpinLocker locker(sConditionVariablesLock);
|
SpinLocker locker(sConditionVariablesLock);
|
||||||
|
|
||||||
#if KDEBUG
|
#if KDEBUG
|
||||||
PrivateConditionVariable* variable = sConditionVariableHash.Lookup(fObject);
|
ConditionVariable* variable = sConditionVariableHash.Lookup(fObject);
|
||||||
if (variable != this) {
|
if (variable != this) {
|
||||||
panic("Condition variable %p not published, found: %p", this, variable);
|
panic("Condition variable %p not published, found: %p", this, variable);
|
||||||
return;
|
return;
|
||||||
@@ -253,7 +251,7 @@ PrivateConditionVariable::Notify(bool all, bool threadsLocked)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (!fEntries.IsEmpty())
|
if (!fEntries.IsEmpty())
|
||||||
_Notify(all, B_OK);
|
_NotifyChecked(all, B_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -261,10 +259,10 @@ PrivateConditionVariable::Notify(bool all, bool threadsLocked)
|
|||||||
thread lock held.
|
thread lock held.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
PrivateConditionVariable::_Notify(bool all, status_t result)
|
ConditionVariable::_NotifyChecked(bool all, status_t result)
|
||||||
{
|
{
|
||||||
// dequeue and wake up the blocked threads
|
// dequeue and wake up the blocked threads
|
||||||
while (PrivateConditionVariableEntry* entry = fEntries.RemoveHead()) {
|
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
|
||||||
entry->fVariable = NULL;
|
entry->fVariable = NULL;
|
||||||
|
|
||||||
thread_unblock_locked(entry->fThread, B_OK);
|
thread_unblock_locked(entry->fThread, B_OK);
|
||||||
|
|||||||
@@ -84,10 +84,10 @@ class ReadRequest : public DoublyLinkedListLinkImpl<ReadRequest> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConditionVariable<>& WaitCondition() { return fWaitCondition; }
|
ConditionVariable& WaitCondition() { return fWaitCondition; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ConditionVariable<> fWaitCondition;
|
ConditionVariable fWaitCondition;
|
||||||
bool fNotified;
|
bool fNotified;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ class Inode {
|
|||||||
|
|
||||||
benaphore fRequestLock;
|
benaphore fRequestLock;
|
||||||
|
|
||||||
ConditionVariable<> fWriteCondition;
|
ConditionVariable fWriteCondition;
|
||||||
|
|
||||||
int32 fReaderCount;
|
int32 fReaderCount;
|
||||||
int32 fWriterCount;
|
int32 fWriterCount;
|
||||||
@@ -358,7 +358,7 @@ Inode::WriteDataToBuffer(const void *_data, size_t *_length, bool nonBlocking)
|
|||||||
if (nonBlocking)
|
if (nonBlocking)
|
||||||
return B_WOULD_BLOCK;
|
return B_WOULD_BLOCK;
|
||||||
|
|
||||||
ConditionVariableEntry<> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(this, B_CAN_INTERRUPT);
|
entry.Add(this, B_CAN_INTERRUPT);
|
||||||
|
|
||||||
WriteRequest request(minToWrite);
|
WriteRequest request(minToWrite);
|
||||||
@@ -468,11 +468,11 @@ Inode::WaitForReadRequest(ReadRequest &request)
|
|||||||
request.SetUnnotified();
|
request.SetUnnotified();
|
||||||
|
|
||||||
// publish the condition variable
|
// publish the condition variable
|
||||||
ConditionVariable<>& conditionVariable = request.WaitCondition();
|
ConditionVariable& conditionVariable = request.WaitCondition();
|
||||||
conditionVariable.Publish(&request, "pipe request");
|
conditionVariable.Publish(&request, "pipe request");
|
||||||
|
|
||||||
// add the entry to wait on
|
// add the entry to wait on
|
||||||
ConditionVariableEntry<> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(&request, B_CAN_INTERRUPT);
|
entry.Add(&request, B_CAN_INTERRUPT);
|
||||||
|
|
||||||
// wait
|
// wait
|
||||||
|
|||||||
@@ -15,7 +15,6 @@
|
|||||||
#include <OS.h>
|
#include <OS.h>
|
||||||
#include <KernelExport.h>
|
#include <KernelExport.h>
|
||||||
|
|
||||||
#include <condition_variable.h>
|
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <kernel.h>
|
#include <kernel.h>
|
||||||
#include <kscheduler.h>
|
#include <kscheduler.h>
|
||||||
@@ -786,22 +785,14 @@ int
|
|||||||
sigwait(const sigset_t *set, int *_signal)
|
sigwait(const sigset_t *set, int *_signal)
|
||||||
{
|
{
|
||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
int signalsPending = 0;
|
|
||||||
|
|
||||||
ConditionVariable<sigset_t> conditionVar;
|
while (!has_signals_pending(thread)) {
|
||||||
conditionVar.Publish(set, "sigwait");
|
thread_prepare_to_block(thread, B_CAN_INTERRUPT,
|
||||||
|
THREAD_BLOCK_TYPE_SIGNAL, NULL);
|
||||||
while (true) {
|
thread_block();
|
||||||
ConditionVariableEntry<sigset_t> entry;
|
|
||||||
entry.Wait(set, B_CAN_INTERRUPT);
|
|
||||||
|
|
||||||
if (has_signals_pending(thread)) {
|
|
||||||
signalsPending = atomic_get(&thread->sig_pending) & *set;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionVar.Unpublish();
|
int signalsPending = atomic_get(&thread->sig_pending) & *set;
|
||||||
|
|
||||||
update_current_thread_signals_flag();
|
update_current_thread_signals_flag();
|
||||||
|
|
||||||
@@ -828,24 +819,16 @@ sigsuspend(const sigset_t *mask)
|
|||||||
struct thread *thread = thread_get_current_thread();
|
struct thread *thread = thread_get_current_thread();
|
||||||
sigset_t oldMask = atomic_get(&thread->sig_block_mask);
|
sigset_t oldMask = atomic_get(&thread->sig_block_mask);
|
||||||
|
|
||||||
// Set the new block mask and interuptably block wait for a condition
|
// Set the new block mask and block until interrupted.
|
||||||
// variable no one will ever notify.
|
|
||||||
|
|
||||||
atomic_set(&thread->sig_block_mask, *mask & BLOCKABLE_SIGNALS);
|
atomic_set(&thread->sig_block_mask, *mask & BLOCKABLE_SIGNALS);
|
||||||
|
|
||||||
ConditionVariable<sigset_t> conditionVar;
|
while (!has_signals_pending(thread)) {
|
||||||
conditionVar.Publish(mask, "sigsuspend");
|
thread_prepare_to_block(thread, B_CAN_INTERRUPT,
|
||||||
|
THREAD_BLOCK_TYPE_SIGNAL, NULL);
|
||||||
while (true) {
|
thread_block();
|
||||||
ConditionVariableEntry<sigset_t> entry;
|
|
||||||
entry.Wait(mask, B_CAN_INTERRUPT);
|
|
||||||
|
|
||||||
if (has_signals_pending(thread))
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
conditionVar.Unpublish();
|
|
||||||
|
|
||||||
// restore the original block mask
|
// restore the original block mask
|
||||||
atomic_set(&thread->sig_block_mask, oldMask);
|
atomic_set(&thread->sig_block_mask, oldMask);
|
||||||
|
|
||||||
|
|||||||
@@ -1740,9 +1740,9 @@ wait_for_child(pid_t child, uint32 flags, int32 *_reason,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we haven't got anything yet, add prepare for waiting for the
|
// If we haven't got anything yet, prepare for waiting for the
|
||||||
// condition variable.
|
// condition variable.
|
||||||
ConditionVariableEntry<team_dead_children> 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, B_CAN_INTERRUPT);
|
||||||
|
|||||||
@@ -666,12 +666,12 @@ get_thread_wait_sem(struct thread* thread)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static PrivateConditionVariable*
|
static ConditionVariable*
|
||||||
get_thread_wait_cvar(struct thread* thread)
|
get_thread_wait_cvar(struct thread* thread)
|
||||||
{
|
{
|
||||||
if (thread->state == B_THREAD_WAITING
|
if (thread->state == B_THREAD_WAITING
|
||||||
&& thread->wait.type == THREAD_BLOCK_TYPE_CONDITION_VARIABLE) {
|
&& thread->wait.type == THREAD_BLOCK_TYPE_CONDITION_VARIABLE) {
|
||||||
return (PrivateConditionVariable*)thread->wait.object;
|
return (ConditionVariable*)thread->wait.object;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3952,7 +3952,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
|
|
||||||
// page must be busy -- wait for it to become unbusy
|
// page must be busy -- wait for it to become unbusy
|
||||||
{
|
{
|
||||||
ConditionVariableEntry<vm_page> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(page);
|
entry.Add(page);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
@@ -3963,7 +3963,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
// The cache became busy, which means, it is about to be
|
// The cache became busy, which means, it is about to be
|
||||||
// removed by vm_cache_remove_consumer(). We start again with
|
// removed by vm_cache_remove_consumer(). We start again with
|
||||||
// the top cache.
|
// the top cache.
|
||||||
ConditionVariableEntry<vm_cache> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(cache);
|
entry.Add(cache);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
vm_cache_release_ref(cache);
|
vm_cache_release_ref(cache);
|
||||||
@@ -3986,7 +3986,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
page = vm_page_allocate_page(PAGE_STATE_FREE, true);
|
page = vm_page_allocate_page(PAGE_STATE_FREE, true);
|
||||||
vm_cache_insert_page(cache, page, cacheOffset);
|
vm_cache_insert_page(cache, page, cacheOffset);
|
||||||
|
|
||||||
ConditionVariable<vm_page> busyCondition;
|
ConditionVariable busyCondition;
|
||||||
busyCondition.Publish(page, "page");
|
busyCondition.Publish(page, "page");
|
||||||
|
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
@@ -4045,7 +4045,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
// The cache became busy, which means, it is about to be
|
// The cache became busy, which means, it is about to be
|
||||||
// removed by vm_cache_remove_consumer(). We start again with
|
// removed by vm_cache_remove_consumer(). We start again with
|
||||||
// the top cache.
|
// the top cache.
|
||||||
ConditionVariableEntry<vm_cache> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(cache);
|
entry.Add(cache);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
vm_cache_release_ref(cache);
|
vm_cache_release_ref(cache);
|
||||||
@@ -4079,7 +4079,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache,
|
|||||||
// The cache became busy, which means, it is about to be
|
// The cache became busy, which means, it is about to be
|
||||||
// removed by vm_cache_remove_consumer(). We start again with
|
// removed by vm_cache_remove_consumer(). We start again with
|
||||||
// the top cache.
|
// the top cache.
|
||||||
ConditionVariableEntry<vm_cache> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(cache);
|
entry.Add(cache);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
vm_cache_release_ref(cache);
|
vm_cache_release_ref(cache);
|
||||||
@@ -4249,7 +4249,7 @@ if (cacheOffset == 0x12000)
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// The page is busy, wait till it becomes unbusy.
|
// The page is busy, wait till it becomes unbusy.
|
||||||
ConditionVariableEntry<vm_page> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(newPage);
|
entry.Add(newPage);
|
||||||
mutex_unlock(&topCache->lock);
|
mutex_unlock(&topCache->lock);
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
|
|||||||
@@ -507,7 +507,7 @@ vm_cache_resize(vm_cache* cache, off_t newSize)
|
|||||||
page = next;
|
page = next;
|
||||||
} else {
|
} else {
|
||||||
// wait for page to become unbusy
|
// wait for page to become unbusy
|
||||||
ConditionVariableEntry<vm_page> entry;
|
ConditionVariableEntry entry;
|
||||||
entry.Add(page);
|
entry.Add(page);
|
||||||
mutex_unlock(&cache->lock);
|
mutex_unlock(&cache->lock);
|
||||||
entry.Wait();
|
entry.Wait();
|
||||||
@@ -569,7 +569,7 @@ vm_cache_remove_consumer(vm_cache* cache, vm_cache* consumer)
|
|||||||
// to, so we need to check if this cache is really the last
|
// to, so we need to check if this cache is really the last
|
||||||
// consumer of the cache we want to merge it with.
|
// consumer of the cache we want to merge it with.
|
||||||
|
|
||||||
ConditionVariable<vm_cache> busyCondition;
|
ConditionVariable busyCondition;
|
||||||
|
|
||||||
if (merge) {
|
if (merge) {
|
||||||
// But since we need to keep the locking order upper->lower cache, we
|
// But since we need to keep the locking order upper->lower cache, we
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ static size_t sReservedPages;
|
|||||||
static vint32 sPageDeficit;
|
static vint32 sPageDeficit;
|
||||||
static size_t sModifiedTemporaryPages;
|
static size_t sModifiedTemporaryPages;
|
||||||
|
|
||||||
static ConditionVariable<page_queue> sFreePageCondition;
|
static ConditionVariable sFreePageCondition;
|
||||||
static spinlock sPageLock;
|
static spinlock sPageLock;
|
||||||
|
|
||||||
static sem_id sWriterWaitSem;
|
static sem_id sWriterWaitSem;
|
||||||
@@ -966,7 +966,7 @@ page_writer(void* /*unused*/)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const uint32 kNumPages = 32;
|
const uint32 kNumPages = 32;
|
||||||
ConditionVariable<vm_page> busyConditions[kNumPages];
|
ConditionVariable busyConditions[kNumPages];
|
||||||
union {
|
union {
|
||||||
vm_page *pages[kNumPages];
|
vm_page *pages[kNumPages];
|
||||||
vm_cache *caches[kNumPages];
|
vm_cache *caches[kNumPages];
|
||||||
@@ -1278,7 +1278,7 @@ steal_pages(vm_page **pages, size_t count, bool reserve)
|
|||||||
|
|
||||||
// we need to wait for pages to become inactive
|
// we need to wait for pages to become inactive
|
||||||
|
|
||||||
ConditionVariableEntry<page_queue> freeConditionEntry;
|
ConditionVariableEntry freeConditionEntry;
|
||||||
sPageDeficit++;
|
sPageDeficit++;
|
||||||
freeConditionEntry.Add(&sFreePageQueue);
|
freeConditionEntry.Add(&sFreePageQueue);
|
||||||
locker.Unlock();
|
locker.Unlock();
|
||||||
@@ -1324,7 +1324,7 @@ vm_page_write_modified_pages(vm_cache *cache, bool fsReenter)
|
|||||||
page->state = PAGE_STATE_BUSY;
|
page->state = PAGE_STATE_BUSY;
|
||||||
page->busy_writing = true;
|
page->busy_writing = true;
|
||||||
|
|
||||||
ConditionVariable<vm_page> busyCondition;
|
ConditionVariable busyCondition;
|
||||||
busyCondition.Publish(page, "page");
|
busyCondition.Publish(page, "page");
|
||||||
|
|
||||||
// We have a modified page - however, while we're writing it back,
|
// We have a modified page - however, while we're writing it back,
|
||||||
@@ -1482,7 +1482,7 @@ vm_page_init_post_area(kernel_args *args)
|
|||||||
status_t
|
status_t
|
||||||
vm_page_init_post_thread(kernel_args *args)
|
vm_page_init_post_thread(kernel_args *args)
|
||||||
{
|
{
|
||||||
new (&sFreePageCondition) ConditionVariable<page_queue>;
|
new (&sFreePageCondition) ConditionVariable;
|
||||||
sFreePageCondition.Publish(&sFreePageQueue, "free page");
|
sFreePageCondition.Publish(&sFreePageQueue, "free page");
|
||||||
|
|
||||||
// create a kernel thread to clear out pages
|
// create a kernel thread to clear out pages
|
||||||
@@ -1613,7 +1613,7 @@ vm_page_reserve_pages(uint32 count)
|
|||||||
vm_page *
|
vm_page *
|
||||||
vm_page_allocate_page(int pageState, bool reserved)
|
vm_page_allocate_page(int pageState, bool reserved)
|
||||||
{
|
{
|
||||||
ConditionVariableEntry<page_queue> freeConditionEntry;
|
ConditionVariableEntry freeConditionEntry;
|
||||||
page_queue *queue;
|
page_queue *queue;
|
||||||
page_queue *otherQueue;
|
page_queue *otherQueue;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user