diff --git a/Source/Shared/arcana/threading/blocking_concurrent_queue.h b/Source/Shared/arcana/threading/blocking_concurrent_queue.h index 61f6c0a..ca6b6a7 100644 --- a/Source/Shared/arcana/threading/blocking_concurrent_queue.h +++ b/Source/Shared/arcana/threading/blocking_concurrent_queue.h @@ -3,12 +3,34 @@ #include "cancellation.h" #include +#include +#include #include #include -#include +#include +#include + +#ifdef ARCANA_TESTING_HOOKS +#include +#endif namespace arcana { +#ifdef ARCANA_TESTING_HOOKS + namespace detail + { + inline std::function beforeWaitCallback{[]() {}}; + } + + // Set a callback to be invoked while holding the queue mutex, right before + // condition_variable::wait(). This is used for deterministic testing of + // lost-wakeup race conditions. Pass an empty lambda [](){} to reset. + inline void set_before_wait_callback(std::function callback) + { + detail::beforeWaitCallback = std::move(callback); + } +#endif + template::max()> class blocking_concurrent_queue { @@ -95,6 +117,9 @@ namespace arcana { while (!cancel.cancelled() && m_data.empty()) { +#ifdef ARCANA_TESTING_HOOKS + detail::beforeWaitCallback(); +#endif m_dataReady.wait(lock); } } @@ -116,6 +141,9 @@ namespace arcana { while (!cancel.cancelled() && m_data.empty()) { +#ifdef ARCANA_TESTING_HOOKS + detail::beforeWaitCallback(); +#endif m_dataReady.wait(lock); } }