From 2e736633779676466a4beeaae9e56c85e3930305 Mon Sep 17 00:00:00 2001
From: PulkoMandy <pulkomandy@pulkomandy.tk>
Date: Sun, 5 Oct 2025 11:47:40 +0200
Subject: [PATCH] Add documentation for kernel condition variables API

Change-Id: Ib747c0b4559dba9c2985771447ea95c1a430e085

2	0	docs/user/Doxyfile
1	1	docs/user/drivers/KernelExport.dox
23	7	docs/user/drivers/synchronization_primitives.dox
213	0	docs/user/kernel/condition_variable.dox
0	2	src/system/kernel/condition_variable.cpp

diff --git a/docs/user/Doxyfile b/docs/user/Doxyfile
index fa43259da9..98ae11c616 100644
--- a/docs/user/Doxyfile
+++ b/docs/user/Doxyfile
@@ -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 \
diff --git a/docs/user/drivers/KernelExport.dox b/docs/user/drivers/KernelExport.dox
index 62e9e278bf..7e2f911a4f 100644
--- a/docs/user/drivers/KernelExport.dox
+++ b/docs/user/drivers/KernelExport.dox
@@ -6,7 +6,7 @@
  *		Adrien Destugues, pulkomandy@pulkomandy.tk
  *
  * Corresponds to:
- *		headers/os/drivers/KernelExport;h rev 57477
+ *		headers/os/drivers/KernelExport.h rev 57477
  */
 
 /*!
diff --git a/docs/user/drivers/synchronization_primitives.dox b/docs/user/drivers/synchronization_primitives.dox
index f2511841a5..f708f774f7 100644
--- a/docs/user/drivers/synchronization_primitives.dox
+++ b/docs/user/drivers/synchronization_primitives.dox
@@ -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, and wakes 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.
 */
diff --git a/docs/user/kernel/condition_variable.dox b/docs/user/kernel/condition_variable.dox
new file mode 100644
index 0000000000..d2ab46c865
--- /dev/null
+++ b/docs/user/kernel/condition_variable.dox
@@ -0,0 +1,213 @@
+/*
+ * Copyright 2025 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Adrien Destugues, pulkomandy@pulkomandy.tk
+ *
+ * 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
+*/
+
+
+/*!
+	\struct ConditionVariableEntry
+	\ingroup kernel
+	\brief Waiting on a condition variable.
+
+	Waiting on a confition 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 B_RELATIVE_TIMEOUT or B_ABSOLUTE_TIMEOUT to enable timeouts
+	\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.
+*/
+
+
+/*!
+	\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.
+*/
+
+
+/*!
+	\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.
+*/
+
+
+/*!
+	\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 a device tree node to easily access
+	it from multiple drivers or kernel modules.
+*/
+
+
+/*!
+	\fn void ConditionVariable::Unpublish()
+	\brief Unpublish a previously publised condition variable.
+*/
+
+
+/*!
+	\fn inline void 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.
+
+	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 not yet waited,
+	its call to Wait will not block and its execution will continue immediately.
+*/
+
+
+/*!
+	\fn inline void ConditionVariable::NotifyAll(status_t result)
+	\brief Notify all the threads waiting on the condition variable.
+*/
+
+
+/*!
+	\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-aquire 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-aquire 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.
+*/
diff --git a/src/system/kernel/condition_variable.cpp b/src/system/kernel/condition_variable.cpp
index c97b15aa61..252ade8315 100644
--- a/src/system/kernel/condition_variable.cpp
+++ b/src/system/kernel/condition_variable.cpp
@@ -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)
 {
-- 
2.47.3

