diff --git a/ostd/generic_condvar.hh b/ostd/generic_condvar.hh index bdb5b18..d86098c 100644 --- a/ostd/generic_condvar.hh +++ b/ostd/generic_condvar.hh @@ -1,6 +1,12 @@ -/* A generic condvar that can store any other condvar as a single type. +/** @addtogroup Concurrency + * @{ + */ + +/** @file generic_condvar.hh * - * This file is part of OctaSTD. See COPYING.md for futher information. + * A single type that can encapsulate different condvar types. + * + * @copyright See COPYING.md in the project tree for further information. */ #ifndef OSTD_GENERIC_CONDVAR_HH @@ -12,6 +18,10 @@ namespace ostd { +/** @addtogroup Concurrency + * @{ + */ + namespace detail { struct cond_iface { cond_iface() {} @@ -40,42 +50,113 @@ namespace detail { }; } /* namespace detail */ +/** @brief A generic condition variable type. + * + * This is a type that implements a condition variable interface but can + * encapsulate different real condition variable types while still having + * just one static type. This is useful when you need to implement a data + * structure that requires a condition variable but still want it to be + * compatible with custom schedulers (which can use a custom condition + * variable implementation for their logical threads) without having to + * template it. + * + * The storage for the custom type is at least 6 pointers, depending on + * the size of a standard std::condition_variable (if it's bigger, the + * space is the size of that). + */ struct generic_condvar { + /** Constructs the condvar using std::condition_variable. */ generic_condvar() { new (reinterpret_cast(&p_condbuf)) detail::cond_impl(); } + + /** @brief Constructs the condvar using a custom type. + * + * As condvars don't have to be move constructible and your own + * condvar type can internally contain some custom state, the + * condvar to store is constructed using a function, which is + * required to return it. + * + * @param[in] func The function that is called to get the condvar. + */ template generic_condvar(F &&func) { new (reinterpret_cast(&p_condbuf)) detail::cond_impl>(func); } + /** Condvars are not copy constructible. */ generic_condvar(generic_condvar const &) = delete; + + /** Condvars are not move constructible. */ generic_condvar(generic_condvar &&) = delete; + + /** Condvars are not copy assignable. */ generic_condvar &operator=(generic_condvar const &) = delete; + + /** Condvars are not move assignable. */ generic_condvar &operator=(generic_condvar &&) = delete; + /** Destroys the stored condvar. */ ~generic_condvar() { reinterpret_cast(&p_condbuf)->~cond_iface(); } + /** @brief Notifies one waiting thread. + * + * If any threads are waiting on this condvar, this unblocks one of + * them. The actual semantics and what the threads are are defined by + * the condition variable type that is stored. This simply calls + * `.notify_one()` on the stored condvar. + * + * @see notify_all(), wait(std::unique_lock) + */ void notify_one() { reinterpret_cast(&p_condbuf)->notify_one(); } + + /** @brief Notifies all waiting threads. + * + * If any threads are waiting on this condvar, this unblocks all of + * them. The actual semantics and what the threads are are defined by + * the condition variable type that is stored. This simply calls + * `.notify_all()` on the stored condvar. + * + * @see notify_one(), wait(std::unique_lock) + */ void notify_all() { reinterpret_cast(&p_condbuf)->notify_all(); } + + /** @brief Blocks the current thread until the condvar is woken up. + * + * This atomically releases the given lock, blocks the current thread + * and adds it to the waiting threads list, until unblocked by notify_one() + * or notify_all(). It may also be unblocked spuriously, depending on the + * implementation. The actual specific semantics and what the current + * thread is depends on the implementation of the stored condvar. This + * simply calls `.wait(l)` on it. + * + * @see notify_one(), notify_all() + */ void wait(std::unique_lock &l) { reinterpret_cast(&p_condbuf)->wait(l); } private: + static constexpr size_t cvars = sizeof(std::condition_variable); + static constexpr size_t icvars = + sizeof(detail::cond_impl); std::aligned_storage_t) + 6 * sizeof(void *) + (icvars - cvars), icvars )> p_condbuf; }; +/** @} */ + } /* namespace ostd */ #endif + +/** @} */ diff --git a/ostd/thread_pool.hh b/ostd/thread_pool.hh index e7f45d4..ee3f3bd 100644 --- a/ostd/thread_pool.hh +++ b/ostd/thread_pool.hh @@ -221,6 +221,6 @@ private: } /* namespace ostd */ -/** @} */ - #endif + +/** @} */