/* * 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 \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. */