From 9693d0ff61196288371b597fe4e73da879f81708 Mon Sep 17 00:00:00 2001 From: Bhumit Attarde Date: Sun, 25 Sep 2022 23:18:52 +0530 Subject: [PATCH 01/22] docs: add cppref NamedRequirements support --- cmake/templates/conf.py.in | 7 ++- .../synchronization/condition_variable.hpp | 61 +++++++++++-------- .../include/hpx/synchronization/mutex.hpp | 5 +- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/cmake/templates/conf.py.in b/cmake/templates/conf.py.in index 7392b345fc6d..95d20e445fe9 100644 --- a/cmake/templates/conf.py.in +++ b/cmake/templates/conf.py.in @@ -206,9 +206,14 @@ breathe_doxygen_config_options = { 'MACRO_EXPANSION': 'YES', 'DIRECTORY_GRAPH': 'NO', 'PREDEFINED': '@doxygen_definitions@', - 'STRIP_FROM_PATH': hpx_source_dir + 'STRIP_FROM_PATH': hpx_source_dir, + 'ALIASES': r'namedrequirement{1}="\1"' } +# ! this should work but doesn't. check after updating breathe version. +# breathe_doxygen_aliases = { +# } + numfig = True primary_domain = 'cpp' highlight_language = 'cpp' diff --git a/libs/core/synchronization/include/hpx/synchronization/condition_variable.hpp b/libs/core/synchronization/include/hpx/synchronization/condition_variable.hpp index ddeb5548ee3f..ad0ecee3de1d 100644 --- a/libs/core/synchronization/include/hpx/synchronization/condition_variable.hpp +++ b/libs/core/synchronization/include/hpx/synchronization/condition_variable.hpp @@ -86,16 +86,19 @@ namespace hpx { /// \a hpx::condition_variable works only with \a std::unique_lock. /// This restriction allows for maximal efficiency on some platforms. /// \a hpx::condition_variable_any provides a condition variable that works - /// with any \a BasicLockable object, such as \a std::shared_lock. + /// with any \namedrequirement{BasicLockable} object, such as + /// \a std::shared_lock. /// /// Condition variables permit concurrent invocation of the \a wait, /// \a wait_for, \a wait_until, \a notify_one and \a notify_all member /// functions. /// - /// The class \a hpx::condition_variable is a \a StandardLayoutType. - /// It is not \a CopyConstructible, \a MoveConstructible, \a CopyAssignable, - /// or \a MoveAssignable. - /// + /// The class \a hpx::condition_variable is a + /// \namedrequirement{StandardLayoutType}. + /// It is not \namedrequirement{CopyConstructible}, + /// \namedrequirement{MoveConstructible}, + /// \namedrequirement{CopyAssignable}, or + /// \namedrequirement{MoveAssignable}. /// class condition_variable { @@ -507,13 +510,15 @@ namespace hpx { /// \brief The \a condition_variable_any class is a generalization of /// \a hpx::condition_variable. Whereas \a hpx::condition_variable works /// only on \a std::unique_lock, \a acondition_variable_any can - /// operate on any lock that meets the \a BasicLockable requirements. + /// operate on any lock that meets the \namedrequirement{BasicLockable} + /// requirements. /// /// See \a hpx::condition_variable for the description of the semantics of /// condition variables. - /// The class \a hpx::condition_variable_any is a \a StandardLayoutType. It - /// is not \a CopyConstructible, \a MoveConstructible, \a CopyAssignable, - /// or \a MoveAssignable. + /// It is not \namedrequirement{CopyConstructible}, + /// \namedrequirement{MoveConstructible}, + /// \namedrequirement{CopyAssignable}, or + /// \namedrequirement{MoveAssignable}. /// class condition_variable_any { @@ -675,8 +680,9 @@ namespace hpx { /// /// \tparam Lock Type of \a lock. /// - /// \param lock An object of type Lock that meets the \a BasicLockable - /// requirements, which must be locked by the current thread + /// \param lock An object of type Lock that meets the + /// \namedrequirement{BasicLockable} requirements, which + /// must be locked by the current thread /// \param ec Used to hold error code value originated during the /// operation. Defaults to \a throws -- A special'throw on /// error' \a error_code. @@ -740,8 +746,9 @@ namespace hpx { /// \tparam Lock Type of \a lock. /// \tparam Predicate Type of \a pred. /// - /// \param lock an object of type Lock that meets the \a BasicLockable - /// requirements, which must be locked by the current thread + /// \param lock an object of type Lock that meets the + /// \namedrequirement{BasicLockable} requirements, which + /// must be locked by the current thread /// \param pred predicate which returns `false` if the waiting should /// be continued `(bool(pred()) == false)`. /// The signature of the predicate function should be @@ -785,7 +792,8 @@ namespace hpx { /// \tparam Lock Type of \a lock. /// /// \param lock an object of type \a Lock that meets the - /// requirements of \a BasicLockable, which must be + /// requirements of + /// \namedrequirement{BasicLockable}, which must be /// locked by the current thread /// \param abs_time represents the time when waiting should be stopped. /// \param ec used to hold error code value originated during the @@ -860,8 +868,8 @@ namespace hpx { /// \tparam Predicate Type of \a pred. /// /// \param lock an object of type \a Lock that meets the - /// requirements of \a BasicLockable, which must be - /// locked by the current thread + /// requirements of \namedrequirement{BasicLockable}, + /// which must be locked by the current thread /// \param abs_time represents the time when waiting should be stopped. /// \param pred predicate which returns \a false if the waiting /// should be continued @@ -916,8 +924,8 @@ namespace hpx { /// \tparam Lock Type of \a lock. /// /// \param lock an object of type \a Lock that meets the - /// \a BasicLockable requirements, which must be locked - /// by the current thread. + /// \namedrequirement{BasicLockable} requirements, + /// which must be locked by the current thread. /// \param rel_time an object of type \a hpx::chrono::duration /// representing the maximum time to spend waiting. Note /// that \a rel_time must be small enough not to @@ -962,7 +970,8 @@ namespace hpx { /// \tparam Predicate Type of \a pred. /// /// \param lock an object of type \a Lock that meets the - /// \a BasicLockable requirements, which must be locked + /// \namedrequirement{BasicLockable} requirements,which + /// must be locked /// by the current thread. /// \param rel_time an object of type \a hpx::chrono::duration /// representing the maximum time to spend waiting. Note @@ -1021,9 +1030,9 @@ namespace hpx { /// \tparam Lock Type of \a lock. /// \tparam Predicate Type of \a pred. /// - /// \param lock an object of type Lock that meets the \a BasicLockable - /// requirements, which must be locked by the current - /// thread + /// \param lock an object of type Lock that meets the + /// \namedrequirement{BasicLockable} requirements, which + /// must be locked by the current thread /// \param stoken a \a hpx::stop_token to register interruption for /// \param pred predicate which returns `false` if the waiting should /// be continued `(bool(pred()) == false)`. @@ -1111,8 +1120,8 @@ namespace hpx { /// \tparam Predicate Type of \a pred. /// /// \param lock an object of type \a Lock that meets the - /// requirements of \a BasicLockable, which must be - /// locked by the current thread. + /// requirements of \namedrequirement{BasicLockable}, + /// which must be locked by the current thread. /// \param stoken a \a hpx::stop_token to register interruption for. /// \param abs_time represents the time when waiting should be stopped. /// \param pred predicate which returns \a false if the waiting @@ -1207,8 +1216,8 @@ namespace hpx { /// \tparam Predicate Type of \a pred. /// /// \param lock an object of type \a Lock that meets the - /// \a BasicLockable requirements, which must be locked - /// by the current thread. + /// \namedrequirement{BasicLockable} requirements, + /// which must be locked by the current thread. /// \param stoken a \a hpx::stop_token to register interruption for. /// \param rel_time an object of type \a hpx::chrono::duration /// representing the maximum time to spend waiting. Note diff --git a/libs/core/synchronization/include/hpx/synchronization/mutex.hpp b/libs/core/synchronization/include/hpx/synchronization/mutex.hpp index 823d0d823f77..ba918f0c7159 100644 --- a/libs/core/synchronization/include/hpx/synchronization/mutex.hpp +++ b/libs/core/synchronization/include/hpx/synchronization/mutex.hpp @@ -52,7 +52,7 @@ namespace hpx { /// The behavior of a program is undefined if a \a mutex is /// destroyed while still owned by any threads, or a thread /// terminates while owning a \a mutex. The mutex class satisfies - /// all requirements of \a Mutex and \a StandardLayoutType. + /// all requirements of \namedrequirement{Mutex} and \namedrequirement{StandardLayoutType}. /// /// \a hpx::mutex is neither copyable nor movable. /// @@ -242,7 +242,8 @@ namespace hpx { /// \a timed_mutex with a timeout via the member functions /// \a try_lock_for() and \a try_lock_until(). /// The \a timed_mutex class satisfies all requirements of - /// \a TimedMutex and \a StandardLayoutType. + /// \namedrequirement{TimedMutex} and + /// \namedrequirement{StandardLayoutType}. /// /// \a hpx::timed_mutex is neither copyable nor movable. /// From 4530bc5667b21da0d2203134446af692d72dd87d Mon Sep 17 00:00:00 2001 From: Giannis Gonidelis Date: Tue, 27 Sep 2022 00:56:27 -0500 Subject: [PATCH 02/22] Minor fixes on "How to build on Windows" Minor fixes on "How to build on Windows" --- docs/sphinx/manual/building_hpx.rst | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/sphinx/manual/building_hpx.rst b/docs/sphinx/manual/building_hpx.rst index 4df46bdae228..ccc33a9560be 100644 --- a/docs/sphinx/manual/building_hpx.rst +++ b/docs/sphinx/manual/building_hpx.rst @@ -253,14 +253,14 @@ To build |hpx| under Windows 10 x64 with Visual Studio 2015: .. code-block:: bash - bootstrap.bat + .\bootstrap.bat This batch file will set up everything needed to create a successful build. Now execute: .. code-block:: bash - b2.exe link=shared variant=release,debug architecture=x86 address-model=64 threading=multi --build-type=complete install + .\b2.exe link=shared variant=release,debug architecture=x86 address-model=64 threading=multi --build-type=complete install This command will start a (very long) build of all available Boost libraries. Please, be patient. @@ -285,12 +285,14 @@ To build |hpx| under Windows 10 x64 with Visual Studio 2015: will build |hpx| packages out of the |hpx| source tree. * Set three new environment variables (in CMake, not in Windows environment): - ``BOOST_ROOT``, ``HWLOC_ROOT``, ``CMAKE_INSTALL_PREFIX``. The meaning of + ``BOOST_ROOT``, ``HWLOC_ROOT``, ``ASIO_ROOT``, ``CMAKE_INSTALL_PREFIX``. The meaning of these variables is as follows: * ``BOOST_ROOT`` the |hpx| root directory of the unpacked Boost headers/cpp files. * ``HWLOC_ROOT`` the |hpx| root directory of the unpacked Portable Hardware Locality files. + * ``ASIO_ROOT`` the |hpx| root directory of the unpacked ASIO files. Alternatively use + ``HPX_WITH_FETCH_ASIO`` with value ``True``. * ``CMAKE_INSTALL_PREFIX`` the |hpx| root directory where the future builds of |hpx| should be installed. From 696dc060dbc3f8575281625b1e306dd43277c43d Mon Sep 17 00:00:00 2001 From: "Steven R. Brandt" Date: Tue, 27 Sep 2022 21:05:06 +0000 Subject: [PATCH 03/22] Add --start-group and --end-group before libraries are added for linking --- cmake/templates/hpxcxx.in | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cmake/templates/hpxcxx.in b/cmake/templates/hpxcxx.in index 81f38f89367d..9a0196e0d4eb 100755 --- a/cmake/templates/hpxcxx.in +++ b/cmake/templates/hpxcxx.in @@ -126,12 +126,14 @@ if pkg in os.environ: else: os.environ[pkg] = pkgconf +args += ["-Wl,--start-group"] if application: args += ["`pkg-config --cflags --libs hpx_application" + pkgconf_suffix + "`"] elif component: args += ["`pkg-config --cflags --libs hpx_component" + pkgconf_suffix + "`"] else: args += ["`pkg-config --cflags hpx_application" + pkgconf_suffix + "`"] +args += ["-Wl,--end-group"] if not component and not application and not minusc: usage() From beece3e9814938d310887481f629f1a6c0ad2bad Mon Sep 17 00:00:00 2001 From: Bhumit Attarde Date: Wed, 28 Sep 2022 12:00:33 +0530 Subject: [PATCH 04/22] build(docs): rm leftover sections --- cmake/HPX_Documentation.cmake | 20 +------------------- cmake/templates/autodoc.doxy.in | 18 ------------------ docs/CMakeLists.txt | 24 +----------------------- 3 files changed, 2 insertions(+), 60 deletions(-) delete mode 100644 cmake/templates/autodoc.doxy.in diff --git a/cmake/HPX_Documentation.cmake b/cmake/HPX_Documentation.cmake index aaac29a32c32..fe9b38887fcb 100644 --- a/cmake/HPX_Documentation.cmake +++ b/cmake/HPX_Documentation.cmake @@ -5,6 +5,7 @@ # 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) +# find required packages if(HPX_WITH_DOCUMENTATION) find_package(Doxygen) find_package(Sphinx) @@ -27,22 +28,3 @@ if(HPX_WITH_DOCUMENTATION) set(HPX_WITH_DOCUMENTATION OFF) endif() endif() - -# C++ Source -> Doxygen XML -function(hpx_source_to_doxygen name) - set(options) - set(one_value_args) - set(multi_value_args DEPENDENCIES DOXYGEN_ARGS) - cmake_parse_arguments( - ${name} "${options}" "${one_value_args}" "${multi_value_args}" ${ARGN} - ) - - add_custom_command( - OUTPUT "${name}/index.xml" - COMMAND "${DOXYGEN_EXECUTABLE}" ${${name}_DOXYGEN_ARGS} - "${CMAKE_CURRENT_BINARY_DIR}/${name}.doxy" - COMMENT "Generating Doxygen." - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/${name}.doxy" ${${name}_DEPENDENCIES} - VERBATIM - ) -endfunction() diff --git a/cmake/templates/autodoc.doxy.in b/cmake/templates/autodoc.doxy.in deleted file mode 100644 index 94113e0f146d..000000000000 --- a/cmake/templates/autodoc.doxy.in +++ /dev/null @@ -1,18 +0,0 @@ -# Copyright (c) 2012 Bryce Adelstein-Lelbach -# -# 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) - -EXTRACT_ALL = YES -EXPAND_ONLY_PREDEF = YES -GENERATE_HTML = NO -GENERATE_XML = YES -MACRO_EXPANSION = YES -PREDEFINED = @doxygen_definitions@ -XML_OUTPUT = @doxygen_output_file@ -OUTPUT_DIRECTORY = @doxygen_output_dir@ -GENERATE_LATEX = NO -INPUT = @doxygen_inputs@ -EXCLUDE_SYMBOLS = detail -EXTRACT_PRIVATE = NO diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index b2b06a9347a9..437aa6671b00 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -4,20 +4,7 @@ # 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) -# Add all files here which should be passed to doxygen -set(doxygen_dependencies - "${PROJECT_SOURCE_DIR}/components/component_storage/include/hpx/components/component_storage/migrate_from_storage.hpp" - "${PROJECT_SOURCE_DIR}/components/component_storage/include/hpx/components/component_storage/migrate_to_storage.hpp" -) - -# Definitions for autodoc.doxy.in -foreach(doxygen_input ${doxygen_dependencies}) - set(doxygen_inputs "${doxygen_inputs} ${doxygen_input}") -endforeach() - -set(doxygen_output_file "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc") -set(doxygen_output_dir "${CMAKE_CURRENT_BINARY_DIR}/doxygen") - +# used while generating sphinx config file set(doxygen_definition_list "DOXYGEN:=1" "BOOST_SYSTEM_NOEXCEPT=" @@ -36,12 +23,6 @@ foreach(doxygen_predef ${doxygen_definition_list}) set(doxygen_definitions "${doxygen_definitions} \"${doxygen_predef}\"") endforeach() -hpx_info("Creating Doxyfile: ${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc.doxy") -configure_file( - "${PROJECT_SOURCE_DIR}/cmake/templates/autodoc.doxy.in" - "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc.doxy" @ONLY -) - # Generate rst files with CMake variables and toolchains set(HPX_CMAKE_OPTIONS_RST "") foreach(_cat ${HPX_OPTION_CATEGORIES}) @@ -215,8 +196,6 @@ create_symbolic_link( "${PROJECT_SOURCE_DIR}/libs" "${CMAKE_CURRENT_BINARY_DIR}/libs" ) -hpx_source_to_doxygen(hpx_autodoc DEPENDENCIES ${doxygen_dependencies}) - add_custom_target(docs) add_custom_target(docs-html) add_custom_target(docs-singlehtml) @@ -258,7 +237,6 @@ foreach(output_format ${HPX_WITH_DOCUMENTATION_OUTPUT_FORMATS}) add_custom_command( OUTPUT "${SPHINX_DOCS_OUTPUT_FILE}" DEPENDS "${sphinx_source_files_build}" - "${CMAKE_CURRENT_BINARY_DIR}/hpx_autodoc/index.xml" COMMAND ${SPHINX_DOCS_BUILD_COMMAND} ) From 0fd233795fa68f240267f2b8985acf2978e6a5c3 Mon Sep 17 00:00:00 2001 From: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com> Date: Wed, 28 Sep 2022 10:55:16 +0200 Subject: [PATCH 05/22] add option hpx:force_ipv4 to force resolving hostnames to ipv4 adresses --- ...ching_and_configuring_hpx_applications.rst | 7 ++++++ libs/core/asio/include/hpx/asio/asio_util.hpp | 4 ++-- .../asio/include/hpx/asio/map_hostnames.hpp | 8 ++++++- libs/core/asio/src/asio_util.cpp | 24 +++++++++++++------ libs/core/asio/src/map_hostnames.cpp | 2 +- .../src/command_line_handling.cpp | 1 + .../src/parse_command_line.cpp | 1 + 7 files changed, 36 insertions(+), 11 deletions(-) diff --git a/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst b/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst index 01de5595f226..1151c731fade 100644 --- a/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst +++ b/docs/sphinx/manual/launching_and_configuring_hpx_applications.rst @@ -1461,6 +1461,13 @@ The predefined command line options for any application using Sed-style search and replace (``s/search/replace/``) used to transform host names to the proper network interconnect. +.. option:: --hpx:force_ipv4 + + Network hostnames will be resolved to ipv4 adresses instead of using the + first resolved endpoint. This is especially useful on Windows where the + local hostname will resolve to an ipv6 adress while remote network hostnames + are commonly resolved to ipv4 adresses. + .. option:: --hpx:localities arg The number of localities to wait for at application startup (default: ``1``). diff --git a/libs/core/asio/include/hpx/asio/asio_util.hpp b/libs/core/asio/include/hpx/asio/asio_util.hpp index 9de4b56b339c..23b372f50745 100644 --- a/libs/core/asio/include/hpx/asio/asio_util.hpp +++ b/libs/core/asio/include/hpx/asio/asio_util.hpp @@ -27,7 +27,7 @@ namespace hpx { namespace util { /////////////////////////////////////////////////////////////////////////// HPX_CORE_EXPORT bool get_endpoint(std::string const& addr, - std::uint16_t port, asio::ip::tcp::endpoint& ep); + std::uint16_t port, asio::ip::tcp::endpoint& ep, bool force_ipv4 = false); HPX_CORE_EXPORT std::string get_endpoint_name( asio::ip::tcp::endpoint const& ep); @@ -36,7 +36,7 @@ namespace hpx { namespace util { // properly resolve a give host name to the corresponding IP address HPX_CORE_EXPORT asio::ip::tcp::endpoint resolve_hostname( std::string const& hostname, std::uint16_t port, - asio::io_context& io_service); + asio::io_context& io_service, bool force_ipv4 = false); /////////////////////////////////////////////////////////////////////////// // return the public IP address of the local node diff --git a/libs/core/asio/include/hpx/asio/map_hostnames.hpp b/libs/core/asio/include/hpx/asio/map_hostnames.hpp index 73db45f4129f..64dbd2de71e5 100644 --- a/libs/core/asio/include/hpx/asio/map_hostnames.hpp +++ b/libs/core/asio/include/hpx/asio/map_hostnames.hpp @@ -27,7 +27,7 @@ namespace hpx { namespace util { transform_function_type; map_hostnames(bool debug = false) - : debug_(debug) + : ipv4_(false), debug_(debug) { } @@ -46,12 +46,18 @@ namespace hpx { namespace util { transform_ = f; } + void force_ipv4(bool const& f) + { + ipv4_ = f; + } + std::string map(std::string host_name, std::uint16_t port) const; private: transform_function_type transform_; std::string suffix_; std::string prefix_; + bool ipv4_; bool debug_; }; }} // namespace hpx::util diff --git a/libs/core/asio/src/asio_util.cpp b/libs/core/asio/src/asio_util.cpp index 53086784f39c..89af33ca1ece 100644 --- a/libs/core/asio/src/asio_util.cpp +++ b/libs/core/asio/src/asio_util.cpp @@ -52,7 +52,7 @@ namespace hpx { namespace util { /////////////////////////////////////////////////////////////////////////// bool get_endpoint(std::string const& addr, std::uint16_t port, - asio::ip::tcp::endpoint& ep) + asio::ip::tcp::endpoint& ep, bool force_ipv4) { using namespace asio::ip; std::error_code ec; @@ -63,11 +63,14 @@ namespace hpx { namespace util { return true; } - address_v6 addr6 = address_v6::from_string(addr.c_str(), ec); - if (!ec) - { // it's an IPV6 address - ep = tcp::endpoint(address(addr6), port); - return true; + if (!force_ipv4) + { + address_v6 addr6 = address_v6::from_string(addr.c_str(), ec); + if (!ec) + { // it's an IPV6 address + ep = tcp::endpoint(address(addr6), port); + return true; + } } return false; } @@ -81,7 +84,7 @@ namespace hpx { namespace util { /////////////////////////////////////////////////////////////////////////// // properly resolve a give host name to the corresponding IP address asio::ip::tcp::endpoint resolve_hostname(std::string const& hostname, - std::uint16_t port, asio::io_context& io_service) + std::uint16_t port, asio::io_context& io_service, bool force_ipv4) { using asio::ip::tcp; @@ -108,6 +111,13 @@ namespace hpx { namespace util { tcp::resolver::query query(hostname, std::to_string(port)); asio::ip::tcp::resolver::iterator it = resolver.resolve(query); + + while (force_ipv4 && + it != tcp::resolver::iterator() && !it->endpoint().address().is_v4()) + { + ++it; + } + HPX_ASSERT(it != asio::ip::tcp::resolver::iterator()); return *it; } diff --git a/libs/core/asio/src/map_hostnames.cpp b/libs/core/asio/src/map_hostnames.cpp index 8c6d6aa4a861..56d3249625b8 100644 --- a/libs/core/asio/src/map_hostnames.cpp +++ b/libs/core/asio/src/map_hostnames.cpp @@ -48,7 +48,7 @@ namespace hpx { namespace util { // do full host name resolution asio::io_context io_service; asio::ip::tcp::endpoint ep = util::resolve_hostname( - prefix_ + host_name + suffix_, port, io_service); + prefix_ + host_name + suffix_, port, io_service, ipv4_); std::string resolved_addr(util::get_endpoint_name(ep)); if (debug_) diff --git a/libs/full/command_line_handling/src/command_line_handling.cpp b/libs/full/command_line_handling/src/command_line_handling.cpp index 8677c530e614..671373ab1123 100644 --- a/libs/full/command_line_handling/src/command_line_handling.cpp +++ b/libs/full/command_line_handling/src/command_line_handling.cpp @@ -647,6 +647,7 @@ namespace hpx { namespace util { mapnames.use_suffix(vm["hpx:ifsuffix"].as()); if (vm.count("hpx:ifprefix")) mapnames.use_prefix(vm["hpx:ifprefix"].as()); + mapnames.force_ipv4(vm.count("hpx:force_ipv4") > 0); // The AGAS host name and port number are pre-initialized from //the command line diff --git a/libs/full/command_line_handling/src/parse_command_line.cpp b/libs/full/command_line_handling/src/parse_command_line.cpp index 5518ba5a7f0a..d10121650c16 100644 --- a/libs/full/command_line_handling/src/parse_command_line.cpp +++ b/libs/full/command_line_handling/src/parse_command_line.cpp @@ -479,6 +479,7 @@ namespace hpx { namespace util { ("hpx:iftransform", value(), "sed-style search and replace (s/search/replace/) used to " "transform host names to the proper network interconnect") + ("hpx:force_ipv4", "Force ipv4 for resolving network hostnames") #endif #if defined(HPX_HAVE_DISTRIBUTED_RUNTIME) ("hpx:localities", value(), From c93809b5f99c74a7bd5564344b059a12f09639ec Mon Sep 17 00:00:00 2001 From: Alexander Neumann <30894796+Neumann-A@users.noreply.github.com> Date: Wed, 28 Sep 2022 23:25:42 +0200 Subject: [PATCH 06/22] use just bool --- libs/core/asio/include/hpx/asio/map_hostnames.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/core/asio/include/hpx/asio/map_hostnames.hpp b/libs/core/asio/include/hpx/asio/map_hostnames.hpp index 64dbd2de71e5..e5f66a786d02 100644 --- a/libs/core/asio/include/hpx/asio/map_hostnames.hpp +++ b/libs/core/asio/include/hpx/asio/map_hostnames.hpp @@ -46,7 +46,7 @@ namespace hpx { namespace util { transform_ = f; } - void force_ipv4(bool const& f) + void force_ipv4(bool f) { ipv4_ = f; } From 3809faae435e7d0b62c4a65ccf6f923a84f0e809 Mon Sep 17 00:00:00 2001 From: kadimitra Date: Wed, 28 Sep 2022 12:26:48 +0200 Subject: [PATCH 07/22] Add doc shared_mutex --- .../hpx/synchronization/shared_mutex.hpp | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/libs/core/synchronization/include/hpx/synchronization/shared_mutex.hpp b/libs/core/synchronization/include/hpx/synchronization/shared_mutex.hpp index 24b0b7fd5869..c3a6796b2b6d 100644 --- a/libs/core/synchronization/include/hpx/synchronization/shared_mutex.hpp +++ b/libs/core/synchronization/include/hpx/synchronization/shared_mutex.hpp @@ -6,6 +6,8 @@ // 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) +/// \file shared_mutex.hpp + #pragma once #include @@ -237,6 +239,25 @@ namespace hpx { }; } // namespace detail + /// \brief The \a shared_mutex class is a synchronization primitive that can be used to protect + /// shared data from being simultaneously accessed by multiple threads. In contrast to + /// other mutex types which facilitate exclusive access, a \a shared_mutex has two levels + /// of access: + /// - \a shared - several threads can share ownership of the same mutex. + /// - \a exclusive - only one thread can own the mutex. + /// \details If one thread has acquired the exclusive lock (through \a lock, \a try_lock), no other + /// threads can acquire the lock (including the shared). + /// If one thread has acquired the shared lock (through \a lock_shared, \a try_lock_shared), + /// no other thread can acquire the exclusive lock, but can acquire the shared lock. + /// Only when the exclusive lock has not been acquired by any thread, the shared lock + /// can be acquired by multiple threads. + /// Within one thread, only one lock (shared or exclusive) can be acquired at the same + /// time. + /// Shared mutexes are especially useful when shared data can be safely read by any + /// number of threads simultaneously, but a thread may only write the same data when no + /// other thread is reading or writing at the same time. + /// The \a shared_mutex class satisfies all requirements of \a SharedMutex and \a + /// StandardLayoutType. using shared_mutex = detail::shared_mutex<>; } // namespace hpx From 0cbbcac11d1d2d6e00b74f0cf6ddd45d3345501a Mon Sep 17 00:00:00 2001 From: kadimitra Date: Wed, 28 Sep 2022 15:29:47 +0200 Subject: [PATCH 08/22] Fix doc namespace --- libs/core/async_base/include/hpx/async_base/async.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/core/async_base/include/hpx/async_base/async.hpp b/libs/core/async_base/include/hpx/async_base/async.hpp index 60cf689b6627..ad1dd88e4c0b 100644 --- a/libs/core/async_base/include/hpx/async_base/async.hpp +++ b/libs/core/async_base/include/hpx/async_base/async.hpp @@ -28,8 +28,8 @@ namespace hpx { /// with arguments \a ts according to a specific launch policy. /// - If the async flag is set (i.e. (policy & hpx::launch::async) != 0), then /// async executes the callable object f on a new thread of execution (with all - /// thread-locals initialized) as if spawned by hpx::thread(hpx::forward(f), - /// hpx::forward(ts)...), except that if the function f returns a value + /// thread-locals initialized) as if spawned by hpx::thread(std::forward(f), + /// std::forward(ts)...), except that if the function f returns a value /// or throws an exception, it is stored in the shared state accessible through /// the hpx::future that async returns to the caller. /// - If the deferred flag is set (i.e. (policy & hpx::launch::deferred) != 0), From c5403fa99f82b3415b5de08c4df7da53161f12dd Mon Sep 17 00:00:00 2001 From: kadimitra Date: Wed, 28 Sep 2022 15:41:29 +0200 Subject: [PATCH 09/22] Add doc once --- .../include/hpx/synchronization/once.hpp | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/libs/core/synchronization/include/hpx/synchronization/once.hpp b/libs/core/synchronization/include/hpx/synchronization/once.hpp index 8540bfea219b..c813ff6f9e5b 100644 --- a/libs/core/synchronization/include/hpx/synchronization/once.hpp +++ b/libs/core/synchronization/include/hpx/synchronization/once.hpp @@ -8,6 +8,8 @@ // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +/// \file once.hpp + #pragma once #include @@ -19,12 +21,19 @@ namespace hpx { + /// \brief The class \c hpx::once_flag is a helper structure for \c hpx::call_once. + /// An object of type \c hpx::once_flag that is passed to multiple calls to + /// \c hpx::call_once allows those calls to coordinate with each other such + /// that only one of the calls will actually run to completion. + /// \c hpx::once_flag is neither copyable nor movable. struct once_flag { public: HPX_NON_COPYABLE(once_flag); public: + /// \brief Constructs an \a once_flag object. The internal state is set to indicate + /// that no function has been called yet. once_flag() noexcept : status_(0) { @@ -41,6 +50,48 @@ namespace hpx { #define HPX_ONCE_INIT ::hpx::once_flag() /////////////////////////////////////////////////////////////////////////// + /// \brief Executes the Callable object \a f exactly once, even if called + /// concurrently, from several threads. + /// \details In detail: + /// - If, by the time \a call_once is called, flag indicates that + /// \a f was already called, \a call_once returns right away (such + /// a call to \a call_once is known as passive). + /// - Otherwise, \a call_once invokes \c std::forward(f) + /// with the arguments \c std::forward(args)... + /// (as if by \c hpx::invoke). Unlike the \c hpx::thread constructor or + /// \c hpx::async, the arguments are not moved or copied because they + /// don't need to be transferred to another thread of execution. + /// (such a call to \a call_once is known as active). + /// - If that invocation throws an exception, it is propagated to + /// the caller of \a call_once, and the flag is not flipped so that + /// another call will be attempted (such a call to \a call_once is + /// known as exceptional). + /// - If that invocation returns normally (such a call to \a call_once + /// is known as returning), the flag is flipped, and all other calls + /// to \a call_once with the same flag are guaranteed to be passive. + /// All active calls on the same flag form a single total order consisting + /// of zero or more exceptional calls, followed by one returning call. + /// The end of each active call synchronizes-with the next active call in + /// that order. + /// The return from the returning call synchronizes-with the returns from + /// all passive calls on the same flag: this means that all concurrent calls + /// to \a call_once are guaranteed to observe any side-effects made by the + /// active call, with no additional synchronization. + /// + /// \param flag an object, for which exactly one function gets executed + /// \param f Callable object to invoke + /// \param args... arguments to pass to the function + /// + /// \throws std::system_error if any condition prevents calls to \a call_once + /// from executing as specified or any exception thrown by \a f + /// + /// \note If concurrent calls to \a call_once pass different functions \a f, + /// it is unspecified which f will be called. The selected function runs in the + /// same thread as the \a call_once invocation it was passed to. + /// Initialization of function-local statics is guaranteed to occur only once + /// even when called from multiple threads, and may be more efficient than the + /// equivalent code using \c hpx::call_once. + /// The POSIX equivalent of this function is \a pthread_once. template void call_once(once_flag& flag, F&& f, Args&&... args) { From 78f0e60df5d5871553e372f1cd33ce417a696551 Mon Sep 17 00:00:00 2001 From: kadimitra Date: Thu, 29 Sep 2022 16:45:36 +0200 Subject: [PATCH 10/22] Add doc chrono --- .../include/hpx/timing/high_resolution_clock.hpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/libs/core/timing/include/hpx/timing/high_resolution_clock.hpp b/libs/core/timing/include/hpx/timing/high_resolution_clock.hpp index fe94be1b9332..2adf642263c6 100644 --- a/libs/core/timing/include/hpx/timing/high_resolution_clock.hpp +++ b/libs/core/timing/include/hpx/timing/high_resolution_clock.hpp @@ -4,6 +4,8 @@ // 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) +/// \file high_resolution_clock.hpp + #pragma once #include @@ -17,10 +19,18 @@ namespace hpx { namespace chrono { + /// \brief Class \c hpx::chrono::high_resolution_clock represents the clock + /// with the smallest tick period provided by the implementation. It + /// may be an alias of \c std::chrono::system_clock or + /// \c std::chrono::steady_clock, or a third, independent clock. + /// \c hpx::chrono::high_resolution_clock meets the requirements of + /// \a TrivialClock. struct high_resolution_clock { // This function returns a tick count with a resolution (not // precision!) of 1 ns. + /// returns a \c std::chrono::time_point representing the current value + /// of the clock static std::uint64_t now() noexcept { #if defined(__bgq__) From 471f8f86bb504e0fc9bf8034ade38ae90f563d25 Mon Sep 17 00:00:00 2001 From: Hartmut Kaiser Date: Thu, 29 Sep 2022 10:11:23 -0500 Subject: [PATCH 11/22] Simplify startup code - flyby: add more parameter checking to command line handling - flyby: fix lifetime issue in make_ready_future_at --- .../src/parse_command_line_local.cpp | 19 ++++++++++++++++++- .../hpx/futures/detail/future_data.hpp | 9 ++++++--- .../futures/include/hpx/futures/future.hpp | 10 ++++++++-- .../init_runtime_local/init_runtime_local.hpp | 9 ++++----- .../src/init_runtime_local.cpp | 7 +++++++ .../include/hpx/actions/register_action.hpp | 9 ++++++--- .../src/parse_command_line.cpp | 19 ++++++++++++++++++- .../include/hpx/hpx_init_impl.hpp | 11 ++++++----- .../include/hpx/hpx_init_params.hpp | 18 +++--------------- .../include/hpx/hpx_start_impl.hpp | 11 ++++++----- 10 files changed, 82 insertions(+), 40 deletions(-) diff --git a/libs/core/command_line_handling_local/src/parse_command_line_local.cpp b/libs/core/command_line_handling_local/src/parse_command_line_local.cpp index 51c3b537dd0c..ac53ff851f80 100644 --- a/libs/core/command_line_handling_local/src/parse_command_line_local.cpp +++ b/libs/core/command_line_handling_local/src/parse_command_line_local.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2022 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -280,6 +280,19 @@ namespace hpx { namespace local { namespace detail { } } + void verify_unknown_options(std::vector const& opts) + { + for (auto const& opt : opts) + { + std::string::size_type p = opt.find("--hpx:"); + if (p != std::string::npos) + { + throw hpx::detail::command_line_error( + "Unknown/misspelled HPX command line option found: " + opt); + } + } + } + /////////////////////////////////////////////////////////////////////////// // parse the command line bool parse_commandline(util::section const& rtcfg, @@ -468,6 +481,8 @@ namespace hpx { namespace local { namespace detail { using hpx::program_options::exclude_positional; *unregistered_options = collect_unrecognized(opts.options, exclude_positional); + + verify_unknown_options(*unregistered_options); } store(opts, vm); @@ -491,6 +506,8 @@ namespace hpx { namespace local { namespace detail { using hpx::program_options::include_positional; *unregistered_options = collect_unrecognized(opts.options, include_positional); + + verify_unknown_options(*unregistered_options); } store(opts, vm); diff --git a/libs/core/futures/include/hpx/futures/detail/future_data.hpp b/libs/core/futures/include/hpx/futures/detail/future_data.hpp index add8b07c94c5..fcf0116f3f22 100644 --- a/libs/core/futures/include/hpx/futures/detail/future_data.hpp +++ b/libs/core/futures/include/hpx/futures/detail/future_data.hpp @@ -749,21 +749,24 @@ namespace hpx { namespace lcos { namespace detail { public: using base_type = future_data; using result_type = typename base_type::result_type; + using init_no_addref = typename base_type::init_no_addref; public: timed_future_data() = default; template - timed_future_data(std::chrono::steady_clock::time_point const& abs_time, + timed_future_data(init_no_addref no_addref, + std::chrono::steady_clock::time_point const& abs_time, Result_&& init) + : base_type(no_addref) { hpx::intrusive_ptr this_(this); error_code ec; threads::thread_init_data data( threads::make_thread_function_nullary( - [this_, init = HPX_FORWARD(Result_, init)]() { - this_->set_value(init); + [this_, init = HPX_FORWARD(Result_, init)]() mutable { + this_->set_value(HPX_MOVE(init)); }), "timed_future_data::timed_future_data", threads::thread_priority::boost, diff --git a/libs/core/futures/include/hpx/futures/future.hpp b/libs/core/futures/include/hpx/futures/future.hpp index 1888fc56c298..d649f77f7ffd 100644 --- a/libs/core/futures/include/hpx/futures/future.hpp +++ b/libs/core/futures/include/hpx/futures/future.hpp @@ -1600,9 +1600,12 @@ namespace hpx { { using result_type = hpx::util::decay_unwrap_t; using shared_state = lcos::detail::timed_future_data; + using init_no_addref = typename shared_state::init_no_addref; hpx::intrusive_ptr p( - new shared_state(abs_time.value(), HPX_FORWARD(T, init))); + new shared_state( + init_no_addref{}, abs_time.value(), HPX_FORWARD(T, init)), + false); return hpx::traits::future_access>::create( HPX_MOVE(p)); @@ -1650,9 +1653,12 @@ namespace hpx { hpx::chrono::steady_time_point const& abs_time) { using shared_state = lcos::detail::timed_future_data; + using init_no_addref = typename shared_state::init_no_addref; hpx::intrusive_ptr p( - new shared_state(abs_time.value(), hpx::util::unused)); + new shared_state( + init_no_addref{}, abs_time.value(), hpx::util::unused), + false); return hpx::traits::future_access>::create(HPX_MOVE(p)); } diff --git a/libs/core/init_runtime_local/include/hpx/init_runtime_local/init_runtime_local.hpp b/libs/core/init_runtime_local/include/hpx/init_runtime_local/init_runtime_local.hpp index 6629f20317bd..57f2001008f3 100644 --- a/libs/core/init_runtime_local/include/hpx/init_runtime_local/init_runtime_local.hpp +++ b/libs/core/init_runtime_local/include/hpx/init_runtime_local/init_runtime_local.hpp @@ -82,12 +82,11 @@ namespace hpx { HPX_MAYBE_UNUSED static char app_name[] = HPX_APPLICATION_STRING; static char* default_argv[2] = {app_name, nullptr}; HPX_MAYBE_UNUSED static char** dummy_argv = default_argv; + // HPX_APPLICATION_STRING is specific to an application and therefore // cannot be in the source file - HPX_MAYBE_UNUSED static const hpx::program_options:: - options_description default_desc = - hpx::program_options::options_description( - "Usage: " HPX_APPLICATION_STRING " [options]"); + HPX_CORE_EXPORT hpx::program_options::options_description const& + default_desc(); // Utilities to init the thread_pools of the resource partitioner using rp_callback_type = @@ -99,7 +98,7 @@ namespace hpx { { std::reference_wrapper< hpx::program_options::options_description const> - desc_cmdline = detail::default_desc; + desc_cmdline = detail::default_desc(); std::vector cfg; mutable startup_function_type startup; mutable shutdown_function_type shutdown; diff --git a/libs/core/init_runtime_local/src/init_runtime_local.cpp b/libs/core/init_runtime_local/src/init_runtime_local.cpp index 417770a1fc0d..839a055e5a4a 100644 --- a/libs/core/init_runtime_local/src/init_runtime_local.cpp +++ b/libs/core/init_runtime_local/src/init_runtime_local.cpp @@ -528,6 +528,13 @@ namespace hpx { } return result; } + + hpx::program_options::options_description const& default_desc() + { + static hpx::program_options::options_description default_desc_( + std::string("Usage: ") + app_name + " [options]"); + return default_desc_; + } } // namespace detail } // namespace local } // namespace hpx diff --git a/libs/full/actions/include/hpx/actions/register_action.hpp b/libs/full/actions/include/hpx/actions/register_action.hpp index e06e6a30894f..d7395e2e9713 100644 --- a/libs/full/actions/include/hpx/actions/register_action.hpp +++ b/libs/full/actions/include/hpx/actions/register_action.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2016 Thomas Heller -// Copyright (c) 2020 Hartmut Kaiser +// Copyright (c) 2020-2022 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -11,6 +11,7 @@ #include #include #include +#include #if defined(HPX_HAVE_NETWORKING) @@ -43,9 +44,11 @@ namespace hpx { namespace actions { namespace detail { template register_action::register_action() { + char const* action_name = + hpx::actions::detail::get_action_name(); + HPX_ASSERT(nullptr != action_name); action_registry::instance().register_factory( - hpx::actions::detail::get_action_name(), &create, - &create_cont); + action_name, &create, &create_cont); } template diff --git a/libs/full/command_line_handling/src/parse_command_line.cpp b/libs/full/command_line_handling/src/parse_command_line.cpp index 5518ba5a7f0a..28eaaa1b03a2 100644 --- a/libs/full/command_line_handling/src/parse_command_line.cpp +++ b/libs/full/command_line_handling/src/parse_command_line.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2007-2022 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -350,6 +350,19 @@ namespace hpx { namespace util { } } // namespace detail + void verify_unknown_options(std::vector const& opts) + { + for (auto const& opt : opts) + { + std::string::size_type p = opt.find("--hpx:"); + if (p != std::string::npos) + { + throw hpx::detail::command_line_error( + "Unknown/misspelled HPX command line option found: " + opt); + } + } + } + /////////////////////////////////////////////////////////////////////////// // parse the command line bool parse_commandline(util::section const& rtcfg, @@ -724,6 +737,8 @@ namespace hpx { namespace util { using hpx::program_options::exclude_positional; *unregistered_options = collect_unrecognized(opts.options, exclude_positional); + + verify_unknown_options(*unregistered_options); } store(opts, vm); @@ -747,6 +762,8 @@ namespace hpx { namespace util { using hpx::program_options::include_positional; *unregistered_options = collect_unrecognized(opts.options, include_positional); + + verify_unknown_options(*unregistered_options); } store(opts, vm); diff --git a/libs/full/init_runtime/include/hpx/hpx_init_impl.hpp b/libs/full/init_runtime/include/hpx/hpx_init_impl.hpp index 69ec596a4149..afd372b767fc 100644 --- a/libs/full/init_runtime/include/hpx/hpx_init_impl.hpp +++ b/libs/full/init_runtime/include/hpx/hpx_init_impl.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2018 Mikael Simberg -// Copyright (c) 2007-2016 Hartmut Kaiser +// Copyright (c) 2007-2022 Hartmut Kaiser // Copyright (c) 2011 Bryce Lelbach // // SPDX-License-Identifier: BSL-1.0 @@ -52,8 +52,8 @@ namespace hpx { { if (argc == 0 || argv == nullptr) { - argc = dummy_argc; - argv = dummy_argv; + argc = hpx::local::detail::dummy_argc; + argv = hpx::local::detail::dummy_argv; } #if defined(HPX_WINDOWS) @@ -139,7 +139,8 @@ namespace hpx { { hpx::function main_f = static_cast(::hpx_main); - return detail::init_impl( - HPX_MOVE(main_f), detail::dummy_argc, detail::dummy_argv, params); + return detail::init_impl(HPX_MOVE(main_f), + hpx::local::detail::dummy_argc, hpx::local::detail::dummy_argv, + params); } } // namespace hpx diff --git a/libs/full/init_runtime/include/hpx/hpx_init_params.hpp b/libs/full/init_runtime/include/hpx/hpx_init_params.hpp index 02b654952d67..b3b7b335f84b 100644 --- a/libs/full/init_runtime/include/hpx/hpx_init_params.hpp +++ b/libs/full/init_runtime/include/hpx/hpx_init_params.hpp @@ -1,4 +1,5 @@ -// Copyright (c) 2020 ETH Zurich +// Copyright (c) 2020 ETH Zurich +// Copyright (c) 2022 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -52,19 +53,6 @@ namespace hpx { } // namespace resource /// \endcond - namespace detail { - // Default params to initialize the init_params struct - HPX_MAYBE_UNUSED static int dummy_argc = 1; - HPX_MAYBE_UNUSED static char app_name[] = HPX_APPLICATION_STRING; - static char* default_argv[2] = {app_name, nullptr}; - HPX_MAYBE_UNUSED static char** dummy_argv = default_argv; - // HPX_APPLICATION_STRING is specific to an application and therefore - // cannot be in the source file - HPX_MAYBE_UNUSED static const hpx::program_options::options_description - default_desc = hpx::program_options::options_description( - "Usage: " HPX_APPLICATION_STRING " [options]"); - } // namespace detail - #if !defined(DOXYGEN) typedef int (*hpx_main_type)(hpx::program_options::variables_map&); typedef int (*hpx_user_main_type)(int argc, char** argv); @@ -111,7 +99,7 @@ namespace hpx { { // Parameters std::reference_wrapper - desc_cmdline = detail::default_desc; + desc_cmdline = hpx::local::detail::default_desc(); std::vector cfg; mutable startup_function_type startup; mutable shutdown_function_type shutdown; diff --git a/libs/full/init_runtime/include/hpx/hpx_start_impl.hpp b/libs/full/init_runtime/include/hpx/hpx_start_impl.hpp index dcb92a72a709..95fbd9efeed0 100644 --- a/libs/full/init_runtime/include/hpx/hpx_start_impl.hpp +++ b/libs/full/init_runtime/include/hpx/hpx_start_impl.hpp @@ -1,5 +1,5 @@ // Copyright (c) 2018 Mikael Simberg -// Copyright (c) 2007-2016 Hartmut Kaiser +// Copyright (c) 2007-2022 Hartmut Kaiser // // SPDX-License-Identifier: BSL-1.0 // Distributed under the Boost Software License, Version 1.0. (See accompanying @@ -50,8 +50,8 @@ namespace hpx { { if (argc == 0 || argv == nullptr) { - argc = dummy_argc; - argv = dummy_argv; + argc = local::detail::dummy_argc; + argv = local::detail::dummy_argv; } #if defined(HPX_WINDOWS) @@ -149,7 +149,8 @@ namespace hpx { { hpx::function main_f = static_cast(::hpx_main); - return detail::start_impl( - HPX_MOVE(main_f), detail::dummy_argc, detail::dummy_argv, params); + return detail::start_impl(HPX_MOVE(main_f), + hpx::local::detail::dummy_argc, hpx::local::detail::dummy_argv, + params); } } // namespace hpx From 9f2007deee14f90df5d4fa047f7b3e46f58d1268 Mon Sep 17 00:00:00 2001 From: chuanqiu Date: Sun, 18 Sep 2022 12:02:02 -0500 Subject: [PATCH 12/22] Integarting sync_wait & with_variant --- .../hpx/execution/algorithms/sync_wait.hpp | 156 ++++++++- libs/core/execution/tests/unit/CMakeLists.txt | 1 + .../unit/algorithm_sync_wait_with_variant.cpp | 299 ++++++++++++++++++ .../tests/include/algorithm_test_utils.hpp | 55 ++++ 4 files changed, 499 insertions(+), 12 deletions(-) create mode 100644 libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp diff --git a/libs/core/execution/include/hpx/execution/algorithms/sync_wait.hpp b/libs/core/execution/include/hpx/execution/algorithms/sync_wait.hpp index 06a75059682b..abfc2d744123 100644 --- a/libs/core/execution/include/hpx/execution/algorithms/sync_wait.hpp +++ b/libs/core/execution/include/hpx/execution/algorithms/sync_wait.hpp @@ -35,6 +35,12 @@ #include #include +enum class Sync_wait_type + { + single, + variant + }; + namespace hpx::execution::experimental::detail { struct sync_wait_error_visitor @@ -84,7 +90,7 @@ namespace hpx::execution::experimental::detail { template using make_decayed_pack_t = typename make_decayed_pack::type; - template + template struct sync_wait_receiver { // value and error_types of the predecessor sender @@ -108,9 +114,11 @@ namespace hpx::execution::experimental::detail { single_variant_t>>; // The template should compute the result type of whatever returned from - // sync_wait, which should be optional of the variant of the tuples. The - // sync_wait works when the variant has one tuple. - using result_type = hpx::variant; + // sync_wait or sync_wait_with_variant by checking Sync_wait_type is single or variant + using result_type = + std::conditional, + predecessor_value_types>; // The type of errors to store in the variant. This in itself is a // variant. @@ -131,8 +139,19 @@ namespace hpx::execution::experimental::detail { { // pull the tuple out of the variant and wrap it into an // optional, make sure to remove the references - return hpx::optional( - hpx::get<0>(hpx::get(HPX_MOVE(value)))); + // return hpx::optional( + // hpx::get<0>(hpx::get(HPX_MOVE(value)))); + + if constexpr (Type == Sync_wait_type::single) + { + return hpx::optional(hpx::get<0>( + hpx::get(HPX_MOVE(value)))); + } + else if constexpr (Type == Sync_wait_type::variant) + { + return hpx::optional( + hpx::get(HPX_MOVE(value))); + } } else if (hpx::holds_alternative(value)) { @@ -331,7 +350,7 @@ namespace hpx::this_thread::experimental { } // clang-format off - template @@ -342,8 +361,8 @@ namespace hpx::this_thread::experimental { Sender&& sender) { using receiver_type = - hpx::execution::experimental::detail::sync_wait_receiver< - Sender>; + hpx::execution::experimental::detail::sync_wait_receiver; using state_type = typename receiver_type::shared_state; hpx::execution::experimental::run_loop& loop = sched.get_run_loop(); @@ -359,7 +378,7 @@ namespace hpx::this_thread::experimental { } // clang-format off - template @@ -369,8 +388,8 @@ namespace hpx::this_thread::experimental { sync_wait_t, Sender&& sender) { using receiver_type = - hpx::execution::experimental::detail::sync_wait_receiver< - Sender>; + hpx::execution::experimental::detail::sync_wait_receiver; using state_type = typename receiver_type::shared_state; hpx::execution::experimental::run_loop loop{}; @@ -404,4 +423,117 @@ namespace hpx::this_thread::experimental { sync_wait_t>{}; } } sync_wait{}; + + //////////////////////////////////////////////////////////////////// + // DPO for sync_wait_with_variant + + // this_thread::sync_wait_with_variant is a sender consumer that submits + // the work described by the provided sender for execution, similarly to + // ensure_started, except that it blocks the current std::thread or + // thread of main until the work is completed, and returns an optional + // of variant of tuples that were sent by the provided sender on its + // completion of work. + inline constexpr struct sync_wait_with_variant_t final + : hpx::functional::detail::tag_priority + { + private: + // clang-format off + template && + hpx::execution::experimental::detail:: + is_completion_scheduler_tag_invocable_v< + hpx::execution::experimental::set_value_t, + Sender, sync_wait_with_variant_t + > + )> + // clang-format on + friend constexpr HPX_FORCEINLINE auto tag_override_invoke( + sync_wait_with_variant_t, Sender&& sender) + { + auto scheduler = + hpx::execution::experimental::get_completion_scheduler< + hpx::execution::experimental::set_value_t>(sender); + + return hpx::functional::tag_invoke(sync_wait_with_variant_t{}, + HPX_MOVE(scheduler), HPX_FORWARD(Sender, sender)); + } + + // clang-format off + template + )> + // clang-format on + friend auto tag_invoke(sync_wait_with_variant_t, + hpx::execution::experimental::run_loop_scheduler const& sched, + Sender&& sender) + { + using receiver_type = + hpx::execution::experimental::detail::sync_wait_receiver; + using state_type = typename receiver_type::shared_state; + + hpx::execution::experimental::run_loop& loop = sched.get_run_loop(); + state_type state{}; + auto op_state = hpx::execution::experimental::connect( + HPX_FORWARD(Sender, sender), receiver_type{state, loop}); + hpx::execution::experimental::start(op_state); + + // Wait for the variant to be filled in. + loop.run(); + + return state.get_value(); + } + + // clang-format off + template + )> + // clang-format on + friend HPX_FORCEINLINE auto tag_fallback_invoke( + sync_wait_with_variant_t, Sender&& sender) + { + using receiver_type = + hpx::execution::experimental::detail::sync_wait_receiver; + using state_type = typename receiver_type::shared_state; + + hpx::execution::experimental::run_loop loop{}; + state_type state{}; + auto op_state = hpx::execution::experimental::connect( + HPX_FORWARD(Sender, sender), receiver_type{state, loop}); + hpx::execution::experimental::start(op_state); + + // Wait for the variant to be filled in. + loop.run(); + + return state.get_value(); + } + + // clang-format off + template + )> + // clang-format on + friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke( + sync_wait_with_variant_t, Scheduler&& scheduler) + { + return hpx::execution::experimental::detail::inject_scheduler< + sync_wait_with_variant_t, Scheduler>{ + HPX_FORWARD(Scheduler, scheduler)}; + } + + friend constexpr HPX_FORCEINLINE auto tag_fallback_invoke( + sync_wait_with_variant_t) + { + return hpx::execution::experimental::detail::partial_algorithm< + sync_wait_with_variant_t>{}; + } + } sync_wait_with_variant{}; } // namespace hpx::this_thread::experimental diff --git a/libs/core/execution/tests/unit/CMakeLists.txt b/libs/core/execution/tests/unit/CMakeLists.txt index 87a295db2e49..3152cf28af38 100644 --- a/libs/core/execution/tests/unit/CMakeLists.txt +++ b/libs/core/execution/tests/unit/CMakeLists.txt @@ -18,6 +18,7 @@ set(tests algorithm_split algorithm_start_detached algorithm_sync_wait + algorithm_sync_wait_with_variant algorithm_then algorithm_transfer algorithm_transfer_just diff --git a/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp b/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp new file mode 100644 index 000000000000..ea33b1b06d85 --- /dev/null +++ b/libs/core/execution/tests/unit/algorithm_sync_wait_with_variant.cpp @@ -0,0 +1,299 @@ +// Copyright (c) 2021 ETH Zurich +// Copyright (c) 2022 Chuanqiu He +// +// 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 "algorithm_test_utils.hpp" + +#include +#include +#include +#include +#include +#include + +namespace ex = hpx::execution::experimental; +namespace tt = hpx::this_thread::experimental; + +// NOTE: This is not a conforming sync_wait_with_variant implementation. +// It only exists to check that the tag_invoke overload is called. +void tag_invoke(tt::sync_wait_with_variant_t, custom_sender2 s) +{ + s.tag_invoke_overload_called = true; +} +void tag_invoke(tt::sync_wait_with_variant_t, custom_sender_multiTuple s) +{ + s.tag_invoke_overload_called = true; +} + +int hpx_main() +{ + // Success path + { + std::atomic start_called{false}; + std::atomic connect_called{false}; + std::atomic tag_invoke_overload_called{false}; + tt::sync_wait_with_variant(custom_sender{ + start_called, connect_called, tag_invoke_overload_called}); + HPX_TEST(start_called); + HPX_TEST(connect_called); + HPX_TEST(!tag_invoke_overload_called); + } + // sync_wait_with_variant can accept single value senders : + // assume currently have one tuple + { + auto result = ex::just(42) | tt::sync_wait_with_variant(); + + auto v = *result; + static_assert( + std::is_same_v>>); + HPX_TEST(hpx::holds_alternative>(v)); + + auto t = hpx::get>(v); + static_assert(std::is_same_v>); + + auto i = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST(i == 42); + } + + { + auto result = ex::just(3, 4.0) | tt::sync_wait_with_variant(); + + auto v = *result; + static_assert( + std::is_same_v>>); + + auto t = hpx::get>(v); + static_assert(std::is_same_v>); + + auto i = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST(i == 3); + + auto j = hpx::get<1>(t); + static_assert(std::is_same_v); + + HPX_TEST(j == 4.0); + } + + { + auto result = + tt::sync_wait_with_variant(ex::just(3, 4.0, std::string("42"))); + auto v = *result; + + static_assert(std::is_same_v>>); + + auto t = hpx::get>(v); + static_assert( + std::is_same_v>); + + auto i = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST(i == 3); + + auto j = hpx::get<1>(t); + static_assert(std::is_same_v); + + HPX_TEST(j == 4.0); + + auto k = hpx::get<2>(t); + static_assert(std::is_same_v); + + HPX_TEST(k == "42"); + } + + { + auto s1 = ex::just(custom_type_non_default_constructible{42}); + auto result = tt::sync_wait_with_variant(std::move(s1)); + auto v = *result; + check_value_types< + hpx::variant>>( + s1); + + auto t = hpx::get>(v); + auto p = hpx::get<0>(t); + static_assert( + std::is_same_v); + + HPX_TEST_EQ(p.x, 42); + } + + { + auto result = tt::sync_wait_with_variant( + ex::just(custom_type_non_default_constructible_non_copyable{42})); + auto const& v = *result; + static_assert(std::is_same_v, + hpx::variant>>); + + auto const& t = hpx::get< + hpx::tuple>(v); + auto const& p = hpx::get<0>(t); + static_assert(std::is_same_v, + custom_type_non_default_constructible_non_copyable>); + + HPX_TEST_EQ(p.x, 42); + } + + // sync_wait_with_variant can accept more than one senders: + // (accept variant of multi_tuple senders ) + // tests a sender which has two different value types + // Success path + { + std::atomic start_called{false}; + std::atomic connect_called{false}; + std::atomic tag_invoke_overload_called{false}; + tt::sync_wait_with_variant(custom_sender_multiTuple{ + start_called, connect_called, tag_invoke_overload_called, true}); + HPX_TEST(start_called); + HPX_TEST(connect_called); + HPX_TEST(!tag_invoke_overload_called); + } + + { + std::atomic start_called{false}; + std::atomic connect_called{false}; + std::atomic tag_invoke_overload_called{false}; + tt::sync_wait_with_variant(custom_sender_multiTuple{ + start_called, connect_called, tag_invoke_overload_called, false}); + HPX_TEST(start_called); + HPX_TEST(connect_called); + HPX_TEST(!tag_invoke_overload_called); + } + + { + auto sender = ex::just(3) | ex::let_error([](std::exception_ptr) { + HPX_TEST(false); + return ex::just(std::string{"err"}); + }); + + auto result = tt::sync_wait_with_variant(std::move(sender)); + + // variant + auto v = *result; + static_assert(std::is_same_v, hpx::tuple>>); + + HPX_TEST(hpx::holds_alternative>(v)); + + // tuple + auto t = hpx::get<1>(v); + static_assert(std::is_same_v>); + + auto i = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST_EQ(i, 3); + } + + { + auto s1 = ex::just(custom_type_non_default_constructible{42}); + auto s2 = ex::let_value(std::move(s1), + [](custom_type_non_default_constructible const& value) { + HPX_TEST_EQ(value.x, 42); + return ex::just(std::to_string(value.x)); + }); + + auto result = tt::sync_wait_with_variant(std::move(s2)); + + // variant + auto v = *result; + static_assert( + std::is_same_v>>); + + // tuple + auto t = hpx::get<0>(v); + static_assert(std::is_same_v>); + + auto j = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST_EQ(j, std::string("42")); + } + + // operator| overload + { + std::atomic start_called{false}; + std::atomic connect_called{false}; + std::atomic tag_invoke_overload_called{false}; + custom_sender{ + start_called, connect_called, tag_invoke_overload_called} | + tt::sync_wait_with_variant(); + HPX_TEST(start_called); + HPX_TEST(connect_called); + HPX_TEST(!tag_invoke_overload_called); + } + + { + auto result = ex::just(3) | tt::sync_wait_with_variant(); + + auto v = *result; + static_assert( + std::is_same_v>>); + HPX_TEST(hpx::holds_alternative>(v)); + + auto t = hpx::get>(v); + static_assert(std::is_same_v>); + + auto i = hpx::get<0>(t); + static_assert(std::is_same_v); + + HPX_TEST(i == 3); + } + + // tag_invoke overload + { + std::atomic start_called{false}; + std::atomic connect_called{false}; + std::atomic tag_invoke_overload_called{false}; + tt::sync_wait_with_variant(custom_sender2{custom_sender{ + start_called, connect_called, tag_invoke_overload_called}}); + HPX_TEST(!start_called); + HPX_TEST(!connect_called); + HPX_TEST(tag_invoke_overload_called); + } + + // Failure path + { + bool exception_thrown = false; + try + { + tt::sync_wait_with_variant(error_sender{}); + HPX_TEST(false); + } + catch (std::runtime_error const& e) + { + HPX_TEST_EQ(std::string(e.what()), std::string("error")); + exception_thrown = true; + } + HPX_TEST(exception_thrown); + } + + // cancellation path + { + auto result = + (stopped_sender_with_value_type{} | tt::sync_wait_with_variant()); + HPX_TEST(!result); // returned optional should be empty + } + + return hpx::local::finalize(); +} + +int main(int argc, char* argv[]) +{ + HPX_TEST_EQ_MSG(hpx::local::init(hpx_main, argc, argv), 0, + "HPX main exited with non-zero status"); + + return hpx::util::report_errors(); +} \ No newline at end of file diff --git a/libs/core/execution_base/tests/include/algorithm_test_utils.hpp b/libs/core/execution_base/tests/include/algorithm_test_utils.hpp index 7db61a9a8d5b..4668b3705c72 100644 --- a/libs/core/execution_base/tests/include/algorithm_test_utils.hpp +++ b/libs/core/execution_base/tests/include/algorithm_test_utils.hpp @@ -410,6 +410,61 @@ struct custom_sender hpx::execution::experimental::set_error_t(std::exception_ptr)>; }; +struct custom_sender_multiTuple +{ + std::atomic& start_called; + std::atomic& connect_called; + std::atomic& tag_invoke_overload_called; + + bool expect_set_value = true; + + template