diff --git a/cmake/HPX_AddConfigTest.cmake b/cmake/HPX_AddConfigTest.cmake index e6d29636388a..ef7513a9a30a 100644 --- a/cmake/HPX_AddConfigTest.cmake +++ b/cmake/HPX_AddConfigTest.cmake @@ -633,6 +633,15 @@ function(hpx_check_for_cxx20_std_bit_cast) ) endfunction() +# ############################################################################## +function(hpx_check_for_cxx20_constexpr_destructor) + add_hpx_config_test( + HPX_WITH_CXX20_CONSTEXPR_DESTRUCTOR + SOURCE cmake/tests/cxx20_constexpr_destructor.cpp + FILE ${ARGN} + ) +endfunction() + # ############################################################################## function(hpx_check_for_cxx23_std_generator) add_hpx_config_test( @@ -642,6 +651,15 @@ function(hpx_check_for_cxx23_std_generator) ) endfunction() +# ############################################################################## +function(hpx_check_for_cxx26_experimental_scope) + add_hpx_config_test( + HPX_WITH_CXX26_EXPERIMENTAL_SCOPE + SOURCE cmake/tests/cxx26_experimental_scope.cpp + FILE ${ARGN} + ) +endfunction() + # ############################################################################## function(hpx_check_for_cxx_lambda_capture_decltype) add_hpx_config_test( diff --git a/cmake/HPX_PerformCxxFeatureTests.cmake b/cmake/HPX_PerformCxxFeatureTests.cmake index 8de5a0b55c41..ea43a3bb1a76 100644 --- a/cmake/HPX_PerformCxxFeatureTests.cmake +++ b/cmake/HPX_PerformCxxFeatureTests.cmake @@ -151,12 +151,20 @@ function(hpx_perform_cxx_feature_tests) ) hpx_check_for_cxx20_std_bit_cast(DEFINITIONS HPX_HAVE_CXX20_STD_BIT_CAST) + + hpx_check_for_cxx20_constexpr_destructor( + DEFINITIONS HPX_HAVE_CXX20_CONSTEXPR_DESTRUCTOR + ) endif() if(HPX_WITH_CXX_STANDARD GREATER_EQUAL 23) hpx_check_for_cxx23_std_generator(DEFINITIONS HPX_HAVE_CXX23_STD_GENERATOR) endif() + hpx_check_for_cxx26_experimental_scope( + DEFINITIONS HPX_HAVE_CXX26_EXPERIMENTAL_SCOPE + ) + hpx_check_for_cxx_lambda_capture_decltype( DEFINITIONS HPX_HAVE_CXX_LAMBDA_CAPTURE_DECLTYPE ) diff --git a/cmake/tests/cxx20_constexpr_destructor.cpp b/cmake/tests/cxx20_constexpr_destructor.cpp new file mode 100644 index 000000000000..0902cc836a92 --- /dev/null +++ b/cmake/tests/cxx20_constexpr_destructor.cpp @@ -0,0 +1,19 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include + +struct A +{ + constexpr A() noexcept {} + constexpr ~A() {} +}; + +int main() +{ + [[maybe_unused]] A a; + return 0; +} diff --git a/cmake/tests/cxx26_experimental_scope.cpp b/cmake/tests/cxx26_experimental_scope.cpp new file mode 100644 index 000000000000..07dbfd7daadd --- /dev/null +++ b/cmake/tests/cxx26_experimental_scope.cpp @@ -0,0 +1,22 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// test for availability of std::experimental::scope_xxx + +#include + +#if !defined(__cpp_lib_experimental_scope) +# error "__cpp_lib_experimental_scope not defined, assume scope_exit etc. is not supported" +#endif + +int main() +{ + std::experimental::scope_exit se([] {}); + std::experimental::scope_failure sf([] {}); + std::experimental::scope_success ss([] {}); + + return 0; +} diff --git a/components/containers/unordered/include/hpx/components/containers/unordered/partition_unordered_map_component.hpp b/components/containers/unordered/include/hpx/components/containers/unordered/partition_unordered_map_component.hpp index 1c5107a32dea..4e5ff198d5c8 100644 --- a/components/containers/unordered/include/hpx/components/containers/unordered/partition_unordered_map_component.hpp +++ b/components/containers/unordered/include/hpx/components/containers/unordered/partition_unordered_map_component.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -203,22 +204,6 @@ namespace hpx { namespace server { /// \return Return the value of the element at position represented /// by \a pos. /// - struct erase_on_exit - { - erase_on_exit(data_type& m, typename data_type::iterator& it) - : m_(m) - , it_(it) - { - } - ~erase_on_exit() - { - m_.erase(it_); - } - - data_type& m_; - typename data_type::iterator& it_; - }; - T get_value(Key const& key, bool erase) { typename data_type::iterator it = @@ -234,7 +219,9 @@ namespace hpx { namespace server { if (!erase) return it->second; - erase_on_exit t(partition_unordered_map_, it); + auto on_exit = hpx::experimental::scope_exit( + [this, &it] { partition_unordered_map_.erase(it); }); + return it->second; } diff --git a/libs/core/algorithms/include/hpx/parallel/task_group.hpp b/libs/core/algorithms/include/hpx/parallel/task_group.hpp index cfddc1a324ba..f85975055a2e 100644 --- a/libs/core/algorithms/include/hpx/parallel/task_group.hpp +++ b/libs/core/algorithms/include/hpx/parallel/task_group.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2023 Hartmut Kaiser +// Copyright (c) 2021-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -44,21 +45,6 @@ namespace hpx::experimental { task_group& operator=(task_group const&) = delete; task_group& operator=(task_group&&) = delete; - private: - struct on_exit - { - HPX_CORE_EXPORT explicit on_exit(task_group& tg); - HPX_CORE_EXPORT ~on_exit(); - - on_exit(on_exit const& rhs) = delete; - on_exit& operator=(on_exit const& rhs) = delete; - - HPX_CORE_EXPORT on_exit(on_exit&& rhs) noexcept; - HPX_CORE_EXPORT on_exit& operator=(on_exit&& rhs) noexcept; - - hpx::lcos::local::latch* latch_; - }; - public: /// \brief Adds a task to compute \c f() and returns immediately. /// @@ -82,13 +68,19 @@ namespace hpx::experimental { void run(Executor&& exec, F&& f, Ts&&... ts) { // make sure exceptions don't leave the latch in the wrong state - on_exit l(*this); + if (latch_.reset_if_needed_and_count_up(1, 1)) + { + has_arrived_.store(false, std::memory_order_release); + } + + auto on_exit = + hpx::experimental::scope_exit([this] { latch_.count_down(1); }); hpx::parallel::execution::post(HPX_FORWARD(Executor, exec), - [this, l = HPX_MOVE(l), f = HPX_FORWARD(F, f), + [this, on_exit = HPX_MOVE(on_exit), f = HPX_FORWARD(F, f), t = hpx::make_tuple(HPX_FORWARD(Ts, ts)...)]() mutable { // latch needs to be released before the lambda exits - on_exit _(HPX_MOVE(l)); + auto _(HPX_MOVE(on_exit)); hpx::detail::try_catch_exception_ptr( [&]() { hpx::invoke_fused(HPX_MOVE(f), HPX_MOVE(t)); }, diff --git a/libs/core/algorithms/src/task_group.cpp b/libs/core/algorithms/src/task_group.cpp index 6b027be4e511..5d827a692b6b 100644 --- a/libs/core/algorithms/src/task_group.cpp +++ b/libs/core/algorithms/src/task_group.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021-2023 Hartmut Kaiser +// Copyright (c) 2021-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -16,37 +16,6 @@ namespace hpx::experimental { - /////////////////////////////////////////////////////////////////////////// - task_group::on_exit::on_exit(task_group& tg) - : latch_(&tg.latch_) - { - if (latch_->reset_if_needed_and_count_up(1, 1)) - { - tg.has_arrived_.store(false, std::memory_order_release); - } - } - - task_group::on_exit::~on_exit() - { - if (latch_ != nullptr) - { - latch_->count_down(1); - } - } - - task_group::on_exit::on_exit(on_exit&& rhs) noexcept - : latch_(rhs.latch_) - { - rhs.latch_ = nullptr; - } - - task_group::on_exit& task_group::on_exit::operator=(on_exit&& rhs) noexcept - { - latch_ = rhs.latch_; - rhs.latch_ = nullptr; - return *this; - } - /////////////////////////////////////////////////////////////////////////// task_group::task_group() : latch_(1) diff --git a/libs/core/async_cuda/CMakeLists.txt b/libs/core/async_cuda/CMakeLists.txt index b2a7954877bb..df9777753950 100644 --- a/libs/core/async_cuda/CMakeLists.txt +++ b/libs/core/async_cuda/CMakeLists.txt @@ -62,6 +62,7 @@ add_hpx_module( hpx_debugging hpx_errors hpx_execution_base + hpx_functional hpx_futures hpx_memory hpx_runtime_local diff --git a/libs/core/async_cuda/include/hpx/async_cuda/cuda_future.hpp b/libs/core/async_cuda/include/hpx/async_cuda/cuda_future.hpp index e5e617c47171..e698f02ec638 100644 --- a/libs/core/async_cuda/include/hpx/async_cuda/cuda_future.hpp +++ b/libs/core/async_cuda/include/hpx/async_cuda/cuda_future.hpp @@ -1,7 +1,7 @@ -// Copyright (c) 2023 Gregor Daiß +// Copyright (c) 2023 Gregor Daiß // Copyright (c) 2020 John Biddiscombe // Copyright (c) 2016 Thomas Heller -// Copyright (c) 2016 Hartmut Kaiser +// Copyright (c) 2016-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -47,26 +48,6 @@ namespace hpx { namespace cuda { namespace experimental { template struct future_data; - // ------------------------------------------------------------- - // helper struct to delete future data in destructor - template - struct release_on_exit - { - explicit release_on_exit( - future_data* data) - : data_(data) - { - } - - ~release_on_exit() - { - // release the shared state - lcos::detail::intrusive_ptr_release(data_); - } - - future_data* data_; - }; - template struct future_data : lcos::detail::future_data_allocator(user_data); - release_on_exit on_exit(this_); + auto on_exit = hpx::experimental::scope_exit( + [&] { hpx::lcos::detail::intrusive_ptr_release(this_); }); if (error != cudaSuccess) { diff --git a/libs/core/config/include/hpx/config/constexpr.hpp b/libs/core/config/include/hpx/config/constexpr.hpp index e05f17d93441..de8d8fc92598 100644 --- a/libs/core/config/include/hpx/config/constexpr.hpp +++ b/libs/core/config/include/hpx/config/constexpr.hpp @@ -27,3 +27,9 @@ #else #define HPX_HOST_DEVICE_CONSTEXPR constexpr #endif + +#if defined(HPX_HAVE_CXX20_CONSTEXPR_DESTRUCTOR) +#define HPX_CONSTEXPR_DESTRUCTOR constexpr +#else +#define HPX_CONSTEXPR_DESTRUCTOR +#endif diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp index e6f1ff9e8f9c..4abd61508e54 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2006, Giovanni P. Deretta -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // // This code may be used under either of the following two licences: // diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp index 8737af27def7..14efe693b7d9 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp @@ -43,33 +43,6 @@ namespace hpx::threads::coroutines::detail { class coroutine_self { - public: - HPX_NON_COPYABLE(coroutine_self); - - protected: - // store the current this and write it back to the TSS on exit - struct reset_self_on_exit - { - explicit reset_self_on_exit(coroutine_self* self) noexcept - : self_(self) - { - set_self(self->next_self_); - } - - reset_self_on_exit(reset_self_on_exit const&) = delete; - reset_self_on_exit(reset_self_on_exit&&) = delete; - - reset_self_on_exit& operator=(reset_self_on_exit const&) = delete; - reset_self_on_exit& operator=(reset_self_on_exit&&) = delete; - - ~reset_self_on_exit() - { - set_self(self_); - } - - coroutine_self* self_; - }; - public: using thread_id_type = hpx::threads::thread_id; @@ -83,6 +56,11 @@ namespace hpx::threads::coroutines::detail { { } + coroutine_self(coroutine_self const&) = delete; + coroutine_self(coroutine_self&&) = delete; + coroutine_self& operator=(coroutine_self const&) = delete; + coroutine_self& operator=(coroutine_self&&) = delete; + arg_type yield(result_type arg = result_type()) { return !yield_decorator_.empty() ? yield_decorator_(HPX_MOVE(arg)) : @@ -176,32 +154,8 @@ namespace hpx::threads::coroutines::detail { return local_self(); } - private: + protected: yield_decorator_type yield_decorator_; coroutine_self* next_self_; }; - - //////////////////////////////////////////////////////////////////////////// - struct reset_self_on_exit - { - explicit reset_self_on_exit( - coroutine_self* val, coroutine_self* old_val = nullptr) noexcept - : old_self(old_val) - { - coroutine_self::set_self(val); - } - - reset_self_on_exit(reset_self_on_exit const&) = delete; - reset_self_on_exit(reset_self_on_exit&&) = delete; - - reset_self_on_exit& operator=(reset_self_on_exit const&) = delete; - reset_self_on_exit& operator=(reset_self_on_exit&&) = delete; - - ~reset_self_on_exit() - { - coroutine_self::set_self(old_self); - } - - coroutine_self* old_self; - }; } // namespace hpx::threads::coroutines::detail diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackful_self.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackful_self.hpp index 20d34a2c5541..8dd81b8cc7f6 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackful_self.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackful_self.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2021 Hartmut Kaiser +// Copyright (c) 2019-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -34,7 +35,11 @@ namespace hpx::threads::coroutines::detail { this->pimpl_->bind_result(arg); { - reset_self_on_exit on_exit(this); + // store the current this and write it back to the TSS on exit + set_self(this->next_self_); + auto on_exit = + hpx::experimental::scope_exit([this] { set_self(this); }); + this->pimpl_->yield(); } diff --git a/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp b/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp index b1783a6b8ba7..2904b3721b26 100644 --- a/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2021 Hartmut Kaiser +// Copyright (c) 2021-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. @@ -14,6 +14,7 @@ #include #include #include +#include #include #if defined(HPX_HAVE_THREAD_LOCAL_STORAGE) #include @@ -214,30 +215,6 @@ namespace hpx::threads::coroutines { id_.reset(); } - private: - struct reset_on_exit - { - explicit constexpr reset_on_exit(stackless_coroutine& that) noexcept - : this_(that) - { - this_.state_ = context_state::running; - } - - reset_on_exit(reset_on_exit const&) = delete; - reset_on_exit(reset_on_exit&&) = delete; - - reset_on_exit& operator=(reset_on_exit const&) = delete; - reset_on_exit& operator=(reset_on_exit&&) = delete; - - ~reset_on_exit() - { - this_.state_ = context_state::exited; - } - - stackless_coroutine& this_; - }; - friend struct reset_on_exit; - public: HPX_FORCEINLINE result_type operator()(arg_type arg = arg_type()); @@ -298,10 +275,15 @@ namespace hpx::threads::coroutines { { detail::coroutine_stackless_self self(this); - detail::reset_self_on_exit on_self_exit(&self, nullptr); + + detail::coroutine_self::set_self(&self); + auto on_exit = hpx::experimental::scope_exit( + [] { detail::coroutine_self::set_self(nullptr); }); { - [[maybe_unused]] reset_on_exit const on_exit{*this}; + state_ = context_state::running; + auto on_exit_inner = hpx::experimental::scope_exit( + [this] { state_ = context_state::exited; }); result = f_(arg); // invoke wrapped function diff --git a/libs/core/coroutines/src/detail/coroutine_impl.cpp b/libs/core/coroutines/src/detail/coroutine_impl.cpp index 66d1490ac3f8..306896c0841f 100644 --- a/libs/core/coroutines/src/detail/coroutine_impl.cpp +++ b/libs/core/coroutines/src/detail/coroutine_impl.cpp @@ -1,5 +1,5 @@ // Copyright (c) 2006, Giovanni P. Deretta -// Copyright (c) 2007-2023 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // // This code may be used under either of the following two licences: // @@ -55,7 +55,7 @@ namespace hpx::threads::coroutines::detail { using context_state = super_type::context_state; using context_exit_status = super_type::context_exit_status; - context_exit_status status = context_exit_status::not_exited; + auto status = context_exit_status::not_exited; // yield value once the thread function has finished executing result_type result_last( @@ -71,7 +71,11 @@ namespace hpx::threads::coroutines::detail { { coroutine_self* old_self = coroutine_self::get_self(); coroutine_stackful_self self(this, old_self); - reset_self_on_exit on_exit(&self, old_self); + + coroutine_self::set_self(&self); + auto on_exit = hpx::experimental::scope_exit( + [&] { coroutine_self::set_self(old_self); }); + try { result_last = m_fun(*this->args()); @@ -108,9 +112,9 @@ namespace hpx::threads::coroutines::detail { using context_state = super_type::context_state; using context_exit_status = super_type::context_exit_status; - context_exit_status status = context_exit_status::not_exited; + auto status = context_exit_status::not_exited; - result_type result_last( + constexpr result_type result_last( thread_schedule_state::unknown, invalid_thread_id); this->m_state = context_state::running; @@ -119,7 +123,11 @@ namespace hpx::threads::coroutines::detail { { coroutine_self* old_self = coroutine_self::get_self(); coroutine_stackful_self_direct self(this, old_self); - reset_self_on_exit on_exit(&self, old_self); + + coroutine_self::set_self(&self); + auto on_exit = hpx::experimental::scope_exit( + [&] { coroutine_self::set_self(old_self); }); + try { this->m_result = this->m_fun(arg); diff --git a/libs/core/executors/examples/executor_with_thread_hooks.cpp b/libs/core/executors/examples/executor_with_thread_hooks.cpp index 5dc5bd7b113e..9aa62b00b435 100644 --- a/libs/core/executors/examples/executor_with_thread_hooks.cpp +++ b/libs/core/executors/examples/executor_with_thread_hooks.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2020-2022 Hartmut Kaiser +// Copyright (c) 2020-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -29,29 +30,16 @@ namespace executor_example { class executor_with_thread_hooks { private: - struct on_exit - { - explicit on_exit(executor_with_thread_hooks const& exec) - : exec_(exec) - { - exec_.on_start_(); - } - - ~on_exit() - { - exec_.on_stop_(); - } - - executor_with_thread_hooks const& exec_; - }; - template struct hook_wrapper { template decltype(auto) operator()(Ts&&... ts) { - on_exit _{exec_}; + exec_.on_start_(); + auto on_exit = hpx::experimental::scope_exit( + [this]() mutable { exec_.on_stop_(); }); + return hpx::invoke(f_, std::forward(ts)...); } diff --git a/libs/core/executors/include/hpx/executors/limiting_executor.hpp b/libs/core/executors/include/hpx/executors/limiting_executor.hpp index ede0cb760f76..0a880d101e19 100644 --- a/libs/core/executors/include/hpx/executors/limiting_executor.hpp +++ b/libs/core/executors/include/hpx/executors/limiting_executor.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -41,26 +42,6 @@ namespace hpx::execution::experimental { template struct limiting_executor { - // -------------------------------------------------------------------- - // RAII wrapper for counting task completions (count_down) - // count_up is done in the executor when the task is first scheduled - // This object is destructed when the task has completed - // -------------------------------------------------------------------- - struct on_exit - { - explicit on_exit(limiting_executor const& this_e) noexcept - : executor_(this_e) - { - } - ~on_exit() - { - lim_debug.debug(hpx::debug::str<>("Count Down")); - executor_.count_down(); - } - - limiting_executor const& executor_; - }; - // -------------------------------------------------------------------- // this is the default wrapper struct that invokes count up / down // and uses the limiting executor counter to control throttling @@ -90,7 +71,11 @@ namespace hpx::execution::experimental { template decltype(auto) operator()(Ts&&... ts) { - on_exit _{limiting_}; + auto on_exit = hpx::experimental::scope_exit([&] { + lim_debug.debug(hpx::debug::str<>("Count Down")); + limiting_.count_down(); + }); + return HPX_INVOKE(f_, HPX_FORWARD(Ts, ts)...); } diff --git a/libs/core/functional/CMakeLists.txt b/libs/core/functional/CMakeLists.txt index 1b78978ffb3d..c37d19e05e8c 100644 --- a/libs/core/functional/CMakeLists.txt +++ b/libs/core/functional/CMakeLists.txt @@ -30,6 +30,9 @@ set(functional_headers hpx/functional/move_only_function.hpp hpx/functional/one_shot.hpp hpx/functional/protect.hpp + hpx/functional/experimental/scope_exit.hpp + hpx/functional/experimental/scope_fail.hpp + hpx/functional/experimental/scope_success.hpp hpx/functional/serialization/detail/serializable_basic_function.hpp hpx/functional/serialization/detail/vtable/serializable_function_vtable.hpp hpx/functional/serialization/detail/vtable/serializable_vtable.hpp diff --git a/libs/core/functional/include/hpx/functional/experimental/scope_exit.hpp b/libs/core/functional/include/hpx/functional/experimental/scope_exit.hpp new file mode 100644 index 000000000000..84294cbb7285 --- /dev/null +++ b/libs/core/functional/include/hpx/functional/experimental/scope_exit.hpp @@ -0,0 +1,71 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2020 Martin Moene +// This is inspired by https://github.com/martinmoene/scope-lite + +#pragma once + +#include + +#if !defined(HPX_HAVE_CXX26_EXPERIMENTAL_SCOPE) + +#include + +namespace hpx::experimental { + + template + struct scope_exit + { + explicit constexpr scope_exit(F&& f) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(f)) + { + } + + explicit constexpr scope_exit(F const& f) noexcept( + std::is_nothrow_copy_constructible_v) + : f(f) + { + } + + constexpr scope_exit(scope_exit&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(rhs.f)) + , active(rhs.active) + { + rhs.release(); + } + + scope_exit(scope_exit const&) = delete; + scope_exit& operator=(scope_exit const&) = delete; + scope_exit& operator=(scope_exit&& rhs) = delete; + + HPX_CONSTEXPR_DESTRUCTOR ~scope_exit() noexcept + { + if (active) + { + f(); + } + } + + constexpr void release() noexcept + { + active = false; + } + + private: + F f; + bool active = true; + }; + + template + scope_exit(F) -> scope_exit; +} // namespace hpx::experimental + +#endif diff --git a/libs/core/functional/include/hpx/functional/experimental/scope_fail.hpp b/libs/core/functional/include/hpx/functional/experimental/scope_fail.hpp new file mode 100644 index 000000000000..3046a776e791 --- /dev/null +++ b/libs/core/functional/include/hpx/functional/experimental/scope_fail.hpp @@ -0,0 +1,75 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2020 Martin Moene +// This is inspired by https://github.com/martinmoene/scope-lite + +#pragma once + +#include + +#if !defined(HPX_HAVE_CXX26_EXPERIMENTAL_SCOPE) + +#include +#include +#include + +namespace hpx::experimental { + + template + struct scope_fail + { + explicit constexpr scope_fail(F&& f) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(f)) + , active(std::uncaught_exceptions()) + { + } + + explicit constexpr scope_fail(F const& f) noexcept( + std::is_nothrow_copy_constructible_v) + : f(f) + , active(std::uncaught_exceptions()) + { + } + + constexpr scope_fail(scope_fail&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(rhs.f)) + , active(rhs.active) + { + rhs.release(); + } + + scope_fail(scope_fail const&) = delete; + scope_fail& operator=(scope_fail const&) = delete; + scope_fail& operator=(scope_fail&& rhs) = delete; + + HPX_CONSTEXPR_DESTRUCTOR ~scope_fail() noexcept + { + if (active < std::uncaught_exceptions()) + { + f(); + } + } + + constexpr void release() noexcept + { + active = (std::numeric_limits::max)(); + } + + private: + F f; + int active; + }; + + template + scope_fail(F) -> scope_fail; +} // namespace hpx::experimental + +#endif diff --git a/libs/core/functional/include/hpx/functional/experimental/scope_success.hpp b/libs/core/functional/include/hpx/functional/experimental/scope_success.hpp new file mode 100644 index 000000000000..9b7a2d6e72aa --- /dev/null +++ b/libs/core/functional/include/hpx/functional/experimental/scope_success.hpp @@ -0,0 +1,74 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2020 Martin Moene +// This is inspired by https://github.com/martinmoene/scope-lite + +#pragma once + +#include + +#if !defined(HPX_HAVE_CXX26_EXPERIMENTAL_SCOPE) + +#include +#include + +namespace hpx::experimental { + + template + struct scope_success + { + explicit constexpr scope_success(F&& f) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(f)) + , active(std::uncaught_exceptions()) + { + } + + explicit constexpr scope_success(F const& f) noexcept( + std::is_nothrow_copy_constructible_v) + : f(f) + , active(std::uncaught_exceptions()) + { + } + + constexpr scope_success(scope_success&& rhs) noexcept( + std::is_nothrow_move_constructible_v || + std::is_nothrow_copy_constructible_v) + : f(HPX_MOVE(rhs.f)) + , active(rhs.active) + { + rhs.release(); + } + + scope_success(scope_success const&) = delete; + scope_success& operator=(scope_success const&) = delete; + scope_success& operator=(scope_success&& rhs) = delete; + + HPX_CONSTEXPR_DESTRUCTOR ~scope_success() noexcept(noexcept(this->f())) + { + if (active >= std::uncaught_exceptions()) + { + f(); + } + } + + constexpr void release() noexcept + { + active = -1; + } + + private: + F f; + int active; + }; + + template + scope_success(F) -> scope_success; +} // namespace hpx::experimental + +#endif diff --git a/libs/core/functional/tests/unit/CMakeLists.txt b/libs/core/functional/tests/unit/CMakeLists.txt index 1014a4b7ea18..944ef10c5792 100644 --- a/libs/core/functional/tests/unit/CMakeLists.txt +++ b/libs/core/functional/tests/unit/CMakeLists.txt @@ -36,6 +36,7 @@ set(function_tests mem_fn_void_test nothrow_swap protect_test + scope stateless_test sum_avg ) diff --git a/libs/core/functional/tests/unit/scope.cpp b/libs/core/functional/tests/unit/scope.cpp new file mode 100644 index 000000000000..374b85f38688 --- /dev/null +++ b/libs/core/functional/tests/unit/scope.cpp @@ -0,0 +1,309 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// Copyright (c) 2020 Martin Moene +// This is inspired by https://github.com/martinmoene/scope-lite + +#include +#include +#include + +#include + +static bool is_called = false; + +namespace on { + + void exit() + { + is_called = true; + } + + void fail() + { + is_called = true; + } + + void success() + { + is_called = true; + } +} // namespace on + +#if __cplusplus >= 202302L +namespace cexpr { + + constexpr bool is_called_exit() + { + bool result = false; + { + auto change = hpx::experimental::scope_exit([&] { result = true; }); + } + return result; + } + + constexpr bool is_not_called_fail() + { + bool result = false; + { + auto change = hpx::experimental::scope_fail([&] { result = true; }); + } + return result; + } + + constexpr bool is_called_success() + { + bool result = false; + { + auto guard = + hpx::experimental::scope_success([&]() { result = true; }); + } + return result; + } +} // namespace cexpr +#endif + +// scope_exit: exit function is called at end of scope +void scope_exit_called() +{ + is_called = false; + + // scope: + { + auto guard = hpx::experimental::scope_exit(on::exit); + } + + HPX_TEST(is_called); +} + +// scope_exit: exit function is called at end of scope (lambda) +void scope_exit_called_lambda() +{ + is_called = false; + + { + auto guard = hpx::experimental::scope_exit([]() { is_called = true; }); + } + + HPX_TEST(is_called); +} + +// scope_exit: exit function is called when an exception occurs +void scope_exit_called_exception() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_exit(on::exit); + throw std::exception(); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +// scope_exit: exit function is not called at end of scope when released +void scope_exit_not_called_released() +{ + is_called = false; + + { + auto guard = hpx::experimental::scope_exit(on::exit); + guard.release(); + } + + HPX_TEST(!is_called); +} + +// scope_fail: exit function is called when an exception occurs +void scope_fail_called_exception() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_fail(on::fail); + throw std::exception(); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +// scope_fail: exit function is called when an exception occurs (lambda) +void scope_fail_called_exception_lambda() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_fail([]() { is_called = true; }); + throw std::exception(); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +// scope_fail: exit function is not called when no exception occurs +void scope_fail_not_called_no_exception() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_fail(on::fail); + } + catch (...) + { + } + + HPX_TEST(!is_called); +} + +// scope_fail: exit function is not called when released +void scope_fail_not_called_released() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_fail(on::fail); + guard.release(); + + throw std::exception(); + } + catch (...) + { + } + + HPX_TEST(!is_called); +} + +// scope_success: exit function is called when no exception occurs +void scope_success_called_no_exception() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_success(on::success); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +// scope_success: exit function is called when no exception occurs (lambda) +void scope_success_called_no_exception_lambda() +{ + is_called = false; + + try + { + auto guard = + hpx::experimental::scope_success([]() { is_called = true; }); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +// scope_success: exit function is not called when an exception occurs +void scope_success_not_called_exception() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_success(on::success); + throw std::exception(); + } + catch (...) + { + } + + HPX_TEST(!is_called); +} + +// scope_success: exit function is not called when released +void scope_success_not_called_released() +{ + is_called = false; + + try + { + auto guard = hpx::experimental::scope_success(on::success); + guard.release(); + } + catch (...) + { + } + + HPX_TEST(!is_called); +} + +// scope_success: exit function can throw (lambda) +void scope_success_exit_throws() +{ + is_called = false; + + try + { + // skipped_guard is expected to not be called, as the destructor of + // guard will throw. + auto skipped_guard = + hpx::experimental::scope_success([]() { is_called = false; }); + + auto guard = hpx::experimental::scope_success([]() { + is_called = true; + throw std::exception(); + }); + } + catch (...) + { + } + + HPX_TEST(is_called); +} + +int main() +{ +#if __cplusplus >= 202302L + HPX_TEST(cexpr::is_called_exit()); + HPX_TEST(!cexpr::is_not_called_fail()); + HPX_TEST(cexpr::is_called_success()); +#endif + + scope_exit_called(); + scope_exit_called_lambda(); + scope_exit_called_exception(); + scope_exit_not_called_released(); + + scope_fail_called_exception(); + scope_fail_called_exception_lambda(); + scope_fail_not_called_no_exception(); + scope_fail_not_called_released(); + + scope_success_called_no_exception(); + scope_success_called_no_exception_lambda(); + scope_success_not_called_exception(); + scope_success_not_called_released(); + scope_success_exit_throws(); + + return hpx::util::report_errors(); +} diff --git a/libs/core/futures/include/hpx/futures/future.hpp b/libs/core/futures/include/hpx/futures/future.hpp index a27f7aa7654b..b0f4547cf183 100644 --- a/libs/core/futures/include/hpx/futures/future.hpp +++ b/libs/core/futures/include/hpx/futures/future.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // Copyright (c) 2013 Agustin Berge // // SPDX-License-Identifier: BSL-1.0 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -542,27 +543,6 @@ namespace hpx { using result_type = R; using shared_state_type = typename base_type::shared_state_type; - private: - struct invalidate - { - constexpr explicit invalidate(future& f) noexcept - : f_(f) - { - } - - invalidate(invalidate const&) = delete; - invalidate(invalidate&&) = delete; - invalidate& operator=(invalidate const&) = delete; - invalidate& operator=(invalidate&&) = delete; - - ~invalidate() - { - f_.shared_state_.reset(); - } - - future& f_; - }; - private: template friend struct hpx::traits::future_access; @@ -687,7 +667,8 @@ namespace hpx { "this future has no valid shared state"); } - invalidate on_exit(*this); + auto on_exit = hpx::experimental::scope_exit( + [this] { this->shared_state_.reset(); }); using result_type = typename shared_state_type::result_type; auto* result = lcos::detail::future_get_result::call( @@ -707,7 +688,8 @@ namespace hpx { return lcos::detail::future_value::get_default(); } - invalidate on_exit(*this); + auto on_exit = hpx::experimental::scope_exit( + [this] { this->shared_state_.reset(); }); using result_type = typename shared_state_type::result_type; result_type* result = @@ -786,7 +768,9 @@ namespace hpx { // clang-format on return future_type{}; #else - invalidate on_exit(*this); + auto on_exit = hpx::experimental::scope_exit( + [this] { this->shared_state_.reset(); }); + return base_type::then(HPX_MOVE(*this), HPX_FORWARD(F, f), ec); #endif } @@ -821,7 +805,9 @@ namespace hpx { HPX_MOVE(*this), HPX_FORWARD(T0, t0), HPX_FORWARD(F, f), ec)); return future_type{}; #else - invalidate on_exit(*this); + auto on_exit = hpx::experimental::scope_exit( + [this] { this->shared_state_.reset(); }); + return base_type::then( HPX_MOVE(*this), HPX_FORWARD(T0, t0), HPX_FORWARD(F, f), ec); #endif @@ -842,7 +828,9 @@ namespace hpx { alloc, std::move(*this), std::forward(f), ec)); return future_type{}; #else - invalidate on_exit(*this); + auto on_exit = hpx::experimental::scope_exit( + [this] { this->shared_state_.reset(); }); + return base_type::then_alloc( alloc, HPX_MOVE(*this), HPX_FORWARD(F, f), ec); #endif diff --git a/libs/core/include_local/CMakeLists.txt b/libs/core/include_local/CMakeLists.txt index 6bae183b3cfe..fb321730a8b9 100644 --- a/libs/core/include_local/CMakeLists.txt +++ b/libs/core/include_local/CMakeLists.txt @@ -29,6 +29,7 @@ set(include_local_headers hpx/tuple.hpp hpx/type_traits.hpp hpx/unwrap.hpp + hpx/experimental/scope.hpp hpx/experimental/task_group.hpp ) diff --git a/libs/core/include_local/include/hpx/experimental/scope.hpp b/libs/core/include_local/include/hpx/experimental/scope.hpp new file mode 100644 index 000000000000..7bf815dc22d4 --- /dev/null +++ b/libs/core/include_local/include/hpx/experimental/scope.hpp @@ -0,0 +1,28 @@ +// Copyright (c) 2024 Hartmut Kaiser +// +// SPDX-License-Identifier: BSL-1.0 +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#include + +#if defined(HPX_HAVE_CXX26_EXPERIMENTAL_SCOPE) + +#include + +namespace hpx::experimental { + + using std::experimental::scope_exit; + using std::experimental::scope_failure; + using std::experimental::scope_success; +} // namespace hpx::experimental + +#else + +#include +#include +#include + +#endif diff --git a/libs/core/lcos_local/include/hpx/lcos_local/receive_buffer.hpp b/libs/core/lcos_local/include/hpx/lcos_local/receive_buffer.hpp index 53b7921fa5a1..a97370f686c2 100644 --- a/libs/core/lcos_local/include/hpx/lcos_local/receive_buffer.hpp +++ b/libs/core/lcos_local/include/hpx/lcos_local/receive_buffer.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2022 Hartmut Kaiser +// Copyright (c) 2014-2024 Hartmut Kaiser // Copyright (c) 2014 Thomas Heller // // SPDX-License-Identifier: BSL-1.0 @@ -9,11 +9,11 @@ #include #include +#include #include #include #include #include -#include #include #include @@ -74,23 +74,6 @@ namespace hpx::lcos::local { std::map>; using iterator = typename buffer_map_type::iterator; - struct erase_on_exit - { - erase_on_exit(buffer_map_type& buffer_map, iterator it) - : buffer_map_(buffer_map) - , it_(it) - { - } - - ~erase_on_exit() - { - buffer_map_.erase(it_); - } - - buffer_map_type& buffer_map_; - iterator it_; - }; - public: receive_buffer() = default; @@ -127,7 +110,8 @@ namespace hpx::lcos::local { auto& elem = it->second; if (elem->can_be_deleted_) { - erase_on_exit t(buffer_map_, it); + auto on_exit = hpx::experimental::scope_exit( + [this, &it] { buffer_map_.erase(it); }); return it->second->get_future(); } @@ -151,7 +135,8 @@ namespace hpx::lcos::local { { if (f != nullptr) { - erase_on_exit t(buffer_map_, it); + auto on_exit = hpx::experimental::scope_exit( + [this, &it] { buffer_map_.erase(it); }); *f = elem->get_future(); } return true; @@ -181,8 +166,8 @@ namespace hpx::lcos::local { if (!entry->can_be_deleted_) { - // if the future was not retrieved yet mark the entry as - // to be deleted after it was be retrieved + // if the future was not retrieved yet mark the entry as to + // be deleted after it was retrieved entry->can_be_deleted_ = true; } else @@ -298,23 +283,6 @@ namespace hpx::lcos::local { std::map>; using iterator = typename buffer_map_type::iterator; - struct erase_on_exit - { - erase_on_exit(buffer_map_type& buffer_map, iterator it) - : buffer_map_(buffer_map) - , it_(it) - { - } - - ~erase_on_exit() - { - buffer_map_.erase(it_); - } - - buffer_map_type& buffer_map_; - iterator it_; - }; - public: receive_buffer() = default; @@ -323,12 +291,12 @@ namespace hpx::lcos::local { HPX_ASSERT(buffer_map_.empty()); } - receive_buffer(receive_buffer&& other) + receive_buffer(receive_buffer&& other) noexcept : buffer_map_(HPX_MOVE(other.buffer_map_)) { } - receive_buffer& operator=(receive_buffer&& other) + receive_buffer& operator=(receive_buffer&& other) noexcept { if (this != &other) { @@ -349,7 +317,8 @@ namespace hpx::lcos::local { auto& elem = it->second; if (elem->can_be_deleted_) { - erase_on_exit t(buffer_map_, it); + auto on_exit = hpx::experimental::scope_exit( + [this, &it] { buffer_map_.erase(it); }); return elem->get_future(); } @@ -373,7 +342,8 @@ namespace hpx::lcos::local { { if (f != nullptr) { - erase_on_exit t(buffer_map_, it); + auto on_exit = hpx::experimental::scope_exit( + [this, &it] { buffer_map_.erase(it); }); *f = elem->get_future(); } return true; @@ -403,8 +373,8 @@ namespace hpx::lcos::local { if (!entry->can_be_deleted_) { - // if the future was not retrieved yet mark the entry as - // to be deleted after it was be retrieved + // if the future was not retrieved yet mark the entry as to + // be deleted after it was retrieved entry->can_be_deleted_ = true; } else diff --git a/libs/core/lock_registration/src/register_locks.cpp b/libs/core/lock_registration/src/register_locks.cpp index 8cf469a75c59..fe76203f8dea 100644 --- a/libs/core/lock_registration/src/register_locks.cpp +++ b/libs/core/lock_registration/src/register_locks.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // Copyright (c) 2014 Thomas Heller // // SPDX-License-Identifier: BSL-1.0 @@ -9,9 +9,9 @@ #ifdef HPX_HAVE_VERIFY_LOCKS #include +#include #include #include -#include #include #include @@ -121,21 +121,6 @@ namespace hpx::util { bool register_locks::lock_detection_enabled_ = false; std::size_t register_locks::lock_detection_trace_depth_ = HPX_HAVE_THREAD_BACKTRACE_DEPTH; - - struct reset_lock_enabled_on_exit - { - reset_lock_enabled_on_exit() - : old_value_(register_locks::get_lock_enabled()) - { - register_locks::set_lock_enabled(false); - } - ~reset_lock_enabled_on_exit() - { - register_locks::set_lock_enabled(old_value_); - } - - bool old_value_; - }; } // namespace detail // retrieve the current thread_local data about held locks @@ -290,7 +275,12 @@ namespace hpx::util { { // Temporarily disable verifying locks in case verify_no_locks // gets called recursively. - detail::reset_lock_enabled_on_exit e; + auto old_value = detail::register_locks::get_lock_enabled(); + + detail::register_locks::set_lock_enabled(false); + auto on_exit = hpx::experimental::scope_exit([old_value] { + detail::register_locks::set_lock_enabled(old_value); + }); if (detail::some_locks_are_not_ignored(held_locks)) { @@ -346,7 +336,7 @@ namespace hpx::util { held_locks.find(lock); if (it == held_locks.end()) { - // this can happen if the lock was registered to be ignore + // this can happen if the lock was registered to be ignored // on a different OS thread // HPX_THROW_EXCEPTION( // hpx::error::invalid_status, "set_ignore_status", diff --git a/libs/core/runtime_local/include/hpx/runtime_local/runtime_local.hpp b/libs/core/runtime_local/include/hpx/runtime_local/runtime_local.hpp index 710f64c4a9b5..bb3175b615f7 100644 --- a/libs/core/runtime_local/include/hpx/runtime_local/runtime_local.hpp +++ b/libs/core/runtime_local/include/hpx/runtime_local/runtime_local.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // Copyright (c) 2011 Bryce Lelbach // // SPDX-License-Identifier: BSL-1.0 diff --git a/libs/core/threading_base/src/execution_agent.cpp b/libs/core/threading_base/src/execution_agent.cpp index cb55d7fb0846..d4e642109c65 100644 --- a/libs/core/threading_base/src/execution_agent.cpp +++ b/libs/core/threading_base/src/execution_agent.cpp @@ -1,4 +1,5 @@ // Copyright (c) 2019 Thomas Heller +// Copyright (c) 2020-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -11,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -29,7 +31,6 @@ #include #include -#include #include #include @@ -131,27 +132,6 @@ namespace hpx::threads { } while (now < sleep_time.value()); } -#if defined(HPX_HAVE_VERIFY_LOCKS) - struct on_exit_reset_held_lock_data - { - on_exit_reset_held_lock_data() - : data_(hpx::util::get_held_locks_data()) - { - } - - ~on_exit_reset_held_lock_data() - { - hpx::util::set_held_locks_data(HPX_MOVE(data_)); - } - - std::unique_ptr data_; - }; -#else - struct on_exit_reset_held_lock_data - { - }; -#endif - hpx::threads::thread_restart_state execution_agent::do_yield( char const* desc, threads::thread_schedule_state state) { @@ -182,15 +162,19 @@ namespace hpx::threads { threads::thread_restart_state statex; { -#ifdef HPX_HAVE_THREAD_DESCRIPTION +#if defined(HPX_HAVE_THREAD_DESCRIPTION) [[maybe_unused]] threads::detail::reset_lco_description reset_desc( id.noref(), threads::thread_description(desc)); #endif -#ifdef HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION +#if defined(HPX_HAVE_THREAD_BACKTRACE_ON_SUSPENSION) [[maybe_unused]] threads::detail::reset_backtrace reset_bt(id); #endif - [[maybe_unused]] on_exit_reset_held_lock_data held_locks; - +#if defined(HPX_HAVE_VERIFY_LOCKS) + [[maybe_unused]] auto held_locks = hpx::experimental::scope_exit( + [data = hpx::util::get_held_locks_data()] mutable { + hpx::util::set_held_locks_data(HPX_MOVE(data)); + }); +#endif HPX_ASSERT(thrd_data != nullptr && thrd_data->get_state().state() == thread_schedule_state::active); diff --git a/libs/full/agas_base/include/hpx/agas_base/server/locality_namespace.hpp b/libs/full/agas_base/include/hpx/agas_base/server/locality_namespace.hpp index 33d58a8c2cb0..ac013919a98d 100644 --- a/libs/full/agas_base/include/hpx/agas_base/server/locality_namespace.hpp +++ b/libs/full/agas_base/include/hpx/agas_base/server/locality_namespace.hpp @@ -65,10 +65,8 @@ namespace hpx { namespace agas { namespace server { std::uint32_t prefix_counter_; primary_namespace* primary_; - struct update_time_on_exit; - public: - // data structure holding all counters for the omponent_namespace + // data structure holding all counters for the component_namespace // component struct counter_data { diff --git a/libs/full/agas_base/include/hpx/agas_base/server/primary_namespace.hpp b/libs/full/agas_base/include/hpx/agas_base/server/primary_namespace.hpp index 8d0489e131a2..c05c07408d11 100644 --- a/libs/full/agas_base/include/hpx/agas_base/server/primary_namespace.hpp +++ b/libs/full/agas_base/include/hpx/agas_base/server/primary_namespace.hpp @@ -148,8 +148,6 @@ namespace hpx::agas::server { naming::gid_type locality_; // our locality id migration_table_type migrating_objects_; - struct update_time_on_exit; - public: // data structure holding all counters for the component_namespace // component diff --git a/libs/full/components_base/include/hpx/components_base/server/migration_support.hpp b/libs/full/components_base/include/hpx/components_base/server/migration_support.hpp index 9cc6d7a5508a..23870c6fe93f 100644 --- a/libs/full/components_base/include/hpx/components_base/server/migration_support.hpp +++ b/libs/full/components_base/include/hpx/components_base/server/migration_support.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2023 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -144,34 +145,13 @@ namespace hpx::components { } } - private: - struct release_on_exit - { - explicit release_on_exit( - detail::migration_support_data* data) noexcept - : data_(data) - { - } - - release_on_exit(release_on_exit const&) = delete; - release_on_exit(release_on_exit&&) = delete; - release_on_exit& operator=(release_on_exit const&) = delete; - release_on_exit& operator=(release_on_exit&&) = delete; - - ~release_on_exit() - { - intrusive_ptr_release(data_); - } - - detail::migration_support_data* data_; - }; - public: bool unpin() { // pin() acquired an additional reference count that needs to be // released after unpinning. - release_on_exit _(data_.get()); + auto on_exit = hpx::experimental::scope_exit( + [&] { intrusive_ptr_release(data_); }); { // no need to go through AGAS if the object is currently pinned diff --git a/libs/full/runtime_components/tests/unit/components/action_invoke_no_more_than.hpp b/libs/full/runtime_components/tests/unit/components/action_invoke_no_more_than.hpp index 4fb82f6d2d8f..03fede783152 100644 --- a/libs/full/runtime_components/tests/unit/components/action_invoke_no_more_than.hpp +++ b/libs/full/runtime_components/tests/unit/components/action_invoke_no_more_than.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2024 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -25,31 +26,13 @@ #include #include -namespace hpx { namespace actions { namespace detail { - /////////////////////////////////////////////////////////////////////////// - template - struct signal_on_exit - { - signal_on_exit(Semaphore& sem) - : sem_(sem) - { - sem_.wait(); - } - - ~signal_on_exit() - { - sem_.signal(); - } - - private: - Semaphore& sem_; - }; +namespace hpx::actions::detail { /////////////////////////////////////////////////////////////////////////// template struct action_decorate_function_semaphore { - typedef hpx::counting_semaphore_var semaphore_type; + using semaphore_type = hpx::counting_semaphore_var; struct tag { @@ -67,19 +50,20 @@ namespace hpx { namespace actions { namespace detail { struct action_decorate_function { static constexpr bool value = true; + // This wrapper is needed to stop infinite recursion when // trying to get the possible additional function decoration // from the component struct action_wrapper { - typedef typename Action::component_type component_type; + using component_type = typename Action::component_type; }; static_assert(!Action::direct_execution::value, "explicit decoration of direct actions is not supported"); - typedef action_decorate_function_semaphore - construct_semaphore_type; + using construct_semaphore_type = + action_decorate_function_semaphore; // If the action returns something which is not a future, we inject // a semaphore into the call graph. @@ -87,11 +71,10 @@ namespace hpx { namespace actions { namespace detail { threads::thread_restart_state state, threads::thread_function_type f) { - typedef typename construct_semaphore_type::semaphore_type - semaphore_type; + construct_semaphore_type::get_sem().wait(); + auto on_exit = hpx::experimental::scope_exit( + [] { construct_semaphore_type::get_sem().signal(); }); - signal_on_exit on_exit( - construct_semaphore_type::get_sem()); return f(state); } @@ -159,7 +142,7 @@ namespace hpx { namespace actions { namespace detail { template void serialize(Archive& ar, unsigned int) { - ar& addr_; + ar & addr_; } }; @@ -197,24 +180,22 @@ namespace hpx { namespace actions { namespace detail { } } }; -}}} // namespace hpx::actions::detail +} // namespace hpx::actions::detail /////////////////////////////////////////////////////////////////////////////// #define HPX_ACTION_INVOKE_NO_MORE_THAN(action, maxnum) \ - namespace hpx { namespace traits { \ - template <> \ - struct action_decorate_function \ - : hpx::actions::detail::action_decorate_function \ - { \ - }; \ + namespace hpx::traits { \ + template <> \ + struct action_decorate_function \ + : hpx::actions::detail::action_decorate_function \ + { \ + }; \ \ - template <> \ - struct action_decorate_continuation \ - : hpx::actions::detail::action_decorate_continuation \ - { \ - }; \ - } \ + template <> \ + struct action_decorate_continuation \ + : hpx::actions::detail::action_decorate_continuation \ + { \ + }; \ } \ /**/