2007-08-10 00:03:17 +04:00
|
|
|
/*
|
2011-06-12 04:00:23 +04:00
|
|
|
* Copyright 2007-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
|
2007-08-10 00:03:17 +04:00
|
|
|
* Distributed under the terms of the MIT License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <condition_variable.h>
|
|
|
|
|
|
|
|
#include <new>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <debug.h>
|
|
|
|
#include <kscheduler.h>
|
2007-08-27 03:53:12 +04:00
|
|
|
#include <ksignal.h>
|
2007-08-10 00:03:17 +04:00
|
|
|
#include <int.h>
|
2009-04-23 17:47:52 +04:00
|
|
|
#include <listeners.h>
|
2008-09-03 19:10:44 +04:00
|
|
|
#include <scheduling_analysis.h>
|
2007-08-10 00:03:17 +04:00
|
|
|
#include <thread.h>
|
|
|
|
#include <util/AutoLock.h>
|
|
|
|
|
|
|
|
|
2008-05-17 14:21:37 +04:00
|
|
|
#define STATUS_ADDED 1
|
|
|
|
#define STATUS_WAITING 2
|
|
|
|
|
|
|
|
|
2007-10-02 02:28:54 +04:00
|
|
|
static const int kConditionVariableHashSize = 512;
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
|
|
|
|
struct ConditionVariableHashDefinition {
|
|
|
|
typedef const void* KeyType;
|
2008-04-22 22:32:15 +04:00
|
|
|
typedef ConditionVariable ValueType;
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
size_t HashKey(const void* key) const
|
|
|
|
{ return (size_t)key; }
|
2008-04-22 22:32:15 +04:00
|
|
|
size_t Hash(ConditionVariable* variable) const
|
2007-08-10 00:03:17 +04:00
|
|
|
{ return (size_t)variable->fObject; }
|
2008-04-22 22:32:15 +04:00
|
|
|
bool Compare(const void* key, ConditionVariable* variable) const
|
2007-08-10 00:03:17 +04:00
|
|
|
{ return key == variable->fObject; }
|
2009-07-27 04:39:12 +04:00
|
|
|
ConditionVariable*& GetLink(ConditionVariable* variable) const
|
|
|
|
{ return variable->fNext; }
|
2007-08-10 00:03:17 +04:00
|
|
|
};
|
|
|
|
|
2009-07-27 04:39:12 +04:00
|
|
|
typedef BOpenHashTable<ConditionVariableHashDefinition> ConditionVariableHash;
|
2007-08-10 00:03:17 +04:00
|
|
|
static ConditionVariableHash sConditionVariableHash;
|
|
|
|
static spinlock sConditionVariablesLock;
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
list_condition_variables(int argc, char** argv)
|
|
|
|
{
|
2008-04-22 22:32:15 +04:00
|
|
|
ConditionVariable::ListAll();
|
2007-08-10 00:03:17 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
dump_condition_variable(int argc, char** argv)
|
|
|
|
{
|
2008-01-18 02:22:29 +03:00
|
|
|
if (argc != 2) {
|
|
|
|
print_debugger_command_usage(argv[0]);
|
2007-08-10 00:03:17 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-18 02:22:29 +03:00
|
|
|
addr_t address = parse_expression(argv[1]);
|
|
|
|
if (address == 0)
|
2007-08-10 00:03:17 +04:00
|
|
|
return 0;
|
|
|
|
|
2008-04-22 22:32:15 +04:00
|
|
|
ConditionVariable* variable = sConditionVariableHash.Lookup((void*)address);
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
if (variable == NULL) {
|
2008-07-29 05:52:20 +04:00
|
|
|
// It must be a direct pointer to a condition variable.
|
|
|
|
variable = (ConditionVariable*)address;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
2008-01-18 02:22:29 +03:00
|
|
|
if (variable != NULL) {
|
2007-08-10 00:03:17 +04:00
|
|
|
variable->Dump();
|
2008-01-18 02:22:29 +03:00
|
|
|
|
|
|
|
set_debug_variable("_cvar", (addr_t)variable);
|
|
|
|
set_debug_variable("_object", (addr_t)variable->Object());
|
|
|
|
|
|
|
|
} else
|
2007-08-10 00:03:17 +04:00
|
|
|
kprintf("no condition variable at or with key %p\n", (void*)address);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-22 22:32:15 +04:00
|
|
|
// #pragma mark - ConditionVariableEntry
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
|
|
|
|
bool
|
2008-05-17 14:21:37 +04:00
|
|
|
ConditionVariableEntry::Add(const void* object)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
|
|
|
ASSERT(object != NULL);
|
|
|
|
|
|
|
|
fThread = thread_get_current_thread();
|
|
|
|
|
2008-04-23 01:46:23 +04:00
|
|
|
InterruptsSpinLocker _(sConditionVariablesLock);
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
fVariable = sConditionVariableHash.Lookup(object);
|
|
|
|
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
if (fVariable == NULL) {
|
2008-05-17 14:21:37 +04:00
|
|
|
fWaitStatus = B_ENTRY_NOT_FOUND;
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-05-17 14:21:37 +04:00
|
|
|
fWaitStatus = STATUS_ADDED;
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
fVariable->fEntries.Add(this);
|
|
|
|
|
|
|
|
return true;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-28 00:17:31 +04:00
|
|
|
status_t
|
2008-05-17 14:21:37 +04:00
|
|
|
ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
|
|
|
if (!are_interrupts_enabled()) {
|
2008-08-04 06:45:06 +04:00
|
|
|
panic("ConditionVariableEntry::Wait() called with interrupts "
|
|
|
|
"disabled, entry: %p, variable: %p", this, fVariable);
|
2007-08-28 00:17:31 +04:00
|
|
|
return B_ERROR;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
InterruptsLocker _;
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
|
2008-05-17 14:21:37 +04:00
|
|
|
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();
|
|
|
|
|
2008-04-23 01:46:23 +04:00
|
|
|
status_t error;
|
2008-05-17 14:21:37 +04:00
|
|
|
if ((flags & (B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT)) != 0)
|
2013-11-05 02:45:14 +04:00
|
|
|
error = thread_block_with_timeout(flags, timeout);
|
2008-04-23 01:46:23 +04:00
|
|
|
else
|
2013-11-05 02:45:14 +04:00
|
|
|
error = thread_block();
|
2007-08-10 00:03:17 +04:00
|
|
|
|
2008-05-17 14:21:37 +04:00
|
|
|
conditionLocker.Lock();
|
2007-08-27 03:53:12 +04:00
|
|
|
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
// remove entry from variable, if not done yet
|
|
|
|
if (fVariable != NULL) {
|
|
|
|
fVariable->fEntries.Remove(this);
|
|
|
|
fVariable = NULL;
|
2008-02-17 17:38:23 +03:00
|
|
|
}
|
|
|
|
|
* Introduced a set of functions (thread_prepare_to_block(),
thread_block(), thread_unblock(),...) that allow a thread to wait for
something without needing a semaphore or condition variable. It can
simply block and another thread can unblock it. Supports timeouts and
interrupting. Both semaphores and condition variables use this
common mechanism, now.
* Semaphores:
- Some simplifications due to the thread blocking mechanism.
- Changed locking order to sem -> thread. It was the other way around
before and when introducing the wait_for_objects() support I had
also introduced a situation where the locking was reverse, which
could potentially cause a dead lock on SMP systems.
- Instead of queueing thread structures, a semaphore queues
queued_thread entries now, which are created on the stack. The
thread::sem structure could thus be removed.
- Added sem_entry::net_count, which is sem_entry::count plus the
acquisition count of all waiting threads. This number is needed in
remove_thread_from_sem() and instead of computing it there we
maintain it.
- Fixed remove_thread_from_sem(). It would not unblock threads, if
the sem count was <= 0.
- Made sem::last_acquirer unconditional. It is actually needed for
sem_info::latest_holder. Fixed fill_sem_info() accordingly.
- Added some optional tracing output, though only via ktrace_printf().
* Condition variables:
- Could be simplified significantly through the use of the thread
blocking mechanism. Removed a good deal of unnecessary code.
- Moved the ConditionVariableEntry "flags" parameter from Wait() to
Add(), and adjusted all places where condition variables are used
accordingly.
* snooze() uses thread_block_with_timeout() instead of a semaphore.
* Simplified thread interrupting in the signal and user debugger code.
Instead of separate functions for threads waiting on a semaphore or
condititon variable, we only have a single thread_interrupt(), now.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@25099 a95241bf-73f2-0310-859d-f6bbb57e9c96
2008-04-22 20:22:42 +04:00
|
|
|
return error;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-28 00:17:31 +04:00
|
|
|
status_t
|
2008-04-23 01:46:23 +04:00
|
|
|
ConditionVariableEntry::Wait(const void* object, uint32 flags,
|
|
|
|
bigtime_t timeout)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
2008-05-17 14:21:37 +04:00
|
|
|
if (Add(object))
|
2008-04-23 01:46:23 +04:00
|
|
|
return Wait(flags, timeout);
|
2007-08-28 00:17:31 +04:00
|
|
|
return B_ENTRY_NOT_FOUND;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-23 01:46:23 +04:00
|
|
|
inline void
|
2008-07-17 02:43:50 +04:00
|
|
|
ConditionVariableEntry::AddToVariable(ConditionVariable* variable)
|
2008-04-23 01:46:23 +04:00
|
|
|
{
|
|
|
|
fThread = thread_get_current_thread();
|
|
|
|
|
|
|
|
InterruptsSpinLocker _(sConditionVariablesLock);
|
|
|
|
|
|
|
|
fVariable = variable;
|
2008-07-17 02:43:50 +04:00
|
|
|
fWaitStatus = STATUS_ADDED;
|
2008-04-23 01:46:23 +04:00
|
|
|
fVariable->fEntries.Add(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-22 22:32:15 +04:00
|
|
|
// #pragma mark - ConditionVariable
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
|
2008-04-23 01:46:23 +04:00
|
|
|
/*! Initialization method for anonymous (unpublished) condition variables.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
ConditionVariable::Init(const void* object, const char* objectType)
|
|
|
|
{
|
|
|
|
fObject = object;
|
|
|
|
fObjectType = objectType;
|
|
|
|
new(&fEntries) EntryList;
|
2008-09-03 19:10:44 +04:00
|
|
|
|
|
|
|
T_SCHEDULING_ANALYSIS(InitConditionVariable(this, object, objectType));
|
2009-04-23 17:47:52 +04:00
|
|
|
NotifyWaitObjectListeners(&WaitObjectListener::ConditionVariableInitialized,
|
|
|
|
this);
|
2008-04-23 01:46:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-10 00:03:17 +04:00
|
|
|
void
|
2008-04-22 22:32:15 +04:00
|
|
|
ConditionVariable::Publish(const void* object, const char* objectType)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
|
|
|
ASSERT(object != NULL);
|
|
|
|
|
|
|
|
fObject = object;
|
|
|
|
fObjectType = objectType;
|
2008-04-20 19:19:48 +04:00
|
|
|
new(&fEntries) EntryList;
|
2007-08-10 00:03:17 +04:00
|
|
|
|
2008-09-03 19:10:44 +04:00
|
|
|
T_SCHEDULING_ANALYSIS(InitConditionVariable(this, object, objectType));
|
2009-04-23 17:47:52 +04:00
|
|
|
NotifyWaitObjectListeners(&WaitObjectListener::ConditionVariableInitialized,
|
|
|
|
this);
|
2008-09-03 19:10:44 +04:00
|
|
|
|
2007-08-10 00:03:17 +04:00
|
|
|
InterruptsLocker _;
|
|
|
|
SpinLocker locker(sConditionVariablesLock);
|
|
|
|
|
|
|
|
ASSERT_PRINT(sConditionVariableHash.Lookup(object) == NULL,
|
|
|
|
"condition variable: %p\n", sConditionVariableHash.Lookup(object));
|
|
|
|
|
|
|
|
sConditionVariableHash.InsertUnchecked(this);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-08 05:41:26 +04:00
|
|
|
ConditionVariable::Unpublish()
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
|
|
|
ASSERT(fObject != NULL);
|
|
|
|
|
2013-11-08 05:41:26 +04:00
|
|
|
InterruptsSpinLocker locker(sConditionVariablesLock);
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
#if KDEBUG
|
2008-04-22 22:32:15 +04:00
|
|
|
ConditionVariable* variable = sConditionVariableHash.Lookup(fObject);
|
2007-08-10 00:03:17 +04:00
|
|
|
if (variable != this) {
|
|
|
|
panic("Condition variable %p not published, found: %p", this, variable);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
sConditionVariableHash.RemoveUnchecked(this);
|
|
|
|
fObject = NULL;
|
|
|
|
fObjectType = NULL;
|
|
|
|
|
2008-04-20 19:19:48 +04:00
|
|
|
if (!fEntries.IsEmpty())
|
2009-10-22 03:44:59 +04:00
|
|
|
_NotifyLocked(true, B_ENTRY_NOT_FOUND);
|
2008-04-22 22:32:15 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-23 01:46:23 +04:00
|
|
|
void
|
2008-07-17 02:43:50 +04:00
|
|
|
ConditionVariable::Add(ConditionVariableEntry* entry)
|
2008-04-23 01:46:23 +04:00
|
|
|
{
|
2008-07-17 02:43:50 +04:00
|
|
|
entry->AddToVariable(this);
|
2008-04-23 01:46:23 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-07-23 00:36:32 +04:00
|
|
|
status_t
|
|
|
|
ConditionVariable::Wait(uint32 flags, bigtime_t timeout)
|
|
|
|
{
|
|
|
|
ConditionVariableEntry entry;
|
|
|
|
Add(&entry);
|
|
|
|
return entry.Wait(flags, timeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-03 16:05:39 +03:00
|
|
|
/*static*/ void
|
2013-11-08 05:41:26 +04:00
|
|
|
ConditionVariable::NotifyOne(const void* object, status_t result)
|
2009-12-03 15:24:17 +03:00
|
|
|
{
|
|
|
|
InterruptsSpinLocker locker(sConditionVariablesLock);
|
|
|
|
ConditionVariable* variable = sConditionVariableHash.Lookup(object);
|
|
|
|
locker.Unlock();
|
|
|
|
if (variable == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-11-08 05:41:26 +04:00
|
|
|
variable->NotifyOne(result);
|
2009-12-03 15:24:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2009-12-03 16:05:39 +03:00
|
|
|
/*static*/ void
|
2013-11-08 05:41:26 +04:00
|
|
|
ConditionVariable::NotifyAll(const void* object, status_t result)
|
2009-12-03 15:24:17 +03:00
|
|
|
{
|
|
|
|
InterruptsSpinLocker locker(sConditionVariablesLock);
|
|
|
|
ConditionVariable* variable = sConditionVariableHash.Lookup(object);
|
|
|
|
locker.Unlock();
|
|
|
|
if (variable == NULL)
|
|
|
|
return;
|
|
|
|
|
2013-11-08 05:41:26 +04:00
|
|
|
variable->NotifyAll(result);
|
2009-12-03 15:24:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-22 22:32:15 +04:00
|
|
|
/*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
|
2009-04-07 01:06:19 +04:00
|
|
|
int count = variable->fEntries.Count();
|
2008-04-22 22:32:15 +04:00
|
|
|
|
|
|
|
kprintf("%p %p %-20s %15d\n", variable, variable->fObject,
|
|
|
|
variable->fObjectType, count);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
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();) {
|
2012-06-13 20:42:46 +04:00
|
|
|
kprintf(" %" B_PRId32, entry->fThread->id);
|
2008-04-22 22:32:15 +04:00
|
|
|
}
|
|
|
|
kprintf("\n");
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
2013-11-08 05:41:26 +04:00
|
|
|
ConditionVariable::_Notify(bool all, status_t result)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
2013-11-08 05:41:26 +04:00
|
|
|
InterruptsSpinLocker locker(sConditionVariablesLock);
|
2007-08-10 00:03:17 +04:00
|
|
|
|
2009-10-22 03:44:59 +04:00
|
|
|
if (!fEntries.IsEmpty()) {
|
|
|
|
if (result > B_OK) {
|
2012-06-13 20:42:46 +04:00
|
|
|
panic("tried to notify with invalid result %" B_PRId32 "\n", result);
|
2009-10-22 03:44:59 +04:00
|
|
|
result = B_ERROR;
|
|
|
|
}
|
|
|
|
|
|
|
|
_NotifyLocked(all, result);
|
|
|
|
}
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-10-02 02:24:42 +04:00
|
|
|
/*! Called with interrupts disabled and the condition variable spinlock and
|
2011-06-12 04:00:23 +04:00
|
|
|
scheduler lock held.
|
2007-10-02 02:24:42 +04:00
|
|
|
*/
|
2007-08-10 00:03:17 +04:00
|
|
|
void
|
2009-10-22 03:44:59 +04:00
|
|
|
ConditionVariable::_NotifyLocked(bool all, status_t result)
|
2007-08-10 00:03:17 +04:00
|
|
|
{
|
|
|
|
// dequeue and wake up the blocked threads
|
2008-04-22 22:32:15 +04:00
|
|
|
while (ConditionVariableEntry* entry = fEntries.RemoveHead()) {
|
2007-08-28 07:34:06 +04:00
|
|
|
entry->fVariable = NULL;
|
|
|
|
|
2008-05-17 14:21:37 +04:00
|
|
|
if (entry->fWaitStatus <= 0)
|
|
|
|
continue;
|
|
|
|
|
2013-11-08 05:41:26 +04:00
|
|
|
if (entry->fWaitStatus == STATUS_WAITING) {
|
|
|
|
SpinLocker _(entry->fThread->scheduler_lock);
|
2008-05-17 14:21:37 +04:00
|
|
|
thread_unblock_locked(entry->fThread, result);
|
2013-11-08 05:41:26 +04:00
|
|
|
}
|
2008-05-17 14:21:37 +04:00
|
|
|
|
|
|
|
entry->fWaitStatus = result;
|
2007-08-10 00:03:17 +04:00
|
|
|
|
2007-08-27 03:53:12 +04:00
|
|
|
if (!all)
|
|
|
|
break;
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-08-27 03:53:12 +04:00
|
|
|
// #pragma mark -
|
2007-08-10 00:03:17 +04:00
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
condition_variable_init()
|
|
|
|
{
|
2008-06-25 02:23:57 +04:00
|
|
|
new(&sConditionVariableHash) ConditionVariableHash;
|
2007-08-10 00:03:17 +04:00
|
|
|
|
2008-06-25 02:23:57 +04:00
|
|
|
status_t error = sConditionVariableHash.Init(kConditionVariableHashSize);
|
2007-08-10 00:03:17 +04:00
|
|
|
if (error != B_OK) {
|
|
|
|
panic("condition_variable_init(): Failed to init hash table: %s",
|
|
|
|
strerror(error));
|
|
|
|
}
|
|
|
|
|
2008-01-18 02:22:29 +03:00
|
|
|
add_debugger_command_etc("cvar", &dump_condition_variable,
|
|
|
|
"Dump condition variable info",
|
|
|
|
"<address>\n"
|
|
|
|
"Prints info for the specified condition variable.\n"
|
|
|
|
" <address> - Address of the condition variable or the object it is\n"
|
|
|
|
" associated with.\n", 0);
|
|
|
|
add_debugger_command_etc("cvars", &list_condition_variables,
|
|
|
|
"List condition variables",
|
|
|
|
"\n"
|
|
|
|
"Lists all existing condition variables\n", 0);
|
2007-08-10 00:03:17 +04:00
|
|
|
}
|