From 752e5cc25274556a8dbab7a0da772d54bf7c89bb Mon Sep 17 00:00:00 2001 From: Giulio Eulisse Date: Sun, 14 Jun 2020 18:33:59 +0200 Subject: [PATCH] DPL: improve ScopedExit --- Framework/Core/src/DataProcessingDevice.cxx | 4 +- Framework/Core/src/ScopedExit.h | 143 +++++++++++++++++--- 2 files changed, 129 insertions(+), 18 deletions(-) diff --git a/Framework/Core/src/DataProcessingDevice.cxx b/Framework/Core/src/DataProcessingDevice.cxx index a835ea02ea50e..b2e1799a88ad5 100644 --- a/Framework/Core/src/DataProcessingDevice.cxx +++ b/Framework/Core/src/DataProcessingDevice.cxx @@ -424,7 +424,7 @@ bool DataProcessingDevice::handleData(FairMQParts& parts, InputChannelInfo& info // fine grain control what is exposed at each state. auto& monitoringService = mServiceRegistry.get(); StateMonitoring::moveTo(DataProcessingStatus::IN_DPL_OVERHEAD); - ScopedExit metricFlusher([&monitoringService] { + auto metricFlusher = make_scope_guard([]() noexcept { StateMonitoring::moveTo(DataProcessingStatus::IN_DPL_OVERHEAD); }); @@ -554,7 +554,7 @@ bool DataProcessingDevice::tryDispatchComputation(std::vector(); StateMonitoring::moveTo(DataProcessingStatus::IN_DPL_OVERHEAD); - ScopedExit metricFlusher([&monitoringService] { + auto metricFlusher = make_scope_guard([]() noexcept -> void { StateMonitoring::moveTo(DataProcessingStatus::IN_DPL_OVERHEAD); }); diff --git a/Framework/Core/src/ScopedExit.h b/Framework/Core/src/ScopedExit.h index feb40fee2556d..cf5533591fcd9 100644 --- a/Framework/Core/src/ScopedExit.h +++ b/Framework/Core/src/ScopedExit.h @@ -7,30 +7,141 @@ // In applying this license CERN does not waive the privileges and immunities // granted to it by virtue of its status as an Intergovernmental Organization // or submit itself to any jurisdiction. -#include +#include +#include -namespace o2 +namespace o2::framework { -namespace framework +namespace detail { +// Original from https://github.com/ricab/scope_guard +// which is licensed to public domain +// Type trait determining whether a type is callable with no arguments +template +struct is_noarg_callable_t + : public std::false_type { +}; // in general, false -/// Helper class which invokes @a callback when going out of scope. -class ScopedExit +template +struct is_noarg_callable_t()())> + : public std::true_type { +}; // only true when call expression valid + +// Type trait determining whether a no-argument callable returns void +template +struct returns_void_t + : public std::is_same()())> { +}; + +/* Type trait determining whether a no-arg callable is nothrow invocable if + required. This is where SG_REQUIRE_NOEXCEPT logic is encapsulated. */ +template +struct is_nothrow_invocable_if_required_t + : public std::is_nothrow_invocable /* Note: _r variants not enough to + confirm void return: any return can be + discarded so all returns are + compatible with void */ +{ +}; + +template +struct and_t : public and_t> { +}; + +template +struct and_t : public std::conditional::type { +}; + +template +struct is_proper_sg_callback_t + : public and_t, + returns_void_t, + is_nothrow_invocable_if_required_t, + std::is_nothrow_destructible> { +}; + +template ::value>::type> +class scope_guard; + +template +detail::scope_guard make_scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value); + +template +class scope_guard final { public: - ScopedExit(std::function callback) - : mCallback{callback} - { - } + typedef Callback callback_type; - ~ScopedExit() - { - mCallback(); - } + scope_guard(scope_guard&& other) noexcept(std::is_nothrow_constructible::value); + + ~scope_guard() noexcept; // highlight noexcept dtor + + void dismiss() noexcept; + + public: + scope_guard() = delete; + scope_guard(const scope_guard&) = delete; + scope_guard& operator=(const scope_guard&) = delete; + scope_guard& operator=(scope_guard&&) = delete; + + private: + explicit scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value); /* + meant for friends only */ + + friend scope_guard make_scope_guard(Callback&&) noexcept(std::is_nothrow_constructible::value); /* + only make_scope_guard can create scope_guards from scratch (i.e. non-move) + */ private: - std::function mCallback; + Callback mCallback; + bool mActive; }; -} // namespace framework -} // namespace o2 +} // namespace detail + +using detail::make_scope_guard; // see comment on declaration above + +template +detail::scope_guard::scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value) + : mCallback(std::forward(callback)) /* use () instead of {} because + of DR 1467 (https://is.gd/WHmWuo), which still impacts older compilers + (e.g. GCC 4.x and clang <=3.6, see https://godbolt.org/g/TE9tPJ and + https://is.gd/Tsmh8G) */ + , + mActive{true} +{ +} + +template +detail::scope_guard::~scope_guard() noexcept +{ + if (mActive) { + mCallback(); + } +} + +template +detail::scope_guard::scope_guard(scope_guard&& other) noexcept(std::is_nothrow_constructible::value) + : mCallback(std::forward(other.mCallback)) // idem + , + mActive{std::move(other.mActive)} +{ + other.mActive = false; +} + +template +inline void detail::scope_guard::dismiss() noexcept +{ + mActive = false; +} + +template +inline auto detail::make_scope_guard(Callback&& callback) noexcept(std::is_nothrow_constructible::value) + -> detail::scope_guard +{ + return detail::scope_guard{std::forward(callback)}; +} + +} // namespace o2::framework