diff --git a/emper/Blockable.hpp b/emper/Blockable.hpp index 04cbb493ab0cc112ecbc4cd40b6ec06c3fbf7fcb..7b2378f6508e7120588e9160cc73dc257c95af72 100644 --- a/emper/Blockable.hpp +++ b/emper/Blockable.hpp @@ -9,7 +9,11 @@ #include "Context.hpp" #include "ContextManager.hpp" #include "Debug.hpp" +#include "Emper.hpp" #include "Runtime.hpp" +#include "lib/adt/LockedSet.hpp" + +static emper::lib::adt::LockedSet<Context*> blockedContexts; template <LogSubsystem logSubsystem> class Blockable : public Logger<logSubsystem> { @@ -29,12 +33,21 @@ class Blockable : public Logger<logSubsystem> { assert(Runtime::inRuntime()); LOGD("block() blockedContext is " << Context::getCurrentContext()); + + if constexpr (emper::BLOCKED_CONTEXT_SET) { + blockedContexts.insert(Context::getCurrentContext()); + } + contextManager.saveAndStartNew(std::move(freshContextHook)); } template <CallerEnvironment callerEnvironment = CallerEnvironment::EMPER> void unblock(Context* context) { assert(context != nullptr); + if constexpr (emper::BLOCKED_CONTEXT_SET) { + blockedContexts.erase(context); + } + // cppcheck-suppress unsafeClassCanLeak Fiber* unblockFiber = Fiber::from([this, context]() { contextManager.discardAndResume(context); }); diff --git a/emper/Emper.hpp b/emper/Emper.hpp index 995a567e7fa34280fdcaccb616ab94b01b8ffbc2..a766160f1cc67138cad63c74ca85ce48725c2e40 100644 --- a/emper/Emper.hpp +++ b/emper/Emper.hpp @@ -65,4 +65,12 @@ static const bool OVERFLOW_QUEUE = ; auto getFullVersion() -> std::string; + +static const bool BLOCKED_CONTEXT_SET = +#ifdef EMPER_BLOCKED_CONTEXT_SET + DEBUG +#else + false +#endif + ; } // namespace emper diff --git a/emper/lib/adt/LockedSet.hpp b/emper/lib/adt/LockedSet.hpp new file mode 100644 index 0000000000000000000000000000000000000000..e3e1b1928a1e037cd3f2dbcf391c106c9f39a4a6 --- /dev/null +++ b/emper/lib/adt/LockedSet.hpp @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: LGPL-3.0-or-later +// Copyright © 2020 Florian Fischer +#pragma once + +#include <iterator> +#include <mutex> +#include <set> + +namespace emper::lib::adt { + +template <class Key, class Compare = std::less<Key>, class Allocator = std::allocator<Key>> +class LockedSet { + private: + std::mutex _mutex; + std::set<Key, Compare, Allocator> _set; + + public: + auto insert(const Key& item) + -> std::pair<typename std::set<Key, Compare, Allocator>::iterator, bool> { + std::lock_guard<std::mutex> lock(_mutex); + return _set.insert(item); + } + + template <class InputIt> + void insert(InputIt first, InputIt last) { + std::lock_guard<std::mutex> lock(_mutex); + _set.insert(first, last); + } + + size_t erase(const Key& key) { + std::lock_guard<std::mutex> lock(_mutex); + return _set.erase(key); + } +}; +} // namespace emper::lib::adt diff --git a/meson.build b/meson.build index ba757b68be9c486b08dc37ead46d57e3ed1e4a1f..e161441dc9b19398c6ee4f6e3522205c3df19706 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,7 @@ conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) conf_data.set('EMPER_LOCKED_MPSC_QUEUE', get_option('locked_mpsc_queue')) conf_data.set('EMPER_STATS', get_option('stats')) conf_data.set('EMPER_OVERFLOW_QUEUE', get_option('overflow_queue')) +conf_data.set('EMPER_BLOCKED_CONTEXT_SET', get_option('blocked_context_set')) default_scheduling_strategy = get_option('default_scheduling_strategy') conf_data.set('EMPER_DEFAULT_SCHEDULING_STRATEGY_' + default_scheduling_strategy.to_upper(), true) diff --git a/meson_options.txt b/meson_options.txt index e4f8a399783aaa724905ecb68f52a9fad9a7ba63..5e8d939d9a50dfd1905a54844a27ffaa9768db54 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,6 +10,12 @@ option( choices: ['automatic', 'OFF', 'Error', 'Warning', 'Info', 'Debug', 'FineDebug', 'FinerDebug', 'FinestDebug', 'ALL'], value: 'automatic', ) +option( + 'blocked_context_set', + type: 'boolean', + value: false, + description: 'Store all currently blocked contexts for debugging in the set Blockable<LogLevel>::blocked' +) option( 'log_timestamp', type: 'boolean',