From 334df4e48409405f98bdab66035d1a95e8a80f81 Mon Sep 17 00:00:00 2001 From: dimitraka Date: Thu, 9 Mar 2023 14:04:25 +0100 Subject: [PATCH 01/32] Remove lock mutex --- examples/quickstart/mutex_docs.cpp | 6 ++---- examples/quickstart/shared_mutex.cpp | 31 +++++++++++++++------------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/examples/quickstart/mutex_docs.cpp b/examples/quickstart/mutex_docs.cpp index 0aad5e44be9d..041ca144e20c 100644 --- a/examples/quickstart/mutex_docs.cpp +++ b/examples/quickstart/mutex_docs.cpp @@ -18,15 +18,13 @@ int hpx_main() hpx::mutex m; hpx::future f1 = hpx::async([&m]() { - m.lock(); + std::scoped_lock sl(m); std::cout << "Thread 1 acquired the mutex" << std::endl; - m.unlock(); }); hpx::future f2 = hpx::async([&m]() { - m.lock(); + std::scoped_lock sl(m); std::cout << "Thread 2 acquired the mutex" << std::endl; - m.unlock(); }); hpx::wait_all(f1, f2); diff --git a/examples/quickstart/shared_mutex.cpp b/examples/quickstart/shared_mutex.cpp index caefd8ed85af..55cb9f4d51dd 100644 --- a/examples/quickstart/shared_mutex.cpp +++ b/examples/quickstart/shared_mutex.cpp @@ -49,13 +49,16 @@ int hpx_main() for (int j = 0; j < cycles; ++j) { - std::unique_lock ul(stm); + // scope of unique_lock + { + std::unique_lock ul(stm); - std::cout << "^^^ Writer " << i << " starting..." << std::endl; - hpx::this_thread::sleep_for(milliseconds(dist(urng))); - std::cout << "vvv Writer " << i << " finished." << std::endl; - - ul.unlock(); + std::cout << "^^^ Writer " << i << " starting..." + << std::endl; + hpx::this_thread::sleep_for(milliseconds(dist(urng))); + std::cout << "vvv Writer " << i << " finished." + << std::endl; + } hpx::this_thread::sleep_for(milliseconds(dist(urng))); } @@ -76,14 +79,14 @@ int hpx_main() for (int j = 0; j < cycles; ++j) { - std::shared_lock sl(stm); - - std::cout << "Reader " << i << " starting..." << std::endl; - hpx::this_thread::sleep_for(milliseconds(dist(urng))); - std::cout << "Reader " << i << " finished." << std::endl; - - sl.unlock(); - + // scope of shared_lock + { + std::shared_lock sl(stm); + + std::cout << "Reader " << i << " starting..." << std::endl; + hpx::this_thread::sleep_for(milliseconds(dist(urng))); + std::cout << "Reader " << i << " finished." << std::endl; + } hpx::this_thread::sleep_for(milliseconds(dist(urng))); } }); From b92a877bf6be3c24c8d99a23a6817bc98c2e7864 Mon Sep 17 00:00:00 2001 From: dimitraka Date: Thu, 9 Mar 2023 14:05:39 +0100 Subject: [PATCH 02/32] Update docs --- .../writing_single_node_hpx_applications.rst | 79 ++++++++++--------- 1 file changed, 43 insertions(+), 36 deletions(-) diff --git a/docs/sphinx/manual/writing_single_node_hpx_applications.rst b/docs/sphinx/manual/writing_single_node_hpx_applications.rst index 8f859689ef74..7184cf773041 100644 --- a/docs/sphinx/manual/writing_single_node_hpx_applications.rst +++ b/docs/sphinx/manual/writing_single_node_hpx_applications.rst @@ -137,9 +137,21 @@ is released. The code below shows the basic use of mutexes: :start-after: //[mutex_docs :end-before: //] -In this example, two |hpx| threads created using ``hpx::async`` are acquiring a ``hpx::mutex m``. The ``m.lock()`` -function is called before accessing the shared resource, and ``m.unlock()`` is called after the access is complete. -This ensures that only one thread can access the shared resource at a time. +In this example, two |hpx| threads created using ``hpx::async`` are acquiring a ``hpx::mutex m``. +``std::scoped_lock sl(m)`` is used to take ownership of the given mutex ``m``. When control leaves +the scope in which the ``scoped_lock`` object was created, the ``scoped_lock`` is destructed and +the mutex is released. + +.. attention:: + + A common way to acquire and release mutexes is by using the function ``m.lock()`` before accessing + the shared resource, and ``m.unlock()`` called after the access is complete. However, these functions + may lead to deadlocks in case of exception(s). That is, if an exception happens when the mutex is locked + then the code that unlocks the mutex will never be executed, the lock will remain held by the thread + that acquired it, and other threads will be unable to access the shared resource. This can cause a + deadlock if the other threads are also waiting to acquire the same lock. For this reason, we suggest + you use ``std::scoped_lock``, which prevents this issue by releasing the lock when control leaves the + scope in which the ``scoped_lock`` object was created. .. _shared_mutex: @@ -175,9 +187,9 @@ Both the writer and reader threads use the ``hpx::shared_mutex`` object ``stm`` resource. * For the writer threads, a ``unique_lock`` on the shared mutex is acquired before each write operation and is released - after the operation is complete. + after control leaves the scope in which the ``unique_lock`` object was created. * For the reader threads, a ``shared_lock`` on the shared mutex is acquired before each read operation and is released - after the operation is complete. + after control leaves the scope in which the ``shared_lock`` object was created. Before each operation, both the reader and writer threads sleep for a random time period, which is generated using a random number generator. The random time period simulates the processing time of the operation. @@ -196,7 +208,7 @@ access to a shared resource. The two types of semaphores are: the counter by releasing the semaphore. Unlike ``hpx::mutex``, an ``hpx::counting_semaphore`` is not bound to a thread, which means that the acquire and release call of a semaphore can happen on different threads. * binary semaphore: it is an alias for a ``hpx::counting_semaphore<1>``. In this case, the least maximal value - is 1. ``hpx::binary_semaphores`` can be used to implement locks. + is 1. ``hpx::binary_semaphore`` can be used to implement locks. .. literalinclude:: ../../examples/quickstart/counting_semaphore_docs.cpp :language: c++ @@ -232,8 +244,8 @@ To call an application with a single guard, simply declare the guard and call If a single method needs to run with multiple guards, use a guard set:: - boost::shared gu1(new hpx::lcos::local::guard()); - boost::shared gu2(new hpx::lcos::local::guard()); + std::shared_ptr gu1(new hpx::lcos::local::guard()); + std::shared_ptr gu2(new hpx::lcos::local::guard()); gs.add(*gu1); gs.add(*gu2); run_guarded(gs,task); @@ -641,8 +653,8 @@ the ``wait()`` method to synchronize the tasks and wait for them to complete. .. note:: - `task groups` and `task blocks`` are both ways to group and synchronize parallel tasks, but - `task groups`` are used to group multiple tasks together as a single unit, while `task blocks`` + `task groups` and `task blocks` are both ways to group and synchronize parallel tasks, but + `task groups` are used to group multiple tasks together as a single unit, while `task blocks` are used to execute a loop in parallel, with each iteration of the loop executing in a separate task. If the difference is not clear yet, continue reading. @@ -667,7 +679,7 @@ such as futures or shared data structures. The example below demonstrates how to launch multiple threads and synchronize them using a ``hpx::latch`` object. It also shows how to query the state of threads and wait for futures to complete. -.. literalinclude:: ../../examples/quickstart/task_group_docs.cpp +.. literalinclude:: ../../examples/quickstart/enumerate_threads.cpp :language: c++ :start-after: //[threads_docs :end-before: //] @@ -726,16 +738,8 @@ Using parallel algorithms .. |exception_list| replace:: :cpp:class:`hpx::exception_list` .. |for_each| replace:: :cpp:class:`hpx::for_each` -A parallel algorithm is a function template described by this document -which is declared in the (inline) namespace ``hpx::parallel``. - -.. note:: - - For compilers that do not support inline namespaces, all of the ``namespace - v1`` is imported into the namespace ``hpx::parallel``. The effect is similar - to what inline namespaces would do, namely all names defined in - ``hpx::parallel`` are accessible from the namespace ``hpx::parallel`` as - well. +A parallel algorithm is a function template declared in the namespace +``hpx::parallel``. All parallel algorithms are very similar in semantics to their sequential counterparts (as defined in the ``namespace std``) with an additional formal @@ -760,19 +764,6 @@ thread. It is the caller's responsibility to ensure correctness, such as making sure that the invocation does not introduce data races or deadlocks. -The applications of function objects in parallel algorithms invoked with an -execution policy of type |parallel_unsequenced_execution_policy| is, in |hpx|, -equivalent to the use of the execution policy |parallel_execution_policy|. - -Algorithms invoked with an execution policy object of type |execution_policy| -execute internally as if invoked with the contained execution policy object. No -exception is thrown when an |execution_policy| contains an execution policy of -type |sequenced_task_execution_policy| or |parallel_task_execution_policy| -(which normally turn the algorithm into its asynchronous version). In this case -the execution is semantically equivalent to the case of passing a -|sequenced_execution_policy| or |parallel_execution_policy| contained in the -|execution_policy| object respectively. - Parallel exceptions ------------------- @@ -876,6 +867,8 @@ Parallel algorithms * Searches for a number consecutive copies of an element in a range. * :cppreference-algorithm:`search_n` +| + .. list-table:: Modifying parallel algorithms of header :ref:`public_api_header_hpx_algorithm` :widths: 25 55 20 @@ -968,6 +961,8 @@ Parallel algorithms * Copies the elements from one range to another in such a way that there are no consecutive equal elements. * :cppreference-algorithm:`unique_copy` +| + .. list-table:: Set operations on sorted sequences of header :ref:`public_api_header_hpx_algorithm` :widths: 25 55 20 @@ -996,6 +991,8 @@ Parallel algorithms * Computes the union of two sets. * :cppreference-algorithm:`set_union` +| + .. list-table:: Heap operations of header :ref:`public_api_header_hpx_algorithm` :widths: 25 55 20 @@ -1028,6 +1025,8 @@ Parallel algorithms * Returns the smallest and the largest element in a range. * :cppreference-algorithm:`minmax_element` +| + .. list-table:: Partitioning Operations of header :ref:`public_api_header_hpx_algorithm` :widths: 25 55 20 @@ -1050,6 +1049,8 @@ Parallel algorithms * Divides elements into two groups while preserving their relative order. * :cppreference-algorithm:`stable_partition` +| + .. list-table:: Sorting Operations of header :ref:`public_api_header_hpx_algorithm` :widths: 25 55 20 @@ -1078,6 +1079,8 @@ Parallel algorithms * Sorts one range of data using keys supplied in another range. * +| + .. list-table:: Numeric Parallel Algorithms of header :ref:`public_api_header_hpx_numeric` :widths: 25 55 20 @@ -1106,6 +1109,7 @@ Parallel algorithms * Sums up a range of elements after applying a function. Also, accumulates the inner products of two input ranges. * :cppreference-algorithm:`transform_reduce` +| .. list-table:: Dynamic Memory Management of header :ref:`public_api_header_hpx_memory` :widths: 25 55 20 @@ -1150,6 +1154,8 @@ Parallel algorithms * Constructs objects in an uninitialized area of memory. * :cppreference-memory:`uninitialized_value_construct_n` +| + .. list-table:: Index-based for-loops of header :ref:`public_api_header_hpx_algorithm` * * Name @@ -1195,8 +1201,9 @@ number of cores ``num_cores`` and tasks to schedule is given by ``num_tasks``. The lambda function exposes a means of test-probing the execution of a single iteration for performance measurement purposes. The execution parameter type might dynamically determine the execution time of one or more tasks in order -to calculate the chunk size; see :cpp:class:`hpx::execution::auto_chunk_size` -for an example of this executor parameter type. +to calculate the chunk size; see +:cpp:class:`hpx::execution::experimental::auto_chunk_size` for an example of +this executor parameter type. Other functions in the interface exist to discover whether an executor parameter type should be invoked once (i.e., it returns a static chunk size; see From f71dafb2441602b61898618c97d3528830572782 Mon Sep 17 00:00:00 2001 From: dimitraka Date: Thu, 9 Mar 2023 19:18:32 +0100 Subject: [PATCH 03/32] Document future functions --- .../futures/include/hpx/futures/future.hpp | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/libs/core/futures/include/hpx/futures/future.hpp b/libs/core/futures/include/hpx/futures/future.hpp index b786cc7a6d72..0cddf5851990 100644 --- a/libs/core/futures/include/hpx/futures/future.hpp +++ b/libs/core/futures/include/hpx/futures/future.hpp @@ -919,6 +919,47 @@ namespace hpx { using base_type::is_ready; using base_type::valid; + /// \brief Attaches a continuation to \a *this. The behavior is undefined + /// if \a *this has no associated shared state (i.e., + /// \a valid()==false ). + /// \details In cases where \a decltype(func(*this)) is \a future, + /// the resulting type is \a future instead of + /// \a future>. + /// Effects: + /// - The continuation is called when the object's shared + /// state is ready (has a value or exception stored). + /// - The continuation launches according to the specified + /// launch policy or executor. + /// - When the executor or launch policy is not provided the + /// continuation inherits the parent's launch policy or + /// executor. + /// - If the parent was created with \a std::promise or with a + /// packaged_task (has no associated launch policy), the + /// continuation behaves the same as the third overload + /// with a policy argument of \a launch::async | + /// \a launch::deferred and the same argument for \a func. + /// - If the parent has a policy of \a launch::deferred and the + /// continuation does not have a specified launch policy or + /// scheduler, then the parent is filled by immediately + /// calling \a .wait(), and the policy of the antecedent is + /// \a launch::deferred + /// + /// \tparam F The type of the function/function object to use + /// (deduced). F must meet requirements of + /// \a MoveConstructible. + /// \tparam error_code The type of error code. + /// + /// \param f A continuation to be attached. + /// \param ec Used to hold error code value originated during the + /// operation. Defaults to \a throws -- A special + /// 'throw on error' \a error_code. + /// \returns An object of type \a future that + /// refers to the shared state created by the continuation. + /// \note Postcondition: + /// - The future object is moved to the parameter of the + /// continuation function. + /// - valid() == false on original future object immediately + /// after it returns. template decltype(auto) then(F&& f, error_code& ec = throws) { @@ -940,6 +981,27 @@ namespace hpx { #endif } + /// \copybrief hpx::future::then(F&& f, error_code& ec = throws) + /// \copydetail hpx::future::then(F&& f, error_code& ec = throws) + /// + /// \tparam T0 The type of executor or launch policy. + /// \tparam F The type of the function/function object to use + /// (deduced). F must meet requirements of + /// \a MoveConstructible. + /// \tparam error_code The type of error code. + /// + /// \param t0 The executor or launch policy to be used. + /// \param f A continuation to be attached. + /// \param ec Used to hold error code value originated during the + /// operation. Defaults to \a throws -- A special + /// 'throw on error' \a error_code. + /// \returns An object of type \a future that + /// refers to the shared state created by the continuation. + /// \note Postcondition: + /// - The future object is moved to the parameter of the + /// continuation function. + /// - valid() == false on original future object immediately + /// after it returns. template decltype(auto) then(T0&& t0, F&& f, error_code& ec = throws) { @@ -1202,6 +1264,7 @@ namespace hpx { using base_type::is_ready; using base_type::valid; + /// \copydoc hpx::future::then(F&& f, error_code& ec = throws) template decltype(auto) then(F&& f, error_code& ec = throws) const { @@ -1217,6 +1280,7 @@ namespace hpx { #endif } + /// \copydoc hpx::future::then(T0&& t0, F&& f, error_code& ec = throws) template decltype(auto) then(T0&& t0, F&& f, error_code& ec = throws) const { From 9d51a9373cfd5cb6ca450f13c9cd9dc451720354 Mon Sep 17 00:00:00 2001 From: dimitraka Date: Thu, 9 Mar 2023 19:18:55 +0100 Subject: [PATCH 04/32] Add for_each example --- examples/quickstart/CMakeLists.txt | 1 + examples/quickstart/for_each_docs.cpp | 38 +++++++++++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 examples/quickstart/for_each_docs.cpp diff --git a/examples/quickstart/CMakeLists.txt b/examples/quickstart/CMakeLists.txt index 67a4e0b7d91d..b86d8b748a98 100644 --- a/examples/quickstart/CMakeLists.txt +++ b/examples/quickstart/CMakeLists.txt @@ -18,6 +18,7 @@ set(example_programs fibonacci_futures fibonacci_local file_serialization + for_each_docs hello_world_3 latch_local local_channel_docs diff --git a/examples/quickstart/for_each_docs.cpp b/examples/quickstart/for_each_docs.cpp new file mode 100644 index 000000000000..17d8af69940a --- /dev/null +++ b/examples/quickstart/for_each_docs.cpp @@ -0,0 +1,38 @@ +// Copyright (c) 2023 Dimitra Karatza +// +// 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) + +// This example is meant for inclusion in the documentation. + +//[for_each_docs + +#include +#include +#include +#include + +int hpx_main() +{ + std::vector v{1, 2, 3, 4, 5}; + + auto print = [](const int& n) { std::cout << n << ' '; }; + + std::cout << "Print sequential: "; + hpx::for_each(v.begin(), v.end(), print); + std::cout << '\n'; + + std::cout << "Print parallel: "; + hpx::for_each(hpx::execution::par, v.begin(), v.end(), print); + std::cout << '\n'; + + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + return hpx::local::init(hpx_main, argc, argv); +} + +//] From 95bbf4b8b79eef9a71d20488332e52f73a4a2295 Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Sun, 26 Mar 2023 19:01:07 -0500 Subject: [PATCH 05/32] Modernize modules of level 11, 12, and 13 --- cmake/HPX_AddConfigTest.cmake | 9 + cmake/HPX_PerformCxxFeatureTests.cmake | 2 + cmake/tests/cxx20_std_bit_cast.cpp | 18 ++ .../batch_environments/batch_environment.hpp | 1 - .../batch_environments/pbs_environment.hpp | 2 +- .../src/alps_environment.cpp | 6 +- .../src/batch_environment.cpp | 24 +- .../src/pbs_environment.cpp | 34 +-- .../src/pjm_environment.cpp | 7 +- .../src/slurm_environment.cpp | 2 +- libs/core/concurrency/CMakeLists.txt | 1 + .../include/hpx/concurrency/barrier.hpp | 10 +- .../hpx/concurrency/cache_line_data.hpp | 6 +- .../include/hpx/concurrency/deque.hpp | 19 +- .../hpx/concurrency/detail/freelist.hpp | 6 +- .../hpx/concurrency/detail/freelist_stack.hpp | 46 ++-- .../concurrency/detail/tagged_ptr_dcas.hpp | 19 +- .../concurrency/detail/tagged_ptr_pair.hpp | 136 +++++++----- .../detail/tagged_ptr_ptrcompression.hpp | 63 ++++-- .../include/hpx/concurrency/queue.hpp | 12 +- .../include/hpx/concurrency/spinlock_pool.hpp | 8 +- .../include/hpx/concurrency/stack.hpp | 8 +- libs/core/concurrency/src/barrier.cpp | 7 +- libs/core/coroutines/CMakeLists.txt | 1 + .../include/hpx/coroutines/coroutine.hpp | 18 +- .../include/hpx/coroutines/coroutine_fwd.hpp | 2 - .../detail/combined_tagged_state.hpp | 26 +-- .../hpx/coroutines/detail/context_base.hpp | 28 +-- .../detail/context_generic_context.hpp | 29 ++- .../hpx/coroutines/detail/context_posix.hpp | 4 +- .../hpx/coroutines/detail/coroutine_impl.hpp | 11 +- .../hpx/coroutines/detail/coroutine_self.hpp | 15 +- .../detail/coroutine_stackful_self.hpp | 2 - .../detail/coroutine_stackless_self.hpp | 2 - .../hpx/coroutines/detail/posix_utility.hpp | 2 +- .../hpx/coroutines/stackless_coroutine.hpp | 33 +-- .../include/hpx/coroutines/thread_id_type.hpp | 97 +++----- .../coroutines/src/detail/coroutine_self.cpp | 6 +- .../coroutines/src/detail/posix_utility.cpp | 8 +- libs/core/coroutines/src/thread_id_type.cpp | 70 ++++++ .../include/hpx/execution_base/agent_base.hpp | 4 +- .../include/hpx/execution_base/agent_ref.hpp | 33 +-- .../include/hpx/execution_base/any_sender.hpp | 59 +++-- .../execution_base/completion_signatures.hpp | 111 ++++++---- .../hpx/execution_base/context_base.hpp | 3 - .../hpx/execution_base/coroutine_utils.hpp | 26 +-- .../include/hpx/execution_base/receiver.hpp | 94 ++++---- .../include/hpx/execution_base/sender.hpp | 8 +- .../hpx/execution_base/this_thread.hpp | 10 +- .../traits/coroutine_traits.hpp | 2 +- libs/core/execution_base/src/agent_ref.cpp | 16 +- .../src/spinlock_deadlock_detection.cpp | 5 +- libs/core/execution_base/src/this_thread.cpp | 14 +- libs/core/ini/include/hpx/ini/ini.hpp | 19 +- libs/core/ini/src/ini.cpp | 207 +++++++++--------- .../prefix/include/hpx/prefix/find_prefix.hpp | 13 +- libs/core/prefix/src/find_prefix.cpp | 7 +- .../include/hpx/modules/program_options.hpp | 8 +- .../include/hpx/program_options/cmdline.hpp | 8 +- .../include/hpx/program_options/config.hpp | 7 +- .../hpx/program_options/detail/cmdline.hpp | 38 ++-- .../program_options/detail/config_file.hpp | 25 ++- .../hpx/program_options/detail/convert.hpp | 34 +-- .../hpx/program_options/detail/parsers.hpp | 12 +- .../detail/utf8_codecvt_facet.hpp | 11 +- .../program_options/detail/value_semantic.hpp | 18 +- .../program_options/environment_iterator.hpp | 8 +- .../hpx/program_options/eof_iterator.hpp | 11 +- .../include/hpx/program_options/errors.hpp | 31 +-- .../include/hpx/program_options/option.hpp | 8 +- .../program_options/options_description.hpp | 8 +- .../include/hpx/program_options/parsers.hpp | 31 +-- .../program_options/positional_options.hpp | 8 +- .../hpx/program_options/value_semantic.hpp | 19 +- .../hpx/program_options/variables_map.hpp | 22 +- .../include/hpx/program_options/version.hpp | 8 +- libs/core/program_options/src/cmdline.cpp | 165 +++++++------- libs/core/program_options/src/config_file.cpp | 35 +-- libs/core/program_options/src/convert.cpp | 14 +- .../src/options_description.cpp | 94 ++++---- libs/core/program_options/src/parsers.cpp | 26 ++- .../src/positional_options.cpp | 8 +- libs/core/program_options/src/split.cpp | 8 +- .../src/utf8_codecvt_facet.cpp | 11 +- .../program_options/src/value_semantic.cpp | 52 +++-- .../program_options/src/variables_map.cpp | 47 ++-- libs/core/program_options/src/winmain.cpp | 15 +- .../tests/unit/options_exception.cpp | 2 +- .../static_reinit/reinitializable_static.hpp | 9 +- libs/core/static_reinit/src/static_reinit.cpp | 6 +- .../testing/include/hpx/modules/testing.hpp | 4 +- .../include/hpx/testing/performance.hpp | 2 +- libs/core/testing/src/performance.cpp | 13 +- libs/core/testing/src/testing.cpp | 27 ++- libs/core/type_support/CMakeLists.txt | 1 + .../include/hpx/type_support/bit_cast.hpp | 68 ++++++ libs/core/version/include/hpx/version.hpp | 38 ++-- libs/core/version/src/version.cpp | 4 +- .../include/hpx/parcelport_mpi/header.hpp | 4 +- 99 files changed, 1336 insertions(+), 1063 deletions(-) create mode 100644 cmake/tests/cxx20_std_bit_cast.cpp create mode 100644 libs/core/coroutines/src/thread_id_type.cpp create mode 100644 libs/core/type_support/include/hpx/type_support/bit_cast.hpp diff --git a/cmake/HPX_AddConfigTest.cmake b/cmake/HPX_AddConfigTest.cmake index 1220e4f0bbc1..8fa35e969aad 100644 --- a/cmake/HPX_AddConfigTest.cmake +++ b/cmake/HPX_AddConfigTest.cmake @@ -587,6 +587,15 @@ function(hpx_check_for_cxx20_std_default_sentinel) ) endfunction() +# ############################################################################## +function(hpx_check_for_cxx20_std_bit_cast) + add_hpx_config_test( + HPX_WITH_CXX20_STD_BIT_CAST + SOURCE cmake/tests/cxx20_std_bit_cast.cpp + FILE ${ARGN} + ) +endfunction() + # ############################################################################## function(hpx_check_for_cxx23_std_generator) add_hpx_config_test( diff --git a/cmake/HPX_PerformCxxFeatureTests.cmake b/cmake/HPX_PerformCxxFeatureTests.cmake index f2f6071b9e8c..851c44f6cdd2 100644 --- a/cmake/HPX_PerformCxxFeatureTests.cmake +++ b/cmake/HPX_PerformCxxFeatureTests.cmake @@ -144,6 +144,8 @@ function(hpx_perform_cxx_feature_tests) hpx_check_for_cxx20_std_default_sentinel( DEFINITIONS HPX_HAVE_CXX20_STD_DEFAULT_SENTINEL ) + + hpx_check_for_cxx20_std_bit_cast(DEFINITIONS HPX_HAVE_CXX20_STD_BIT_CAST) endif() if(HPX_WITH_CXX_STANDARD GREATER_EQUAL 23) diff --git a/cmake/tests/cxx20_std_bit_cast.cpp b/cmake/tests/cxx20_std_bit_cast.cpp new file mode 100644 index 000000000000..5a79e6d1568f --- /dev/null +++ b/cmake/tests/cxx20_std_bit_cast.cpp @@ -0,0 +1,18 @@ +// Copyright (c) 2023 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 if std::bit_cast is available + +#include +#include + +int main() +{ + float a = 42.0; + std::uint32_t i = std::bit_cast(a); + (void) i; + return 0; +} diff --git a/libs/core/batch_environments/include/hpx/batch_environments/batch_environment.hpp b/libs/core/batch_environments/include/hpx/batch_environments/batch_environment.hpp index 6786cb5a2fba..81a45b7c2633 100644 --- a/libs/core/batch_environments/include/hpx/batch_environments/batch_environment.hpp +++ b/libs/core/batch_environments/include/hpx/batch_environments/batch_environment.hpp @@ -12,7 +12,6 @@ #include #include -#include #include #include #include diff --git a/libs/core/batch_environments/include/hpx/batch_environments/pbs_environment.hpp b/libs/core/batch_environments/include/hpx/batch_environments/pbs_environment.hpp index 69f75f6e1ee3..2d37f0a503ed 100644 --- a/libs/core/batch_environments/include/hpx/batch_environments/pbs_environment.hpp +++ b/libs/core/batch_environments/include/hpx/batch_environments/pbs_environment.hpp @@ -49,6 +49,6 @@ namespace hpx::util::batch_environments { HPX_CORE_EXPORT void read_nodefile( std::vector& nodelist, bool have_mpi, bool debug); HPX_CORE_EXPORT void read_nodelist( - std::vector& nodelist, bool debug); + std::vector const& nodelist, bool debug); }; } // namespace hpx::util::batch_environments diff --git a/libs/core/batch_environments/src/alps_environment.cpp b/libs/core/batch_environments/src/alps_environment.cpp index 03bdd555f167..c70222e56d1b 100644 --- a/libs/core/batch_environments/src/alps_environment.cpp +++ b/libs/core/batch_environments/src/alps_environment.cpp @@ -21,7 +21,7 @@ namespace hpx::util::batch_environments { , num_localities_(0) , valid_(false) { - char* node_num = std::getenv("ALPS_APP_PE"); + char const* node_num = std::getenv("ALPS_APP_PE"); valid_ = node_num != nullptr; if (valid_) { @@ -29,7 +29,7 @@ namespace hpx::util::batch_environments { node_num_ = from_string(node_num); // Get the number of threads - char* num_threads = std::getenv("ALPS_APP_DEPTH"); + char const* num_threads = std::getenv("ALPS_APP_DEPTH"); if (!num_threads) { valid_ = false; @@ -38,7 +38,7 @@ namespace hpx::util::batch_environments { num_threads_ = from_string(num_threads); // Get the number of localities - char* total_num_threads = std::getenv("PBS_NP"); + char const* total_num_threads = std::getenv("PBS_NP"); if (!total_num_threads) { valid_ = false; diff --git a/libs/core/batch_environments/src/batch_environment.cpp b/libs/core/batch_environments/src/batch_environment.cpp index fceac2995180..f51c696858ca 100644 --- a/libs/core/batch_environments/src/batch_environment.cpp +++ b/libs/core/batch_environments/src/batch_environment.cpp @@ -30,9 +30,9 @@ namespace hpx::util { batch_environment::batch_environment(std::vector& nodelist, bool have_mpi, bool debug, bool enable) : agas_node_num_(0) - , node_num_(std::size_t(-1)) - , num_threads_(std::size_t(-1)) - , num_localities_(std::size_t(-1)) + , node_num_(static_cast(-1)) + , num_threads_(static_cast(-1)) + , num_localities_(static_cast(-1)) , debug_(debug) { if (!enable) @@ -45,6 +45,12 @@ namespace hpx::util { { } + onexit(onexit const&) = delete; + onexit(onexit&&) = delete; + + onexit& operator=(onexit const&) = delete; + onexit& operator=(onexit&&) = delete; + ~onexit() { if (env_.debug_) @@ -64,7 +70,7 @@ namespace hpx::util { onexit _(*this); - batch_environments::alps_environment alps_env(nodelist, debug); + batch_environments::alps_environment const alps_env(nodelist, debug); if (alps_env.valid()) { batch_name_ = "ALPS"; @@ -74,7 +80,8 @@ namespace hpx::util { return; } - batch_environments::pjm_environment pjm_env(nodelist, have_mpi, debug); + batch_environments::pjm_environment const pjm_env( + nodelist, have_mpi, debug); if (pjm_env.valid()) { batch_name_ = "PJM"; @@ -84,7 +91,7 @@ namespace hpx::util { return; } - batch_environments::slurm_environment slurm_env(nodelist, debug); + batch_environments::slurm_environment const slurm_env(nodelist, debug); if (slurm_env.valid()) { batch_name_ = "SLURM"; @@ -94,7 +101,8 @@ namespace hpx::util { return; } - batch_environments::pbs_environment pbs_env(nodelist, have_mpi, debug); + batch_environments::pbs_environment const pbs_env( + nodelist, have_mpi, debug); if (pbs_env.valid()) { batch_name_ = "PBS"; @@ -178,7 +186,7 @@ namespace hpx::util { } std::cerr << "Nodes from nodelist:" << std::endl; - node_map_type::const_iterator end = nodes_.end(); + node_map_type::const_iterator const end = nodes_.end(); for (node_map_type::const_iterator it = nodes_.begin(); it != end; ++it) { diff --git a/libs/core/batch_environments/src/pbs_environment.cpp b/libs/core/batch_environments/src/pbs_environment.cpp index 44f6e403f0ed..986383905cfe 100644 --- a/libs/core/batch_environments/src/pbs_environment.cpp +++ b/libs/core/batch_environments/src/pbs_environment.cpp @@ -21,17 +21,18 @@ namespace hpx::util::batch_environments { pbs_environment::pbs_environment( std::vector& nodelist, bool have_mpi, bool debug) - : node_num_(std::size_t(-1)) - , num_localities_(std::size_t(-1)) - , num_threads_(std::size_t(-1)) + : node_num_(static_cast(-1)) + , num_localities_(static_cast(-1)) + , num_threads_(static_cast(-1)) , valid_(false) { - char* node_num = std::getenv("PBS_NODENUM"); + char const* node_num = std::getenv("PBS_NODENUM"); valid_ = node_num != nullptr; if (valid_) { // Initialize our node number - node_num_ = from_string(node_num, std::size_t(1)); + node_num_ = + from_string(node_num, static_cast(1)); if (nodelist.empty()) { @@ -46,12 +47,12 @@ namespace hpx::util::batch_environments { read_nodelist(nodelist, debug); } - char* thread_num = std::getenv("PBS_NUM_PPN"); + char const* thread_num = std::getenv("PBS_NUM_PPN"); if (thread_num != nullptr) { // Initialize number of cores to run on - num_threads_ = - from_string(thread_num, std::size_t(-1)); + num_threads_ = from_string( + thread_num, static_cast(-1)); } } } @@ -70,12 +71,14 @@ namespace hpx::util::batch_environments { if (ifs.is_open()) { std::set nodes; - typedef std::set::iterator nodes_iterator; + using nodes_iterator = std::set::iterator; - bool fill_nodelist = nodelist.empty(); + bool const fill_nodelist = nodelist.empty(); if (debug) + { std::cerr << "opened: " << node_file << std::endl; + } std::string line; while (std::getline(ifs, line)) @@ -98,7 +101,9 @@ namespace hpx::util::batch_environments { else { if (debug) + { std::cerr << "failed opening: " << node_file << std::endl; + } // if MPI is active we can ignore the missing node-file if (have_mpi) @@ -113,7 +118,7 @@ namespace hpx::util::batch_environments { } void pbs_environment::read_nodelist( - std::vector& nodelist, bool debug) + std::vector const& nodelist, bool debug) { if (nodelist.empty()) { @@ -122,17 +127,18 @@ namespace hpx::util::batch_environments { } std::set nodes; - typedef std::set::iterator nodes_iterator; + using nodes_iterator = std::set::iterator; if (debug) + { std::cerr << "parsing nodelist" << std::endl; + } for (std::string const& s : nodelist) { if (!s.empty()) { - nodes_iterator it = nodes.find(s); - if (it == nodes.end()) + if (nodes_iterator it = nodes.find(s); it == nodes.end()) { nodes.insert(s); } diff --git a/libs/core/batch_environments/src/pjm_environment.cpp b/libs/core/batch_environments/src/pjm_environment.cpp index 6c6f87592041..80468aa1a142 100644 --- a/libs/core/batch_environments/src/pjm_environment.cpp +++ b/libs/core/batch_environments/src/pjm_environment.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -8,7 +8,6 @@ #include #include -#include #include #include #include @@ -35,7 +34,7 @@ namespace hpx::util::batch_environments { , num_localities_(0) , valid_(false) { - char* num_nodes = std::getenv("PJM_NODE"); + char const* num_nodes = std::getenv("PJM_NODE"); valid_ = num_nodes != nullptr; if (valid_) { @@ -45,7 +44,7 @@ namespace hpx::util::batch_environments { if (have_mpi) { // Initialize our node number, if available - char* var = std::getenv("PMIX_RANK"); + char const* var = std::getenv("PMIX_RANK"); if (var != nullptr) { node_num_ = from_string(var); diff --git a/libs/core/batch_environments/src/slurm_environment.cpp b/libs/core/batch_environments/src/slurm_environment.cpp index 3d3cfcf6e4ff..a6edd18a723f 100644 --- a/libs/core/batch_environments/src/slurm_environment.cpp +++ b/libs/core/batch_environments/src/slurm_environment.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2022 Hartmut Kaiser +// Copyright (c) 2007-2023 Hartmut Kaiser // Copyright (c) 2013-2015 Thomas Heller // // SPDX-License-Identifier: BSL-1.0 diff --git a/libs/core/concurrency/CMakeLists.txt b/libs/core/concurrency/CMakeLists.txt index 332fb0a6cadd..b5169a94d099 100644 --- a/libs/core/concurrency/CMakeLists.txt +++ b/libs/core/concurrency/CMakeLists.txt @@ -62,6 +62,7 @@ add_hpx_module( hpx_itt_notify hpx_lock_registration hpx_thread_support + hpx_type_support hpx_version CMAKE_SUBDIRS examples tests ) diff --git a/libs/core/concurrency/include/hpx/concurrency/barrier.hpp b/libs/core/concurrency/include/hpx/concurrency/barrier.hpp index de27219d6d6a..dd120889e203 100644 --- a/libs/core/concurrency/include/hpx/concurrency/barrier.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/barrier.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Hartmut Kaiser +// Copyright (c) 2017-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -28,7 +28,13 @@ namespace hpx::util { << (CHAR_BIT * sizeof(std::size_t) - 1); public: - barrier(std::size_t number_of_threads); + explicit barrier(std::size_t number_of_threads); + + barrier(barrier const&) = delete; + barrier(barrier&&) = delete; + barrier& operator=(barrier const&) = delete; + barrier& operator=(barrier&&) = delete; + ~barrier(); void wait(); diff --git a/libs/core/concurrency/include/hpx/concurrency/cache_line_data.hpp b/libs/core/concurrency/include/hpx/concurrency/cache_line_data.hpp index eee99479a7d8..8df03a0ffec8 100644 --- a/libs/core/concurrency/include/hpx/concurrency/cache_line_data.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/cache_line_data.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include #include #include @@ -191,9 +192,10 @@ namespace hpx { /////////////////////////////////////////////////////////////////////////// template - constexpr inline auto align_up(T value, std::size_t alignment) noexcept + constexpr auto align_up(T value, std::size_t alignment) noexcept { - return T(std::size_t(value + (alignment - 1)) & ~(alignment - 1)); + return T(hpx::bit_cast(value + (alignment - 1)) & + ~(alignment - 1)); } } // namespace util diff --git a/libs/core/concurrency/include/hpx/concurrency/deque.hpp b/libs/core/concurrency/include/hpx/concurrency/deque.hpp index 60c88932dee1..f3e28f9ac29c 100644 --- a/libs/core/concurrency/include/hpx/concurrency/deque.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/deque.hpp @@ -4,6 +4,7 @@ // Link: http://www.research.ibm.com/people/m/michael/europar-2003.pdf // // C++ implementation - Copyright (C) 2011 Bryce Lelbach +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -166,26 +167,26 @@ namespace hpx::lockfree { return pair_.load(mo).get_right_tag(); } - bool cas(deque_anchor& expected, deque_anchor const& desired, + bool cas(deque_anchor const& expected, deque_anchor const& desired, std::memory_order mo = std::memory_order_acq_rel) noexcept { return pair_.compare_exchange_strong( - expected.load(std::memory_order_acquire), - desired.load(std::memory_order_acquire), mo); + expected.lrs(std::memory_order_acquire), + desired.lrs(std::memory_order_acquire), mo); } bool cas(pair& expected, deque_anchor const& desired, std::memory_order mo = std::memory_order_acq_rel) noexcept { return pair_.compare_exchange_strong( - expected, desired.load(std::memory_order_acquire), mo); + expected, desired.lrs(std::memory_order_acquire), mo); } - bool cas(deque_anchor& expected, pair const& desired, + bool cas(deque_anchor const& expected, pair const& desired, std::memory_order mo = std::memory_order_acq_rel) noexcept { return pair_.compare_exchange_strong( - expected.load(std::memory_order_acquire), desired, mo); + expected.lrs(std::memory_order_acquire), desired, mo); } bool cas(pair& expected, pair const& desired, @@ -229,7 +230,7 @@ namespace hpx::lockfree { return !(lhs == rhs); } - bool is_lock_free() const noexcept + [[nodiscard]] bool is_lock_free() const noexcept { return pair_.is_lock_free(); } @@ -417,7 +418,7 @@ namespace hpx::lockfree { // Not thread-safe. // Complexity: O(Processes) // FIXME: Should we check both pointers here? - bool empty() const noexcept + [[nodiscard]] bool empty() const noexcept { return anchor_.lrs(std::memory_order_relaxed).get_left_ptr() == nullptr; @@ -425,7 +426,7 @@ namespace hpx::lockfree { // Thread-safe and non-blocking. // Complexity: O(1) - bool is_lock_free() const noexcept + [[nodiscard]] bool is_lock_free() const noexcept { return anchor_.is_lock_free(); } diff --git a/libs/core/concurrency/include/hpx/concurrency/detail/freelist.hpp b/libs/core/concurrency/include/hpx/concurrency/detail/freelist.hpp index 28d662dcd511..901e7fd093b1 100644 --- a/libs/core/concurrency/include/hpx/concurrency/detail/freelist.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/detail/freelist.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2012 Hartmut Kaiser +// Copyright (c) 2007-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,7 +20,7 @@ namespace hpx::lockfree { using base_type = lockfree::detail::freelist_stack; public: - caching_freelist(std::size_t n = 0) + explicit caching_freelist(std::size_t n = 0) : lockfree::detail::freelist_stack(Alloc(), n) { } @@ -42,7 +42,7 @@ namespace hpx::lockfree { using base_type = lockfree::detail::freelist_stack; public: - static_freelist(std::size_t n = 0) + explicit static_freelist(std::size_t n = 0) : lockfree::detail::freelist_stack(Alloc(), n) { } diff --git a/libs/core/concurrency/include/hpx/concurrency/detail/freelist_stack.hpp b/libs/core/concurrency/include/hpx/concurrency/detail/freelist_stack.hpp index 5cb685c0c396..75bae5077d6c 100644 --- a/libs/core/concurrency/include/hpx/concurrency/detail/freelist_stack.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/detail/freelist_stack.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2008-2016 Tim Blechmann -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -56,7 +57,7 @@ namespace hpx::lockfree::detail { for (std::size_t i = 0; i != count; ++i) { T* node = Alloc::allocate(1); - std::memset((void*) node, 0, sizeof(T)); + std::memset(static_cast(node), 0, sizeof(T)); deallocate(node); } } @@ -94,7 +95,7 @@ namespace hpx::lockfree::detail { freelist_node* current_ptr = current.get_ptr(); if (current_ptr) current = current_ptr->next; - Alloc::deallocate((T*) current_ptr, 1); + Alloc::deallocate(hpx::bit_cast(current_ptr), 1); } } @@ -155,7 +156,7 @@ namespace hpx::lockfree::detail { if constexpr (!Bounded) { T* ptr = Alloc::allocate(1); - std::memset((void*) ptr, 0, sizeof(T)); + std::memset(static_cast(ptr), 0, sizeof(T)); return ptr; } else @@ -170,7 +171,7 @@ namespace hpx::lockfree::detail { if (pool_.compare_exchange_weak(old_pool, new_pool)) { void* ptr = old_pool.get_ptr(); - return reinterpret_cast(ptr); + return static_cast(ptr); } } } @@ -185,7 +186,7 @@ namespace hpx::lockfree::detail { if constexpr (!Bounded) { T* ptr = Alloc::allocate(1); - std::memset((void*) ptr, 0, sizeof(T)); + std::memset(static_cast(ptr), 0, sizeof(T)); return ptr; } else @@ -199,7 +200,7 @@ namespace hpx::lockfree::detail { pool_.store(new_pool, std::memory_order_relaxed); void* ptr = old_pool.get_ptr(); - return reinterpret_cast(ptr); + return static_cast(ptr); } protected: @@ -221,8 +222,7 @@ namespace hpx::lockfree::detail { { void* node = n; tagged_node_ptr old_pool = pool_.load(std::memory_order_consume); - freelist_node* new_pool_ptr = - reinterpret_cast(node); + auto* new_pool_ptr = static_cast(node); for (;;) { @@ -238,8 +238,7 @@ namespace hpx::lockfree::detail { { void* node = n; tagged_node_ptr old_pool = pool_.load(std::memory_order_relaxed); - freelist_node* new_pool_ptr = - reinterpret_cast(node); + auto* new_pool_ptr = static_cast(node); tagged_node_ptr new_pool(new_pool_ptr, old_pool.get_tag()); new_pool->next.set_ptr(old_pool.get_ptr()); @@ -303,7 +302,8 @@ namespace hpx::lockfree::detail { constexpr tag_t get_next_tag() const noexcept { - tag_t next = (get_tag() + 1u) & (std::numeric_limits::max)(); + tag_t const next = + (get_tag() + 1u) & (std::numeric_limits::max)(); return next; } @@ -358,7 +358,7 @@ namespace hpx::lockfree::detail { data_pointer, hpx::threads::get_cache_line_size())); } - constexpr std::size_t node_count() const noexcept + static constexpr std::size_t node_count() noexcept { return Size; } @@ -393,7 +393,7 @@ namespace hpx::lockfree::detail { "of 65535 objects"); } nodes_ = allocator_type::allocate(count); - std::memset((void*) nodes_, 0, sizeof(T) * count); + std::memset(static_cast(nodes_), 0, sizeof(T) * count); } ~runtime_sized_freelist_storage() @@ -548,10 +548,10 @@ namespace hpx::lockfree::detail { return index; T* old_node = NodeStorage::nodes() + index; - tagged_index* next_index = + tagged_index const* next_index = reinterpret_cast(old_node); - tagged_index new_pool( + tagged_index const new_pool( next_index->get_index(), old_pool.get_next_tag()); if (pool_.compare_exchange_weak(old_pool, new_pool)) @@ -561,17 +561,17 @@ namespace hpx::lockfree::detail { index_t allocate_impl_unsafe() { - tagged_index old_pool = pool_.load(std::memory_order_consume); + tagged_index const old_pool = pool_.load(std::memory_order_consume); index_t index = old_pool.get_index(); if (index == null_handle()) return index; T* old_node = NodeStorage::nodes() + index; - tagged_index* next_index = + tagged_index const* next_index = reinterpret_cast(old_node); - tagged_index new_pool( + tagged_index const new_pool( next_index->get_index(), old_pool.get_next_tag()); pool_.store(new_pool, std::memory_order_relaxed); @@ -599,7 +599,7 @@ namespace hpx::lockfree::detail { for (;;) { - tagged_index new_pool(index, old_pool.get_tag()); + tagged_index const new_pool(index, old_pool.get_tag()); new_pool_node->next.set_index(old_pool.get_index()); if (pool_.compare_exchange_weak(old_pool, new_pool)) @@ -611,9 +611,9 @@ namespace hpx::lockfree::detail { { freelist_node* new_pool_node = reinterpret_cast(NodeStorage::nodes() + index); - tagged_index old_pool = pool_.load(std::memory_order_consume); + tagged_index const old_pool = pool_.load(std::memory_order_consume); - tagged_index new_pool(index, old_pool.get_tag()); + tagged_index const new_pool(index, old_pool.get_tag()); new_pool_node->next.set_index(old_pool.get_index()); pool_.store(new_pool); @@ -643,6 +643,6 @@ namespace hpx::lockfree::detail { std::conditional_t, tagged_index>; using handle_type = - std::conditional_t; + std::conditional_t; }; } // namespace hpx::lockfree::detail diff --git a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_dcas.hpp b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_dcas.hpp index 726ec43e8591..86ebd05122a9 100644 --- a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_dcas.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_dcas.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2008, 2016 Tim Blechmann -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -24,11 +24,12 @@ namespace hpx::lockfree::detail { using index_t = T*; /** uninitialized constructor */ - tagged_ptr() noexcept //: ptr(0), tag(0) + constexpr tagged_ptr() noexcept //: ptr(0), tag(0) { } tagged_ptr(tagged_ptr const& p) = default; + tagged_ptr(tagged_ptr&& p) = default; explicit constexpr tagged_ptr(T* p, tag_t t = 0) noexcept : ptr(p) @@ -39,8 +40,11 @@ namespace hpx::lockfree::detail { /** unsafe set operation */ /* @{ */ tagged_ptr& operator=(tagged_ptr const& p) = default; + tagged_ptr& operator=(tagged_ptr&& p) = default; - void set(T* p, tag_t t) noexcept + ~tagged_ptr() = default; + + constexpr void set(T* p, tag_t t) noexcept { ptr = p; tag = t; @@ -67,7 +71,7 @@ namespace hpx::lockfree::detail { return ptr; } - void set_ptr(T* p) noexcept + constexpr void set_ptr(T* p) noexcept { ptr = p; } @@ -82,11 +86,12 @@ namespace hpx::lockfree::detail { constexpr tag_t get_next_tag() const noexcept { - tag_t next = (get_tag() + 1) & (std::numeric_limits::max)(); + tag_t const next = + (get_tag() + 1) & (std::numeric_limits::max)(); return next; } - void set_tag(tag_t t) noexcept + constexpr void set_tag(tag_t t) noexcept { tag = t; } @@ -106,7 +111,7 @@ namespace hpx::lockfree::detail { explicit constexpr operator bool() const noexcept { - return ptr != 0; + return ptr != nullptr; } /* @} */ diff --git a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_pair.hpp b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_pair.hpp index 588b1a87436b..cc2afb9f940f 100644 --- a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_pair.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_pair.hpp @@ -1,6 +1,6 @@ // Copyright (C) 2008-2011 Tim Blechmann // Copyright (C) 2011 Bryce Lelbach -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -12,6 +12,7 @@ #pragma once #include +#include #include // for std::size_t #include @@ -20,13 +21,28 @@ namespace hpx::lockfree { struct HPX_LOCKFREE_DCAS_ALIGNMENT uint128_type { - std::uint64_t left; - std::uint64_t right; + std::uint64_t left = 0; + std::uint64_t right = 0; + + uint128_type() = default; + + constexpr uint128_type(std::uint64_t l, std::uint64_t r) noexcept + : left(l) + , right(r) + { + } + + uint128_type(uint128_type const&) = default; + uint128_type(uint128_type&&) = default; + uint128_type& operator=(uint128_type const&) = default; + uint128_type& operator=(uint128_type&&) = default; + + ~uint128_type() = default; friend constexpr bool operator==(uint128_type const& lhs, //-V835 uint128_type const& rhs) noexcept //-V835 { - return (lhs.left == rhs.left) && (lhs.right == rhs.right); + return lhs.left == rhs.left && lhs.right == rhs.right; } friend constexpr bool operator!=(uint128_type const& lhs, //-V835 @@ -43,65 +59,79 @@ namespace hpx::lockfree { using compressed_ptr_t = std::uint64_t; using tag_t = std::uint16_t; - union HPX_LOCKFREE_DCAS_ALIGNMENT cast_unit + struct HPX_LOCKFREE_DCAS_ALIGNMENT cast_unit { - compressed_ptr_pair_t value; - tag_t tags[8]; + union + { + compressed_ptr_pair_t value; + tag_t tags[8]; + }; + + explicit constexpr cast_unit(compressed_ptr_pair_t i) noexcept + : value(i) + { + } + constexpr cast_unit(compressed_ptr_t l, compressed_ptr_t r, + tag_t ltag, tag_t rtag) noexcept + : value(l, r) + { + tags[left_tag_index] = ltag; + tags[right_tag_index] = rtag; + } }; static constexpr std::size_t left_tag_index = 3; static constexpr std::size_t right_tag_index = 7; static constexpr compressed_ptr_t ptr_mask = 0xffffffffffff; - static Left* extract_left_ptr(compressed_ptr_pair_t i) noexcept + static constexpr Left* extract_left_ptr( + compressed_ptr_pair_t i) noexcept { - return reinterpret_cast(i.left & ptr_mask); + return hpx::bit_cast(i.left & ptr_mask); } - static Right* extract_right_ptr(compressed_ptr_pair_t i) noexcept + static constexpr Right* extract_right_ptr( + compressed_ptr_pair_t i) noexcept { - return reinterpret_cast(i.right & ptr_mask); + return hpx::bit_cast(i.right & ptr_mask); } - static tag_t extract_left_tag(compressed_ptr_pair_t i) noexcept + static constexpr tag_t extract_left_tag( + compressed_ptr_pair_t i) noexcept { - cast_unit cu; - cu.value.left = i.left; - cu.value.right = i.right; + cast_unit cu(i); return cu.tags[left_tag_index]; } - static tag_t extract_right_tag(compressed_ptr_pair_t i) noexcept + static constexpr tag_t extract_right_tag( + compressed_ptr_pair_t i) noexcept { - cast_unit cu; - cu.value.left = i.left; - cu.value.right = i.right; + cast_unit cu(i); return cu.tags[right_tag_index]; } template - static void pack_ptr_pair(compressed_ptr_pair_t& pair, Left* lptr, - Right* rptr, IntegralL ltag, IntegralR rtag) noexcept - { - cast_unit ret; - ret.value.left = reinterpret_cast(lptr); - ret.value.right = reinterpret_cast(rptr); - ret.tags[left_tag_index] = static_cast(ltag); - ret.tags[right_tag_index] = static_cast(rtag); + static constexpr void pack_ptr_pair(compressed_ptr_pair_t& pair, + Left* lptr, Right* rptr, IntegralL ltag, IntegralR rtag) noexcept + { + cast_unit ret(hpx::bit_cast(lptr), + hpx::bit_cast(rptr), static_cast(ltag), + static_cast(rtag)); pair = ret.value; } /** uninitialized constructor */ - tagged_ptr_pair() {} //-V730 //-V832 + constexpr tagged_ptr_pair() {} //-V730 //-V832 template - tagged_ptr_pair(Left* lptr, Right* rptr, IntegralL ltag) noexcept + constexpr tagged_ptr_pair( + Left* lptr, Right* rptr, IntegralL ltag) noexcept { pack_ptr_pair(pair_, lptr, rptr, ltag, 0); } template - tagged_ptr_pair( + constexpr tagged_ptr_pair( Left* lptr, Right* rptr, IntegralL ltag, IntegralR rtag) noexcept { pack_ptr_pair(pair_, lptr, rptr, ltag, rtag); @@ -109,8 +139,9 @@ namespace hpx::lockfree { /** copy constructors */ tagged_ptr_pair(tagged_ptr_pair const& p) = default; + tagged_ptr_pair(tagged_ptr_pair&& p) = default; - tagged_ptr_pair(Left* lptr, Right* rptr) noexcept + constexpr tagged_ptr_pair(Left* lptr, Right* rptr) noexcept { pack_ptr_pair(pair_, lptr, rptr, 0, 0); } @@ -118,38 +149,41 @@ namespace hpx::lockfree { /** unsafe set operations */ /* @{ */ tagged_ptr_pair& operator=(tagged_ptr_pair const& p) = default; + tagged_ptr_pair& operator=(tagged_ptr_pair&& p) = default; + + ~tagged_ptr_pair() = default; - void set(Left* lptr, Right* rptr) noexcept + constexpr void set(Left* lptr, Right* rptr) noexcept { pack_ptr_pair(pair_, lptr, rptr, 0, 0); } - void reset(Left* lptr, Right* rptr) noexcept + constexpr void reset(Left* lptr, Right* rptr) noexcept { set(lptr, rptr, 0, 0); } template - void set(Left* lptr, Right* rptr, IntegralL ltag) noexcept + constexpr void set(Left* lptr, Right* rptr, IntegralL ltag) noexcept { pack_ptr_pair(pair_, lptr, rptr, ltag, 0); } template - void set( + constexpr void set( Left* lptr, Right* rptr, IntegralL ltag, IntegralR rtag) noexcept { pack_ptr_pair(pair_, lptr, rptr, ltag, rtag); } template - void reset(Left* lptr, Right* rptr, IntegralL ltag) noexcept + constexpr void reset(Left* lptr, Right* rptr, IntegralL ltag) noexcept { set(lptr, rptr, ltag, 0); } template - void reset( + constexpr void reset( Left* lptr, Right* rptr, IntegralL ltag, IntegralR rtag) noexcept { set(lptr, rptr, ltag, rtag); @@ -173,47 +207,47 @@ namespace hpx::lockfree { /** pointer access */ /* @{ */ - Left* get_left_ptr() const noexcept + constexpr Left* get_left_ptr() const noexcept { return extract_left_ptr(pair_); } - Right* get_right_ptr() const noexcept + constexpr Right* get_right_ptr() const noexcept { return extract_right_ptr(pair_); } - void set_left_ptr(Left* lptr) noexcept + constexpr void set_left_ptr(Left* lptr) noexcept { Right* rptr = get_right_ptr(); - tag_t ltag = get_left_tag(); - tag_t rtag = get_right_tag(); + tag_t const ltag = get_left_tag(); + tag_t const rtag = get_right_tag(); pack_ptr_pair(pair_, lptr, rptr, ltag, rtag); } - void set_right_ptr(Right* rptr) noexcept + constexpr void set_right_ptr(Right* rptr) noexcept { Left* lptr = get_left_ptr(); - tag_t ltag = get_left_tag(); - tag_t rtag = get_right_tag(); + tag_t const ltag = get_left_tag(); + tag_t const rtag = get_right_tag(); pack_ptr_pair(pair_, lptr, rptr, ltag, rtag); } /* @} */ /** tag access */ /* @{ */ - tag_t get_left_tag() const noexcept + constexpr tag_t get_left_tag() const noexcept { return extract_left_tag(pair_); } - tag_t get_right_tag() const noexcept + constexpr tag_t get_right_tag() const noexcept { return extract_right_tag(pair_); } template - void set_left_tag(Integral ltag) noexcept + constexpr void set_left_tag(Integral ltag) noexcept { Left* lptr = get_left_ptr(); Right* rptr = get_right_ptr(); @@ -222,7 +256,7 @@ namespace hpx::lockfree { } template - void set_right_tag(Integral rtag) noexcept + constexpr void set_right_tag(Integral rtag) noexcept { Left* lptr = get_left_ptr(); Right* rptr = get_right_ptr(); @@ -233,9 +267,9 @@ namespace hpx::lockfree { /** smart pointer support */ /* @{ */ - explicit operator bool() const noexcept + explicit constexpr operator bool() const noexcept { - return (get_left_ptr() != 0) && (get_right_ptr() != 0); + return get_left_ptr() != nullptr && get_right_ptr() != nullptr; } /* @} */ diff --git a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_ptrcompression.hpp b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_ptrcompression.hpp index ae1bd0af9418..e40e0164b78f 100644 --- a/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_ptrcompression.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/detail/tagged_ptr_ptrcompression.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2008, 2009, 2016 Tim Blechmann, based on code by Cory Nelson -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include @@ -28,33 +29,44 @@ namespace hpx::lockfree::detail { using index_t = T*; private: - union cast_unit - { - compressed_ptr_t value; - tag_t tag[4]; + struct cast_unit + { + union + { + compressed_ptr_t value; + tag_t tag[4]; + }; + + explicit constexpr cast_unit(compressed_ptr_t i) noexcept + : value(i) + { + } + + constexpr cast_unit(compressed_ptr_t i, tag_t t) noexcept + : value(i) + { + tag[tag_index] = t; + } }; static constexpr int tag_index = 3; static constexpr compressed_ptr_t ptr_mask = 0xffffffffffffUL; // (1L<<48L)-1; - static T* extract_ptr(compressed_ptr_t i) noexcept + static constexpr T* extract_ptr(compressed_ptr_t i) noexcept { - return reinterpret_cast(i & ptr_mask); + return hpx::bit_cast(i & ptr_mask); } - static tag_t extract_tag(compressed_ptr_t i) noexcept + static constexpr tag_t extract_tag(compressed_ptr_t i) noexcept { - cast_unit cu; - cu.value = i; + cast_unit cu(i); return cu.tag[tag_index]; } - static compressed_ptr_t pack_ptr(T* ptr, tag_t tag) noexcept + static constexpr compressed_ptr_t pack_ptr(T* ptr, tag_t tag) noexcept { - cast_unit ret; - ret.value = compressed_ptr_t(ptr); - ret.tag[tag_index] = tag; + cast_unit ret(hpx::bit_cast(ptr), tag); return ret.value; } @@ -66,8 +78,9 @@ namespace hpx::lockfree::detail { /** copy constructor */ tagged_ptr(tagged_ptr const& p) = default; + tagged_ptr(tagged_ptr&& p) = default; - explicit tagged_ptr(T* p, tag_t t = 0) noexcept + explicit constexpr tagged_ptr(T* p, tag_t t = 0) noexcept : ptr(pack_ptr(p, t)) { } @@ -75,6 +88,9 @@ namespace hpx::lockfree::detail { /** unsafe set operation */ /* @{ */ tagged_ptr& operator=(tagged_ptr const& p) = default; + tagged_ptr& operator=(tagged_ptr&& p) = default; + + ~tagged_ptr() = default; void set(T* p, tag_t t) noexcept { @@ -99,28 +115,29 @@ namespace hpx::lockfree::detail { /** pointer access */ /* @{ */ - T* get_ptr() const noexcept + constexpr T* get_ptr() const noexcept { return extract_ptr(ptr); } void set_ptr(T* p) noexcept { - tag_t tag = get_tag(); + tag_t const tag = get_tag(); ptr = pack_ptr(p, tag); } /* @} */ /** tag access */ /* @{ */ - tag_t get_tag() const noexcept + constexpr tag_t get_tag() const noexcept { return extract_tag(ptr); } - tag_t get_next_tag() const noexcept + constexpr tag_t get_next_tag() const noexcept { - tag_t next = (get_tag() + 1u) & (std::numeric_limits::max)(); + tag_t const next = + (get_tag() + 1u) & (std::numeric_limits::max)(); return next; } @@ -133,17 +150,17 @@ namespace hpx::lockfree::detail { /** smart pointer support */ /* @{ */ - T& operator*() const noexcept + constexpr T& operator*() const noexcept { return *get_ptr(); } - T* operator->() const noexcept + constexpr T* operator->() const noexcept { return get_ptr(); } - explicit operator bool() const noexcept + constexpr explicit operator bool() const noexcept { return get_ptr() != nullptr; } diff --git a/libs/core/concurrency/include/hpx/concurrency/queue.hpp b/libs/core/concurrency/include/hpx/concurrency/queue.hpp index d8abd5a6a9b2..8315ce66ff2d 100644 --- a/libs/core/concurrency/include/hpx/concurrency/queue.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/queue.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2008-2013 Tim Blechmann -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -149,10 +149,12 @@ namespace hpx::lockfree { using size_type = std::size_t; }; + public: queue(queue const&) = delete; + queue(queue&&) = delete; queue& operator=(queue const&) = delete; + queue& operator=(queue&&) = delete; - public: using value_type = T; using allocator = typename implementation_defined::allocator; using size_type = typename implementation_defined::size_type; @@ -168,7 +170,7 @@ namespace hpx::lockfree { * need to test every internal node, which is impossible if further * nodes will be allocated from the operating system. */ - constexpr bool is_lock_free() const noexcept + [[nodiscard]] constexpr bool is_lock_free() const noexcept { return head_.is_lock_free() && tail_.is_lock_free() && pool.is_lock_free(); @@ -295,7 +297,7 @@ namespace hpx::lockfree { * queue. Therefore it is rarely practical to use this value in * program logic. */ - bool empty() const noexcept + [[nodiscard]] bool empty() const noexcept { return pool.get_handle(head_.load()) == pool.get_handle(tail_.load()); @@ -595,7 +597,7 @@ namespace hpx::lockfree { bool consume_one(F&& f) { T element; - bool success = pop(element); + bool const success = pop(element); if (success) f(element); diff --git a/libs/core/concurrency/include/hpx/concurrency/spinlock_pool.hpp b/libs/core/concurrency/include/hpx/concurrency/spinlock_pool.hpp index 95475828ad7a..b1751a1e7120 100644 --- a/libs/core/concurrency/include/hpx/concurrency/spinlock_pool.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/spinlock_pool.hpp @@ -1,4 +1,4 @@ -// Copyright (c) 2012 Hartmut Kaiser +// Copyright (c) 2012-2023 Hartmut Kaiser // // taken from: // boost/detail/spinlock_pool.hpp @@ -21,7 +21,7 @@ #include -namespace hpx { namespace util { +namespace hpx::util { namespace detail { #if HPX_HAVE_ITTNOTIFY != 0 @@ -56,6 +56,7 @@ namespace hpx { namespace util { #if HPX_HAVE_ITTNOTIFY != 0 namespace detail { + template itt_spinlock_init::itt_spinlock_init() noexcept { @@ -79,5 +80,4 @@ namespace hpx { namespace util { template util::detail::itt_spinlock_init spinlock_pool::init_; #endif - -}} // namespace hpx::util +} // namespace hpx::util diff --git a/libs/core/concurrency/include/hpx/concurrency/stack.hpp b/libs/core/concurrency/include/hpx/concurrency/stack.hpp index da9aa47f561d..ffeb832a40dc 100644 --- a/libs/core/concurrency/include/hpx/concurrency/stack.hpp +++ b/libs/core/concurrency/include/hpx/concurrency/stack.hpp @@ -1,5 +1,5 @@ // Copyright (C) 2008-2013 Tim Blechmann -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -113,10 +113,12 @@ namespace hpx::lockfree { using size_type = std::size_t; }; + public: stack(stack const&) = delete; + stack(stack&&) = delete; stack& operator=(stack const&) = delete; + stack& operator=(stack&&) = delete; - public: using value_type = T; using allocator = typename implementation_defined::allocator; using size_type = typename implementation_defined::size_type; @@ -132,7 +134,7 @@ namespace hpx::lockfree { * to test every internal node, which is impossible if further * nodes will be allocated from the operating system. */ - constexpr bool is_lock_free() const noexcept + [[nodiscard]] constexpr bool is_lock_free() const noexcept { return tos.is_lock_free() && pool.is_lock_free(); } diff --git a/libs/core/concurrency/src/barrier.cpp b/libs/core/concurrency/src/barrier.cpp index 00b895de64d4..510aeb59498a 100644 --- a/libs/core/concurrency/src/barrier.cpp +++ b/libs/core/concurrency/src/barrier.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017 Hartmut Kaiser +// Copyright (c) 2017-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -9,7 +9,8 @@ #include -namespace hpx { namespace util { +namespace hpx::util { + barrier::barrier(std::size_t number_of_threads) : number_of_threads_(number_of_threads) , total_(barrier_flag) @@ -66,4 +67,4 @@ namespace hpx { namespace util { } } } -}} // namespace hpx::util +} // namespace hpx::util diff --git a/libs/core/coroutines/CMakeLists.txt b/libs/core/coroutines/CMakeLists.txt index 348ebbc43070..ca8560283b9b 100644 --- a/libs/core/coroutines/CMakeLists.txt +++ b/libs/core/coroutines/CMakeLists.txt @@ -58,6 +58,7 @@ set(coroutines_sources detail/tss.cpp swapcontext.cpp thread_enums.cpp + thread_id_type.cpp signal_handler_debugging.cpp ) diff --git a/libs/core/coroutines/include/hpx/coroutines/coroutine.hpp b/libs/core/coroutines/include/hpx/coroutines/coroutine.hpp index 9d2df4973ecd..0bc356698ba7 100644 --- a/libs/core/coroutines/include/hpx/coroutines/coroutine.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/coroutine.hpp @@ -37,7 +37,6 @@ #include #include #include -#include #include #include @@ -64,7 +63,7 @@ namespace hpx::threads::coroutines { coroutine(functor_type&& f, thread_id_type id, std::ptrdiff_t stack_size = detail::default_stack_size) - : impl_(HPX_MOVE(f), id, stack_size) + : impl_(HPX_MOVE(f), HPX_MOVE(id), stack_size) { HPX_ASSERT(impl_.is_ready()); } @@ -74,6 +73,8 @@ namespace hpx::threads::coroutines { coroutine(coroutine&& src) = delete; coroutine& operator=(coroutine&& src) = delete; + ~coroutine() = default; + constexpr thread_id_type get_thread_id() const noexcept { return impl_.get_thread_id(); @@ -91,7 +92,7 @@ namespace hpx::threads::coroutines { return impl_.get_thread_data(); } - std::size_t set_thread_data(std::size_t data) noexcept + std::size_t set_thread_data(std::size_t data) const noexcept { return impl_.set_thread_data(data); } @@ -102,7 +103,7 @@ namespace hpx::threads::coroutines { return impl_.get_libcds_data(); } - std::size_t set_libcds_data(std::size_t data) + std::size_t set_libcds_data(std::size_t data) const { return impl_.set_libcds_data(data); } @@ -112,7 +113,7 @@ namespace hpx::threads::coroutines { return impl_.get_libcds_hazard_pointer_data(); } - std::size_t set_libcds_hazard_pointer_data(std::size_t data) + std::size_t set_libcds_hazard_pointer_data(std::size_t data) const { return impl_.set_libcds_hazard_pointer_data(data); } @@ -122,7 +123,8 @@ namespace hpx::threads::coroutines { return impl_.get_libcds_dynamic_hazard_pointer_data(); } - std::size_t set_libcds_dynamic_hazard_pointer_data(std::size_t data) + std::size_t set_libcds_dynamic_hazard_pointer_data( + std::size_t data) const { return impl_.set_libcds_dynamic_hazard_pointer_data(data); } @@ -135,7 +137,7 @@ namespace hpx::threads::coroutines { void rebind(functor_type&& f, thread_id_type id) { - impl_.rebind(HPX_MOVE(f), id); + impl_.rebind(HPX_MOVE(f), HPX_MOVE(id)); } HPX_FORCEINLINE result_type operator()(arg_type arg = arg_type()) @@ -160,7 +162,7 @@ namespace hpx::threads::coroutines { return impl_.get_available_stack_space(); } #else - std::ptrdiff_t get_available_stack_space() const noexcept + static std::ptrdiff_t get_available_stack_space() noexcept { return (std::numeric_limits::max)(); } diff --git a/libs/core/coroutines/include/hpx/coroutines/coroutine_fwd.hpp b/libs/core/coroutines/include/hpx/coroutines/coroutine_fwd.hpp index 276117834df9..dcf8f49837eb 100644 --- a/libs/core/coroutines/include/hpx/coroutines/coroutine_fwd.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/coroutine_fwd.hpp @@ -30,8 +30,6 @@ #pragma once -#include - namespace hpx::threads::coroutines { namespace detail { diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/combined_tagged_state.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/combined_tagged_state.hpp index 8e495e090f2b..22d56cfde006 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/combined_tagged_state.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/combined_tagged_state.hpp @@ -26,15 +26,14 @@ namespace hpx::threads::detail { using thread_state_ex_type = std::int8_t; using tag_type = std::int64_t; - static constexpr std::size_t const state_shift = 56; // 8th byte - static constexpr std::size_t const state_ex_shift = 48; // 7th byte + static constexpr std::size_t state_shift = 56; // 8th byte + static constexpr std::size_t state_ex_shift = 48; // 7th byte - static constexpr tagged_state_type const state_mask = 0xffull; - static constexpr tagged_state_type const state_ex_mask = 0xffull; + static constexpr tagged_state_type state_mask = 0xffull; + static constexpr tagged_state_type state_ex_mask = 0xffull; // (1L << 48L) - 1; - static constexpr tagged_state_type const tag_mask = - 0x0000ffffffffffffull; + static constexpr tagged_state_type tag_mask = 0x0000ffffffffffffull; static constexpr tag_type extract_tag(tagged_state_type i) noexcept { @@ -44,21 +43,22 @@ namespace hpx::threads::detail { static constexpr thread_state_type extract_state( tagged_state_type i) noexcept { - return (i >> state_shift) & state_mask; + return static_cast( + (i >> state_shift) & state_mask); } static constexpr thread_state_ex_type extract_state_ex( tagged_state_type i) noexcept { - return (i >> state_ex_shift) & state_ex_mask; + return static_cast( + (i >> state_ex_shift) & state_ex_mask); } static tagged_state_type pack_state( T1 state_, T2 state_ex_, tag_type tag) noexcept { - tagged_state_type state = static_cast(state_); - tagged_state_type state_ex = - static_cast(state_ex_); + auto const state = static_cast(state_); + auto const state_ex = static_cast(state_ex_); HPX_ASSERT(!(state & ~state_mask)); HPX_ASSERT(!(state_ex & ~state_ex_mask)); @@ -91,12 +91,12 @@ namespace hpx::threads::detail { } /////////////////////////////////////////////////////////////////////// - bool operator==(combined_tagged_state const& p) const + constexpr bool operator==(combined_tagged_state const& p) const noexcept { return state_ == p.state_; } - bool operator!=(combined_tagged_state const& p) const + constexpr bool operator!=(combined_tagged_state const& p) const noexcept { return !operator==(p); } diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/context_base.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/context_base.hpp index c22c854ae232..01262b449087 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/context_base.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/context_base.hpp @@ -30,14 +30,6 @@ #pragma once -/* - * Currently asio can, in some cases. call copy constructors and - * operator= from different threads, even if in the - * one-thread-per-service model. (i.e. from the resolver thread) - * This will be corrected in future versions, but for now - * we will play it safe and use an atomic count. The overhead shouldn't - * be big. - */ #include // This needs to be first for building on Macs @@ -48,11 +40,9 @@ #include #include -#include #include #include #include -#include #include namespace hpx::threads::coroutines::detail { @@ -89,12 +79,18 @@ namespace hpx::threads::coroutines::detail { , libcds_dynamic_hazard_pointer_data_(0) #endif , m_type_info() - , m_thread_id(id) + , m_thread_id(HPX_MOVE(id)) , continuation_recursion_count_(0) { } - void reset_tss() + context_base(context_base const&) = delete; + context_base(context_base&&) = delete; + + context_base& operator=(context_base const&) = delete; + context_base& operator=(context_base&&) = delete; + + void reset_tss() const { #if defined(HPX_HAVE_THREAD_LOCAL_STORAGE) delete_tss_storage(m_thread_data); @@ -243,14 +239,14 @@ namespace hpx::threads::coroutines::detail { #endif #if defined(HPX_HAVE_THREAD_LOCAL_STORAGE) - std::size_t set_thread_data(std::size_t data) + std::size_t set_thread_data(std::size_t data) const { return set_tss_thread_data(m_thread_data, data); } #else - std::size_t set_thread_data(std::size_t data) noexcept + std::size_t set_thread_data(std::size_t data) const noexcept { - std::size_t olddata = m_thread_data; + std::size_t const olddata = m_thread_data; m_thread_data = data; return olddata; } @@ -335,7 +331,7 @@ namespace hpx::threads::coroutines::detail { { HPX_ASSERT(!running()); - m_thread_id = id; + m_thread_id = HPX_MOVE(id); m_state = context_state::ready; m_exit_state = context_exit_state::not_requested; m_exit_status = context_exit_status::not_exited; diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/context_generic_context.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/context_generic_context.hpp index 54f98d405b47..9a1856327b73 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/context_generic_context.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/context_generic_context.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2014 Thomas Heller -// Copyright (c) 2012-2022 Hartmut Kaiser +// Copyright (c) 2012-2023 Hartmut Kaiser // Copyright (c) 2009 Oliver Kowalke // // SPDX-License-Identifier: BSL-1.0 @@ -13,10 +13,12 @@ #include #include #include +#if defined(HPX_HAVE_COROUTINE_COUNTERS) #include +#endif -// include unist.d conditionally to check for POSIX version. Not all OSs have the -// unistd header... +// include unistd.h conditionally to check for POSIX version. Not all OSs have +// the unistd header... #if defined(HPX_HAVE_UNISTD_H) #include #endif @@ -29,16 +31,18 @@ #endif #include -#include #include #include #include #include -#include #include #include +#if !defined(HPX_HAVE_THREADS_GET_STACK_POINTER) +#include +#endif + /////////////////////////////////////////////////////////////////////////////// #if defined(HPX_GENERIC_CONTEXT_USE_SEGMENTED_STACKS) @@ -93,7 +97,7 @@ namespace hpx::threads::coroutines { return HPX_SMALL_STACK_SIZE; } - void* allocate(std::size_t size) const + static void* allocate(std::size_t size) { // Condition excludes MacOS/M1 from using posix mmap #if defined(HPX_USE_POSIX_STACK_UTILITIES) @@ -107,7 +111,7 @@ namespace hpx::threads::coroutines { return static_cast(limit) + size; } - void deallocate(void* vp, std::size_t size) const noexcept + static void deallocate(void* vp, std::size_t size) noexcept { HPX_ASSERT(vp); void* limit = static_cast(vp) - size; @@ -169,7 +173,7 @@ namespace hpx::threads::coroutines { template [[noreturn]] void trampoline(boost::context::detail::transfer_t tr) { - auto arg = static_cast< + auto const arg = static_cast< std::pair*>( tr.data); @@ -197,10 +201,11 @@ namespace hpx::threads::coroutines { explicit fcontext_context_impl(std::ptrdiff_t stack_size = -1) : cb_(std::make_pair(static_cast(this), nullptr)) , funp_(&trampoline) - , ctx_(0) + , ctx_(nullptr) , alloc_() - , stack_size_((stack_size == -1) ? alloc_.minimum_stacksize() : - std::size_t(stack_size)) + , stack_size_((stack_size == -1) ? + alloc_.minimum_stacksize() : + static_cast(stack_size)) , stack_pointer_(nullptr) { } @@ -247,7 +252,7 @@ namespace hpx::threads::coroutines { return (std::numeric_limits::max)(); } #endif - void reset_stack() + void reset_stack() const { if (ctx_) { diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/context_posix.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/context_posix.hpp index 734e138f1bbe..4a38b5325bad 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/context_posix.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/context_posix.hpp @@ -47,8 +47,8 @@ #include #include -// include unist.d conditionally to check for POSIX version. Not all OSs have the -// unistd header... +// include unistd.h conditionally to check for POSIX version. Not all OSs have +// the unistd header... #if defined(HPX_HAVE_UNISTD_H) #include #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 6f758b20a446..c72859ef5b38 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_impl.hpp @@ -34,7 +34,6 @@ #include #include #include -#include #include #include #include @@ -65,7 +64,7 @@ namespace hpx::threads::coroutines::detail { coroutine_impl(functor_type&& f, thread_id_type id, std::ptrdiff_t stack_size) noexcept - : context_base(stack_size, id) + : context_base(stack_size, HPX_MOVE(id)) , m_result(thread_schedule_state::unknown, invalid_thread_id) , m_arg(nullptr) , m_fun(HPX_MOVE(f)) @@ -80,7 +79,7 @@ namespace hpx::threads::coroutines::detail { HPX_CORE_EXPORT void operator()() noexcept; public: - void bind_result(result_type res) noexcept + void bind_result(result_type const& res) noexcept { HPX_ASSERT(m_result.first != thread_schedule_state::terminated); m_result = res; @@ -90,11 +89,11 @@ namespace hpx::threads::coroutines::detail { { return m_result; } - arg_type* args() noexcept + arg_type* args() const noexcept { HPX_ASSERT(m_arg); return m_arg; - }; + } void bind_args(arg_type* arg) noexcept { @@ -134,7 +133,7 @@ namespace hpx::threads::coroutines::detail { result_type(thread_schedule_state::unknown, invalid_thread_id); m_arg = nullptr; m_fun = HPX_MOVE(f); - this->super_type::rebind_base(id); + this->super_type::rebind_base(HPX_MOVE(id)); } private: 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 a251ee349578..ebfed04f8e7a 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_self.hpp @@ -30,7 +30,6 @@ #pragma once #include -#include #include #include #include @@ -38,8 +37,6 @@ #include #include -#include -#include #include namespace hpx::threads::coroutines::detail { @@ -59,6 +56,12 @@ namespace hpx::threads::coroutines::detail { 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_); @@ -183,6 +186,12 @@ namespace hpx::threads::coroutines::detail { 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); 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 1ea891f357ba..8819b21ab375 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 @@ -10,11 +10,9 @@ #include #include #include -#include #include #include -#include #include #include diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackless_self.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackless_self.hpp index e44c8950cc3e..903e911817ff 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackless_self.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/coroutine_stackless_self.hpp @@ -11,10 +11,8 @@ #include #include #include -#include #include -#include #include #include diff --git a/libs/core/coroutines/include/hpx/coroutines/detail/posix_utility.hpp b/libs/core/coroutines/include/hpx/coroutines/detail/posix_utility.hpp index 88255e18080a..4af47013f87b 100644 --- a/libs/core/coroutines/include/hpx/coroutines/detail/posix_utility.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/detail/posix_utility.hpp @@ -189,7 +189,7 @@ namespace hpx::threads::coroutines::detail::posix { * mmap (might be required on some systems) and/or * using a pooling allocator. * NOTE: the SuSv3 documentation explicitly allows - * the use of malloc to allocate stacks for makectx. + * the use of malloc to allocate stacks for makecontext. * We use new/delete for guaranteed alignment. */ inline void* alloc_stack(std::size_t size) diff --git a/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp b/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp index ff558d7168eb..b1783a6b8ba7 100644 --- a/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/stackless_coroutine.hpp @@ -11,14 +11,16 @@ #include #include #include -#include #include #include #include #include -#include +#if defined(HPX_HAVE_THREAD_LOCAL_STORAGE) +#include +#endif #include +#include #include namespace hpx::threads::coroutines { @@ -60,7 +62,7 @@ namespace hpx::threads::coroutines { std::ptrdiff_t /*stack_size*/ = default_stack_size) noexcept : f_(HPX_MOVE(f)) , state_(context_state::ready) - , id_(id) + , id_(HPX_MOVE(id)) #if defined(HPX_HAVE_THREAD_PHASE_INFORMATION) , phase_(0) #endif @@ -118,9 +120,9 @@ namespace hpx::threads::coroutines { return detail::set_tss_thread_data(thread_data_, data); } #else - std::size_t set_thread_data(std::size_t data) noexcept + std::size_t set_thread_data(std::size_t data) const noexcept { - std::size_t olddata = thread_data_; + std::size_t const olddata = thread_data_; thread_data_ = data; return olddata; } @@ -175,7 +177,7 @@ namespace hpx::threads::coroutines { HPX_ASSERT(exited()); f_ = HPX_MOVE(f); - id_ = id; + id_ = HPX_MOVE(id); #if defined(HPX_HAVE_THREAD_PHASE_INFORMATION) phase_ = 0; @@ -194,7 +196,7 @@ namespace hpx::threads::coroutines { detail::delete_tss_storage(thread_data_); } #else - void reset_tss() noexcept + void reset_tss() const noexcept { thread_data_ = 0; } @@ -215,13 +217,18 @@ namespace hpx::threads::coroutines { private: struct reset_on_exit { - explicit constexpr reset_on_exit( - stackless_coroutine& this__) noexcept - : this_(this__) + 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; @@ -244,7 +251,7 @@ namespace hpx::threads::coroutines { return state_ == context_state::ready; } - constexpr std::ptrdiff_t get_available_stack_space() const noexcept + static constexpr std::ptrdiff_t get_available_stack_space() noexcept { return (std::numeric_limits::max)(); } @@ -294,9 +301,7 @@ namespace hpx::threads::coroutines { detail::reset_self_on_exit on_self_exit(&self, nullptr); { - reset_on_exit on_exit{*this}; - - HPX_UNUSED(on_exit); + [[maybe_unused]] reset_on_exit const on_exit{*this}; result = f_(arg); // invoke wrapped function diff --git a/libs/core/coroutines/include/hpx/coroutines/thread_id_type.hpp b/libs/core/coroutines/include/hpx/coroutines/thread_id_type.hpp index 2e71a241ffaa..4e5803ae70dc 100644 --- a/libs/core/coroutines/include/hpx/coroutines/thread_id_type.hpp +++ b/libs/core/coroutines/include/hpx/coroutines/thread_id_type.hpp @@ -10,8 +10,6 @@ #pragma once #include -#include -#include #include #include @@ -36,6 +34,8 @@ namespace hpx::threads { thread_id(thread_id const&) = default; thread_id& operator=(thread_id const&) = default; + ~thread_id() = default; + constexpr thread_id(thread_id&& rhs) noexcept : thrd_(rhs.thrd_) { @@ -136,23 +136,10 @@ namespace hpx::threads { return !(rhs < lhs); } - template - friend std::basic_ostream& operator<<( - std::basic_ostream& os, thread_id const& id) - { - os << id.get(); - return os; - } - - friend void format_value( - std::ostream& os, std::string_view spec, thread_id const& id) - { - // propagate spec - char format[16]; - std::snprintf( - format, 16, "{:%.*s}", (int) spec.size(), spec.data()); - hpx::util::format_to(os, format, id.get()); - } + HPX_CORE_EXPORT friend std::ostream& operator<<( + std::ostream& os, thread_id const& id); + HPX_CORE_EXPORT friend void format_value( + std::ostream& os, std::string_view spec, thread_id const& id); private: thread_id_repr thrd_ = nullptr; @@ -169,8 +156,10 @@ namespace hpx::threads { struct thread_data_reference_counting; - void intrusive_ptr_add_ref(thread_data_reference_counting* p) noexcept; - void intrusive_ptr_release(thread_data_reference_counting* p) noexcept; + HPX_CORE_EXPORT void intrusive_ptr_add_ref( + thread_data_reference_counting* p) noexcept; + HPX_CORE_EXPORT void intrusive_ptr_release( + thread_data_reference_counting* p) noexcept; struct thread_data_reference_counting { @@ -183,26 +172,23 @@ namespace hpx::threads { { } + thread_data_reference_counting( + thread_data_reference_counting const&) = delete; + thread_data_reference_counting( + thread_data_reference_counting&&) = delete; + thread_data_reference_counting& operator=( + thread_data_reference_counting const&) = delete; + thread_data_reference_counting& operator=( + thread_data_reference_counting&&) = delete; + virtual ~thread_data_reference_counting() = default; virtual void destroy_thread() = 0; // reference counting - friend void intrusive_ptr_add_ref( - thread_data_reference_counting* p) noexcept - { - ++p->count_; - } - - friend void intrusive_ptr_release( - thread_data_reference_counting* p) noexcept - { - HPX_ASSERT(p->count_ != 0); - if (--p->count_ == 0) - { - // give this object back to the system - p->destroy_thread(); - } - } + HPX_CORE_EXPORT friend void intrusive_ptr_add_ref( + thread_data_reference_counting* p) noexcept; + HPX_CORE_EXPORT friend void intrusive_ptr_release( + thread_data_reference_counting* p) noexcept; util::atomic_count count_; }; @@ -224,6 +210,8 @@ namespace hpx::threads { thread_id_ref(thread_id_ref&& rhs) noexcept = default; thread_id_ref& operator=(thread_id_ref&& rhs) noexcept = default; + ~thread_id_ref() = default; + explicit thread_id_ref(thread_id_repr const& thrd) noexcept : thrd_(thrd) { @@ -248,7 +236,7 @@ namespace hpx::threads { explicit thread_id_ref(thread_repr* thrd, thread_id_addref addref = thread_id_addref::yes) noexcept - : thrd_(thrd, addref == thread_id_addref::yes ? 1 : 0) + : thrd_(thrd, addref == thread_id_addref::yes) { } @@ -287,21 +275,21 @@ namespace hpx::threads { return nullptr != thrd_; } - constexpr thread_id noref() const noexcept + [[nodiscard]] constexpr thread_id noref() const noexcept { return thread_id(thrd_.get()); } - constexpr thread_id_repr& get() & noexcept + [[nodiscard]] constexpr thread_id_repr& get() & noexcept { return thrd_; } - thread_id_repr&& get() && noexcept + [[nodiscard]] thread_id_repr&& get() && noexcept { return HPX_MOVE(thrd_); } - constexpr thread_id_repr const& get() const& noexcept + [[nodiscard]] constexpr thread_id_repr const& get() const& noexcept { return thrd_; } @@ -383,23 +371,10 @@ namespace hpx::threads { return !(rhs < lhs); } - template - friend std::basic_ostream& operator<<( - std::basic_ostream& os, thread_id_ref const& id) - { - os << id.get(); - return os; - } - - friend void format_value( - std::ostream& os, std::string_view spec, thread_id_ref const& id) - { - // propagate spec - char format[16]; - std::snprintf( - format, 16, "{:%.*s}", (int) spec.size(), spec.data()); - hpx::util::format_to(os, format, id.get()); - } + HPX_CORE_EXPORT friend std::ostream& operator<<( + std::ostream& os, thread_id_ref const& id); + HPX_CORE_EXPORT friend void format_value( + std::ostream& os, std::string_view spec, thread_id_ref const& id); private: thread_id_repr thrd_; @@ -422,7 +397,7 @@ namespace std { std::size_t operator()( ::hpx::threads::thread_id const& v) const noexcept { - std::hash hasher_; + constexpr std::hash hasher_; return hasher_(reinterpret_cast(v.get())); } }; @@ -433,7 +408,7 @@ namespace std { std::size_t operator()( ::hpx::threads::thread_id_ref const& v) const noexcept { - std::hash hasher_; + constexpr std::hash hasher_; return hasher_(reinterpret_cast(v.get().get())); } }; diff --git a/libs/core/coroutines/src/detail/coroutine_self.cpp b/libs/core/coroutines/src/detail/coroutine_self.cpp index bf6a917ba61f..9ef24b0663ae 100644 --- a/libs/core/coroutines/src/detail/coroutine_self.cpp +++ b/libs/core/coroutines/src/detail/coroutine_self.cpp @@ -1,16 +1,12 @@ -// Copyright (c) 2008-2022 Hartmut Kaiser +// Copyright (c) 2008-2023 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 -#include #include -#include - namespace hpx::threads::coroutines::detail { coroutine_self*& coroutine_self::local_self() noexcept diff --git a/libs/core/coroutines/src/detail/posix_utility.cpp b/libs/core/coroutines/src/detail/posix_utility.cpp index 8b50e4171d40..cfb53d9763d7 100644 --- a/libs/core/coroutines/src/detail/posix_utility.cpp +++ b/libs/core/coroutines/src/detail/posix_utility.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2005-2022 Hartmut Kaiser +// Copyright (c) 2005-2023 Hartmut Kaiser // Copyright (c) 2011 Bryce Adelstein-Lelbach // // SPDX-License-Identifier: BSL-1.0 @@ -14,9 +14,9 @@ namespace hpx::threads::coroutines::detail::posix { - /////////////////////////////////////////////////////////////////////// - // this global (urghhh) variable is used to control whether guard pages - // will be used or not + /////////////////////////////////////////////////////////////////////////// + // this global variable is used to control whether guard pages will be used + // or not bool use_guard_pages = true; } // namespace hpx::threads::coroutines::detail::posix diff --git a/libs/core/coroutines/src/thread_id_type.cpp b/libs/core/coroutines/src/thread_id_type.cpp new file mode 100644 index 000000000000..ddbfd0f95a58 --- /dev/null +++ b/libs/core/coroutines/src/thread_id_type.cpp @@ -0,0 +1,70 @@ +// Copyright (c) 2018 Thomas Heller +// Copyright (c) 2019-2023 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 +#include +#include +#include + +#include +#include +#include + +namespace hpx::threads { + + std::ostream& operator<<(std::ostream& os, thread_id const& id) + { + os << id.get(); + return os; + } + + void format_value( + std::ostream& os, std::string_view spec, thread_id const& id) + { + // propagate spec + char format[16]; + std::snprintf(format, sizeof(format), "{:%.*s}", + static_cast(spec.size()), spec.data()); + hpx::util::format_to(os, format, id.get()); + } + + namespace detail { + + // reference counting + void intrusive_ptr_add_ref(thread_data_reference_counting* p) noexcept + { + ++p->count_; + } + + void intrusive_ptr_release(thread_data_reference_counting* p) noexcept + { + HPX_ASSERT(p->count_ != 0); + if (--p->count_ == 0) + { + // give this object back to the system + p->destroy_thread(); + } + } + } // namespace detail + + /////////////////////////////////////////////////////////////////////////// + std::ostream& operator<<(std::ostream& os, thread_id_ref const& id) + { + os << id.get(); + return os; + } + + void format_value( + std::ostream& os, std::string_view spec, thread_id_ref const& id) + { + // propagate spec + char format[16]; + std::snprintf( + format, sizeof(format), "{:%.*s}", (int) spec.size(), spec.data()); + hpx::util::format_to(os, format, id.get()); + } +} // namespace hpx::threads diff --git a/libs/core/execution_base/include/hpx/execution_base/agent_base.hpp b/libs/core/execution_base/include/hpx/execution_base/agent_base.hpp index ffcc7e750a39..f45aca42ec7d 100644 --- a/libs/core/execution_base/include/hpx/execution_base/agent_base.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/agent_base.hpp @@ -18,9 +18,9 @@ namespace hpx::execution_base { { virtual ~agent_base() = default; - virtual std::string description() const = 0; + [[nodiscard]] virtual std::string description() const = 0; - virtual context_base const& context() const noexcept = 0; + [[nodiscard]] virtual context_base const& context() const noexcept = 0; virtual void yield(char const* desc) = 0; virtual void yield_k(std::size_t k, char const* desc) = 0; diff --git a/libs/core/execution_base/include/hpx/execution_base/agent_ref.hpp b/libs/core/execution_base/include/hpx/execution_base/agent_ref.hpp index 84956fea1517..6c7b4d0ae37b 100644 --- a/libs/core/execution_base/include/hpx/execution_base/agent_ref.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/agent_ref.hpp @@ -1,4 +1,5 @@ // Copyright (c) 2019 Thomas Heller +// Copyright (c) 2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -21,17 +22,17 @@ namespace hpx::execution_base { { public: agent_ref() = default; + ~agent_ref() = default; - constexpr agent_ref(agent_base* impl) noexcept + explicit constexpr agent_ref(agent_base* impl) noexcept : impl_(impl) { } - constexpr agent_ref(agent_ref const&) noexcept = default; - constexpr agent_ref& operator=(agent_ref const&) noexcept = default; - - constexpr agent_ref(agent_ref&&) noexcept = default; - constexpr agent_ref& operator=(agent_ref&&) noexcept = default; + agent_ref(agent_ref const&) = default; + agent_ref& operator=(agent_ref const&) = default; + agent_ref(agent_ref&&) = default; + agent_ref& operator=(agent_ref&&) = default; explicit constexpr operator bool() const noexcept { @@ -43,14 +44,16 @@ namespace hpx::execution_base { impl_ = impl; } - void yield(char const* desc = "hpx::execution_base::agent_ref::yield"); + void yield( + char const* desc = "hpx::execution_base::agent_ref::yield") const; void yield_k(std::size_t k, - char const* desc = "hpx::execution_base::agent_ref::yield_k"); + char const* desc = "hpx::execution_base::agent_ref::yield_k") const; void suspend( - char const* desc = "hpx::execution_base::agent_ref::suspend"); + char const* desc = "hpx::execution_base::agent_ref::suspend") const; void resume( - char const* desc = "hpx::execution_base::agent_ref::resume"); - void abort(char const* desc = "hpx::execution_base::agent_ref::abort"); + char const* desc = "hpx::execution_base::agent_ref::resume") const; + void abort( + char const* desc = "hpx::execution_base::agent_ref::abort") const; template void sleep_for(std::chrono::duration const& sleep_duration, @@ -67,7 +70,7 @@ namespace hpx::execution_base { sleep_until(hpx::chrono::steady_time_point{sleep_time}, desc); } - agent_base& ref() noexcept + [[nodiscard]] agent_base& ref() const noexcept { return *impl_; } @@ -81,9 +84,9 @@ namespace hpx::execution_base { agent_base* impl_ = nullptr; void sleep_for(hpx::chrono::steady_duration const& sleep_duration, - char const* desc); - void sleep_until( - hpx::chrono::steady_time_point const& sleep_time, char const* desc); + char const* desc) const; + void sleep_until(hpx::chrono::steady_time_point const& sleep_time, + char const* desc) const; friend constexpr bool operator==( agent_ref const& lhs, agent_ref const& rhs) noexcept diff --git a/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp b/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp index c6ec37671671..86f08ec8154a 100644 --- a/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/any_sender.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2021 ETH Zurich -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -101,13 +101,13 @@ namespace hpx::detail { return fits_storage && sufficiently_aligned; } - bool using_embedded_storage() const noexcept + [[nodiscard]] bool using_embedded_storage() const noexcept { return object == reinterpret_cast(&data.embedded_storage); } - bool empty() const noexcept + [[nodiscard]] bool empty() const noexcept { return get().empty(); } @@ -193,12 +193,12 @@ namespace hpx::detail { movable_sbo_storage(movable_sbo_storage const&) = delete; movable_sbo_storage& operator=(movable_sbo_storage const&) = delete; - base_type const& get() const noexcept + [[nodiscard]] base_type const& get() const noexcept { return *object; } - base_type& get() noexcept + [[nodiscard]] base_type& get() noexcept { return *object; } @@ -268,6 +268,7 @@ namespace hpx::detail { using storage_base_type::store; copyable_sbo_storage() = default; + ~copyable_sbo_storage() = default; copyable_sbo_storage(copyable_sbo_storage&&) = default; copyable_sbo_storage& operator=(copyable_sbo_storage&&) = default; @@ -299,7 +300,7 @@ namespace hpx::execution::experimental::detail { { virtual ~any_operation_state_base() = default; - virtual bool empty() const noexcept + [[nodiscard]] virtual bool empty() const noexcept { return false; } @@ -309,21 +310,18 @@ namespace hpx::execution::experimental::detail { struct HPX_CORE_EXPORT empty_any_operation_state final : any_operation_state_base { - bool empty() const noexcept override; + [[nodiscard]] bool empty() const noexcept override; void start() & noexcept override; }; } // namespace hpx::execution::experimental::detail -namespace hpx::detail { - - template <> - struct empty_vtable_type< - hpx::execution::experimental::detail::any_operation_state_base> - { - using type = - hpx::execution::experimental::detail::empty_any_operation_state; - }; -} // namespace hpx::detail +template <> +struct hpx::detail::empty_vtable_type< + hpx::execution::experimental::detail::any_operation_state_base> +{ + using type = + hpx::execution::experimental::detail::empty_any_operation_state; +}; // namespace hpx::detail namespace hpx::execution::experimental::detail { @@ -383,7 +381,7 @@ namespace hpx::execution::experimental::detail { virtual void set_value(Ts... ts) && = 0; virtual void set_error(std::exception_ptr ep) && noexcept = 0; virtual void set_stopped() && noexcept = 0; - virtual bool empty() const noexcept + [[nodiscard]] virtual bool empty() const noexcept { return false; } @@ -400,7 +398,7 @@ namespace hpx::execution::experimental::detail { HPX_UNREACHABLE; } - bool empty() const noexcept override + [[nodiscard]] bool empty() const noexcept override { return true; } @@ -422,16 +420,13 @@ namespace hpx::execution::experimental::detail { }; } // namespace hpx::execution::experimental::detail -namespace hpx::detail { - - template - struct empty_vtable_type< - hpx::execution::experimental::detail::any_receiver_base> - { - using type = - hpx::execution::experimental::detail::empty_any_receiver; - }; -} // namespace hpx::detail +template +struct hpx::detail::empty_vtable_type< + hpx::execution::experimental::detail::any_receiver_base> +{ + using type = + hpx::execution::experimental::detail::empty_any_receiver; +}; // namespace hpx::detail namespace hpx::execution::experimental::detail { @@ -551,7 +546,7 @@ namespace hpx::execution::experimental::detail { virtual void move_into(void* p) = 0; virtual any_operation_state connect( any_receiver&& receiver) && = 0; - virtual bool empty() const noexcept + [[nodiscard]] virtual bool empty() const noexcept { return false; } @@ -576,7 +571,7 @@ namespace hpx::execution::experimental::detail { HPX_UNREACHABLE; } - bool empty() const noexcept override + [[nodiscard]] bool empty() const noexcept override { return true; } @@ -606,7 +601,7 @@ namespace hpx::execution::experimental::detail { HPX_UNREACHABLE; } - bool empty() const noexcept override + [[nodiscard]] bool empty() const noexcept override { return true; } diff --git a/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp b/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp index 36cafc74fdfa..7e26205bed5a 100644 --- a/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/completion_signatures.hpp @@ -290,9 +290,10 @@ namespace hpx::execution::experimental { static constexpr bool sends_stopped = false; #if defined(HPX_HAVE_CXX20_COROUTINES) - bool await_ready(); - void await_suspend(hpx::coroutine_handle>); - dependent_completion_signatures await_resume(); + bool await_ready() = delete; + void await_suspend( + hpx::coroutine_handle>) = delete; + dependent_completion_signatures await_resume() = delete; #endif }; @@ -334,17 +335,16 @@ namespace hpx::execution::experimental { { }; - // sender only checks if T is an awaitable if enable_sender - // is false. Then it checks for awaitability with a promise type - // that doesn't have any environment queries, but that does have an - // await_transform that pipes the T through stdexec::as_awaitable. - // So you have two options for opting into the sender concept if you type - // is not generally awaitable: (1) specialize enable_sender, or (2) - // customize as_awaitable for T. + // sender only checks if T is an awaitable if enable_sender is + // false. Then it checks for awaitability with a promise type that + // doesn't have any environment queries, but that does have an + // await_transform that pipes the T through + // std::execution::as_awaitable. So you have two options for opting into + // the sender concept if you type is not generally awaitable: (1) + // specialize enable_sender, or (2) customize as_awaitable for T. HPX_HAS_MEMBER_XXX_TRAIT_DEF(is_sender) #ifdef HPX_HAVE_CXX20_COROUTINES - template inline constexpr bool is_enable_sender_v = has_is_sender_v; @@ -970,7 +970,7 @@ namespace hpx::execution::experimental { stopped_continuation.resume(); } friend coroutine_env_t tag_invoke( - get_env_t, const type& self) + get_env_t, type const& self) { if constexpr (hpx::functional::is_tag_invocable_v) @@ -996,7 +996,7 @@ namespace hpx::execution::experimental { template struct sender_awaitable_base { - constexpr bool await_ready() const noexcept + static constexpr bool await_ready() noexcept { return false; } @@ -1005,6 +1005,8 @@ namespace hpx::execution::experimental { { switch (result.index()) { + default: + [[fallthrough]]; case 0: // receiver contract not satisfied HPX_ASSERT_MSG(0, "_Should never get here"); break; @@ -1061,28 +1063,34 @@ namespace hpx::execution::experimental { if constexpr (hpx::functional::is_tag_invocable_v) { - using Result = + using result_type = hpx::functional::tag_invoke_result_t; constexpr bool Nothrow = hpx::functional::is_nothrow_tag_invocable_v; - return static_cast(nullptr); + return static_cast( + nullptr); } else if constexpr (is_awaitable_v) - { // NOT awaitable !! - return static_cast < T && (*) () noexcept > (nullptr); + { + // NOT awaitable !! + using func_type = T && (*) () noexcept; + return static_cast(nullptr); } else if constexpr (detail::is_awaitable_sender_v) { - using Result = detail::sender_awaitable_t; - constexpr bool Nothrow = std::is_nothrow_constructible_v>; - return static_cast(nullptr); + using result_type = detail::sender_awaitable_t; + constexpr bool Nothrow = + std::is_nothrow_constructible_v>; + return static_cast( + nullptr); } else { - return static_cast < T && (*) () noexcept > (nullptr); + using func_type = T && (*) () noexcept; + return static_cast(nullptr); } } @@ -1136,8 +1144,8 @@ namespace hpx::execution::experimental { } template - friend auto tag_invoke(get_env_t, const env_promise&) noexcept - -> const T&; + friend auto tag_invoke(get_env_t, env_promise const&) noexcept + -> T const&; }; struct with_awaitable_senders_base @@ -1176,7 +1184,7 @@ namespace hpx::execution::experimental { return continuation_handle; } - hpx::coroutine_handle<> unhandled_stopped() noexcept + hpx::coroutine_handle<> unhandled_stopped() const noexcept { return (*stopped_callback)(continuation_handle.address()); } @@ -1193,7 +1201,7 @@ namespace hpx::execution::experimental { // clang-format off template inline constexpr bool is_derived_from_v = std::is_base_of_v && - std::is_convertible_v; + std::is_convertible_v; // clang-format on template @@ -1211,22 +1219,22 @@ namespace hpx::execution::experimental { struct promise_base { - constexpr hpx::suspend_always initial_suspend() noexcept + static constexpr hpx::suspend_always initial_suspend() noexcept { return {}; } - [[noreturn]] hpx::suspend_always final_suspend() noexcept + [[noreturn]] static hpx::suspend_always final_suspend() noexcept { std::terminate(); } - [[noreturn]] void unhandled_exception() noexcept + [[noreturn]] static void unhandled_exception() noexcept { std::terminate(); } - [[noreturn]] void return_void() noexcept + [[noreturn]] static void return_void() noexcept { std::terminate(); } @@ -1238,7 +1246,7 @@ namespace hpx::execution::experimental { { Fun&& fun; - constexpr bool await_ready() noexcept + static constexpr bool await_ready() noexcept { return false; } @@ -1253,7 +1261,7 @@ namespace hpx::execution::experimental { HPX_FORWARD(Fun, fun)(); } - [[noreturn]] void await_resume() noexcept + [[noreturn]] static void await_resume() noexcept { std::terminate(); } @@ -1272,11 +1280,19 @@ namespace hpx::execution::experimental { { } + operation_base(operation_base const& other) = delete; operation_base(operation_base&& other) noexcept : coro_handle(std::exchange(other.coro_handle, {})) { } + operation_base& operator=(operation_base const&) = delete; + operation_base& operator=(operation_base&& rhs) noexcept + { + coro_handle = std::exchange(rhs.coro_handle, {}); + return *this; + } + ~operation_base() { if (coro_handle) @@ -1390,7 +1406,7 @@ namespace hpx::execution::experimental { fn_(); } - [[noreturn]] void await_resume() noexcept + [[noreturn]] static void await_resume() noexcept { std::terminate(); } @@ -1424,8 +1440,11 @@ namespace hpx::execution::experimental { eptr = std::current_exception(); } - co_await co_call(set_error, HPX_FORWARD(Receiver, rcvr), - HPX_FORWARD(std::exception_ptr, eptr)); + if (eptr) + { + co_await co_call(set_error, HPX_FORWARD(Receiver, rcvr), + HPX_FORWARD(std::exception_ptr, eptr)); + } } template struct sender_awaitable { - using Promise = hpx::meta::type; - using Sender = hpx::meta::type; - using Env = env_of_t; - using Value = single_sender_value_t; + using promise_type = hpx::meta::type; + using sender_type = hpx::meta::type; + using env_type = env_of_t; + using value_type = single_sender_value_t; - struct type : sender_awaitable_base + struct type : sender_awaitable_base { // clang-format off - type(Sender&& sender, hpx::coroutine_handle hcoro) - noexcept(has_nothrow_connect::value) - : op_state_(connect(HPX_FORWARD(Sender, sender), + type(sender_type&& sender, hpx::coroutine_handle hcoro) + noexcept(has_nothrow_connect::value) + : op_state_(connect(HPX_FORWARD(sender_type, sender), receiver{{&this->result, hcoro}})) { } // clang-format on - void await_suspend(hpx::coroutine_handle) noexcept + void await_suspend(hpx::coroutine_handle) noexcept { start(op_state_); } private: - using receiver = receiver_t; - connect_result_t op_state_; + using receiver = receiver_t; + connect_result_t op_state_; }; }; } // namespace detail diff --git a/libs/core/execution_base/include/hpx/execution_base/context_base.hpp b/libs/core/execution_base/include/hpx/execution_base/context_base.hpp index 64af64a2d448..8e88c7d65244 100644 --- a/libs/core/execution_base/include/hpx/execution_base/context_base.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/context_base.hpp @@ -7,9 +7,6 @@ #pragma once #include -#include - -#include namespace hpx::execution_base { diff --git a/libs/core/execution_base/include/hpx/execution_base/coroutine_utils.hpp b/libs/core/execution_base/include/hpx/execution_base/coroutine_utils.hpp index ba79fd05fae8..2125f8e82331 100644 --- a/libs/core/execution_base/include/hpx/execution_base/coroutine_utils.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/coroutine_utils.hpp @@ -1,4 +1,5 @@ // Copyright (c) 2022 Shreyas Atre +// Copyright (c) 2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -9,18 +10,7 @@ #include #if defined(HPX_HAVE_CXX20_COROUTINES) - -#include -#include -#include -#include #include -#include -#include - -#include -#include -#include namespace hpx::execution::experimental { @@ -33,14 +23,14 @@ namespace hpx::execution::experimental { // E names the type decltype((e)) and P names the type decltype((p)), // as_awaitable(e, p) is expression-equivalent to the following: // - // 1. tag_invoke(as_awaitable, e, p) - // if that expression is well-formed. - // -- Mandates: is-awaitable is true, - // where A is the type of the tag_invoke expression above. - // 2. Otherwise, e if is-awaitable is true. - // 3. Otherwise, sender-awaitable{e, p} if awaitable-sender + // 1. tag_invoke(as_awaitable, e, p) + // if that expression is well-formed. + // -- Mandates: is-awaitable is true, + // where A is the type of the tag_invoke expression above. + // 2. Otherwise, e if is-awaitable is true. + // 3. Otherwise, sender-awaitable{e, p} if awaitable-sender // is true. - // 4. Otherwise, e. + // 4. Otherwise, e. struct as_awaitable_t; struct connect_awaitable_t; diff --git a/libs/core/execution_base/include/hpx/execution_base/receiver.hpp b/libs/core/execution_base/include/hpx/execution_base/receiver.hpp index 84dfb965d1a1..61965b969ebb 100644 --- a/libs/core/execution_base/include/hpx/execution_base/receiver.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/receiver.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2020 Thomas Heller -// Copyright (c) 2020 Hartmut Kaiser +// Copyright (c) 2020-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -22,68 +22,73 @@ namespace hpx::execution::experimental { #if defined(DOXYGEN) /// set_value is a customization point object. The expression /// `hpx::execution::set_value(r, as...)` is equivalent to: - /// * `r.set_value(as...)`, if that expression is valid. If the function selected - /// does not send the value(s) `as...` to the Receiver `r`'s value channel, - /// the program is ill-formed (no diagnostic required). + /// * `r.set_value(as...)`, if that expression is valid. If the function + /// selected does not send the value(s) `as...` to the Receiver `r`'s + /// value channel, the program is ill-formed (no diagnostic required). /// * Otherwise, `set_value(r, as...), if that expression is valid, with - /// overload resolution performed in a context that include the declaration - /// `void set_value();` + /// overload resolution performed in a context that include the + /// declaration `void set_value();` /// * Otherwise, the expression is ill-formed. /// - /// The customization is implemented in terms of `hpx::functional::tag_invoke`. + /// The customization is implemented in terms of + /// `hpx::functional::tag_invoke`. template void set_value(R&& r, As&&... as); /// set_stopped is a customization point object. The expression /// `hpx::execution::set_stopped(r)` is equivalent to: - /// * `r.set_stopped()`, if that expression is valid. If the function selected - /// does not signal the Receiver `r`'s done channel, - /// the program is ill-formed (no diagnostic required). + /// * `r.set_stopped()`, if that expression is valid. If the function + /// selected does not signal the Receiver `r`'s done channel, the + /// program is ill-formed (no diagnostic required). /// * Otherwise, `set_stopped(r), if that expression is valid, with - /// overload resolution performed in a context that include the declaration - /// `void set_stopped();` + /// overload resolution performed in a context that include the + /// declaration `void set_stopped();` /// * Otherwise, the expression is ill-formed. /// - /// The customization is implemented in terms of `hpx::functional::tag_invoke`. + /// The customization is implemented in terms of + /// `hpx::functional::tag_invoke`. template void set_stopped(R&& r); /// set_error is a customization point object. The expression /// `hpx::execution::set_error(r, e)` is equivalent to: - /// * `r.set_stopped(e)`, if that expression is valid. If the function selected - /// does not send the error `e` the Receiver `r`'s error channel, - /// the program is ill-formed (no diagnostic required). + /// * `r.set_stopped(e)`, if that expression is valid. If the function + /// selected does not send the error `e` the Receiver `r`'s error + /// channel, the program is ill-formed (no diagnostic required). /// * Otherwise, `set_error(r, e), if that expression is valid, with - /// overload resolution performed in a context that include the declaration - /// `void set_error();` + /// overload resolution performed in a context that include the + /// declaration `void set_error();` /// * Otherwise, the expression is ill-formed. /// - /// The customization is implemented in terms of `hpx::functional::tag_invoke`. + /// The customization is implemented in terms of + /// `hpx::functional::tag_invoke`. template void set_error(R&& r, E&& e); #endif - /// Receiving values from asynchronous computations is handled by the `Receiver` - /// concept. A `Receiver` needs to be able to receive an error or be marked as - /// being canceled. As such, the Receiver concept is defined by having the - /// following two customization points defined, which form the completion-signal - /// operations: - /// * `hpx::execution::experimental::set_stopped` - /// * `hpx::execution::experimental::set_error` + /// Receiving values from asynchronous computations is handled by the + /// `Receiver` concept. A `Receiver` needs to be able to receive an error or + /// be marked as being canceled. As such, the Receiver concept is defined by + /// having the following two customization points defined, which form the + /// completion-signal operations: + /// * `hpx::execution::experimental::set_stopped` * + /// `hpx::execution::experimental::set_error` /// - /// Those two functions denote the completion-signal operations. The Receiver - /// contract is as follows: + /// Those two functions denote the completion-signal operations. The + /// Receiver contract is as follows: /// * None of a Receiver's completion-signal operation shall be invoked - /// before `hpx::execution::experimental::start` has been called on the operation - /// state object that was returned by connecting a Receiver to a sender - /// `hpx::execution::experimental::connect`. + /// before `hpx::execution::experimental::start` has been called on + /// the operation state object that was returned by connecting a + /// Receiver to a sender `hpx::execution::experimental::connect`. /// * Once `hpx::execution::start` has been called on the operation - /// state object, exactly one of the Receiver's completion-signal operation - /// shall complete without an exception before the Receiver is destroyed + /// state object, exactly one of the Receiver's completion-signal + /// operation shall complete without an exception before the Receiver + /// is destroyed /// - /// Once one of the Receiver's completion-signal operation has been completed - /// without throwing an exception, the Receiver contract has been satisfied. - /// In other words: The asynchronous operation has been completed. + /// Once one of the Receiver's completion-signal operation has been + /// completed without throwing an exception, the Receiver contract has been + /// satisfied. In other words: The asynchronous operation has been + /// completed. /// /// \see hpx::execution::experimental::is_receiver_of template @@ -94,13 +99,12 @@ namespace hpx::execution::experimental { /// * `hpx::execution::set_value` /// /// The `receiver_of` concept takes a receiver and an instance of the - /// `completion_signatures<>` class template. - /// The `receiver_of` concept, rather than accepting a receiver and some - /// value types, is changed to take a receiver and an instance of the - /// `completion_signatures<>` class template. - /// A sender uses `completion_signatures<>` to describe the signals - /// with which it completes. The `receiver_of` concept ensures that a - /// particular receiver is capable of receiving those signals. + /// `completion_signatures<>` class template. The `receiver_of` concept, + /// rather than accepting a receiver and some value types, is changed to + /// take a receiver and an instance of the `completion_signatures<>` class + /// template. A sender uses `completion_signatures<>` to describe the + /// signals with which it completes. The `receiver_of` concept ensures that + /// a particular receiver is capable of receiving those signals. /// /// This completion-signal operation adds the following to the Receiver's /// contract: @@ -150,8 +154,8 @@ namespace hpx::execution::experimental { template struct is_receiver : detail::is_receiver_impl< - std::is_move_constructible>::value && - std::is_constructible, T>::value, + std::is_move_constructible_v> && + std::is_constructible_v, T>, T, E> { }; diff --git a/libs/core/execution_base/include/hpx/execution_base/sender.hpp b/libs/core/execution_base/include/hpx/execution_base/sender.hpp index f0de58c030a8..e9da414662f5 100644 --- a/libs/core/execution_base/include/hpx/execution_base/sender.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/sender.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2020 Thomas Heller -// Copyright (c) 2022 Hartmut Kaiser +// Copyright (c) 2022-2023 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -20,9 +20,7 @@ #include #include -#include #include -#include namespace hpx::execution::experimental { @@ -126,12 +124,12 @@ namespace hpx::execution::experimental { } template - [[noreturn]] void set_error(E_&&) noexcept + [[noreturn]] static void set_error(E_&&) noexcept { std::terminate(); } - constexpr void set_stopped() noexcept {} + static constexpr void set_stopped() noexcept {} }; } // namespace detail diff --git a/libs/core/execution_base/include/hpx/execution_base/this_thread.hpp b/libs/core/execution_base/include/hpx/execution_base/this_thread.hpp index d7f86cf5e336..6bfa339d87e5 100644 --- a/libs/core/execution_base/include/hpx/execution_base/this_thread.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/this_thread.hpp @@ -10,16 +10,15 @@ #include #include #include -#include #include #include #include #include #include -#include #ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION #include +#include #endif #include @@ -47,6 +46,11 @@ namespace hpx::execution_base { explicit reset_agent(agent_base& impl); reset_agent(detail::agent_storage*, agent_base& impl); + reset_agent(reset_agent const&) = delete; + reset_agent(reset_agent&&) = delete; + reset_agent& operator=(reset_agent const&) = delete; + reset_agent& operator=(reset_agent&&) = delete; + ~reset_agent(); detail::agent_storage* storage_; @@ -225,7 +229,7 @@ namespace hpx::util { using duration_type = std::chrono::duration; // Initialize timer only if needed - bool use_timeout = timeout >= duration_type(0.0); + bool const use_timeout = timeout >= duration_type(0.0); hpx::chrono::high_resolution_timer t( hpx::chrono::high_resolution_timer::init::no_init); diff --git a/libs/core/execution_base/include/hpx/execution_base/traits/coroutine_traits.hpp b/libs/core/execution_base/include/hpx/execution_base/traits/coroutine_traits.hpp index e02cef46ed81..665fd4f077a6 100644 --- a/libs/core/execution_base/include/hpx/execution_base/traits/coroutine_traits.hpp +++ b/libs/core/execution_base/include/hpx/execution_base/traits/coroutine_traits.hpp @@ -184,7 +184,7 @@ namespace hpx::execution::experimental { // member then the awaitable is the awaited value itself. // // The awaitable concept simply checks whether the type supports applying - // the co_await operator to avalue of that type. If the object has either a + // the co_await operator to a value of that type. If the object has either a // member or non-member operator co_await() then its return value must // satisfy the Awaiter concept. Otherwise, the Awaitable object must satisfy // the Awaiter concept itself. diff --git a/libs/core/execution_base/src/agent_ref.cpp b/libs/core/execution_base/src/agent_ref.cpp index bfa511108788..4aaad279ad71 100644 --- a/libs/core/execution_base/src/agent_ref.cpp +++ b/libs/core/execution_base/src/agent_ref.cpp @@ -15,7 +15,7 @@ namespace hpx::execution_base { - void agent_ref::yield(const char* desc) + void agent_ref::yield(const char* desc) const { HPX_ASSERT(*this == hpx::execution_base::this_thread::agent()); @@ -24,7 +24,7 @@ namespace hpx::execution_base { impl_->yield(desc); } - void agent_ref::yield_k(std::size_t k, const char* desc) + void agent_ref::yield_k(std::size_t k, const char* desc) const { HPX_ASSERT(*this == hpx::execution_base::this_thread::agent()); @@ -33,7 +33,7 @@ namespace hpx::execution_base { impl_->yield_k(k, desc); } - void agent_ref::suspend(const char* desc) + void agent_ref::suspend(const char* desc) const { HPX_ASSERT(*this == hpx::execution_base::this_thread::agent()); @@ -42,27 +42,29 @@ namespace hpx::execution_base { impl_->suspend(desc); } - void agent_ref::resume(const char* desc) + void agent_ref::resume(const char* desc) const { HPX_ASSERT(*this != hpx::execution_base::this_thread::agent()); impl_->resume(desc); } - void agent_ref::abort(const char* desc) + void agent_ref::abort(const char* desc) const { HPX_ASSERT(*this != hpx::execution_base::this_thread::agent()); impl_->abort(desc); } void agent_ref::sleep_for( - hpx::chrono::steady_duration const& sleep_duration, const char* desc) + hpx::chrono::steady_duration const& sleep_duration, + const char* desc) const { HPX_ASSERT(*this == hpx::execution_base::this_thread::agent()); impl_->sleep_for(sleep_duration, desc); } void agent_ref::sleep_until( - hpx::chrono::steady_time_point const& sleep_time, const char* desc) + hpx::chrono::steady_time_point const& sleep_time, + const char* desc) const { HPX_ASSERT(*this == hpx::execution_base::this_thread::agent()); impl_->sleep_until(sleep_time, desc); diff --git a/libs/core/execution_base/src/spinlock_deadlock_detection.cpp b/libs/core/execution_base/src/spinlock_deadlock_detection.cpp index 6cbdf82b2caf..01b03855050b 100644 --- a/libs/core/execution_base/src/spinlock_deadlock_detection.cpp +++ b/libs/core/execution_base/src/spinlock_deadlock_detection.cpp @@ -9,12 +9,12 @@ //////////////////////////////////////////////////////////////////////////////// #include + +#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION #include #include -#ifdef HPX_HAVE_SPINLOCK_DEADLOCK_DETECTION - namespace hpx::util::detail { static bool spinlock_break_on_deadlock_enabled = false; @@ -41,4 +41,5 @@ namespace hpx::util::detail { return spinlock_deadlock_detection_limit; } } // namespace hpx::util::detail + #endif diff --git a/libs/core/execution_base/src/this_thread.cpp b/libs/core/execution_base/src/this_thread.cpp index b2727d338329..93aece98c9cb 100644 --- a/libs/core/execution_base/src/this_thread.cpp +++ b/libs/core/execution_base/src/this_thread.cpp @@ -52,12 +52,13 @@ namespace hpx::execution_base { { default_agent(); - std::string description() const override + [[nodiscard]] std::string description() const override { return hpx::util::format("{}", id_); } - default_context const& context() const noexcept override + [[nodiscard]] default_context const& context() + const noexcept override { return context_; } @@ -199,7 +200,7 @@ namespace hpx::execution_base { namespace detail { - agent_base& get_default_agent() + [[nodiscard]] agent_base& get_default_agent() { static thread_local default_agent agent; return agent; @@ -226,7 +227,7 @@ namespace hpx::execution_base { agent_base* impl_; }; - agent_storage* get_agent_storage() + [[nodiscard]] agent_storage* get_agent_storage() { static thread_local agent_storage storage; return &storage; @@ -250,10 +251,9 @@ namespace hpx::execution_base { storage_->set(old_); } - hpx::execution_base::agent_ref agent() + [[nodiscard]] agent_ref agent() { - return hpx::execution_base::agent_ref( - detail::get_agent_storage()->impl_); + return agent_ref(detail::get_agent_storage()->impl_); } void yield(char const* desc) diff --git a/libs/core/ini/include/hpx/ini/ini.hpp b/libs/core/ini/include/hpx/ini/ini.hpp index 48dbafb588a9..08405e296eb5 100644 --- a/libs/core/ini/include/hpx/ini/ini.hpp +++ b/libs/core/ini/include/hpx/ini/ini.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2005-2007 Andre Merzky -// Copyright (c) 2005-2022 Hartmut Kaiser +// Copyright (c) 2005-2023 Hartmut Kaiser // Copyright (c) 2011 Bryce Lelbach // // SPDX-License-Identifier: BSL-1.0 @@ -73,7 +73,7 @@ namespace hpx::util { protected: void line_msg(std::string msg, std::string const& file, int lnum = 0, - std::string const& line = ""); + std::string const& line = "") const; section& clone_from(section const& rhs, section* root = nullptr); @@ -104,7 +104,7 @@ namespace hpx::util { std::string get_entry( std::unique_lock& l, std::string const& key) const; std::string get_entry(std::unique_lock& l, - std::string const& key, std::string const& dflt) const; + std::string const& key, std::string const& default_val) const; void add_notification_callback(std::unique_lock& l, std::string const& key, entry_changed_func const& callback); @@ -132,7 +132,7 @@ namespace hpx::util { } void read(std::string const& filename); - void merge(std::string const& second); + void merge(std::string const& filename); void merge(section& second); void dump(int ind = 0) const; void dump(int ind, std::ostream& strm) const; @@ -229,7 +229,7 @@ namespace hpx::util { private: std::string expand( - std::unique_lock& l, std::string in) const; + std::unique_lock& l, std::string value) const; void expand(std::unique_lock& l, std::string&, std::string::size_type) const; @@ -238,8 +238,8 @@ namespace hpx::util { void expand_brace(std::unique_lock& l, std::string&, std::string::size_type) const; - std::string expand_only(std::unique_lock& l, std::string in, - std::string const& expand_this) const; + std::string expand_only(std::unique_lock& l, + std::string value, std::string const& expand_this) const; void expand_only(std::unique_lock& l, std::string&, std::string::size_type, std::string const& expand_this) const; @@ -266,9 +266,8 @@ namespace hpx::util { root_ = r; if (recursive) { - section_map::iterator send = sections_.end(); - for (section_map::iterator si = sections_.begin(); si != send; - ++si) + auto const send = sections_.end(); + for (auto si = sections_.begin(); si != send; ++si) si->second.set_root(r, true); } } diff --git a/libs/core/ini/src/ini.cpp b/libs/core/ini/src/ini.cpp index 3c38c1338637..45b47440e304 100644 --- a/libs/core/ini/src/ini.cpp +++ b/libs/core/ini/src/ini.cpp @@ -56,11 +56,11 @@ namespace hpx::util { { typedef std::string::size_type size_type; - size_type first = s.find_first_not_of(" \t\r\n"); + size_type const first = s.find_first_not_of(" \t\r\n"); if (std::string::npos == first) return (std::string()); - size_type last = s.find_last_not_of(" \t\r\n"); + size_type const last = s.find_last_not_of(" \t\r\n"); return s.substr(first, last - first + 1); } @@ -101,13 +101,13 @@ namespace hpx::util { , parent_name_(in.get_parent_name()) { entry_map const& e = in.get_entries(); - entry_map::const_iterator end = e.end(); - for (entry_map::const_iterator i = e.begin(); i != end; ++i) + auto const end = e.end(); + for (auto i = e.begin(); i != end; ++i) add_entry(i->first, i->second); section_map s = in.get_sections(); - section_map::iterator send = s.end(); - for (section_map::iterator si = s.begin(); si != send; ++si) + auto const send = s.end(); + for (auto si = s.begin(); si != send; ++si) add_section(si->first, si->second, get_root()); } @@ -122,13 +122,13 @@ namespace hpx::util { name_ = rhs.get_name(); entry_map const& e = rhs.get_entries(); - entry_map::const_iterator end = e.end(); - for (entry_map::const_iterator i = e.begin(); i != end; ++i) + auto const end = e.end(); + for (auto i = e.begin(); i != end; ++i) add_entry(l, i->first, i->first, i->second); section_map s = rhs.get_sections(); - section_map::iterator send = s.end(); - for (section_map::iterator si = s.begin(); si != send; ++si) + auto const send = s.end(); + for (auto si = s.begin(); si != send; ++si) add_section(l, si->first, si->second, get_root()); } return *this; @@ -145,13 +145,13 @@ namespace hpx::util { name_ = rhs.get_name(); entry_map const& e = rhs.get_entries(); - entry_map::const_iterator end = e.end(); - for (entry_map::const_iterator i = e.begin(); i != end; ++i) + auto const end = e.end(); + for (auto i = e.begin(); i != end; ++i) add_entry(l, i->first, i->first, i->second); section_map s = rhs.get_sections(); - section_map::iterator send = s.end(); - for (section_map::iterator si = s.begin(); si != send; ++si) + auto const send = s.end(); + for (auto si = s.begin(); si != send; ++si) add_section(l, si->first, si->second, get_root()); } return *this; @@ -187,7 +187,7 @@ namespace hpx::util { bool force_entry(std::string& str) { - std::string::size_type p = str.find_last_of('!'); + std::string::size_type const p = str.find_last_of('!'); if (p != std::string::npos && str.find_first_not_of(" \t", p + 1) == std::string::npos) { @@ -207,9 +207,8 @@ namespace hpx::util { std::regex regex_comment(pattern_comment, std::regex_constants::icase); - std::vector::const_iterator end = lines.end(); - for (std::vector::const_iterator it = lines.begin(); - it != end; ++it) + auto const end = lines.end(); + for (auto it = lines.begin(); it != end; ++it) { ++linenum; @@ -233,17 +232,17 @@ namespace hpx::util { continue; } } - // no comments anymore: line is either section, key=val, - // or garbage/empty + // no comments anymore: line is either section, key=val, or + // garbage/empty - // Check if we have a section. - // Example: [sec.ssec] + // Check if we have a section. Example: [sec.ssec] if (line.front() == '[' && line.back() == ']') { current = this; // start adding sections at the root - // got the section name. It might be hierarchical, so split it up, and - // for each elem, check if we have it. If not, create it, and add + // got the section name. It might be hierarchical, so split it + // up, and for each elem, check if we have it. If not, create + // it, and add std::string sec_name(line.substr(1, line.size() - 2)); std::string::size_type pos = 0; for (std::string::size_type pos1 = sec_name.find_first_of('.'); @@ -348,15 +347,15 @@ namespace hpx::util { bool section::has_section( std::unique_lock& l, std::string const& sec_name) const { - std::string::size_type i = sec_name.find('.'); + std::string::size_type const i = sec_name.find('.'); if (i != std::string::npos) { - std::string cor_sec_name = sec_name.substr(0, i); + std::string const cor_sec_name = sec_name.substr(0, i); - section_map::const_iterator it = sections_.find(cor_sec_name); + auto const it = sections_.find(cor_sec_name); if (it != sections_.end()) { - std::string sub_sec_name = sec_name.substr(i + 1); + std::string const sub_sec_name = sec_name.substr(i + 1); hpx::unlock_guard> ul(l); return (*it).second.has_section(sub_sec_name); } @@ -368,14 +367,14 @@ namespace hpx::util { section* section::get_section( std::unique_lock& l, std::string const& sec_name) { - std::string::size_type i = sec_name.find('.'); + std::string::size_type const i = sec_name.find('.'); if (i != std::string::npos) { - std::string cor_sec_name = sec_name.substr(0, i); - section_map::iterator it = sections_.find(cor_sec_name); + std::string const cor_sec_name = sec_name.substr(0, i); + auto const it = sections_.find(cor_sec_name); if (it != sections_.end()) { - std::string sub_sec_name = sec_name.substr(i + 1); + std::string const sub_sec_name = sec_name.substr(i + 1); hpx::unlock_guard> ul(l); return (*it).second.get_section(sub_sec_name); } @@ -387,29 +386,27 @@ namespace hpx::util { HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section", "No such section ({}) in section: {}", sec_name, name); - return nullptr; } - section_map::iterator it = sections_.find(sec_name); + auto const it = sections_.find(sec_name); if (it != sections_.end()) return &((*it).second); HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section", "No such section ({}) in section: {}", sec_name, get_name()); - return nullptr; } section const* section::get_section( std::unique_lock& l, std::string const& sec_name) const { - std::string::size_type i = sec_name.find('.'); + std::string::size_type const i = sec_name.find('.'); if (i != std::string::npos) { - std::string cor_sec_name = sec_name.substr(0, i); - section_map::const_iterator it = sections_.find(cor_sec_name); + std::string const cor_sec_name = sec_name.substr(0, i); + auto const it = sections_.find(cor_sec_name); if (it != sections_.end()) { - std::string sub_sec_name = sec_name.substr(i + 1); + std::string const sub_sec_name = sec_name.substr(i + 1); hpx::unlock_guard> ul(l); return (*it).second.get_section(sub_sec_name); } @@ -421,32 +418,30 @@ namespace hpx::util { HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section", "No such section ({}) in section: {}", sec_name, name); - return nullptr; } - section_map::const_iterator it = sections_.find(sec_name); + auto const it = sections_.find(sec_name); if (it != sections_.end()) return &((*it).second); HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_section", "No such section ({}) in section: {}", sec_name, get_name()); - return nullptr; } void section::add_entry(std::unique_lock& l, std::string const& fullkey, std::string const& key, std::string val) { // first expand the full property name in the value (avoids infinite recursion) - expand_only( - l, val, std::string::size_type(-1), get_full_name() + "." + key); + expand_only(l, val, static_cast(-1), + get_full_name() + "." + key); - std::string::size_type i = key.find_last_of('.'); + std::string::size_type const i = key.find_last_of('.'); if (i != std::string::npos) { section* current = root_; // make sure all sections in key exist - std::string sec_name = key.substr(0, i); + std::string const sec_name = key.substr(0, i); std::string::size_type pos = 0; for (std::string::size_type pos1 = sec_name.find_first_of('.'); @@ -464,15 +459,15 @@ namespace hpx::util { } else { - entry_map::iterator it = entries_.find(key); + auto const it = entries_.find(key); if (it != entries_.end()) { auto& e = it->second; e.first = HPX_MOVE(val); if (!e.second.empty()) { - std::string value = e.first; - entry_changed_func f = e.second; + std::string const value = e.first; + entry_changed_func const f = e.second; hpx::unlock_guard> ul(l); f(fullkey, value); @@ -490,13 +485,13 @@ namespace hpx::util { std::string const& fullkey, std::string const& key, entry_type const& val) { - std::string::size_type i = key.find_last_of('.'); + std::string::size_type const i = key.find_last_of('.'); if (i != std::string::npos) { section* current = root_; // make sure all sections in key exist - std::string sec_name = key.substr(0, i); + std::string const sec_name = key.substr(0, i); std::string::size_type pos = 0; for (std::string::size_type pos1 = sec_name.find_first_of('.'); @@ -514,15 +509,15 @@ namespace hpx::util { } else { - entry_map::iterator it = entries_.find(key); + auto const it = entries_.find(key); if (it != entries_.end()) { auto& second = it->second; second = val; if (!second.second.empty()) { - std::string value = second.first; - entry_changed_func f = second.second; + std::string const value = second.first; + entry_changed_func const f = second.second; hpx::unlock_guard> ul(l); f(fullkey, value); @@ -531,19 +526,19 @@ namespace hpx::util { else { // just add this entry to the section - std::pair p = + std::pair const p = entries_.emplace(key, val); HPX_ASSERT(p.second); - auto& second = p.first->second; + auto const& second = p.first->second; if (!second.second.empty()) { - std::string key = p.first->first; - std::string value = second.first; - entry_changed_func f = second.second; + std::string const k = p.first->first; + std::string const value = second.first; + entry_changed_func const f = second.second; hpx::unlock_guard> ul(l); - f(key, value); + f(k, value); } } } @@ -591,13 +586,13 @@ namespace hpx::util { void section::add_notification_callback(std::unique_lock& l, std::string const& key, entry_changed_func const& callback) { - std::string::size_type i = key.find_last_of('.'); + std::string::size_type const i = key.find_last_of('.'); if (i != std::string::npos) { section* current = root_; // make sure all sections in key exist - std::string sec_name = key.substr(0, i); + std::string const sec_name = key.substr(0, i); std::string::size_type pos = 0; for (std::string::size_type pos1 = sec_name.find_first_of('.'); @@ -616,7 +611,7 @@ namespace hpx::util { else { // just add this entry to the section - entry_map::iterator it = entries_.find(key); + auto const it = entries_.find(key); if (it != entries_.end()) { it->second.second = @@ -632,14 +627,14 @@ namespace hpx::util { bool section::has_entry( std::unique_lock& l, std::string const& key) const { - std::string::size_type i = key.find('.'); + std::string::size_type const i = key.find('.'); if (i != std::string::npos) { - std::string sub_sec = key.substr(0, i); + std::string const sub_sec = key.substr(0, i); if (has_section(l, sub_sec)) { - std::string sub_key = key.substr(i + 1, key.size() - i); - section_map::const_iterator cit = sections_.find(sub_sec); + std::string const sub_key = key.substr(i + 1, key.size() - i); + auto const cit = sections_.find(sub_sec); HPX_ASSERT(cit != sections_.end()); hpx::unlock_guard> ul(l); return (*cit).second.has_entry(sub_key); //-V783 @@ -652,14 +647,14 @@ namespace hpx::util { std::string section::get_entry( std::unique_lock& l, std::string const& key) const { - std::string::size_type i = key.find('.'); - if (i != std::string::npos) + if (std::string::size_type const i = key.find('.'); + i != std::string::npos) { - std::string sub_sec = key.substr(0, i); + std::string const sub_sec = key.substr(0, i); if (has_section(l, sub_sec)) { - std::string sub_key = key.substr(i + 1, key.size() - i); - section_map::const_iterator cit = sections_.find(sub_sec); + std::string const sub_key = key.substr(i + 1, key.size() - i); + auto const cit = sections_.find(sub_sec); HPX_ASSERT(cit != sections_.end()); hpx::unlock_guard> ul(l); return (*cit).second.get_entry(sub_key); //-V783 @@ -667,19 +662,17 @@ namespace hpx::util { HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry", "No such key ({}) in section: {}", key, get_name()); - return ""; } if (entries_.find(key) != entries_.end()) { - entry_map::const_iterator cit = entries_.find(key); + auto const cit = entries_.find(key); HPX_ASSERT(cit != entries_.end()); return expand(l, (*cit).second.first); //-V783 } HPX_THROW_EXCEPTION(hpx::error::bad_parameter, "section::get_entry", "No such section ({}) in section: {}", key, get_name()); - return ""; } std::string section::get_entry(std::unique_lock& l, @@ -691,22 +684,19 @@ namespace hpx::util { hpx::string_util::split( split_key, key, hpx::string_util::is_any_of(".")); - std::string sk = split_key.back(); + std::string const sk = split_key.back(); split_key.pop_back(); section const* cur_section = this; - for (string_vector::const_iterator iter = split_key.begin(), - end = split_key.end(); - iter != end; ++iter) + for (const auto& iter : split_key) { - section_map::const_iterator next = - cur_section->sections_.find(*iter); + auto next = cur_section->sections_.find(iter); if (cur_section->sections_.end() == next) return expand(l, default_val); cur_section = &next->second; } - entry_map::const_iterator entry = cur_section->entries_.find(sk); + auto const entry = cur_section->entries_.find(sk); if (cur_section->entries_.end() == entry) return expand(l, default_val); @@ -747,8 +737,8 @@ namespace hpx::util { } } - entry_map::const_iterator eend = entries_.end(); - for (entry_map::const_iterator i = entries_.begin(); i != eend; ++i) + auto const eend = entries_.end(); + for (auto i = entries_.begin(); i != eend; ++i) { indent(ind, strm); @@ -769,8 +759,8 @@ namespace hpx::util { } } - section_map::const_iterator send = sections_.end(); - for (section_map::const_iterator i = sections_.begin(); i != send; ++i) + auto const send = sections_.end(); + for (auto i = sections_.begin(); i != send; ++i) { indent(ind, strm); strm << "[" << i->first << "]\n"; @@ -795,13 +785,13 @@ namespace hpx::util { // merge entries: keep own entries, and add other entries entry_map const& s_entries = second.get_entries(); - entry_map::const_iterator end = s_entries.end(); - for (entry_map::const_iterator i = s_entries.begin(); i != end; ++i) + auto const end = s_entries.end(); + for (auto i = s_entries.begin(); i != end; ++i) entries_[i->first] = i->second; // merge subsection known in first section - section_map::iterator send = sections_.end(); - for (section_map::iterator i = sections_.begin(); i != send; ++i) + auto const send = sections_.end(); + for (auto i = sections_.begin(); i != send; ++i) { // is there something to merge with? if (second.has_section(l, i->first)) @@ -810,8 +800,8 @@ namespace hpx::util { // merge subsection known in second section section_map s = second.get_sections(); - section_map::iterator secend = s.end(); - for (section_map::iterator i = s.begin(); i != secend; ++i) + auto const secend = s.end(); + for (auto i = s.begin(); i != secend; ++i) { // if THIS knows the section, we already merged it above if (!has_section(l, i->first)) @@ -824,7 +814,7 @@ namespace hpx::util { ///////////////////////////////////////////////////////////////////////////////// void section::line_msg(std::string msg, std::string const& file, int lnum, - std::string const& line) + std::string const& line) const { msg += " " + file; if (lnum > 0) @@ -874,11 +864,11 @@ namespace hpx::util { expand(l, value, begin); // now expand the key itself - std::string::size_type end = find_next("]", value, begin + 1); + std::string::size_type const end = find_next("]", value, begin + 1); if (end != std::string::npos) { std::string to_expand = value.substr(begin + 2, end - begin - 2); - std::string::size_type colon = find_next(":", to_expand); + std::string::size_type const colon = find_next(":", to_expand); if (colon == std::string::npos) { value = detail::replace_substr(value, begin, end - begin + 1, @@ -900,20 +890,20 @@ namespace hpx::util { expand(l, value, begin); // now expand the key itself - std::string::size_type end = find_next("}", value, begin + 1); + std::string::size_type const end = find_next("}", value, begin + 1); if (end != std::string::npos) { std::string to_expand = value.substr(begin + 2, end - begin - 2); - std::string::size_type colon = find_next(":", to_expand); + std::string::size_type const colon = find_next(":", to_expand); if (colon == std::string::npos) { - char* env = getenv(to_expand.c_str()); + char const* env = std::getenv(to_expand.c_str()); value = detail::replace_substr( value, begin, end - begin + 1, nullptr != env ? env : ""); } else { - char* env = getenv(to_expand.substr(0, colon).c_str()); + char* env = std::getenv(to_expand.substr(0, colon).c_str()); value = detail::replace_substr(value, begin, end - begin + 1, nullptr != env ? std::string(env) : to_expand.substr(colon + 1)); @@ -924,7 +914,7 @@ namespace hpx::util { std::string section::expand( std::unique_lock& l, std::string value) const { - expand(l, value, std::string::size_type(-1)); + expand(l, value, static_cast(-1)); return value; } @@ -952,11 +942,11 @@ namespace hpx::util { expand_only(l, value, begin, expand_this); // now expand the key itself - std::string::size_type end = find_next("]", value, begin + 1); + std::string::size_type const end = find_next("]", value, begin + 1); if (end != std::string::npos) { std::string to_expand = value.substr(begin + 2, end - begin - 2); - std::string::size_type colon = find_next(":", to_expand); + std::string::size_type const colon = find_next(":", to_expand); if (colon == std::string::npos) { if (to_expand == expand_this) @@ -983,20 +973,20 @@ namespace hpx::util { expand_only(l, value, begin, expand_this); // now expand the key itself - std::string::size_type end = find_next("}", value, begin + 1); + std::string::size_type const end = find_next("}", value, begin + 1); if (end != std::string::npos) { std::string to_expand = value.substr(begin + 2, end - begin - 2); - std::string::size_type colon = find_next(":", to_expand); + std::string::size_type const colon = find_next(":", to_expand); if (colon == std::string::npos) { - char* env = getenv(to_expand.c_str()); + char const* env = std::getenv(to_expand.c_str()); value = detail::replace_substr( value, begin, end - begin + 1, nullptr != env ? env : ""); } else { - char* env = getenv(to_expand.substr(0, colon).c_str()); + char* env = std::getenv(to_expand.substr(0, colon).c_str()); value = detail::replace_substr(value, begin, end - begin + 1, nullptr != env ? std::string(env) : to_expand.substr(colon + 1)); @@ -1007,7 +997,8 @@ namespace hpx::util { std::string section::expand_only(std::unique_lock& l, std::string value, std::string const& expand_this) const { - expand_only(l, value, std::string::size_type(-1), expand_this); + expand_only( + l, value, static_cast(-1), expand_this); return value; } @@ -1040,7 +1031,7 @@ namespace hpx::util { entries_.clear(); for (std::size_t i = 0; i < size; ++i) { - using value_type = typename entry_map::value_type; + using value_type = entry_map::value_type; value_type v; ar >> const_cast(v.first); diff --git a/libs/core/prefix/include/hpx/prefix/find_prefix.hpp b/libs/core/prefix/include/hpx/prefix/find_prefix.hpp index 25b0d76acf4b..839f88ea881a 100644 --- a/libs/core/prefix/include/hpx/prefix/find_prefix.hpp +++ b/libs/core/prefix/include/hpx/prefix/find_prefix.hpp @@ -17,25 +17,26 @@ namespace hpx::util { // set and query the prefix as configured at compile time HPX_CORE_EXPORT void set_hpx_prefix(const char* prefix) noexcept; - HPX_CORE_EXPORT char const* hpx_prefix() noexcept; + [[nodiscard]] HPX_CORE_EXPORT char const* hpx_prefix() noexcept; // return the installation path of the specified module - HPX_CORE_EXPORT std::string find_prefix(std::string const& library = "hpx"); + [[nodiscard]] HPX_CORE_EXPORT std::string find_prefix( + std::string const& library = "hpx"); // return a list of paths delimited by HPX_INI_PATH_DELIMITER - HPX_CORE_EXPORT std::string find_prefixes( + [[nodiscard]] HPX_CORE_EXPORT std::string find_prefixes( std::string const& suffix, std::string const& library = "hpx"); // return the full path of the current executable - HPX_CORE_EXPORT std::string get_executable_filename( + [[nodiscard]] HPX_CORE_EXPORT std::string get_executable_filename( char const* argv0 = nullptr); - HPX_CORE_EXPORT std::string get_executable_prefix( + [[nodiscard]] HPX_CORE_EXPORT std::string get_executable_prefix( char const* argv0 = nullptr); } // namespace hpx::util // The HPX runtime needs to know where to look for the HPX ini files if no ini // path is specified by the user (default in $HPX_LOCATION/share/hpx-1.0.0/ini). -// Also, the default component path is set within the same prefix +// Also, the default component path is set within the same prefix. // clang-format off #define HPX_BASE_DIR_NAME \ diff --git a/libs/core/prefix/src/find_prefix.cpp b/libs/core/prefix/src/find_prefix.cpp index 3425ea3009a9..6cca5fd6fd23 100644 --- a/libs/core/prefix/src/find_prefix.cpp +++ b/libs/core/prefix/src/find_prefix.cpp @@ -8,7 +8,6 @@ //////////////////////////////////////////////////////////////////////////////// #include -#include #include #include #include @@ -69,7 +68,7 @@ namespace hpx::util { using hpx::filesystem::path; - std::string const prefix = + std::string prefix = path(dll.get_directory(ec)).parent_path().string(); if (ec || prefix.empty()) @@ -79,7 +78,7 @@ namespace hpx::util { } catch (std::logic_error const&) { - ; // just ignore loader problems + // just ignore loader problems } #endif return hpx_prefix(); @@ -124,7 +123,7 @@ namespace hpx::util { std::string get_executable_prefix(char const* argv0) { using hpx::filesystem::path; - path p(get_executable_filename(argv0)); + path const p(get_executable_filename(argv0)); return p.parent_path().parent_path().string(); } diff --git a/libs/core/program_options/include/hpx/modules/program_options.hpp b/libs/core/program_options/include/hpx/modules/program_options.hpp index 472902d96c45..a95526ea6c21 100644 --- a/libs/core/program_options/include/hpx/modules/program_options.hpp +++ b/libs/core/program_options/include/hpx/modules/program_options.hpp @@ -1,8 +1,8 @@ -// Copyright Vladimir Prus 2002. +// Copyright Vladimir Prus 2002. +// // 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) +// 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) // See www.boost.org/libs/program_options for documentation. diff --git a/libs/core/program_options/include/hpx/program_options/cmdline.hpp b/libs/core/program_options/include/hpx/program_options/cmdline.hpp index 26bb8a6481cf..25f7185c9687 100644 --- a/libs/core/program_options/include/hpx/program_options/cmdline.hpp +++ b/libs/core/program_options/include/hpx/program_options/cmdline.hpp @@ -1,8 +1,8 @@ -// Copyright Vladimir Prus 2004. +// Copyright Vladimir Prus 2004. +// // 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) +// 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 diff --git a/libs/core/program_options/include/hpx/program_options/config.hpp b/libs/core/program_options/include/hpx/program_options/config.hpp index e0f9218002be..825cd910d802 100644 --- a/libs/core/program_options/include/hpx/program_options/config.hpp +++ b/libs/core/program_options/include/hpx/program_options/config.hpp @@ -1,9 +1,8 @@ // Copyright (c) 2004 Hartmut Kaiser // -// SPDX-License-Identifier: BSL-1.0 -// Use, modification and distribution is subject to 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) +// 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 diff --git a/libs/core/program_options/include/hpx/program_options/detail/cmdline.hpp b/libs/core/program_options/include/hpx/program_options/detail/cmdline.hpp index 1a41b3b57fdb..f34242013833 100644 --- a/libs/core/program_options/include/hpx/program_options/detail/cmdline.hpp +++ b/libs/core/program_options/include/hpx/program_options/detail/cmdline.hpp @@ -1,8 +1,8 @@ -// Copyright Vladimir Prus 2002-2004. +// Copyright Vladimir Prus 2002-2004. +// // 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) +// 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 @@ -86,7 +86,7 @@ namespace hpx::program_options::detail { * * This is mainly used for the diagnostic messages in exceptions */ - int get_canonical_option_prefix() noexcept; + [[nodiscard]] int get_canonical_option_prefix() const noexcept; void allow_unregistered() noexcept; @@ -96,14 +96,18 @@ namespace hpx::program_options::detail { std::vector