Add documentation for kernel condition variables API
Change-Id: Ib747c0b4559dba9c2985771447ea95c1a430e085 Reviewed-on: https://review.haiku-os.org/c/haiku/+/9676 Reviewed-by: waddlesplash <[email protected]>
This commit is contained in:
committed by
Adrien Destugues
parent
92cbc8ab0d
commit
f6195731ea
@@ -913,6 +913,7 @@ INPUT = . \
|
|||||||
drivers \
|
drivers \
|
||||||
game \
|
game \
|
||||||
interface \
|
interface \
|
||||||
|
kernel \
|
||||||
keyboard \
|
keyboard \
|
||||||
locale \
|
locale \
|
||||||
mail \
|
mail \
|
||||||
@@ -937,6 +938,7 @@ INPUT = . \
|
|||||||
../../headers/os/game \
|
../../headers/os/game \
|
||||||
../../headers/os/interface \
|
../../headers/os/interface \
|
||||||
../../headers/private/interface/ToolTip.h \
|
../../headers/private/interface/ToolTip.h \
|
||||||
|
../../headers/private/kernel/condition_variable.h \
|
||||||
../../headers/os/locale \
|
../../headers/os/locale \
|
||||||
../../headers/os/mail \
|
../../headers/os/mail \
|
||||||
../../headers/os/media \
|
../../headers/os/media \
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* Adrien Destugues, [email protected]
|
* Adrien Destugues, [email protected]
|
||||||
*
|
*
|
||||||
* Corresponds to:
|
* Corresponds to:
|
||||||
* headers/os/drivers/KernelExport;h rev 57477
|
* headers/os/drivers/KernelExport.h rev 57477
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|||||||
@@ -54,9 +54,9 @@
|
|||||||
\section semaphores Semaphores
|
\section semaphores Semaphores
|
||||||
|
|
||||||
Semaphores are the historical way to signal events in BeOS and Haiku. A semaphore has a counter
|
Semaphores are the historical way to signal events in BeOS and Haiku. A semaphore has a counter
|
||||||
that can be incremented (release_sem) and decremented (acquire_sem). The counter is not allowed
|
that can be incremented (\ref release_sem) and decremented (\ref acquire_sem). The counter is
|
||||||
to go below 0, if a thread attempts to acquire an empty semaphore, it will be blocked until
|
not allowed to go below 0, if a thread attempts to acquire an empty semaphore, it will be
|
||||||
someone else releases it.
|
blocked until someone else releases it.
|
||||||
|
|
||||||
Seaphores can be used to implement mutexes: by creating a semaphore with a count of 1, threads
|
Seaphores can be used to implement mutexes: by creating a semaphore with a count of 1, threads
|
||||||
can enter the critical section by acquiring, and exit it by releasing the semaphore. Additional
|
can enter the critical section by acquiring, and exit it by releasing the semaphore. Additional
|
||||||
@@ -78,8 +78,24 @@
|
|||||||
|
|
||||||
\section condition_variables Condition Variables
|
\section condition_variables Condition Variables
|
||||||
|
|
||||||
A more recent addition to Haiku synchronization primitives is condition variables. They allow
|
A more recent addition to Haiku synchronization primitives is \ref ConditionVariable.
|
||||||
a thread to wait for a specific condition, which is notified by another thread. This is
|
Condition variables allow a thread to wait for a specific condition, which is notified by
|
||||||
similar to the use of semaphores outlined above, but provides an easier way to handle race
|
another thread. This is similar to the use of semaphores outlined above, but provides an easier
|
||||||
conditions, spurious wakeups, and so on.
|
way to handle race conditions, spurious wakeups, and so on.
|
||||||
|
|
||||||
|
In user-space programming, condition variables are used for thread synchronization in
|
||||||
|
conjunction with a locking system. One thread will acquire a lock and verify (atomically) that
|
||||||
|
some condition is not satisfied, it will then wait on the condition variable and unlock the
|
||||||
|
lock. Another thread then notifies the condition variable - waking up the thread - when the
|
||||||
|
condition is satisfied.
|
||||||
|
|
||||||
|
The kernel implementation in Haiku is a bit more flexible, which allows it to be used also from
|
||||||
|
interrupt handlers. An interrupt may notify a condition variable. Since interrupts usually
|
||||||
|
cannot be locked with mutexes, the synchronization is provided by other means. In some cases,
|
||||||
|
no synchronization is needed at all: the driver main code can create a ConditionVariableEnty
|
||||||
|
and add it to the condition variable before accessing the hardware in a way that will later
|
||||||
|
schedule an interrupt. In that case, the order of operations is guaranteed: the thread will
|
||||||
|
be watching the condition variable before the interrupt can be triggered, and the interrupt
|
||||||
|
will wake up the thread. In cases where this is possible, condition variables provide a very
|
||||||
|
simple and efficient synchronization primitive and makes writing drivers much safer and simpler.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -0,0 +1,233 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2025 Haiku, Inc. All rights reserved.
|
||||||
|
* Distributed under the terms of the MIT License.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Adrien Destugues, [email protected]
|
||||||
|
*
|
||||||
|
* Corresponds to:
|
||||||
|
* headers/private/kernel/condition_variable.h hrev58325
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\file condition_variable.h
|
||||||
|
\ingroup kernel
|
||||||
|
\brief Kernel condition variables used for thread and interrupt synchronization
|
||||||
|
|
||||||
|
\attention This API is experimental and may change in later versions of Haiku.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\struct ConditionVariableEntry
|
||||||
|
\ingroup kernel
|
||||||
|
\brief Waiting on a condition variable.
|
||||||
|
|
||||||
|
Waiting on a condition variable is implemented by creating a ConditionVariableEntry,
|
||||||
|
associating it to a condition variable (using either Add(const void*) or
|
||||||
|
ConditionVariable::Add(ConditionVariableEntry*) ), and then waiting for the condition
|
||||||
|
variable to be notified using Wait(uint32, bigtime_t).
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn bool ConditionVariableEntry::Add(const void* object)
|
||||||
|
\brief Watch the published condition variable associated with the \a object.
|
||||||
|
|
||||||
|
This method is used to watch a condition variable previously published using
|
||||||
|
ConditionVariable::Publish(const cvoid*, const char*). The condition variable corresponding to
|
||||||
|
the object will be located and the condition variable entry will be added to it.
|
||||||
|
|
||||||
|
A ConditionVariableEntry can only be added to one single ConditionVariable.
|
||||||
|
|
||||||
|
It is safe to delete a ConditionVariableEntry without having waited for the corresponding event.
|
||||||
|
|
||||||
|
\return false if the entry could not be added. In that case, calling Wait() will immediately
|
||||||
|
fail and return the corresponding error code B_ENTRY_NOT_FOUND.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn status_t ConditionVariableEntry::Wait(uint32 flags, bigtime_t timeout)
|
||||||
|
\brief Wait for the condition variable to be notified
|
||||||
|
\param flags timeout and semaphore flags to use
|
||||||
|
\param timeout in microseconds if enabled by flags
|
||||||
|
\return The status code passed to Notify to wake up the thread
|
||||||
|
|
||||||
|
Wait for the previously added condition variable to be notified. The thread is blocked until
|
||||||
|
then, or until a timeout occurs. The entry is then removed from the condition variable waiting
|
||||||
|
list. It can be reused by adding it to the same or another condition variable.
|
||||||
|
|
||||||
|
If the condition variable was already notified since this entry was added to it, the function
|
||||||
|
returns immediately and does not block the thread.
|
||||||
|
|
||||||
|
The \a flags can be used to:
|
||||||
|
- Limit the wait to a timeout using B_RELATIVE_TIMEOUT or B_ABSOLUTE_TIMEOUT
|
||||||
|
- Control semaphore behavior (B_CAN_INTERRUPT, B_KILL_CAN_INTERRUPT)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn status_t ConditionVariableEntry::Wait(const void* object, uint32 flags, bigtime_t timeout)
|
||||||
|
\brief Convenience method to add a condition variable and immediately wait on it
|
||||||
|
|
||||||
|
This combines the effect of the Add and Wait methods. You can use this if you are waiting on
|
||||||
|
a published condition variable, and do not need to perform any other work between adding and
|
||||||
|
waiting (such as releasing other locks to perform a "lock switch").
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn ConditionVariable* ConditionVariableEntry::Variable() const
|
||||||
|
\brief Get a pointer to the added condition variable object
|
||||||
|
|
||||||
|
This allows to access the ConditionVariable object previously added to the condition variable.
|
||||||
|
It is especially useful if you need to access a published condition variable, which you
|
||||||
|
cannot access directly until adding it to a ConditionVariableEntry.
|
||||||
|
|
||||||
|
This returns NULL if the condition variable entry is not attached attached to any condition
|
||||||
|
variable, including when the condition variable has already notified the entry.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\struct ConditionVariable
|
||||||
|
\ingroup kernel
|
||||||
|
\brief Condition variable for thread and interrupt synchronization
|
||||||
|
|
||||||
|
Condition variables implement the wait/notify pattern. They are usually associated with an
|
||||||
|
"object" (for the condition variable's own purposes, that is just an opaque pointer).
|
||||||
|
|
||||||
|
One thread will use the Wait functions or a ConditionVariableEntry to wait on the condition
|
||||||
|
variable. When another thread or an interrupt needs to wake up one such thread, it does so
|
||||||
|
by notifying the condition variable.
|
||||||
|
|
||||||
|
Condition variables are usually used in combination with a mutex, recursive_lock, or some other
|
||||||
|
direct use of the ConditionVariableEntry struct with its two-step interface (Add() then Wait())
|
||||||
|
allows usage of any other locking design, or even with no locking at all if the order of
|
||||||
|
operations is already guaranteed by the code structure.
|
||||||
|
|
||||||
|
There are no restrictions on the destruction order: a condition variable may be destructed
|
||||||
|
while there are condition variable entries waiting on it, or the condition variable entries
|
||||||
|
may be destructed before they are notified.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void ConditionVariable::Init(const void* object, const char* objectType)
|
||||||
|
\brief Initialize an anonymous (unpublished) condition variable.
|
||||||
|
\param object Object that the condition variable is associated with.
|
||||||
|
\param objectType String describing the associated object, for debugging purposes.
|
||||||
|
|
||||||
|
Anonymous condition variables cannot be used with ConditionVariableEntry::Add() and will not
|
||||||
|
appear in the kernel debugger list of condition variables (it can still be examined by the dump
|
||||||
|
command if you have a pointer to it). The other methods can be used without restrictions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void ConditionVariable::Publish(const void* object, const char* objectType)
|
||||||
|
\brief Initialize and publish a condition variable associated with an \a object.
|
||||||
|
|
||||||
|
The condition variable is published: ConditionVariableEntry::Add() can be used on the
|
||||||
|
associated object, and the condition variable will be present in the kernel debugger's
|
||||||
|
condition variables list.
|
||||||
|
|
||||||
|
Publication allows to associate a condition variable with another object that is accessed from
|
||||||
|
multiple drivers or kernel modules. For example, this can be used to notify some events from
|
||||||
|
low level drivers to higher level ones (interrupts, hot-pluggable device being removed, ...)
|
||||||
|
by publishing condition variables associated to device tree nodes.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void ConditionVariable::Unpublish()
|
||||||
|
\brief Unpublish a previously published condition variable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn inline int32 ConditionVariable::NotifyOne(status_t result)
|
||||||
|
\brief Notify one of the threads waiting on the condition variable.
|
||||||
|
\param result Result value that will be returned by the Wait call in the notified thread.
|
||||||
|
\return Number of threads that will receive the result value (0 if no ConditionVariableEntry
|
||||||
|
was attached, or 1 if there were)
|
||||||
|
|
||||||
|
If the thread was already blocked by calling Wait, its execution is resumed.
|
||||||
|
|
||||||
|
If the thread had added a ConditionVariableEntry to the condition variable but is not yet
|
||||||
|
waiting on it, the call to Wait will not block, and will immediately return the \a result
|
||||||
|
value.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn inline int32 ConditionVariable::NotifyAll(status_t result)
|
||||||
|
\brief Notify all the threads waiting on the condition variable.
|
||||||
|
\param result Result value that will be returned by the Wait call in the notified thread.
|
||||||
|
\return Number of threads that will the result value
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn static int32 ConditionVariable::NotifyOne(const void* object, status_t result)
|
||||||
|
\brief Notify one thread waiting on the published condition variable for \a object.
|
||||||
|
\return The number of threads that were notified (0 or 1)
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn static int32 ConditionVariable::NotifyAll(const void* object, status_t result)
|
||||||
|
\brief Notify all threads waiting on the published condition variable for \a object.
|
||||||
|
\return The number of threads that were notified
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn void ConditionVariable::Add(ConditionVariableEntry* entry)
|
||||||
|
\brief Add a ConditionVariableEntry to the waiting list for this condition variable.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn int32 ConditionVariable::EntriesCount()
|
||||||
|
\brief Return the number of ConditionVariableEntries that are currently in the
|
||||||
|
ConditionVariable.
|
||||||
|
|
||||||
|
The threads associated with such entries may already be waiting, or still executing other code
|
||||||
|
between their Add and Wait steps.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn status_t ConditionVariable::Wait(uint32 flags, bigtime_t timeout)
|
||||||
|
\brief Convenience method for waiting without an explicit ConditionVariableEntry.
|
||||||
|
|
||||||
|
Create and add a temporary ConditionVariableEntry to the condition variable, then wait on it.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn status_t ConditionVariable::Wait(mutex* lock, uint32 flags, bigtime_t timeout)
|
||||||
|
\brief Convenience method for atomically unlocking a mutex and waiting on a condition variable.
|
||||||
|
|
||||||
|
Create and add a temporary ConditionVariableEntry to the condition variable, unlock the mutex,
|
||||||
|
wait on the condition variable, and re-acquire the mutex.
|
||||||
|
|
||||||
|
This allows to use the condition variable safely for inter-thread synchronization with mutex.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\fn status_t ConditionVariable::Wait(recursive_lock* lock, uint32 flags, bigtime_t timeout)
|
||||||
|
\brief Convenience method for atomically unlocking a recursive_lock and waiting on a condition
|
||||||
|
variable.
|
||||||
|
|
||||||
|
Create and add a temporary ConditionVariableEntry to the condition variable, unlock the
|
||||||
|
recursive_lock, wait on the condition variable, and re-acquire the recursive_lock.
|
||||||
|
|
||||||
|
The recursion count of the recursive lock is preserved.
|
||||||
|
|
||||||
|
This allows to use the condition variable safely for inter-thread synchronization with
|
||||||
|
a recursive_lock.
|
||||||
|
*/
|
||||||
@@ -225,8 +225,6 @@ ConditionVariableEntry::Wait(const void* object, uint32 flags,
|
|||||||
// #pragma mark - ConditionVariable
|
// #pragma mark - ConditionVariable
|
||||||
|
|
||||||
|
|
||||||
/*! Initialization method for anonymous (unpublished) condition variables.
|
|
||||||
*/
|
|
||||||
void
|
void
|
||||||
ConditionVariable::Init(const void* object, const char* objectType)
|
ConditionVariable::Init(const void* object, const char* objectType)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user