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 \
|
||||
game \
|
||||
interface \
|
||||
kernel \
|
||||
keyboard \
|
||||
locale \
|
||||
mail \
|
||||
@@ -937,6 +938,7 @@ INPUT = . \
|
||||
../../headers/os/game \
|
||||
../../headers/os/interface \
|
||||
../../headers/private/interface/ToolTip.h \
|
||||
../../headers/private/kernel/condition_variable.h \
|
||||
../../headers/os/locale \
|
||||
../../headers/os/mail \
|
||||
../../headers/os/media \
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* Adrien Destugues, [email protected]
|
||||
*
|
||||
* Corresponds to:
|
||||
* headers/os/drivers/KernelExport;h rev 57477
|
||||
* headers/os/drivers/KernelExport.h rev 57477
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
||||
@@ -54,9 +54,9 @@
|
||||
\section semaphores Semaphores
|
||||
|
||||
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
|
||||
to go below 0, if a thread attempts to acquire an empty semaphore, it will be blocked until
|
||||
someone else releases it.
|
||||
that can be incremented (\ref release_sem) and decremented (\ref acquire_sem). The counter is
|
||||
not allowed to go below 0, if a thread attempts to acquire an empty semaphore, it will be
|
||||
blocked until someone else releases it.
|
||||
|
||||
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
|
||||
@@ -78,8 +78,24 @@
|
||||
|
||||
\section condition_variables Condition Variables
|
||||
|
||||
A more recent addition to Haiku synchronization primitives is condition variables. They allow
|
||||
a thread to wait for a specific condition, which is notified by another thread. This is
|
||||
similar to the use of semaphores outlined above, but provides an easier way to handle race
|
||||
conditions, spurious wakeups, and so on.
|
||||
A more recent addition to Haiku synchronization primitives is \ref ConditionVariable.
|
||||
Condition variables allow a thread to wait for a specific condition, which is notified by
|
||||
another thread. This is similar to the use of semaphores outlined above, but provides an easier
|
||||
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
|
||||
|
||||
|
||||
/*! Initialization method for anonymous (unpublished) condition variables.
|
||||
*/
|
||||
void
|
||||
ConditionVariable::Init(const void* object, const char* objectType)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user