mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 17:41:45 +00:00
Compare commits
22 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
16275db125 | ||
|
42ce691f57 | ||
|
58aa2b4f88 | ||
|
c3b273cec0 | ||
|
a982d60ed7 | ||
|
d16e473b91 | ||
|
1881986cca | ||
|
adf91d053d | ||
|
d3be9af9b6 | ||
|
4104636456 | ||
|
af0d668951 | ||
|
072d7cb744 | ||
|
f5c46ce018 | ||
|
d105960444 | ||
|
3aae5bae58 | ||
|
9031029d2c | ||
|
d478e050ba | ||
|
06b2b9b01f | ||
|
b3fa4f6e7e | ||
|
da5cb34416 | ||
|
226733c653 | ||
|
b06efc401e |
15
.github/workflows/fair-software.yml
vendored
Normal file
15
.github/workflows/fair-software.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: fair-software
|
||||
|
||||
on: push
|
||||
|
||||
jobs:
|
||||
verify:
|
||||
name: "fair-software"
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: fair-software/howfairis-github-action@0.2.1
|
||||
name: Measure compliance with fair-software.eu recommendations
|
||||
env:
|
||||
PYCHARM_HOSTED: "Trick colorama into displaying colored output"
|
||||
with:
|
||||
MY_REPO_URL: "https://github.com/${{ github.repository }}"
|
86
.zenodo.json
Normal file
86
.zenodo.json
Normal file
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"creators": [
|
||||
{
|
||||
"name": "Al-Turany, Mohammad"
|
||||
},
|
||||
{
|
||||
"orcid": "0000-0003-3787-1910",
|
||||
"name": "Klein, Dennis"
|
||||
},
|
||||
{
|
||||
"name": "Kollegger, Thorsten"
|
||||
},
|
||||
{
|
||||
"name": "Rybalchenko, Alexey"
|
||||
},
|
||||
{
|
||||
"name": "Winckler, Nicolas"
|
||||
}
|
||||
],
|
||||
"contributors": [
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Aphecetche, Laurent"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Binet, Sebastien"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Eulisse, Giulio"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Karabowicz, Radoslaw"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Kretz, Matthias"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Krzewicki, Mikolaj"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Lebedev, Andrey"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Mrnjavac, Teo"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Neskovic, Gvozden"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Richter, Matthias"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"orcid": "0000-0002-5321-8404",
|
||||
"name": "Tacke, Christian"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Uhlig, Florian"
|
||||
},
|
||||
{
|
||||
"type": "Other",
|
||||
"name": "Wenzel, Sandro"
|
||||
}
|
||||
],
|
||||
"description": "<p>C++ Message Queuing Library and Framework</p>",
|
||||
"related_identifiers": [
|
||||
{
|
||||
"identifier": "https://github.com/FairRootGroup/FairMQ/",
|
||||
"relation": "isSupplementTo",
|
||||
"resource_type": "software",
|
||||
"scheme": "url"
|
||||
}
|
||||
],
|
||||
"title": "FairMQ",
|
||||
"license": "LGPL-3.0-only"
|
||||
}
|
2
AUTHORS
2
AUTHORS
@@ -1,5 +1,5 @@
|
||||
Al-Turany, Mohammad
|
||||
Klein, Dennis
|
||||
Klein, Dennis [https://orcid.org/0000-0003-3787-1910]
|
||||
Kollegger, Thorsten
|
||||
Rybalchenko, Alexey
|
||||
Winckler, Nicolas
|
||||
|
@@ -29,10 +29,16 @@ fairmq_build_option(BUILD_TESTING "Build tests."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
||||
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
|
||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
||||
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
|
||||
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
||||
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
|
||||
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN;BUILD_SDK_COMMANDS")
|
||||
fairmq_build_option(BUILD_TIDY_TOOL "Build the fairmq-tidy tool."
|
||||
DEFAULT OFF)
|
||||
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
|
||||
@@ -51,7 +57,7 @@ include(FairMQDependencies)
|
||||
|
||||
|
||||
# Targets ######################################################################
|
||||
if(BUILD_FAIRMQ)
|
||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||
add_subdirectory(fairmq)
|
||||
endif()
|
||||
|
||||
@@ -86,6 +92,9 @@ endif()
|
||||
if(BUILD_TESTING)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS tests)
|
||||
endif()
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS dds_plugin)
|
||||
endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
||||
endif()
|
||||
@@ -98,6 +107,12 @@ endif()
|
||||
if(BUILD_DOCS)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS docs)
|
||||
endif()
|
||||
if(BUILD_SDK)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk)
|
||||
endif()
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_commands)
|
||||
endif()
|
||||
if(BUILD_TIDY_TOOL)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
|
||||
endif()
|
||||
@@ -110,6 +125,11 @@ if(BUILD_FAIRMQ)
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_SDK OR BUILD_DDS_PLUGIN)
|
||||
install(FILES cmake/Findasio.cmake
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_DOCS)
|
||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
|
||||
|
@@ -3,11 +3,11 @@ Binet, Sebastien
|
||||
Eulisse, Giulio
|
||||
Karabowicz, Radoslaw
|
||||
Kretz, Matthias <kretz@kde.org>
|
||||
Krzewicki, Mikolaj
|
||||
Krzewicki, Mikolaj
|
||||
Lebedev, Andrey
|
||||
Mrnjavac, Teo <teo.m@cern.ch>
|
||||
Neskovic, Gvozden
|
||||
Richter, Matthias
|
||||
Tacke, Christian
|
||||
Tacke, Christian [https://orcid.org/0000-0002-5321-8404]
|
||||
Uhlig, Florian
|
||||
Wenzel, Sandro
|
||||
|
@@ -42,8 +42,11 @@ endif()
|
||||
ctest_start(Continuous)
|
||||
|
||||
list(APPEND options "-DDISABLE_COLOR=ON" "-DBUILD_EXAMPLES=ON" "-DBUILD_TESTING=ON")
|
||||
if(HAS_ASIO AND HAS_DDS)
|
||||
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_SDK=ON" "-DBUILD_DDS_PLUGIN=ON")
|
||||
endif()
|
||||
if(HAS_PMIX)
|
||||
list(APPEND options "-DBUILD_PMIX_PLUGIN=ON")
|
||||
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_PMIX_PLUGIN=ON")
|
||||
endif()
|
||||
if(HAS_ASIO AND HAS_ASIOFI)
|
||||
list(APPEND options "-DBUILD_OFI_TRANSPORT=ON")
|
||||
|
4
Jenkinsfile
vendored
4
Jenkinsfile
vendored
@@ -97,8 +97,8 @@ pipeline{
|
||||
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10', extra: all],
|
||||
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11', extra: all],
|
||||
[os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11', extra: all],
|
||||
[os: 'macos', ver: '12', arch: 'x86_64', compiler: 'apple-clang-13', extra: '-DHAS_ASIO=ON'],
|
||||
[os: 'macos', ver: '12', arch: 'arm64', compiler: 'apple-clang-13', extra: '-DHAS_ASIO=ON'],
|
||||
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12', extra: '-DHAS_ASIO=ON'],
|
||||
[os: 'macos', ver: '11', arch: 'arm64', compiler: 'apple-clang-13', extra: '-DHAS_ASIO=ON'],
|
||||
])
|
||||
|
||||
def all_debug = "${all} -DCMAKE_BUILD_TYPE=Debug"
|
||||
|
13
README.md
13
README.md
@@ -1,5 +1,10 @@
|
||||
<!-- {#mainpage} -->
|
||||
# FairMQ [](COPYRIGHT)
|
||||
# FairMQ
|
||||
|
||||
[](COPYRIGHT)
|
||||
[](https://doi.org/10.5281/zenodo.1689985)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/6915)
|
||||
[](https://github.com/FairRootGroup/FairMQ/actions/workflows/fair-software.yml)
|
||||
|
||||
C++ Message Queuing Library and Framework
|
||||
|
||||
@@ -82,9 +87,11 @@ When building FairMQ, CMake will print a summary table of all available package
|
||||
* [asiofi](https://github.com/FairRootGroup/asiofi)
|
||||
* [Boost](https://www.boost.org/)
|
||||
* [CMake](https://cmake.org/)
|
||||
* [DDS](http://dds.gsi.de)
|
||||
* [Doxygen](http://www.doxygen.org/)
|
||||
* [FairCMakeModules](https://github.com/FairRootGroup/FairCMakeModules) (optionally bundled)
|
||||
* [FairLogger](https://github.com/FairRootGroup/FairLogger)
|
||||
* [Flatbuffers](https://google.github.io/flatbuffers/)
|
||||
* [GTest](https://github.com/google/googletest) (optionally bundled)
|
||||
* [PMIx](https://pmix.org/)
|
||||
* [ZeroMQ](http://zeromq.org/)
|
||||
@@ -159,4 +166,6 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
1. [Usage](docs/Plugins.md#71-usage)
|
||||
2. [Development](docs/Plugins.md#72-development)
|
||||
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
|
||||
2. [PMIx](docs/Plugins.md#731-pmix)
|
||||
1. [DDS](docs/Plugins.md#731-dds)
|
||||
2. [PMIx](docs/Plugins.md#732-pmix)
|
||||
8. [Controller SDK](docs/SDK.md)
|
||||
|
@@ -12,7 +12,7 @@ include(FairCMakeModules)
|
||||
include(FairFindPackage2)
|
||||
include(FairMQBundlePackageHelper)
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package2(PUBLIC Threads REQUIRED)
|
||||
set(Threads_PREFIX "<system>")
|
||||
@@ -23,18 +23,28 @@ if(BUILD_OFI_TRANSPORT)
|
||||
find_package2(PRIVATE OFI REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
find_package2(PRIVATE Flatbuffers REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
|
||||
find_package2(PRIVATE DDS REQUIRED VERSION 3.5.13.7)
|
||||
set(DDS_Boost_COMPONENTS system log log_setup regex filesystem thread)
|
||||
set(DDS_Boost_VERSION 1.67)
|
||||
endif()
|
||||
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
find_package2(PRIVATE PMIx REQUIRED VERSION 2.1.4)
|
||||
endif()
|
||||
|
||||
if(BUILD_FAIRMQ OR BUILD_TIDY_TOOL)
|
||||
if(BUILD_FAIRMQ OR BUILD_SDK OR BUILD_TIDY_TOOL)
|
||||
find_package2(PUBLIC FairLogger REQUIRED VERSION 1.6.0)
|
||||
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
|
||||
COMPONENTS container program_options filesystem date_time regex
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
if(BUILD_OFI_TRANSPORT OR BUILD_SDK OR BUILD_DDS_PLUGIN)
|
||||
set(__old ${CMAKE_FIND_PACKAGE_PREFER_CONFIG})
|
||||
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
|
||||
find_package2(PUBLIC asio REQUIRED VERSION 1.18)
|
||||
@@ -58,7 +68,7 @@ if(BUILD_TESTING)
|
||||
endif()
|
||||
find_package2(BUNDLED GTest REQUIRED)
|
||||
if(GTest_BUNDLED)
|
||||
set(GTest_VERSION "Apr 8 2022 @a1cc8c55")
|
||||
set(GTest_VERSION "Apr 28 2021 @f5e592d8")
|
||||
set(GTest_PREFIX "<bundled>")
|
||||
endif()
|
||||
endif()
|
||||
@@ -91,6 +101,8 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
if(NOT asiofi_PREFIX AND asiofi_ROOT)
|
||||
set(asiofi_PREFIX ${asiofi_ROOT})
|
||||
endif()
|
||||
elseif(${dep} STREQUAL DDS)
|
||||
set(DDS_PREFIX "${DDS_INSTALL_PREFIX}")
|
||||
elseif(${dep} STREQUAL Boost)
|
||||
if(TARGET Boost::headers)
|
||||
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
@@ -104,6 +116,14 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
get_filename_component(Doxygen_PREFIX ${doxygen_bin} DIRECTORY)
|
||||
get_filename_component(Doxygen_PREFIX ${Doxygen_PREFIX}/.. ABSOLUTE)
|
||||
unset(doxygen_bin)
|
||||
elseif(${dep} STREQUAL Flatbuffers)
|
||||
if(TARGET flatbuffers::flatbuffers)
|
||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
get_target_property(flatbuffers_include flatbuffers::flatbuffers_shared INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
get_filename_component(Flatbuffers_PREFIX ${flatbuffers_include}/.. ABSOLUTE)
|
||||
unset(flatbuffers_include)
|
||||
elseif(NOT ${dep}_PREFIX)
|
||||
# try to guess
|
||||
if(TARGET ${dep}::${dep})
|
||||
|
@@ -1,5 +1,5 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
@@ -33,6 +33,12 @@ macro(fairmq_summary_components)
|
||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
set(dds_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_DDS_PLUGIN=OFF${CR})")
|
||||
else()
|
||||
set(dds_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_DDS_PLUGIN=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
set(pmix_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
||||
else()
|
||||
@@ -51,12 +57,39 @@ macro(fairmq_summary_components)
|
||||
set(docs_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DOCS=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
|
||||
if(BUILD_TIDY_TOOL)
|
||||
set(sdk_tidy_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
||||
if(BUILD_SDK)
|
||||
set(sdk_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK=OFF${CR})")
|
||||
else()
|
||||
set(sdk_tidy_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
||||
set(sdk_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}sdk${CR} ${sdk_summary}")
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
set(sdk_commands_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK_COMMANDS=OFF${CR})")
|
||||
else()
|
||||
set(sdk_commands_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK_COMMANDS=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
|
||||
if(BUILD_TIDY_TOOL)
|
||||
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
|
||||
else()
|
||||
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
|
||||
|
||||
set(_deprecated)
|
||||
if(BUILD_SDK)
|
||||
list(APPEND _deprecated sdk)
|
||||
endif()
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
list(APPEND _deprecated sdk_commands)
|
||||
endif()
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
list(APPEND _deprecated dds_plugin)
|
||||
endif()
|
||||
list(JOIN _deprecated ", " _deprecated)
|
||||
if(_deprecated)
|
||||
message(DEPRECATION "You have selected to build deprecated components '${_deprecated}' which will be removed in a future release. See https://github.com/FairRootGroup/FairMQ/discussions/392 for more information. Use '-Wno-deprecated' to silence deprecation warnings.")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(fairmq_summary_static_analysis)
|
||||
|
@@ -18,7 +18,8 @@
|
||||
{
|
||||
"@type": "Person",
|
||||
"givenName": "Dennis",
|
||||
"familyName": "Klein"
|
||||
"familyName": "Klein",
|
||||
"@id": "https://orcid.org/0000-0003-3787-1910"
|
||||
},
|
||||
{
|
||||
"@type": "Person",
|
||||
@@ -92,7 +93,8 @@
|
||||
{
|
||||
"@type": "Person",
|
||||
"givenName": "Christian",
|
||||
"familyName": "Tacke"
|
||||
"familyName": "Tacke",
|
||||
"@id": "https://orcid.org/0000-0002-5321-8404"
|
||||
},
|
||||
{
|
||||
"@type": "Person",
|
||||
|
@@ -16,11 +16,11 @@ Here is an overview of the device/channel options and when they are applied:
|
||||
|
||||
| Property | Applied in |
|
||||
| --- | --- |
|
||||
| `severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
|
||||
| `file-severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
|
||||
| `verbosity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
|
||||
| `color` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
|
||||
| `log-to-file` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
|
||||
| `severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
|
||||
| `file-severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
|
||||
| `verbosity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
|
||||
| `color` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
|
||||
| `log-to-file` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
|
||||
| `id` | at the end of `fair::mq::State::InitializingDevice` |
|
||||
| `io-threads` | at the end of `fair::mq::State::InitializingDevice` |
|
||||
| `transport` | at the end of `fair::mq::State::InitializingDevice` |
|
||||
|
@@ -6,7 +6,7 @@
|
||||
|
||||
For unit testing it is often not feasible to boot up a full-blown distributed system with dozens of processes.
|
||||
|
||||
In some scenarios it is useful to not even instantiate a `fair::mq::Device` at all. Please see [this example](../test/protocols/_push_pull_multipart.cxx) for single and multi threaded unit test without a device instance. If you store your transport factories and channels on the heap, pls make sure, you destroy the channels before you destroy the related transport factory for proper shutdown. Channels provide all the `Send/Receive` and `New*Message/New*Poller` APIs provided by the device too.
|
||||
In some scenarios it is useful to not even instantiate a `FairMQDevice` at all. Please see [this example](../test/protocols/_push_pull_multipart.cxx) for single and multi threaded unit test without a device instance. If you store your transport factories and channels on the heap, pls make sure, you destroy the channels before you destroy the related transport factory for proper shutdown. Channels provide all the `Send/Receive` and `New*Message/New*Poller` APIs provided by the device too.
|
||||
|
||||
## 4.2 Static Analysis
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# 1. Device
|
||||
|
||||
The components encapsulating the tasks are called **devices** and derive from the common base class `fair::mq::Device`. FairMQ provides ready to use devices to organize the dataflow between the components (without touching the contents of a message), providing functionality like merging and splitting of the data stream (see subdirectory `devices`).
|
||||
The components encapsulating the tasks are called **devices** and derive from the common base class `FairMQDevice`. FairMQ provides ready to use devices to organize the dataflow between the components (without touching the contents of a message), providing functionality like merging and splitting of the data stream (see subdirectory `devices`).
|
||||
|
||||
## 1.1 Topology
|
||||
|
||||
|
@@ -35,7 +35,7 @@ Plugin Manager:
|
||||
see man ld.so(8) for details.
|
||||
-P [ --plugin ] arg List of plugin names to load in
|
||||
order,e.g. if the file is called
|
||||
'libfairmq-plugin-example.so', just list
|
||||
'libFairMQPlugin_example.so', just list
|
||||
'example' or 'd:example' here.To load a
|
||||
prelinked plugin, list 'p:example'
|
||||
here.
|
||||
@@ -54,7 +54,37 @@ A more complete example which may serve as a start including example CMake code
|
||||
|
||||
## 7.3 Provided Plugins
|
||||
|
||||
### 7.3.1 PMIx
|
||||
### 7.3.1 DDS
|
||||
|
||||
When launching a FairMQ topology via [DDS](http://dds.gsi.de/) the DDS plugin enables FairMQ devices to interact with DDS' custom command and property subsystems - enable the plugin by passing `-P dds` on the command line.
|
||||
|
||||
Via the property subsystem a FairMQ topology may exchange channel connection data (essentially to do service discovery) needed to connect/bind all FairMQ channels appropriately. DDS is highly optimized for this use case. See [examples/dds](examples/dds/README.md) for more details.
|
||||
|
||||
Via the custom command subsystem a FairMQ device can receive a number of commands. FairMQ provides a convenient command line tool `fairmq-dds-command-ui` that allows interactive or scripted control of a running FairMQ topology managed via DDS. If one develops directly against the custom command DDS API, the following table lists all the commands the DDS plugin currently understands:
|
||||
|
||||
| Custom Command | Response | Error | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `check-state` | `<ID>: <STATE> (pid: <PID>)` | n/a | Query current device state, see state machine for possible states |
|
||||
| `dump-config` | `(<ID>: <PKEY> -> <PVALUE>\n)+` | n/a | Query current device config (list property key/value pairs) |
|
||||
| `INIT DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `BIND` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `CONNECT` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `INIT TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RUN` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `STOP` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RESET TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RESET DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `END` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `subscribe-to-heartbeats` | `heartbeat-subscription: <ID>,OK` | n/a | Subscribe to heartbeats |
|
||||
| on heartbeat subscription | `heartbeat: <ID>,<PID>` | n/a | Heartbeat every 100ms |
|
||||
| `unsubscribe-from-heartbeats` | `heartbeat-unsubscription: <ID>,OK` | n/a | Unsubscribe from heartbeats |
|
||||
| `subscribe-to-state-changes` | `state-changes-subscription: <ID>,OK` | n/a | Subscribe to state changes |
|
||||
| on state changes subscription | `state-change: <ID>,<STATE>` | n/a | State change notification |
|
||||
| `unsubscribe-from-state-changes` | `state-changes-unsubscription: <ID>,OK` | n/a | Unsubscribe from state changes |
|
||||
|
||||
If unknown commands are received the plugin will print a warning.
|
||||
|
||||
### 7.3.2 PMIx
|
||||
|
||||
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
|
||||
|
||||
|
34
docs/SDK.md
Normal file
34
docs/SDK.md
Normal file
@@ -0,0 +1,34 @@
|
||||
← [Back](../README.md)
|
||||
|
||||
# 8. Controller SDK
|
||||
|
||||
The FairMQ Controller Software Development Kit (`-DBUILD_SDK=ON`) contains a (as of today still experimental) set of C++ APIs that provide essential functionality to the implementer of a global controller.
|
||||
|
||||
The FairMQ core library only provides two local controllers - `static` (a fixed sequence of state transitions) and `interactive` (a read-eval-print-loop which reads keyboard commands from standard input). A local controller only knows how steer a single [FairMQ device](Device.md) - in fact, it runs in a thread within the device process.
|
||||
|
||||
A global controller has knowledge about the full topology of connected FairMQ devices. Its responsibility is to facilitate the lifecycle of a distributed FairMQ-based application (*executing a topology*), such as
|
||||
|
||||
* allocating/releasing compute resources from a resource management system,
|
||||
* launching/setting up the run-time environment and the FairMQ devices,
|
||||
* driving the device state machines in lock-step across the full topology,
|
||||
* pushing the device configuration,
|
||||
* monitoring (some aspects of the application's) operation,
|
||||
* and handling/reporting (some) error cases.
|
||||
|
||||
The low-level hook to integrate FairMQ devices with such a global contoller is the [plugin mechanism](Plugins.md) in the FairMQ core library. The FairMQ Controller SDK provides C++ APIs that communicate to the endpoints exposed by such a FairMQ plugin.
|
||||
|
||||
At the moment, the Controller SDK only supports [DDS](https://dds.gsi.de) as resource manager and run-time environment. A second implementation based on [PMIx](https://pmix.org/) (targeting its implementation in [Slurm](https://slurm.schedmd.com/documentation.html) and [OpenRTE](https://www-lb.open-mpi.org/papers/euro-pvmmpi-2005-orte/)) is in development.
|
||||
|
||||
The following section give a short overview on the APIs provided.
|
||||
|
||||
## RMS and run-time environment
|
||||
|
||||
The classes [`fair::mq::sdk::DDSEnvironment`](../fairmq/sdk/DDSEnvironment.h), [`fair::mq::sdk::DDSSession`](../fairmq/sdk/DDSSession.h), and [`fair::mq::sdk::DDSTopology`](../fairmq/sdk/DDSTopology.h) are thin wrappers of most of the synchronous APIs exposed by DDS ([`dds::tools_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1tools__api.html) and [`dds::topology_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1topology__api.html)). E.g. they allow to [start a DDS session](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L26-L28), [allocate resources](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L34) and [launch a topology](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L39) from a C++ program.
|
||||
|
||||
## Driving the global state machine
|
||||
|
||||
The class [`fair::mq::sdk::Topology`](../fairmq/sdk/Topology.h) adds a FairMQ-specific view on an existing DDS session that is executing a topology of FairMQ devices. One can e.g. [initiate a state transition on all devices in the topology simultaneously](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L48-L49). This topology transition completes once a topology-wide barrier is passed (all devices completed the transition). This effectively exposes the device state machine as a topology state machine. The implementation is based on remote procedure calls over the [DDS intercom service](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1intercom__api.html) between the controller and the DDS plugin shipped with FairMQ (`-DBUILD_DDS_PLUGIN=ON`).
|
||||
|
||||
For future versions of the SDK new APIs are planned to inspect and modify the device configurations and also operate only on subsets of a given topology.
|
||||
|
||||
← [Back](../README.md)
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2020-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -93,7 +93,7 @@ struct Receiver : fair::mq::Device
|
||||
unordered_map<uint16_t, TFBuffer> fBuffer;
|
||||
unordered_set<uint16_t> fDiscardedSet;
|
||||
|
||||
unsigned int fNumSenders = 0;
|
||||
int fNumSenders = 0;
|
||||
int fBufferTimeoutInMs = 5000;
|
||||
int fMaxTimeframes = 0;
|
||||
int fTimeframeCounter = 0;
|
||||
|
@@ -19,6 +19,10 @@ SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --rate 10"
|
||||
SAMPLER+=" --transport $transport"
|
||||
# SAMPLER+=" --external-region true"
|
||||
# SAMPLER+=" --shm-no-cleaup true"
|
||||
# SAMPLER+=" --shm-monitor false"
|
||||
# SAMPLER+=" --shmid 1"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777,sndKernelSize=212992"
|
||||
xterm -geometry 120x60+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
@@ -26,5 +30,8 @@ SINK="fairmq-ex-region-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --transport $transport"
|
||||
# SINK+=" --shm-no-cleaup true"
|
||||
# SINK+=" --shm-monitor false"
|
||||
# SINK+=" --shmid 1"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777,rcvKernelSize=212992"
|
||||
xterm -geometry 120x60+750+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -6,10 +6,9 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
#include <fairmq/shmem/Common.h>
|
||||
#include <fairmq/shmem/UnmanagedRegion.h>
|
||||
#include <fairmq/shmem/Segment.h>
|
||||
#include <fairmq/shmem/Monitor.h>
|
||||
|
||||
#include <fairmq/shmem/Segment.h>
|
||||
#include <fairmq/shmem/UnmanagedRegion.h>
|
||||
#include <fairmq/tools/Unique.h>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
@@ -17,9 +16,8 @@
|
||||
#include <boost/algorithm/string.hpp>
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -27,65 +25,117 @@
|
||||
using namespace std;
|
||||
using namespace boost::program_options;
|
||||
|
||||
namespace
|
||||
{
|
||||
volatile sig_atomic_t gStopping = 0;
|
||||
}
|
||||
namespace {
|
||||
volatile sig_atomic_t gStopping = 0;
|
||||
volatile sig_atomic_t gResetContent = 0;
|
||||
} // namespace
|
||||
|
||||
void signalHandler(int /* signal */)
|
||||
{
|
||||
gStopping = 1;
|
||||
}
|
||||
void signalHandler(int /* signal */) { gStopping = 1; }
|
||||
|
||||
void resetContentHandler(int /* signal */) { gResetContent = 1; }
|
||||
|
||||
struct ShmManager
|
||||
{
|
||||
ShmManager(uint64_t _shmId, const vector<string>& _segments, const vector<string>& _regions)
|
||||
ShmManager(uint64_t _shmId, const vector<string>& _segments, const vector<string>& _regions, bool zero = true)
|
||||
: shmId(fair::mq::shmem::makeShmIdStr(_shmId))
|
||||
{
|
||||
LOG(info) << "Starting ShmManager for shmId: " << shmId;
|
||||
LOG(info) << "Performing full reset...";
|
||||
FullReset();
|
||||
LOG(info) << "Done.";
|
||||
LOG(info) << "Adding managed segments...";
|
||||
AddSegments(_segments, zero);
|
||||
LOG(info) << "Done.";
|
||||
LOG(info) << "Adding unmanaged regions...";
|
||||
AddRegions(_regions, zero);
|
||||
LOG(info) << "Done.";
|
||||
LOG(info) << "Shared memory is ready for use.";
|
||||
}
|
||||
|
||||
void AddSegments(const vector<string>& _segments, bool zero)
|
||||
{
|
||||
for (const auto& s : _segments) {
|
||||
vector<string> segmentConf;
|
||||
boost::algorithm::split(segmentConf, s, boost::algorithm::is_any_of(","));
|
||||
if (segmentConf.size() != 2) {
|
||||
LOG(error) << "incorrect format for --segments. Expecting pairs of <id>,<size>.";
|
||||
vector<string> conf;
|
||||
boost::algorithm::split(conf, s, boost::algorithm::is_any_of(","));
|
||||
if (conf.size() != 3) {
|
||||
LOG(error) << "incorrect format for --segments. Expecting pairs of <id>,<size><numaid>.";
|
||||
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
|
||||
throw runtime_error("incorrect format for --segments. Expecting pairs of <id>,<size>.");
|
||||
throw runtime_error("incorrect format for --segments. Expecting pairs of <id>,<size>,<numaid>.");
|
||||
}
|
||||
uint16_t id = stoi(segmentConf.at(0));
|
||||
uint64_t size = stoull(segmentConf.at(1));
|
||||
uint16_t id = stoi(conf.at(0));
|
||||
uint64_t size = stoull(conf.at(1));
|
||||
segmentCfgs.emplace_back(fair::mq::shmem::SegmentConfig{id, size, "rbtree_best_fit"});
|
||||
|
||||
auto ret = segments.emplace(id, fair::mq::shmem::Segment(shmId, id, size, fair::mq::shmem::rbTreeBestFit));
|
||||
fair::mq::shmem::Segment& segment = ret.first->second;
|
||||
LOG(info) << "Created segment " << id << " of size " << segment.GetSize() << ", starting at " << segment.GetData() << ". Locking...";
|
||||
LOG(info) << "Created segment " << id << " of size " << segment.GetSize()
|
||||
<< ", starting at " << segment.GetData() << ". Locking...";
|
||||
segment.Lock();
|
||||
LOG(info) << "Done.";
|
||||
LOG(info) << "Zeroing...";
|
||||
segment.Zero();
|
||||
LOG(info) << "Done.";
|
||||
}
|
||||
|
||||
for (const auto& r : _regions) {
|
||||
vector<string> regionConf;
|
||||
boost::algorithm::split(regionConf, r, boost::algorithm::is_any_of(","));
|
||||
if (regionConf.size() != 2) {
|
||||
LOG(error) << "incorrect format for --regions. Expecting pairs of <id>,<size>.";
|
||||
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
|
||||
throw runtime_error("incorrect format for --regions. Expecting pairs of <id>,<size>.");
|
||||
if (zero) {
|
||||
LOG(info) << "Zeroing...";
|
||||
segment.Zero();
|
||||
LOG(info) << "Done.";
|
||||
}
|
||||
uint16_t id = stoi(regionConf.at(0));
|
||||
uint64_t size = stoull(regionConf.at(1));
|
||||
}
|
||||
}
|
||||
|
||||
void AddRegions(const vector<string>& _regions, bool zero)
|
||||
{
|
||||
for (const auto& r : _regions) {
|
||||
vector<string> conf;
|
||||
boost::algorithm::split(conf, r, boost::algorithm::is_any_of(","));
|
||||
if (conf.size() != 3) {
|
||||
LOG(error) << "incorrect format for --regions. Expecting pairs of <id>,<size>,<numaid>.";
|
||||
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
|
||||
throw runtime_error("incorrect format for --regions. Expecting pairs of <id>,<size>,<numaid>.");
|
||||
}
|
||||
uint16_t id = stoi(conf.at(0));
|
||||
uint64_t size = stoull(conf.at(1));
|
||||
fair::mq::RegionConfig cfg;
|
||||
cfg.id = id;
|
||||
cfg.size = size;
|
||||
regionCfgs.push_back(cfg);
|
||||
|
||||
auto ret = regions.emplace(id, make_unique<fair::mq::shmem::UnmanagedRegion>(shmId, id, size));
|
||||
fair::mq::shmem::UnmanagedRegion& region = *(ret.first->second);
|
||||
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize() << ", starting at " << region.GetData() << ". Locking...";
|
||||
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize()
|
||||
<< ", starting at " << region.GetData() << ". Locking...";
|
||||
region.Lock();
|
||||
LOG(info) << "Done.";
|
||||
LOG(info) << "Zeroing...";
|
||||
region.Zero();
|
||||
LOG(info) << "Done.";
|
||||
if (zero) {
|
||||
LOG(info) << "Zeroing...";
|
||||
region.Zero();
|
||||
LOG(info) << "Done.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CheckPresence()
|
||||
{
|
||||
for (const auto& sc : segmentCfgs) {
|
||||
if (!(fair::mq::shmem::Monitor::SegmentIsPresent(fair::mq::shmem::ShmId{shmId}, sc.id))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (const auto& rc : regionCfgs) {
|
||||
if (!(fair::mq::shmem::Monitor::RegionIsPresent(fair::mq::shmem::ShmId{shmId}, rc.id.value()))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ResetContent()
|
||||
{
|
||||
fair::mq::shmem::Monitor::ResetContent(fair::mq::shmem::ShmId{shmId});
|
||||
fair::mq::shmem::Monitor::ResetContent(fair::mq::shmem::ShmId{shmId}, segmentCfgs, regionCfgs);
|
||||
}
|
||||
|
||||
void FullReset()
|
||||
{
|
||||
segments.clear();
|
||||
regions.clear();
|
||||
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
|
||||
}
|
||||
|
||||
~ShmManager()
|
||||
@@ -97,6 +147,8 @@ struct ShmManager
|
||||
std::string shmId;
|
||||
map<uint16_t, fair::mq::shmem::Segment> segments;
|
||||
map<uint16_t, unique_ptr<fair::mq::shmem::UnmanagedRegion>> regions;
|
||||
std::vector<fair::mq::shmem::SegmentConfig> segmentCfgs;
|
||||
std::vector<fair::mq::RegionConfig> regionCfgs;
|
||||
};
|
||||
|
||||
int main(int argc, char** argv)
|
||||
@@ -105,8 +157,11 @@ int main(int argc, char** argv)
|
||||
|
||||
signal(SIGINT, signalHandler);
|
||||
signal(SIGTERM, signalHandler);
|
||||
signal(SIGUSR1, resetContentHandler);
|
||||
|
||||
try {
|
||||
bool nozero = false;
|
||||
bool checkPresence = true;
|
||||
uint64_t shmId = 0;
|
||||
vector<string> segments;
|
||||
vector<string> regions;
|
||||
@@ -114,8 +169,10 @@ int main(int argc, char** argv)
|
||||
options_description desc("Options");
|
||||
desc.add_options()
|
||||
("shmid", value<uint64_t>(&shmId)->required(), "Shm id")
|
||||
("segments", value<vector<string>>(&segments)->multitoken()->composing(), "Segments, as <id>,<size> <id>,<size> <id>,<size> ...")
|
||||
("regions", value<vector<string>>(®ions)->multitoken()->composing(), "Regions, as <id>,<size> <id>,<size> <id>,<size> ...")
|
||||
("segments", value<vector<string>>(&segments)->multitoken()->composing(), "Segments, as <id>,<size>,<numaid> <id>,<size>,<numaid> <id>,<size>,<numaid> ... (numaid: -2 disabled, -1 interleave, >=0 node)")
|
||||
("regions", value<vector<string>>(®ions)->multitoken()->composing(), "Regions, as <id>,<size> <id>,<size>,<numaid> <id>,<size>,<numaid> ...")
|
||||
("nozero", value<bool>(&nozero)->default_value(false)->implicit_value(true), "Do not zero segments after initialization")
|
||||
("check-presence", value<bool>(&checkPresence)->default_value(true)->implicit_value(true), "Check periodically if configured segments/regions are still present, and cleanup and leave if they are not")
|
||||
("help,h", "Print help");
|
||||
|
||||
variables_map vm;
|
||||
@@ -128,15 +185,35 @@ int main(int argc, char** argv)
|
||||
|
||||
notify(vm);
|
||||
|
||||
ShmManager shmManager(shmId, segments, regions);
|
||||
ShmManager shmManager(shmId, segments, regions, !nozero);
|
||||
|
||||
while (!gStopping) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
std::thread resetContentThread([&shmManager]() {
|
||||
while (!gStopping) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
if (gResetContent == 1) {
|
||||
LOG(info) << "Resetting content for shmId " << shmManager.shmId;
|
||||
shmManager.ResetContent();
|
||||
gResetContent = 0;
|
||||
LOG(info) << "Done resetting content for shmId " << shmManager.shmId;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (checkPresence) {
|
||||
while (!gStopping) {
|
||||
if (shmManager.CheckPresence() == false) {
|
||||
LOG(error) << "Failed to find segments, exiting.";
|
||||
gStopping = true;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
}
|
||||
}
|
||||
|
||||
resetContentThread.join();
|
||||
|
||||
LOG(info) << "stopping.";
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit";
|
||||
LOG(error) << "Exception reached the top of main: " << e.what() << ", exiting";
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
@@ -19,6 +19,7 @@ struct Sampler : fair::mq::Device
|
||||
{
|
||||
void InitTask() override
|
||||
{
|
||||
fExternalRegion = fConfig->GetProperty<bool>("external-region");
|
||||
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
||||
fLinger = fConfig->GetProperty<uint32_t>("region-linger");
|
||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||
@@ -34,18 +35,26 @@ struct Sampler : fair::mq::Device
|
||||
|
||||
fair::mq::RegionConfig regionCfg;
|
||||
regionCfg.linger = fLinger; // delay in ms before region destruction to collect outstanding events
|
||||
regionCfg.lock = true; // mlock region after creation
|
||||
regionCfg.zero = true; // zero region content after creation
|
||||
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor("data", // region is created using the transport of this channel...
|
||||
0, // ... and this sub-channel
|
||||
10000000, // region size
|
||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||
std::lock_guard<std::mutex> lock(fMtx);
|
||||
fNumUnackedMsgs -= blocks.size();
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(info) << "Received " << blocks.size() << " acks";
|
||||
}
|
||||
}, regionCfg));
|
||||
// options for testing with an externally-created -region
|
||||
if (fExternalRegion) {
|
||||
regionCfg.id = 1;
|
||||
regionCfg.removeOnDestruction = false;
|
||||
}
|
||||
regionCfg.lock = !fExternalRegion; // mlock region after creation
|
||||
regionCfg.zero = !fExternalRegion; // zero region content after creation
|
||||
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor(
|
||||
"data", // region is created using the transport of this channel...
|
||||
0, // ... and this sub-channel
|
||||
10000000, // region size
|
||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||
std::lock_guard<std::mutex> lock(fMtx);
|
||||
fNumUnackedMsgs -= blocks.size();
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(info) << "Received " << blocks.size() << " acks";
|
||||
}
|
||||
},
|
||||
regionCfg
|
||||
));
|
||||
}
|
||||
|
||||
bool ConditionalRun() override
|
||||
@@ -76,6 +85,8 @@ struct Sampler : fair::mq::Device
|
||||
|
||||
void ResetTask() override
|
||||
{
|
||||
// give some time for acks to be received
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(250));
|
||||
fRegion.reset();
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fMtx);
|
||||
@@ -89,6 +100,7 @@ struct Sampler : fair::mq::Device
|
||||
}
|
||||
|
||||
private:
|
||||
int fExternalRegion = false;
|
||||
int fMsgSize = 10000;
|
||||
uint32_t fLinger = 100;
|
||||
uint64_t fMaxIterations = 0;
|
||||
@@ -103,7 +115,8 @@ void addCustomOptions(bpo::options_description& options)
|
||||
options.add_options()
|
||||
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
|
||||
("region-linger", bpo::value<uint32_t>()->default_value(100), "Linger period for regions")
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)")
|
||||
("external-region", bpo::value<bool>()->default_value(false), "Use region created by another process");
|
||||
}
|
||||
|
||||
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /*config*/)
|
||||
|
2
extern/googletest
vendored
2
extern/googletest
vendored
Submodule extern/googletest updated: a1cc8c5519...f5e592d8ee
@@ -1,12 +1,12 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2012-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||
|
||||
if(BUILD_TIDY_TOOL)
|
||||
include(FairMQTidy)
|
||||
@@ -23,6 +23,135 @@ if(BUILD_FAIRMQ)
|
||||
DESTINATION ${PROJECT_INSTALL_INCDIR}
|
||||
)
|
||||
|
||||
#########
|
||||
# Tools #
|
||||
#########
|
||||
set(target Tools)
|
||||
|
||||
set(TOOLS_PUBLIC_HEADER_FILES
|
||||
tools/CppSTL.h
|
||||
tools/Exceptions.h
|
||||
tools/InstanceLimit.h
|
||||
tools/IO.h
|
||||
tools/Network.h
|
||||
tools/Process.h
|
||||
tools/RateLimit.h
|
||||
tools/Semaphore.h
|
||||
tools/Strings.h
|
||||
tools/Unique.h
|
||||
tools/Version.h
|
||||
Error.h
|
||||
Tools.h
|
||||
)
|
||||
|
||||
set(TOOLS_SOURCE_FILES
|
||||
Error.cxx
|
||||
tools/Network.cxx
|
||||
tools/Process.cxx
|
||||
tools/Semaphore.cxx
|
||||
tools/Unique.cxx
|
||||
)
|
||||
|
||||
add_library(${target}
|
||||
${TOOLS_SOURCE_FILES}
|
||||
${TOOLS_PUBLIC_HEADER_FILES}
|
||||
)
|
||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_link_libraries(${target}
|
||||
PRIVATE
|
||||
FairLogger::FairLogger
|
||||
Threads::Threads
|
||||
Boost::boost
|
||||
)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
OUTPUT_NAME FairMQ${target}
|
||||
)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${target})
|
||||
endif()
|
||||
install(
|
||||
TARGETS ${target}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
foreach(HEADER ${TOOLS_PUBLIC_HEADER_FILES})
|
||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
|
||||
install(FILES ${HEADER}
|
||||
DESTINATION ${_destination}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
#################
|
||||
# State Machine #
|
||||
#################
|
||||
set(target StateMachine)
|
||||
|
||||
set(FSM_PUBLIC_HEADER_FILES
|
||||
StateMachine.h
|
||||
States.h
|
||||
StateQueue.h
|
||||
)
|
||||
|
||||
set(FSM_SOURCE_FILES
|
||||
StateMachine.cxx
|
||||
States.cxx
|
||||
)
|
||||
|
||||
add_library(${target}
|
||||
${FSM_SOURCE_FILES}
|
||||
${FSM_PUBLIC_HEADER_FILES}
|
||||
)
|
||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
FairLogger::FairLogger
|
||||
|
||||
PRIVATE
|
||||
Boost::boost
|
||||
Tools
|
||||
)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
OUTPUT_NAME FairMQ${target}
|
||||
)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${target})
|
||||
endif()
|
||||
install(
|
||||
TARGETS ${target}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
foreach(HEADER ${FSM_PUBLIC_HEADER_FILES})
|
||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
|
||||
install(FILES ${HEADER}
|
||||
DESTINATION ${_destination}
|
||||
)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
##########################
|
||||
# libFairMQ header files #
|
||||
##########################
|
||||
@@ -30,7 +159,6 @@ if(BUILD_FAIRMQ)
|
||||
Channel.h
|
||||
Device.h
|
||||
DeviceRunner.h
|
||||
Error.h
|
||||
EventManager.h
|
||||
FairMQChannel.h
|
||||
FairMQDevice.h
|
||||
@@ -56,32 +184,17 @@ if(BUILD_FAIRMQ)
|
||||
Properties.h
|
||||
PropertyOutput.h
|
||||
Socket.h
|
||||
StateMachine.h
|
||||
States.h
|
||||
StateQueue.h
|
||||
SuboptParser.h
|
||||
Tools.h
|
||||
TransportFactory.h
|
||||
Transports.h
|
||||
UnmanagedRegion.h
|
||||
options/FairMQProgOptions.h
|
||||
runDevice.h
|
||||
runFairMQDevice.h
|
||||
shmem/Common.h
|
||||
shmem/Monitor.h
|
||||
shmem/Segment.h
|
||||
shmem/Common.h
|
||||
shmem/UnmanagedRegion.h
|
||||
tools/CppSTL.h
|
||||
tools/Exceptions.h
|
||||
tools/IO.h
|
||||
tools/InstanceLimit.h
|
||||
tools/Network.h
|
||||
tools/Process.h
|
||||
tools/RateLimit.h
|
||||
tools/Semaphore.h
|
||||
tools/Strings.h
|
||||
tools/Unique.h
|
||||
tools/Version.h
|
||||
shmem/Segment.h
|
||||
)
|
||||
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES
|
||||
@@ -126,7 +239,6 @@ if(BUILD_FAIRMQ)
|
||||
Channel.cxx
|
||||
Device.cxx
|
||||
DeviceRunner.cxx
|
||||
Error.cxx
|
||||
JSONParser.cxx
|
||||
MemoryResources.cxx
|
||||
Plugin.cxx
|
||||
@@ -134,8 +246,6 @@ if(BUILD_FAIRMQ)
|
||||
PluginServices.cxx
|
||||
ProgOptions.cxx
|
||||
Properties.cxx
|
||||
StateMachine.cxx
|
||||
States.cxx
|
||||
SuboptParser.cxx
|
||||
TransportFactory.cxx
|
||||
plugins/config/Config.cxx
|
||||
@@ -143,10 +253,6 @@ if(BUILD_FAIRMQ)
|
||||
shmem/Common.cxx
|
||||
shmem/Manager.cxx
|
||||
shmem/Monitor.cxx
|
||||
tools/Network.cxx
|
||||
tools/Process.cxx
|
||||
tools/Semaphore.cxx
|
||||
tools/Unique.cxx
|
||||
)
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
@@ -225,6 +331,8 @@ if(BUILD_FAIRMQ)
|
||||
Boost::filesystem
|
||||
Boost::regex
|
||||
FairLogger::FairLogger
|
||||
Tools
|
||||
StateMachine
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
@@ -233,7 +341,7 @@ if(BUILD_FAIRMQ)
|
||||
)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
OUTPUT_NAME ${PROJECT_NAME_LOWER}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${target})
|
||||
@@ -306,7 +414,7 @@ if(BUILD_FAIRMQ)
|
||||
add_executable(fairmq-uuid-gen tools/runUuidGenerator.cxx)
|
||||
target_link_libraries(fairmq-uuid-gen PUBLIC
|
||||
Boost::program_options
|
||||
FairMQ
|
||||
Tools
|
||||
)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET fairmq-uuid-gen)
|
||||
@@ -344,9 +452,20 @@ if(BUILD_FAIRMQ)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
add_subdirectory(sdk/commands)
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK)
|
||||
add_subdirectory(sdk)
|
||||
endif()
|
||||
|
||||
####################
|
||||
# external plugins #
|
||||
####################
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
add_subdirectory(plugins/DDS)
|
||||
endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
add_subdirectory(plugins/PMIx)
|
||||
endif()
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -475,6 +475,7 @@ class Channel
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
|
||||
// using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
|
||||
using FairMQChannel = fair::mq::Channel;
|
||||
|
||||
#endif // FAIR_MQ_CHANNEL_H
|
||||
|
@@ -635,9 +635,15 @@ class Device
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
|
||||
using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] = fair::mq::InputMsgCallback;
|
||||
using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] = fair::mq::InputMultipartCallback;
|
||||
using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
|
||||
// using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
|
||||
// using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] =
|
||||
// fair::mq::InputMsgCallback;
|
||||
// using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] =
|
||||
// fair::mq::InputMultipartCallback;
|
||||
// using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
|
||||
using FairMQChannelMap = fair::mq::ChannelMap;
|
||||
using InputMsgCallback = fair::mq::InputMsgCallback;
|
||||
using InputMultipartCallback = fair::mq::InputMultipartCallback;
|
||||
using FairMQDevice = fair::mq::Device;
|
||||
|
||||
#endif /* FAIR_MQ_DEVICE_H */
|
||||
|
@@ -45,7 +45,7 @@ namespace fair::mq
|
||||
* Each hook has access to all members of the DeviceRunner and really only differs by the point in
|
||||
* time it is called.
|
||||
*
|
||||
* For an example usage of this class see the <fairmq/runDevice.h> header.
|
||||
* For an example usage of this class see the fairmq/runFairMQDevice.h header.
|
||||
*/
|
||||
class DeviceRunner
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQCHANNEL_H_
|
||||
#define FAIRMQCHANNEL_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_CHANNEL_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Channel.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Channel.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2012-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQDEVICE_H_
|
||||
#define FAIRMQDEVICE_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_DEVICE_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Device.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Device.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,8 +9,6 @@
|
||||
#ifndef FAIRMQLOGGER_H_
|
||||
#define FAIRMQLOGGER_H_
|
||||
|
||||
#pragma GCC warning "Deprecated header: Use <fairlogger/Logger.h> instead"
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
|
||||
#endif /* FAIRMQLOGGER_H_ */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQMESSAGE_H_
|
||||
#define FAIRMQMESSAGE_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_MESSAGE_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Message.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Message.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQPARTS_H_
|
||||
#define FAIRMQPARTS_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_PARTS_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Parts.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Parts.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQPOLLER_H_
|
||||
#define FAIRMQPOLLER_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_POLLER_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Poller.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Poller.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQSOCKET_H_
|
||||
#define FAIRMQSOCKET_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_SOCKET_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/Socket.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/Socket.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQTRANSPORTFACTORY_H_
|
||||
#define FAIRMQTRANSPORTFACTORY_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_TRANSPORTFACTORY_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/TransportFactory.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/TransportFactory.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,9 +9,11 @@
|
||||
#ifndef FAIRMQUNMANAGEDREGION_H_
|
||||
#define FAIRMQUNMANAGEDREGION_H_
|
||||
|
||||
#if 0
|
||||
#ifndef FAIR_MQ_UNMANAGEDREGION_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/UnmanagedRegion.h> instead"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <fairmq/UnmanagedRegion.h>
|
||||
|
||||
|
@@ -1,10 +1,10 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Memory allocators and interfaces related to managing memory via the
|
||||
@@ -12,7 +12,7 @@
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#include <fairmq/TransportFactory.h>
|
||||
#include <fairmq/FairMQTransportFactory.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
|
||||
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t alignment)
|
||||
|
@@ -1,6 +1,6 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -103,7 +103,9 @@ class ChannelResource : public MemoryResource
|
||||
};
|
||||
};
|
||||
|
||||
using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] = MemoryResource;
|
||||
// using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] =
|
||||
// MemoryResource;
|
||||
using FairMQMemoryResource = MemoryResource;
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -78,8 +78,11 @@ struct MessageBadAlloc : std::runtime_error
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
|
||||
using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
|
||||
using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
|
||||
// using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
|
||||
// using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
|
||||
// using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
|
||||
using fairmq_free_fn = fair::mq::FreeFn;
|
||||
using FairMQMessage = fair::mq::Message;
|
||||
using FairMQMessagePtr = fair::mq::MessagePtr;
|
||||
|
||||
#endif // FAIR_MQ_MESSAGE_H
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,80 +9,84 @@
|
||||
#ifndef FAIR_MQ_PARTS_H
|
||||
#define FAIR_MQ_PARTS_H
|
||||
|
||||
#include <algorithm> // std::move
|
||||
#include <fairmq/Message.h> // fair::mq::MessagePtr
|
||||
#include <iterator> // std::back_inserter
|
||||
#include <utility> // std::move, std::forward
|
||||
#include <vector> // std::vector
|
||||
#include <fairmq/Message.h>
|
||||
#include <memory> // unique_ptr
|
||||
#include <vector>
|
||||
|
||||
namespace fair::mq {
|
||||
|
||||
/// fair::mq::Parts is a lightweight move-only convenience wrapper around a vector of unique pointers to
|
||||
/// fair::mq::Parts is a lightweight convenience wrapper around a vector of unique pointers to
|
||||
/// Message, used for sending multi-part messages
|
||||
struct Parts
|
||||
class Parts
|
||||
{
|
||||
private:
|
||||
using container = std::vector<MessagePtr>;
|
||||
using size_type = container::size_type;
|
||||
using reference = container::reference;
|
||||
using const_reference = container::const_reference;
|
||||
using iterator = container::iterator;
|
||||
using const_iterator = container::const_iterator;
|
||||
|
||||
Parts() noexcept(noexcept(container())) = default;
|
||||
public:
|
||||
Parts() = default;
|
||||
Parts(const Parts&) = delete;
|
||||
Parts& operator=(const Parts&) = delete;
|
||||
Parts(Parts&&) = default;
|
||||
template<typename... Ts>
|
||||
Parts(Ts&&... messages) { AddPart(std::forward<Ts>(messages)...); }
|
||||
Parts& operator=(const Parts&) = delete;
|
||||
Parts& operator=(Parts&&) = default;
|
||||
~Parts() = default;
|
||||
|
||||
template<typename... Ps>
|
||||
Parts(Ps&&... parts)
|
||||
{
|
||||
AddPart(std::forward<Ps>(parts)...);
|
||||
}
|
||||
/// Adds part (Message) to the container
|
||||
/// @param msg message pointer (for example created with NewMessage() method of Device)
|
||||
void AddPart(Message* msg) { fParts.push_back(MessagePtr(msg)); }
|
||||
|
||||
void AddPart(MessagePtr msg) { fParts.push_back(std::move(msg)); }
|
||||
/// Adds part to the container (move)
|
||||
/// @param msg unique pointer to Message
|
||||
/// rvalue ref (move required when passing argument)
|
||||
void AddPart(MessagePtr&& msg) { fParts.push_back(std::move(msg)); }
|
||||
|
||||
/// Add variable list of parts to the container (move)
|
||||
template<typename... Ts>
|
||||
void AddPart(MessagePtr first, Ts&&... remaining)
|
||||
void AddPart(MessagePtr&& first, Ts&&... remaining)
|
||||
{
|
||||
AddPart(std::move(first));
|
||||
AddPart(std::forward<Ts>(remaining)...);
|
||||
}
|
||||
|
||||
void AddPart(Parts parts)
|
||||
/// Add content of another object by move
|
||||
void AddPart(Parts&& other)
|
||||
{
|
||||
if (fParts.empty()) {
|
||||
fParts = std::move(parts.fParts);
|
||||
} else {
|
||||
fParts.reserve(parts.Size() + fParts.size());
|
||||
std::move(std::begin(parts), std::end(parts), std::back_inserter(fParts));
|
||||
container parts = std::move(other.fParts);
|
||||
for (auto& part : parts) {
|
||||
fParts.push_back(std::move(part));
|
||||
}
|
||||
}
|
||||
|
||||
reference operator[](size_type index) { return fParts[index]; }
|
||||
const_reference operator[](size_type index) const { return fParts[index]; }
|
||||
/// Get reference to part in the container at index (without bounds check)
|
||||
/// @param index container index
|
||||
Message& operator[](const int index) { return *(fParts[index]); }
|
||||
|
||||
reference At(size_type index) { return fParts.at(index); }
|
||||
const_reference At(size_type index) const { return fParts.at(index); }
|
||||
/// Get reference to unique pointer to part in the container at index (with bounds check)
|
||||
/// @param index container index
|
||||
MessagePtr& At(const int index) { return fParts.at(index); }
|
||||
|
||||
size_type Size() const noexcept { return fParts.size(); }
|
||||
bool Empty() const noexcept { return fParts.empty(); }
|
||||
void Clear() noexcept { fParts.clear(); }
|
||||
// ref version
|
||||
Message& AtRef(const int index) { return *(fParts.at(index)); }
|
||||
|
||||
// range access
|
||||
iterator begin() noexcept { return fParts.begin(); }
|
||||
const_iterator begin() const noexcept { return fParts.begin(); }
|
||||
const_iterator cbegin() const noexcept { return fParts.cbegin(); }
|
||||
iterator end() noexcept { return fParts.end(); }
|
||||
const_iterator end() const noexcept { return fParts.end(); }
|
||||
const_iterator cend() const noexcept { return fParts.cend(); }
|
||||
/// Get number of parts in the container
|
||||
/// @return number of parts in the container
|
||||
int Size() const { return fParts.size(); }
|
||||
|
||||
container fParts{};
|
||||
container fParts;
|
||||
|
||||
// forward container iterators
|
||||
using iterator = container::iterator;
|
||||
using const_iterator = container::const_iterator;
|
||||
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
|
||||
auto end() -> decltype(fParts.end()) { return fParts.end(); }
|
||||
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
|
||||
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
|
||||
};
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
|
||||
// using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
|
||||
using FairMQParts = fair::mq::Parts;
|
||||
|
||||
#endif /* FAIR_MQ_PARTS_H */
|
||||
|
@@ -1,17 +1,16 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/PluginManager.h>
|
||||
#include <fairmq/plugins/Builtin.h>
|
||||
#include <fairmq/PluginManager.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <boost/program_options.hpp>
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
@@ -19,23 +18,22 @@
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
using fair::mq::Plugin;
|
||||
using fair::mq::tools::ToString;
|
||||
using fair::mq::tools::ToStrVector;
|
||||
using fair::mq::Plugin;
|
||||
namespace fs = boost::filesystem;
|
||||
namespace po = boost::program_options;
|
||||
namespace dll = boost::dll;
|
||||
using boost::optional;
|
||||
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "fairmq-plugin-";
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefixAlt = "FairMQPlugin_";
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
|
||||
|
||||
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive =
|
||||
std::vector<boost::dll::shared_library>();
|
||||
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive = std::vector<boost::dll::shared_library>();
|
||||
|
||||
fair::mq::PluginManager::PluginManager()
|
||||
: fPluginServices()
|
||||
{}
|
||||
{
|
||||
}
|
||||
|
||||
fair::mq::PluginManager::PluginManager(const vector<string>& args)
|
||||
: fPluginServices()
|
||||
@@ -48,8 +46,7 @@ fair::mq::PluginManager::PluginManager(const vector<string>& args)
|
||||
po::store(parsed, vm);
|
||||
po::notify(vm);
|
||||
} catch (const po::error& e) {
|
||||
throw ProgramOptionsParseError{ToString(
|
||||
"Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
|
||||
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
|
||||
}
|
||||
|
||||
// Process plugin search paths
|
||||
@@ -58,38 +55,24 @@ fair::mq::PluginManager::PluginManager(const vector<string>& args)
|
||||
auto searchPaths = vector<fs::path>{};
|
||||
if (vm.count("plugin-search-path")) {
|
||||
for (const auto& path : vm["plugin-search-path"].as<vector<string>>()) {
|
||||
if (path.substr(0, 1) == "<") {
|
||||
prepend.emplace_back(path.substr(1));
|
||||
} else if (path.substr(0, 1) == ">") {
|
||||
append.emplace_back(path.substr(1));
|
||||
} else {
|
||||
searchPaths.emplace_back(path);
|
||||
}
|
||||
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
|
||||
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
|
||||
else { searchPaths.emplace_back(path); }
|
||||
}
|
||||
}
|
||||
|
||||
// Set supplied options
|
||||
SetSearchPaths(searchPaths);
|
||||
for (const auto& path : prepend) {
|
||||
PrependSearchPath(path);
|
||||
}
|
||||
for (const auto& path : append) {
|
||||
AppendSearchPath(path);
|
||||
}
|
||||
if (vm.count("plugin")) {
|
||||
LoadPlugins(vm["plugin"].as<vector<string>>());
|
||||
}
|
||||
for(const auto& path : prepend) { PrependSearchPath(path); }
|
||||
for(const auto& path : append) { AppendSearchPath(path); }
|
||||
if (vm.count("plugin")) { LoadPlugins(vm["plugin"].as<vector<string>>()); }
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::ValidateSearchPath(const fs::path& path) -> void
|
||||
{
|
||||
if (path.empty()) {
|
||||
throw BadSearchPath{"Specified path is empty."};
|
||||
}
|
||||
if (path.empty()) throw BadSearchPath{"Specified path is empty."};
|
||||
// we ignore non-existing search paths
|
||||
if (fs::exists(path) && !fs::is_directory(path)) {
|
||||
throw BadSearchPath{ToString(path, " is not a directory.")};
|
||||
}
|
||||
if (fs::exists(path) && !fs::is_directory(path)) throw BadSearchPath{ToString(path, " is not a directory.")};
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::SetSearchPaths(const vector<fs::path>& searchPaths) -> void
|
||||
@@ -113,38 +96,31 @@ auto fair::mq::PluginManager::PrependSearchPath(const fs::path& path) -> void
|
||||
auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
|
||||
{
|
||||
auto plugin_options = po::options_description{"Plugin Manager"};
|
||||
plugin_options.add_options()("plugin-search-path,S",
|
||||
po::value<vector<string>>()->multitoken(),
|
||||
"List of plugin search paths.\n\n"
|
||||
"* Override default search path, e.g.\n"
|
||||
" -S /home/user/lib /lib\n"
|
||||
"* Append(>) or prepend(<) to default search path, e.g.\n"
|
||||
" -S >/lib </home/user/lib\n"
|
||||
"* If you mix the overriding and appending/prepending syntaxes, "
|
||||
"the overriding paths act as default search path, e.g.\n"
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in "
|
||||
"/home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
|
||||
"If nothing is found, the default dynamic library lookup is "
|
||||
"performed, see man ld.so(8) for details.")(
|
||||
"plugin,P",
|
||||
po::value<vector<string>>(),
|
||||
"List of plugin names to load in order,"
|
||||
"e.g. if the file is called 'libfairmq-plugin-example.so', just list 'example' or "
|
||||
"'d:example' here."
|
||||
"To load a prelinked plugin, list 'p:example' here.");
|
||||
plugin_options.add_options()
|
||||
("plugin-search-path,S", po::value<vector<string>>()->multitoken(), "List of plugin search paths.\n\n"
|
||||
"* Override default search path, e.g.\n"
|
||||
" -S /home/user/lib /lib\n"
|
||||
"* Append(>) or prepend(<) to default search path, e.g.\n"
|
||||
" -S >/lib </home/user/lib\n"
|
||||
"* If you mix the overriding and appending/prepending syntaxes, the overriding paths act as default search path, e.g.\n"
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
|
||||
"If nothing is found, the default dynamic library lookup is performed, see man ld.so(8) for details.")
|
||||
("plugin,P", po::value<vector<string>>(), "List of plugin names to load in order,"
|
||||
"e.g. if the file is called 'libFairMQPlugin_example.so', just list 'example' or 'd:example' here."
|
||||
"To load a prelinked plugin, list 'p:example' here.");
|
||||
|
||||
return plugin_options;
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
|
||||
{
|
||||
if (pluginName.substr(0, 2) == "p:") {
|
||||
if (pluginName.substr(0,2) == "p:") {
|
||||
// Mechanism A: prelinked dynamic
|
||||
LoadPluginPrelinkedDynamic(pluginName.substr(2));
|
||||
} else if (pluginName.substr(0, 2) == "d:") {
|
||||
} else if (pluginName.substr(0,2) == "d:") {
|
||||
// Mechanism B: dynamic
|
||||
LoadPluginDynamic(pluginName.substr(2));
|
||||
} else if (pluginName.substr(0, 2) == "s:") {
|
||||
} else if (pluginName.substr(0,2) == "s:") {
|
||||
// Mechanism C: static (builtin)
|
||||
LoadPluginStatic(pluginName.substr(2));
|
||||
} else {
|
||||
@@ -161,76 +137,52 @@ auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginNam
|
||||
LoadSymbols(pluginName, dll::program_location());
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading prelinked dynamic plugin ",
|
||||
pluginName,
|
||||
": ",
|
||||
e.what()));
|
||||
throw PluginLoadError(ToString("An error occurred while loading prelinked dynamic plugin ", pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::SearchPluginFile(const string& pluginName) const
|
||||
-> boost::filesystem::path
|
||||
{
|
||||
for (const auto& searchPath : SearchPaths()) {
|
||||
for (const auto& libPrefix : {fgkLibPrefix, fgkLibPrefixAlt}) {
|
||||
auto const file =
|
||||
searchPath
|
||||
/ ToString("lib",
|
||||
libPrefix,
|
||||
pluginName,
|
||||
boost::dll::detail::shared_library_impl::suffix().native());
|
||||
auto const found = boost::filesystem::exists(file);
|
||||
if (found) {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw PluginNotFound(ToString("Could not find plugin file for plugin ", pluginName));
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> void
|
||||
{
|
||||
if (fPluginFactories.find(pluginName) != fPluginFactories.end()) {
|
||||
return; // already loaded, nothing to do
|
||||
}
|
||||
// Search plugin and load, if found
|
||||
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
|
||||
auto success = false;
|
||||
for (const auto& searchPath : SearchPaths()) {
|
||||
try {
|
||||
LoadSymbols(pluginName, searchPath / ToString(LibPrefix(), pluginName),
|
||||
dll::load_mode::append_decorations | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
success = true;
|
||||
break;
|
||||
} catch (boost::system::system_error& e) {
|
||||
if (string{e.what()}.find("No such file or directory") == string::npos) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Search in configured search path
|
||||
try {
|
||||
LoadSymbols(pluginName, SearchPluginFile(pluginName), dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
return;
|
||||
} catch (PluginNotFound& e) {
|
||||
// ignore
|
||||
} catch (boost::system::system_error& e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// Search with system logic (including RPATH, LD_LIBRARY_PATH)
|
||||
for (const auto& libPrefix : {fgkLibPrefix, fgkLibPrefixAlt}) {
|
||||
try {
|
||||
// LoadSymbols(pluginName,
|
||||
// ToString(LibPrefix(), pluginName),
|
||||
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
|
||||
// Not sure, why the above does not work. Workaround for now:
|
||||
LoadSymbols(pluginName,
|
||||
ToString("lib",
|
||||
libPrefix,
|
||||
pluginName,
|
||||
boost::dll::detail::shared_library_impl::suffix().native()),
|
||||
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
return;
|
||||
} catch (boost::system::system_error& e) {
|
||||
// ignore
|
||||
if (!success) {
|
||||
try {
|
||||
// LoadSymbols(pluginName,
|
||||
// ToString(LibPrefix(), pluginName),
|
||||
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
|
||||
// Not sure, why the above does not work. Workaround for now:
|
||||
LoadSymbols(pluginName,
|
||||
ToString("lib",
|
||||
LibPrefix(),
|
||||
pluginName,
|
||||
boost::dll::detail::shared_library_impl::suffix().native()),
|
||||
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw PluginLoadError(ToString("Could not load dynamic plugin ",
|
||||
pluginName,
|
||||
" from configured search paths (-S) nor with ",
|
||||
"system lookup (system libdirs, RUNPATH, $LD_LIBRARY_PATH)."));
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
|
||||
@@ -240,25 +192,20 @@ auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
|
||||
try {
|
||||
if ("control" == pluginName) {
|
||||
try {
|
||||
fPluginProgOptions.insert(
|
||||
{pluginName, plugins::ControlPluginProgramOptions().value()});
|
||||
} catch (const boost::bad_optional_access&) {
|
||||
/* just ignore, if no prog options are declared */
|
||||
fPluginProgOptions.insert({pluginName, plugins::ControlPluginProgramOptions().value()});
|
||||
}
|
||||
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
|
||||
} else if ("config" == pluginName) {
|
||||
try {
|
||||
fPluginProgOptions.insert(
|
||||
{pluginName, plugins::ConfigPluginProgramOptions().value()});
|
||||
} catch (const boost::bad_optional_access&) {
|
||||
/* just ignore, if no prog options are declared */
|
||||
fPluginProgOptions.insert({pluginName, plugins::ConfigPluginProgramOptions().value()});
|
||||
}
|
||||
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
|
||||
} else {
|
||||
LoadSymbols(pluginName, dll::program_location());
|
||||
}
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(ToString(
|
||||
"An error occurred while loading static plugin ", pluginName, ": ", e.what()));
|
||||
throw PluginLoadError(ToString("An error occurred while loading static plugin ", pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -278,12 +225,11 @@ auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> voi
|
||||
|
||||
auto fair::mq::PluginManager::InstantiatePlugins() -> void
|
||||
{
|
||||
for (const auto& pluginName : fPluginOrder) {
|
||||
for(const auto& pluginName : fPluginOrder) {
|
||||
try {
|
||||
InstantiatePlugin(pluginName);
|
||||
} catch (std::exception& e) {
|
||||
throw PluginInstantiationError(ToString(
|
||||
"An error occurred while instantiating plugin ", pluginName, ": ", e.what()));
|
||||
throw PluginInstantiationError(ToString("An error occurred while instantiating plugin ", pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -66,8 +66,6 @@ class PluginManager
|
||||
auto SearchPaths() const -> const std::vector<boost::filesystem::path>& { return fSearchPaths; }
|
||||
struct BadSearchPath : std::invalid_argument { using std::invalid_argument::invalid_argument; };
|
||||
|
||||
auto SearchPluginFile(const std::string&) const -> boost::filesystem::path;
|
||||
struct PluginNotFound : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
auto LoadPlugin(const std::string& pluginName) -> void;
|
||||
auto LoadPlugins(const std::vector<std::string>& pluginNames) -> void { for(const auto& pluginName : pluginNames) { LoadPlugin(pluginName); } }
|
||||
struct PluginLoadError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
@@ -120,7 +118,6 @@ class PluginManager
|
||||
auto InstantiatePlugin(const std::string& pluginName) -> void;
|
||||
|
||||
static const std::string fgkLibPrefix;
|
||||
static const std::string fgkLibPrefixAlt;
|
||||
std::vector<boost::filesystem::path> fSearchPaths;
|
||||
static std::vector<boost::dll::shared_library> fgDLLKeepAlive; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -41,7 +41,9 @@ struct PollerError : std::runtime_error
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
|
||||
using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
|
||||
// using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
|
||||
// using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
|
||||
using FairMQPoller = fair::mq::Poller;
|
||||
using FairMQPollerPtr = fair::mq::PollerPtr;
|
||||
|
||||
#endif // FAIR_MQ_POLLER_H
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -12,7 +12,9 @@
|
||||
* Created on March 11, 2015, 10:20 PM
|
||||
*/
|
||||
|
||||
#include "FairMQLogger.h"
|
||||
#include <fairmq/ProgOptions.h>
|
||||
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/any.hpp>
|
||||
@@ -20,7 +22,6 @@
|
||||
|
||||
#include <algorithm>
|
||||
#include <exception>
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -13,6 +13,7 @@ namespace fair::mq {
|
||||
class ProgOptions;
|
||||
}
|
||||
|
||||
using FairMQProgOptions [[deprecated("Use fair::mq::ProgOptions")]] = fair::mq::ProgOptions;
|
||||
// using FairMQProgOptions [[deprecated("Use fair::mq::ProgOptions")]] = fair::mq::ProgOptions;
|
||||
using FairMQProgOptions = fair::mq::ProgOptions;
|
||||
|
||||
#endif /* FAIR_MQ_PROGOPTIONSFWD_H */
|
||||
|
26
fairmq/SDK.h
Normal file
26
fairmq/SDK.h
Normal file
@@ -0,0 +1,26 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_H
|
||||
#define FAIR_MQ_SDK_H
|
||||
|
||||
// IWYU pragma: begin_exports
|
||||
#include <fairmq/sdk/AsioAsyncOp.h>
|
||||
#include <fairmq/sdk/AsioBase.h>
|
||||
#include <fairmq/sdk/DDSAgent.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <fairmq/sdk/DDSSession.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <fairmq/sdk/DDSTopology.h>
|
||||
#include <fairmq/sdk/Error.h>
|
||||
#include <fairmq/sdk/Topology.h>
|
||||
#include <fairmq/sdk/Traits.h>
|
||||
// IWYU pragma: end_exports
|
||||
|
||||
#endif // FAIR_MQ_SDK_H
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -103,7 +103,9 @@ struct SocketError : std::runtime_error
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQSocket [[deprecated("Use fair::mq::Socket")]] = fair::mq::Socket;
|
||||
using FairMQSocketPtr [[deprecated("Use fair::mq::SocketPtr")]] = fair::mq::SocketPtr;
|
||||
// using FairMQSocket [[deprecated("Use fair::mq::Socket")]] = fair::mq::Socket;
|
||||
// using FairMQSocketPtr [[deprecated("Use fair::mq::SocketPtr")]] = fair::mq::SocketPtr;
|
||||
using FairMQSocket = fair::mq::Socket;
|
||||
using FairMQSocketPtr = fair::mq::SocketPtr;
|
||||
|
||||
#endif // FAIR_MQ_SOCKET_H
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -241,7 +241,11 @@ struct TransportFactoryError : std::runtime_error
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQTransportFactory [[deprecated("Use fair::mq::TransportFactory")]] = fair::mq::TransportFactory;
|
||||
using FairMQTransportFactoryError [[deprecated("Use fair::mq::TransportFactoryError")]] = fair::mq::TransportFactoryError;
|
||||
// using FairMQTransportFactory [[deprecated("Use fair::mq::TransportFactory")]] =
|
||||
// fair::mq::TransportFactory;
|
||||
// using FairMQTransportFactoryError [[deprecated("Use fair::mq::TransportFactoryError")]] =
|
||||
// fair::mq::TransportFactoryError;
|
||||
using FairMQTransportFactory = fair::mq::TransportFactory;
|
||||
using FairMQTransportFactoryError = fair::mq::TransportFactoryError;
|
||||
|
||||
#endif // FAIR_MQ_TRANSPORTFACTORY_H
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -141,14 +141,23 @@ struct RegionConfig
|
||||
|
||||
} // namespace fair::mq
|
||||
|
||||
using FairMQRegionEvent [[deprecated("Use fair::mq::RegionEvent")]] = fair::mq::RegionEvent;
|
||||
using FairMQRegionInfo [[deprecated("Use fair::mq::RegionInfo")]] = fair::mq::RegionInfo;
|
||||
using FairMQRegionBlock [[deprecated("Use fair::mq::RegionBlock")]] = fair::mq::RegionBlock;
|
||||
using FairMQRegionCallback [[deprecated("Use fair::mq::RegionCallback")]] = fair::mq::RegionCallback;
|
||||
using FairMQRegionBulkCallback [[deprecated("Use fair::mq::RegionBulkCallback")]] = fair::mq::RegionBulkCallback;
|
||||
using FairMQRegionEventCallback [[deprecated("Use fair::mq::RegionEventCallback")]] = fair::mq::RegionEventCallback;
|
||||
using FairMQUnmanagedRegion [[deprecated("Use fair::mq::UnmanagedRegion")]] = fair::mq::UnmanagedRegion;
|
||||
using FairMQUnmanagedRegionPtr [[deprecated("Use fair::mq::UnmanagedRegionPtr")]] = fair::mq::UnmanagedRegionPtr;
|
||||
using FairMQRegionConfig [[deprecated("Use fair::mq::RegionConfig")]] = fair::mq::RegionConfig;
|
||||
// using FairMQRegionEvent [[deprecated("Use fair::mq::RegionBlock")]] = fair::mq::RegionEvent;
|
||||
// using FairMQRegionInfo [[deprecated("Use fair::mq::RegionInfo")]] = fair::mq::RegionInfo;
|
||||
// using FairMQRegionBlock [[deprecated("Use fair::mq::RegionBlock")]] = fair::mq::RegionBlock;
|
||||
// using FairMQRegionCallback [[deprecated("Use fair::mq::RegionCallback")]] = fair::mq::RegionCallback;
|
||||
// using FairMQRegionBulkCallback [[deprecated("Use fair::mq::RegionBulkCallback")]] = fair::mq::RegionBulkCallback;
|
||||
// using FairMQRegionEventCallback [[deprecated("Use fair::mq::RegionEventCallback")]] = fair::mq::RegionEventCallback;
|
||||
// using FairMQUnmanagedRegion [[deprecated("Use fair::mq::UnmanagedRegion")]] = fair::mq::UnmanagedRegion;
|
||||
// using FairMQUnmanagedRegionPtr [[deprecated("Use fair::mq::UnmanagedRegionPtr")]] = fair::mq::UnmanagedRegionPtr;
|
||||
// using FairMQRegionConfig [[deprecated("Use fair::mq::RegionConfig")]] = fair::mq::RegionConfig;
|
||||
using FairMQRegionEvent = fair::mq::RegionEvent;
|
||||
using FairMQRegionInfo = fair::mq::RegionInfo;
|
||||
using FairMQRegionBlock = fair::mq::RegionBlock;
|
||||
using FairMQRegionCallback = fair::mq::RegionCallback;
|
||||
using FairMQRegionBulkCallback = fair::mq::RegionBulkCallback;
|
||||
using FairMQRegionEventCallback = fair::mq::RegionEventCallback;
|
||||
using FairMQUnmanagedRegion = fair::mq::UnmanagedRegion;
|
||||
using FairMQUnmanagedRegionPtr = fair::mq::UnmanagedRegionPtr;
|
||||
using FairMQRegionConfig = fair::mq::RegionConfig;
|
||||
|
||||
#endif // FAIR_MQ_UNMANAGEDREGION_H
|
||||
|
@@ -11,10 +11,12 @@
|
||||
#define FAIRMQ_VERSION "@PROJECT_VERSION@"
|
||||
#define FAIRMQ_VERSION_DEC (@PROJECT_VERSION_MAJOR@ * 100000) \
|
||||
+ (@PROJECT_VERSION_MINOR@ * 1000) \
|
||||
+ (@PROJECT_VERSION_PATCH@ * 10)
|
||||
+ (@PROJECT_VERSION_PATCH@ * 10) \
|
||||
+ @PROJECT_VERSION_HOTFIX@
|
||||
#define FAIRMQ_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
|
||||
#define FAIRMQ_VERSION_MINOR @PROJECT_VERSION_MINOR@
|
||||
#define FAIRMQ_VERSION_PATCH @PROJECT_VERSION_PATCH@
|
||||
#define FAIRMQ_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@
|
||||
#define FAIRMQ_GIT_VERSION "@PROJECT_GIT_VERSION@"
|
||||
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
||||
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -71,9 +71,9 @@ class Multiplier : public Device
|
||||
for (unsigned int j = 0; j < GetNumSubChannels(fOutChannelNames.at(i)); ++j) { // all subChannels in a channel
|
||||
Parts parts;
|
||||
|
||||
for (unsigned int k = 0; k < payload.Size(); ++k) {
|
||||
for (int k = 0; k < payload.Size(); ++k) {
|
||||
MessagePtr msgCopy(fTransportFactory->CreateMessage());
|
||||
msgCopy->Copy(*(payload.At(k)));
|
||||
msgCopy->Copy(payload.AtRef(k));
|
||||
parts.AddPart(std::move(msgCopy));
|
||||
}
|
||||
|
||||
@@ -86,9 +86,9 @@ class Multiplier : public Device
|
||||
for (unsigned int i = 0; i < lastChannelSize - 1; ++i) { // iterate over all except last subChannels of the last channel
|
||||
Parts parts;
|
||||
|
||||
for (unsigned int k = 0; k < payload.Size(); ++k) {
|
||||
for (int k = 0; k < payload.Size(); ++k) {
|
||||
MessagePtr msgCopy(fTransportFactory->CreateMessage());
|
||||
msgCopy->Copy(*(payload.At(k)));
|
||||
msgCopy->Copy(payload.AtRef(k));
|
||||
parts.AddPart(std::move(msgCopy));
|
||||
}
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -24,8 +24,8 @@ namespace fair::mq::ofi
|
||||
|
||||
using namespace std;
|
||||
|
||||
Context::Context(mq::TransportFactory& sendFactory,
|
||||
mq::TransportFactory& receiveFactory,
|
||||
Context::Context(FairMQTransportFactory& sendFactory,
|
||||
FairMQTransportFactory& receiveFactory,
|
||||
int numberIoThreads)
|
||||
: fIoWork(fIoContext)
|
||||
, fReceiveFactory(receiveFactory)
|
||||
|
@@ -51,8 +51,8 @@ struct Address {
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(mq::TransportFactory& sendFactory,
|
||||
mq::TransportFactory& receiveFactory,
|
||||
Context(FairMQTransportFactory& sendFactory,
|
||||
FairMQTransportFactory& receiveFactory,
|
||||
int numberIoThreads = 1);
|
||||
Context(const Context&) = delete;
|
||||
Context(Context&&) = delete;
|
||||
@@ -78,8 +78,8 @@ class Context
|
||||
asio::io_context fIoContext;
|
||||
asio::io_context::work fIoWork;
|
||||
std::vector<std::thread> fThreadPool;
|
||||
mq::TransportFactory& fReceiveFactory;
|
||||
mq::TransportFactory& fSendFactory;
|
||||
FairMQTransportFactory& fReceiveFactory;
|
||||
FairMQTransportFactory& fSendFactory;
|
||||
size_t fSizeHint;
|
||||
|
||||
auto InitThreadPool(int numberIoThreads) -> void;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -69,7 +69,7 @@ Message::Message(pmr::memory_resource* pmr, const size_t size, Alignment /* alig
|
||||
Message::Message(pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
const size_t size,
|
||||
FreeFn* ffn,
|
||||
fairmq_free_fn* ffn,
|
||||
void* hint)
|
||||
: fInitialSize(size)
|
||||
, fSize(size)
|
||||
@@ -137,7 +137,7 @@ auto Message::Rebuild(size_t size, Alignment /* alignment */) -> void
|
||||
Rebuild(size);
|
||||
}
|
||||
|
||||
auto Message::Rebuild(void* /*data*/, size_t size, FreeFn* ffn, void* hint) -> void
|
||||
auto Message::Rebuild(void* /*data*/, size_t size, fairmq_free_fn* ffn, void* hint) -> void
|
||||
{
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -37,7 +37,7 @@ class Message final : public fair::mq::Message
|
||||
Message(std::pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
size_t size,
|
||||
FreeFn* ffn,
|
||||
fairmq_free_fn* ffn,
|
||||
void* hint = nullptr);
|
||||
Message(std::pmr::memory_resource* pmr,
|
||||
fair::mq::UnmanagedRegionPtr& region,
|
||||
@@ -54,7 +54,7 @@ class Message final : public fair::mq::Message
|
||||
auto Rebuild(Alignment alignment) -> void override;
|
||||
auto Rebuild(size_t size) -> void override;
|
||||
auto Rebuild(size_t size, Alignment alignment) -> void override;
|
||||
auto Rebuild(void* data, size_t size, FreeFn* ffn, void* hint = nullptr) -> void override;
|
||||
auto Rebuild(void* data, size_t size, fairmq_free_fn* ffn, void* hint = nullptr) -> void override;
|
||||
|
||||
auto GetData() const -> void* override;
|
||||
auto GetSize() const -> size_t override;
|
||||
@@ -71,7 +71,7 @@ class Message final : public fair::mq::Message
|
||||
size_t fInitialSize;
|
||||
size_t fSize;
|
||||
void* fData;
|
||||
FreeFn* fFreeFunction;
|
||||
fairmq_free_fn* fFreeFunction;
|
||||
void* fHint;
|
||||
std::pmr::memory_resource* fPmr;
|
||||
}; /* class Message */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -100,7 +100,7 @@ try {
|
||||
// TODO catch the correct ofi error
|
||||
catch (const SilentSocketError& e)
|
||||
{
|
||||
// do not print error in this case, this is handled by fair::mq::Device
|
||||
// do not print error in this case, this is handled by FairMQDevice
|
||||
// in case no connection could be established after trying a number of random ports from a range.
|
||||
return false;
|
||||
}
|
||||
@@ -189,7 +189,7 @@ try {
|
||||
}
|
||||
catch (const SilentSocketError& e)
|
||||
{
|
||||
// do not print error in this case, this is handled by fair::mq::Device
|
||||
// do not print error in this case, this is handled by FairMQDevice
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,8 +9,8 @@
|
||||
#ifndef FAIR_MQ_OFI_SOCKET_H
|
||||
#define FAIR_MQ_OFI_SOCKET_H
|
||||
|
||||
#include <fairmq/Message.h>
|
||||
#include <fairmq/Socket.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <fairmq/ofi/Context.h>
|
||||
#include <fairmq/ofi/ControlMessages.h>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <fairmq/ofi/Context.h>
|
||||
#include <fairmq/ofi/Message.h>
|
||||
#include <fairmq/ofi/Socket.h>
|
||||
#include <fairmq/ofi/TransportFactory.h>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@@ -83,7 +84,7 @@ struct TransportFactory final : mq::TransportFactory
|
||||
return std::make_unique<Message>(&fMemoryResource, size);
|
||||
}
|
||||
|
||||
auto CreateMessage(void* data, std::size_t size, FreeFn* ffn, void* hint = nullptr)
|
||||
auto CreateMessage(void* data, std::size_t size, fairmq_free_fn* ffn, void* hint = nullptr)
|
||||
-> std::unique_ptr<mq::Message> override
|
||||
{
|
||||
return std::make_unique<Message>(&fMemoryResource, data, size, ffn, hint);
|
||||
@@ -116,7 +117,7 @@ struct TransportFactory final : mq::TransportFactory
|
||||
}
|
||||
|
||||
auto CreatePoller(
|
||||
std::unordered_map<std::string, std::vector<Channel>> const& /*channelsMap*/,
|
||||
std::unordered_map<std::string, std::vector<FairMQChannel>> const& /*channelsMap*/,
|
||||
std::vector<std::string> const& /*channelList*/) const
|
||||
-> std::unique_ptr<mq::Poller> override
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -9,10 +9,6 @@
|
||||
#ifndef FAIRMQPROGOPTIONS_H
|
||||
#define FAIRMQPROGOPTIONS_H
|
||||
|
||||
#ifndef FAIR_MQ_PROGOPTIONS_H
|
||||
#pragma GCC warning "Deprecated header: Use <fairmq/ProgOptions.h> instead"
|
||||
#endif
|
||||
|
||||
#include <fairmq/ProgOptions.h>
|
||||
|
||||
#endif /* FAIRMQPROGOPTIONS_H */
|
||||
|
24
fairmq/plugins/DDS/CMakeLists.txt
Normal file
24
fairmq/plugins/DDS/CMakeLists.txt
Normal file
@@ -0,0 +1,24 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2012-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set(plugin FairMQPlugin_dds)
|
||||
add_library(${plugin} SHARED ${CMAKE_CURRENT_SOURCE_DIR}/DDS.cxx ${CMAKE_CURRENT_SOURCE_DIR}/DDS.h)
|
||||
target_compile_features(${plugin} PUBLIC cxx_std_17)
|
||||
target_link_libraries(${plugin} PUBLIC FairMQ StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib Boost::boost PRIVATE Commands asio::asio)
|
||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(${plugin} PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
set_target_properties(${plugin} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/fairmq
|
||||
)
|
||||
|
||||
install(TARGETS ${plugin}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
457
fairmq/plugins/DDS/DDS.cxx
Normal file
457
fairmq/plugins/DDS/DDS.cxx
Normal file
@@ -0,0 +1,457 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "DDS.h"
|
||||
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/algorithm/string/split.hpp>
|
||||
#include <boost/algorithm/string/classification.hpp>
|
||||
#include <asio/post.hpp>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
using fair::mq::tools::ToString;
|
||||
|
||||
namespace fair::mq::plugins
|
||||
{
|
||||
|
||||
DDS::DDS(const string& name,
|
||||
const Plugin::Version version,
|
||||
const string& maintainer,
|
||||
const string& homepage,
|
||||
PluginServices* pluginServices)
|
||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||
, fDDSTaskId(dds::env_prop<dds::task_id>())
|
||||
, fCurrentState(DeviceState::Idle)
|
||||
, fLastState(DeviceState::Idle)
|
||||
, fDeviceTerminationRequested(false)
|
||||
, fLastExternalController(0)
|
||||
, fExitingAckedByLastExternalController(false)
|
||||
, fUpdatesAllowed(false)
|
||||
, fWorkGuard(fWorkerQueue.get_executor())
|
||||
{
|
||||
try {
|
||||
TakeDeviceControl();
|
||||
|
||||
string deviceId(GetProperty<string>("id"));
|
||||
if (deviceId.empty()) {
|
||||
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
||||
}
|
||||
string sessionId(GetProperty<string>("session"));
|
||||
if (sessionId == "default") {
|
||||
SetProperty<string>("session", dds::env_prop<dds::dds_session_id>());
|
||||
}
|
||||
|
||||
auto control = GetProperty<string>("control");
|
||||
if (control == "static") {
|
||||
LOG(error) << "DDS Plugin: static mode is not supported";
|
||||
throw invalid_argument("DDS Plugin: static mode is not supported");
|
||||
} else if (control == "dynamic" || control == "external" || control == "interactive") {
|
||||
LOG(debug) << "Running DDS controller: external";
|
||||
} else {
|
||||
LOG(error) << "Unrecognized control mode '" << control << "' requested. " << "Ignoring and starting in external control mode.";
|
||||
}
|
||||
|
||||
SubscribeForCustomCommands();
|
||||
SubscribeForConnectingChannels();
|
||||
|
||||
// subscribe to device state changes, pushing new state changes into the event queue
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||
switch (newState) {
|
||||
case DeviceState::Bound: {
|
||||
// Receive addresses of connecting channels from DDS
|
||||
// and propagate addresses of bound channels to DDS.
|
||||
FillChannelContainers();
|
||||
|
||||
// allow updates from key value after channel containers are filled
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = true;
|
||||
}
|
||||
fUpdateCondition.notify_one();
|
||||
|
||||
// publish bound addresses via DDS at keys corresponding to the channel
|
||||
// prefixes, e.g. 'data' in data[i]
|
||||
PublishBoundChannels();
|
||||
} break;
|
||||
case DeviceState::ResettingDevice: {
|
||||
{
|
||||
lock_guard<mutex> lk(fUpdateMutex);
|
||||
fUpdatesAllowed = false;
|
||||
}
|
||||
|
||||
EmptyChannelContainers();
|
||||
} break;
|
||||
case DeviceState::Exiting: {
|
||||
if (!fControllerThread.joinable()) {
|
||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||
}
|
||||
fWorkGuard.reset();
|
||||
fDeviceTerminationRequested = true;
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
ReleaseDeviceControl();
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
using namespace sdk::cmd;
|
||||
auto now = chrono::steady_clock::now();
|
||||
string id = GetProperty<string>("id");
|
||||
fLastState = fCurrentState;
|
||||
fCurrentState = newState;
|
||||
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
for (auto it = fStateChangeSubscribers.cbegin(); it != fStateChangeSubscribers.end();) {
|
||||
// if a subscriber did not send a heartbeat in more than 3 times the promised interval,
|
||||
// remove it from the subscriber list
|
||||
if (chrono::duration<double>(now - it->second.first).count() > 3 * it->second.second) {
|
||||
LOG(warn) << "Controller '" << it->first
|
||||
<< "' did not send heartbeats since over 3 intervals ("
|
||||
<< 3 * it->second.second << " ms), removing it.";
|
||||
fStateChangeSubscribers.erase(it++);
|
||||
} else {
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << it->first;
|
||||
Cmds cmds(make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
||||
fDDS.Send(cmds.Serialize(), to_string(it->first));
|
||||
++it;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
StartWorkerThread();
|
||||
|
||||
fDDS.Start();
|
||||
} catch (PluginServices::DeviceControlError& e) {
|
||||
LOG(debug) << e.what();
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "Error in plugin initialization: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void DDS::EmptyChannelContainers()
|
||||
{
|
||||
fBindingChans.clear();
|
||||
fConnectingChans.clear();
|
||||
}
|
||||
|
||||
auto DDS::StartWorkerThread() -> void
|
||||
{
|
||||
fWorkerThread = thread([this]() {
|
||||
fWorkerQueue.run();
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::WaitForExitingAck() -> void
|
||||
{
|
||||
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
||||
auto timeout = GetProperty<unsigned int>("wait-for-exiting-ack-timeout");
|
||||
fExitingAcked.wait_for(lock, chrono::milliseconds(timeout), [this]() {
|
||||
return fExitingAckedByLastExternalController || fStateChangeSubscribers.empty();
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::FillChannelContainers() -> void
|
||||
{
|
||||
try {
|
||||
unordered_map<string, int> channelInfo(GetChannelInfo());
|
||||
|
||||
// fill binding and connecting chans
|
||||
for (const auto& c : channelInfo) {
|
||||
string methodKey{"chans." + c.first + "." + to_string(c.second - 1) + ".method"};
|
||||
if (GetProperty<string>(methodKey) == "bind") {
|
||||
fBindingChans.insert(make_pair(c.first, vector<string>()));
|
||||
for (int i = 0; i < c.second; ++i) {
|
||||
fBindingChans.at(c.first).push_back(GetProperty<string>(string{"chans." + c.first + "." + to_string(i) + ".address"}));
|
||||
}
|
||||
} else if (GetProperty<string>(methodKey) == "connect") {
|
||||
fConnectingChans.insert(make_pair(c.first, DDSConfig()));
|
||||
LOG(debug) << "preparing to connect: " << c.first << " with " << c.second << " sub-channels.";
|
||||
fConnectingChans.at(c.first).fNumSubChannels = c.second;
|
||||
} else {
|
||||
LOG(error) << "Cannot update address configuration. Channel method (bind/connect) not specified.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// save properties that will have multiple values arriving (with only some of them to be used)
|
||||
vector<string> iValues;
|
||||
if (PropertyExists("dds-i")) {
|
||||
iValues = GetProperty<vector<string>>("dds-i");
|
||||
}
|
||||
vector<string> inValues;
|
||||
if (PropertyExists("dds-i-n")) {
|
||||
inValues = GetProperty<vector<string>>("dds-i-n");
|
||||
}
|
||||
|
||||
for (const auto& vi : iValues) {
|
||||
size_t pos = vi.find(":");
|
||||
string chanName = vi.substr(0, pos);
|
||||
|
||||
// check if provided name is a valid channel name
|
||||
if (fConnectingChans.find(chanName) == fConnectingChans.end()) {
|
||||
throw invalid_argument(ToString("channel provided to dds-i is not an actual connecting channel of this device: ", chanName));
|
||||
}
|
||||
|
||||
int i = stoi(vi.substr(pos + 1));
|
||||
LOG(debug) << "dds-i: adding " << chanName << " -> i of " << i;
|
||||
fI.insert(make_pair(chanName, i));
|
||||
}
|
||||
|
||||
for (const auto& vi : inValues) {
|
||||
size_t pos = vi.find(":");
|
||||
string chanName = vi.substr(0, pos);
|
||||
|
||||
// check if provided name is a valid channel name
|
||||
if (fConnectingChans.find(chanName) == fConnectingChans.end()) {
|
||||
throw invalid_argument(ToString("channel provided to dds-i-n is not an actual connecting channel of this device: ", chanName));
|
||||
}
|
||||
|
||||
string i_n = vi.substr(pos + 1);
|
||||
pos = i_n.find("-");
|
||||
int i = stoi(i_n.substr(0, pos));
|
||||
int n = stoi(i_n.substr(pos + 1));
|
||||
LOG(debug) << "dds-i-n: adding " << chanName << " -> i: " << i << " n: " << n;
|
||||
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
LOG(error) << "Error filling channel containers: " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
auto DDS::SubscribeForConnectingChannels() -> void
|
||||
{
|
||||
LOG(debug) << "Subscribing for DDS properties.";
|
||||
|
||||
fDDS.SubscribeKeyValue([&] (const string& key, const string& value, uint64_t senderTaskID) {
|
||||
LOG(debug) << "Received property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID;
|
||||
|
||||
if (key.compare(0, 8, "fmqchan_") != 0) {
|
||||
LOG(debug) << "property update is not a channel info update: " << key;
|
||||
return;
|
||||
}
|
||||
string channelName = key.substr(8);
|
||||
LOG(info) << "Update for channel name: " << channelName;
|
||||
|
||||
asio::post(fWorkerQueue, [=]() {
|
||||
try {
|
||||
{
|
||||
unique_lock<mutex> lk(fUpdateMutex);
|
||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
||||
}
|
||||
|
||||
if (fConnectingChans.find(channelName) == fConnectingChans.end()) {
|
||||
LOG(error) << "Received an update for a connecting channel, but either no channel with given channel name exists or it has already been configured: '" << channelName << "', ignoring...";
|
||||
return;
|
||||
}
|
||||
|
||||
string val = value;
|
||||
// check if it is to handle as one out of multiple values
|
||||
auto it = fIofN.find(channelName);
|
||||
if (it != fIofN.end()) {
|
||||
it->second.fEntries.push_back(value);
|
||||
if (it->second.fEntries.size() == it->second.fN) {
|
||||
sort(it->second.fEntries.begin(), it->second.fEntries.end());
|
||||
val = it->second.fEntries.at(it->second.fI);
|
||||
} else {
|
||||
LOG(debug) << "received " << it->second.fEntries.size() << " values for " << channelName << ", expecting total of " << it->second.fN;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
vector<string> connectionStrings;
|
||||
boost::algorithm::split(connectionStrings, val, boost::algorithm::is_any_of(","));
|
||||
if (connectionStrings.size() > 1) { // multiple bound channels received
|
||||
auto it2 = fI.find(channelName);
|
||||
if (it2 != fI.end()) {
|
||||
LOG(debug) << "adding connecting channel " << channelName << " : " << connectionStrings.at(it2->second);
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(it2->second).c_str()});
|
||||
} else {
|
||||
LOG(error) << "multiple bound channels received, but no task index specified, only assigning the first";
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, connectionStrings.at(0).c_str()});
|
||||
}
|
||||
} else { // only one bound channel received
|
||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
||||
}
|
||||
|
||||
for (const auto& mi : fConnectingChans) {
|
||||
if (mi.second.fNumSubChannels == mi.second.fDDSValues.size()) {
|
||||
int i = 0;
|
||||
for (const auto& e : mi.second.fDDSValues) {
|
||||
auto result = UpdateProperty<string>(string{"chans." + mi.first + "." + to_string(i) + ".address"}, e.second);
|
||||
if (!result) {
|
||||
LOG(error) << "UpdateProperty failed for: " << "chans." << mi.first << "." << to_string(i) << ".address" << " - property does not exist";
|
||||
}
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (const exception& e) {
|
||||
LOG(error) << "Error handling DDS property: key=" << key << ", value=" << value << ", senderTaskID=" << senderTaskID << ": " << e.what();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::PublishBoundChannels() -> void
|
||||
{
|
||||
for (const auto& chan : fBindingChans) {
|
||||
string joined = boost::algorithm::join(chan.second, ",");
|
||||
LOG(debug) << "Publishing bound addresses (" << chan.second.size() << ") of channel '" << chan.first << "' to DDS under '" << "fmqchan_" + chan.first << "' property name.";
|
||||
fDDS.PutValue("fmqchan_" + chan.first, joined);
|
||||
}
|
||||
}
|
||||
|
||||
auto DDS::SubscribeForCustomCommands() -> void
|
||||
{
|
||||
LOG(debug) << "Subscribing for DDS custom commands.";
|
||||
|
||||
string id = GetProperty<string>("id");
|
||||
|
||||
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
||||
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
||||
sdk::cmd::Cmds inCmds;
|
||||
inCmds.Deserialize(cmdStr);
|
||||
for (const auto& cmd : inCmds) {
|
||||
HandleCmd(id, *cmd, cond, senderId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto DDS::HandleCmd(const string& id, sdk::cmd::Cmd& cmd, const string& cond, uint64_t senderId) -> void
|
||||
{
|
||||
using namespace fair::mq::sdk;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
// LOG(info) << "Received command type: '" << cmd.GetType() << "' from " << senderId;
|
||||
switch (cmd.GetType()) {
|
||||
case Type::check_state: {
|
||||
fDDS.Send(Cmds(make<CurrentState>(id, GetCurrentDeviceState())).Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::change_state: {
|
||||
Transition transition = static_cast<ChangeState&>(cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Ok, transition, GetCurrentDeviceState()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} else {
|
||||
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Failure, transition, GetCurrentDeviceState()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastExternalController = senderId;
|
||||
}
|
||||
} break;
|
||||
case Type::dump_config: {
|
||||
stringstream ss;
|
||||
for (const auto& pKey : GetPropertyKeys()) {
|
||||
ss << id << ": " << pKey << " -> " << GetPropertyAsString(pKey) << "\n";
|
||||
}
|
||||
Cmds outCmds(make<Config>(id, ss.str()));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::state_change_exiting_received: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == senderId) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
} break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
auto _cmd = static_cast<cmd::SubscribeToStateChange&>(cmd);
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.emplace(senderId, make_pair(chrono::steady_clock::now(), _cmd.GetInterval()));
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
||||
|
||||
Cmds outCmds(make<StateChangeSubscription>(id, fDDSTaskId, Result::Ok),
|
||||
make<StateChange>(id, fDDSTaskId, fLastState, fCurrentState));
|
||||
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::subscription_heartbeat: {
|
||||
try {
|
||||
auto _cmd = static_cast<cmd::SubscriptionHeartbeat&>(cmd);
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.at(senderId) = make_pair(chrono::steady_clock::now(), _cmd.GetInterval());
|
||||
} catch(out_of_range& oor) {
|
||||
LOG(warn) << "Received subscription heartbeat from an unknown controller with id '" << senderId << "'";
|
||||
}
|
||||
} break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(senderId);
|
||||
}
|
||||
Cmds outCmds(make<StateChangeUnsubscription>(id, fDDSTaskId, Result::Ok));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::get_properties: {
|
||||
auto _cmd = static_cast<cmd::GetProperties&>(cmd);
|
||||
auto const request_id(_cmd.GetRequestId());
|
||||
auto result(Result::Ok);
|
||||
vector<pair<string, string>> props;
|
||||
try {
|
||||
for (auto const& prop : GetPropertiesAsString(_cmd.GetQuery())) {
|
||||
props.push_back({prop.first, prop.second});
|
||||
}
|
||||
} catch (exception const& e) {
|
||||
LOG(warn) << "Getting properties (request id: " << request_id << ") failed: " << e.what();
|
||||
result = Result::Failure;
|
||||
}
|
||||
Cmds const outCmds(make<cmd::Properties>(id, request_id, result, props));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
case Type::set_properties: {
|
||||
auto _cmd(static_cast<cmd::SetProperties&>(cmd));
|
||||
auto const request_id(_cmd.GetRequestId());
|
||||
auto result(Result::Ok);
|
||||
try {
|
||||
fair::mq::Properties props;
|
||||
for (auto const& prop : _cmd.GetProps()) {
|
||||
props.insert({prop.first, fair::mq::Property(prop.second)});
|
||||
}
|
||||
// TODO Handle builtin keys with different value type than string
|
||||
SetProperties(props);
|
||||
} catch (exception const& e) {
|
||||
LOG(warn) << "Setting properties (request id: " << request_id << ") failed: " << e.what();
|
||||
result = Result::Failure;
|
||||
}
|
||||
Cmds const outCmds(make<PropertiesSet>(id, request_id, result));
|
||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||
} break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmd.GetType();
|
||||
LOG(warn) << "Origin: " << senderId;
|
||||
LOG(warn) << "Destination: " << cond;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DDS::~DDS()
|
||||
{
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
ReleaseDeviceControl();
|
||||
|
||||
if (fControllerThread.joinable()) {
|
||||
fControllerThread.join();
|
||||
}
|
||||
|
||||
fWorkGuard.reset();
|
||||
if (fWorkerThread.joinable()) {
|
||||
fWorkerThread.join();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fair::mq::plugins
|
199
fairmq/plugins/DDS/DDS.h
Normal file
199
fairmq/plugins/DDS/DDS.h
Normal file
@@ -0,0 +1,199 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_PLUGINS_DDS
|
||||
#define FAIR_MQ_PLUGINS_DDS
|
||||
|
||||
#include <fairmq/Plugin.h>
|
||||
#include <fairmq/StateQueue.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <dds/dds.h>
|
||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
|
||||
#include <asio/executor.hpp>
|
||||
#include <asio/executor_work_guard.hpp>
|
||||
#include <asio/io_context.hpp>
|
||||
|
||||
#include <cassert>
|
||||
#include <chrono>
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <utility> // pair
|
||||
#include <vector>
|
||||
|
||||
namespace fair::mq::plugins
|
||||
{
|
||||
|
||||
struct DDSConfig
|
||||
{
|
||||
// container of sub channel addresses
|
||||
unsigned int fNumSubChannels;
|
||||
// dds values for the channel
|
||||
std::map<uint64_t, std::string> fDDSValues;
|
||||
};
|
||||
|
||||
struct DDSSubscription
|
||||
{
|
||||
DDSSubscription()
|
||||
: fDDSCustomCmd(fService)
|
||||
, fDDSKeyValue(fService)
|
||||
{
|
||||
LOG(debug) << "$DDS_TASK_PATH: " << dds::env_prop<dds::task_path>();
|
||||
LOG(debug) << "$DDS_GROUP_NAME: " << dds::env_prop<dds::group_name>();
|
||||
LOG(debug) << "$DDS_COLLECTION_NAME: " << dds::env_prop<dds::collection_name>();
|
||||
LOG(debug) << "$DDS_TASK_NAME: " << dds::env_prop<dds::task_name>();
|
||||
LOG(debug) << "$DDS_TASK_INDEX: " << dds::env_prop<dds::task_index>();
|
||||
LOG(debug) << "$DDS_COLLECTION_INDEX: " << dds::env_prop<dds::collection_index>();
|
||||
LOG(debug) << "$DDS_TASK_ID: " << dds::env_prop<dds::task_id>();
|
||||
LOG(debug) << "$DDS_LOCATION: " << dds::env_prop<dds::dds_location>();
|
||||
std::string dds_session_id(dds::env_prop<dds::dds_session_id>());
|
||||
LOG(debug) << "$DDS_SESSION_ID: " << dds_session_id;
|
||||
|
||||
// subscribe for DDS service errors.
|
||||
fService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& errorMsg) {
|
||||
LOG(error) << "DDS Error received: error code: " << errorCode << ", error message: " << errorMsg;
|
||||
});
|
||||
|
||||
// fDDSCustomCmd.subscribe([](const std::string& cmd, const std::string& cond, uint64_t senderId) {
|
||||
// LOG(debug) << "cmd: " << cmd << ", cond: " << cond << ", senderId: " << senderId;
|
||||
// });
|
||||
assert(!dds_session_id.empty());
|
||||
}
|
||||
|
||||
auto Start() -> void {
|
||||
fService.start(dds::env_prop<dds::dds_session_id>());
|
||||
}
|
||||
|
||||
~DDSSubscription() {
|
||||
fDDSKeyValue.unsubscribe();
|
||||
fDDSCustomCmd.unsubscribe();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto SubscribeCustomCmd(Args&&... args) -> void
|
||||
{
|
||||
fDDSCustomCmd.subscribe(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto SubscribeKeyValue(Args&&... args) -> void
|
||||
{
|
||||
fDDSKeyValue.subscribe(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto Send(Args&&... args) -> void
|
||||
{
|
||||
fDDSCustomCmd.send(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
auto PutValue(Args&&... args) -> void
|
||||
{
|
||||
fDDSKeyValue.putValue(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
private:
|
||||
dds::intercom_api::CIntercomService fService;
|
||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
||||
dds::intercom_api::CKeyValue fDDSKeyValue;
|
||||
};
|
||||
|
||||
struct IofN
|
||||
{
|
||||
IofN(int i, int n)
|
||||
: fI(i)
|
||||
, fN(n)
|
||||
{}
|
||||
|
||||
unsigned int fI;
|
||||
unsigned int fN;
|
||||
std::vector<std::string> fEntries;
|
||||
};
|
||||
|
||||
class DDS : public Plugin
|
||||
{
|
||||
public:
|
||||
DDS(const std::string& name, const Plugin::Version version, const std::string& maintainer, const std::string& homepage, PluginServices* pluginServices);
|
||||
|
||||
~DDS();
|
||||
|
||||
private:
|
||||
auto WaitForExitingAck() -> void;
|
||||
auto StartWorkerThread() -> void;
|
||||
|
||||
auto FillChannelContainers() -> void;
|
||||
auto EmptyChannelContainers() -> void;
|
||||
|
||||
auto SubscribeForConnectingChannels() -> void;
|
||||
auto PublishBoundChannels() -> void;
|
||||
auto SubscribeForCustomCommands() -> void;
|
||||
auto HandleCmd(const std::string& id, sdk::cmd::Cmd& cmd, const std::string& cond, uint64_t senderId) -> void;
|
||||
|
||||
DDSSubscription fDDS;
|
||||
size_t fDDSTaskId;
|
||||
|
||||
std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
|
||||
std::unordered_map<std::string, DDSConfig> fConnectingChans;
|
||||
|
||||
std::unordered_map<std::string, int> fI;
|
||||
std::unordered_map<std::string, IofN> fIofN;
|
||||
|
||||
std::thread fControllerThread;
|
||||
DeviceState fCurrentState, fLastState;
|
||||
|
||||
std::atomic<bool> fDeviceTerminationRequested;
|
||||
|
||||
std::unordered_map<uint64_t, std::pair<std::chrono::steady_clock::time_point, int64_t>> fStateChangeSubscribers;
|
||||
uint64_t fLastExternalController;
|
||||
bool fExitingAckedByLastExternalController;
|
||||
std::condition_variable fExitingAcked;
|
||||
std::mutex fStateChangeSubscriberMutex;
|
||||
|
||||
bool fUpdatesAllowed;
|
||||
std::mutex fUpdateMutex;
|
||||
std::condition_variable fUpdateCondition;
|
||||
|
||||
std::thread fWorkerThread;
|
||||
asio::io_context fWorkerQueue;
|
||||
asio::executor_work_guard<asio::executor> fWorkGuard;
|
||||
};
|
||||
|
||||
Plugin::ProgOptions DDSProgramOptions()
|
||||
{
|
||||
boost::program_options::options_description options{"DDS Plugin"};
|
||||
options.add_options()
|
||||
("dds-i", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (single channel n to m). When all values come via same update.")
|
||||
("dds-i-n", boost::program_options::value<std::vector<std::string>>()->multitoken()->composing(), "Task index for chosing connection target (one out of n values to take). When values come as independent updates.")
|
||||
("wait-for-exiting-ack-timeout", boost::program_options::value<unsigned int>()->default_value(1000), "Wait timeout for EXITING state-change acknowledgement by external controller in milliseconds.");
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
REGISTER_FAIRMQ_PLUGIN(
|
||||
DDS, // Class name
|
||||
dds, // Plugin name (string, lower case chars only)
|
||||
(Plugin::Version{FAIRMQ_VERSION_MAJOR,
|
||||
FAIRMQ_VERSION_MINOR,
|
||||
FAIRMQ_VERSION_PATCH}), // Version
|
||||
"FairRootGroup <fairroot@gsi.de>", // Maintainer
|
||||
"https://github.com/FairRootGroup/FairMQ", // Homepage
|
||||
DDSProgramOptions // custom program options for the plugin
|
||||
)
|
||||
|
||||
} // namespace fair::mq::plugins
|
||||
|
||||
#endif /* FAIR_MQ_PLUGINS_DDS */
|
@@ -1,5 +1,5 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
@@ -14,16 +14,17 @@ add_library(${plugin} SHARED
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/PMIx.hpp
|
||||
)
|
||||
target_compile_features(${plugin} PUBLIC cxx_std_17)
|
||||
target_link_libraries(${plugin} PUBLIC FairMQ PMIx::libpmix)
|
||||
target_link_libraries(${plugin} PUBLIC FairMQ PMIx::libpmix PRIVATE Commands)
|
||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set_target_properties(${plugin} PROPERTIES
|
||||
CXX_VISIBILITY_PRESET hidden
|
||||
OUTPUT_NAME "${PROJECT_NAME_LOWER}-plugin-pmix"
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
set(exe fairmq-pmix-command-ui)
|
||||
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runPMIxCommandUI.cxx)
|
||||
target_link_libraries(${exe} FairMQ PMIx::libpmix)
|
||||
target_link_libraries(${exe} FairMQ Commands StateMachine PMIx::libpmix)
|
||||
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
install(TARGETS ${plugin} ${exe}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include "PMIxPlugin.h"
|
||||
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <sstream>
|
||||
@@ -15,6 +16,7 @@
|
||||
#include <cstdint> // UINT32_MAX
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
|
||||
namespace fair::mq::plugins
|
||||
{
|
||||
@@ -29,7 +31,8 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||
, fPid(getpid())
|
||||
, fPMIxClient(tools::ToString("PMIx client(pid=", fPid, ") "))
|
||||
, fDeviceId(string(fProcess.nspace) + "_" + to_string(fProcess.rank))
|
||||
// , fLastExternalController(UINT32_MAX)
|
||||
, fCommands(fProcess)
|
||||
, fLastExternalController(UINT32_MAX)
|
||||
, fExitingAckedByLastExternalController(false)
|
||||
, fCurrentState(DeviceState::Idle)
|
||||
, fLastState(DeviceState::Idle)
|
||||
@@ -39,6 +42,12 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||
SetProperty<string>("id", fDeviceId);
|
||||
|
||||
Fence("pmix::init");
|
||||
SubscribeForCommands();
|
||||
Fence("subscribed");
|
||||
|
||||
// fCommands.Send("test1");
|
||||
// fCommands.Send("test2", 0);
|
||||
// fCommands.Send("test3", 0);
|
||||
|
||||
// LOG(info) << "PMIX_EXTERNAL_ERR_BASE: " << PMIX_EXTERNAL_ERR_BASE;
|
||||
|
||||
@@ -92,9 +101,11 @@ PMIxPlugin::PMIxPlugin(const string& name,
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastState = fCurrentState;
|
||||
fCurrentState = newState;
|
||||
// for (auto subscriberId : fStateChangeSubscribers) {
|
||||
// LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||
// }
|
||||
for (auto subscriberId : fStateChangeSubscribers) {
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||
Cmds cmds(make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
||||
fCommands.Send(cmds.Serialize(Format::JSON), static_cast<pmix::rank>(subscriberId));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -102,6 +113,7 @@ PMIxPlugin::~PMIxPlugin()
|
||||
{
|
||||
LOG(debug) << "Destroying PMIxPlugin";
|
||||
ReleaseDeviceControl();
|
||||
fCommands.Unsubscribe();
|
||||
while (pmix::initialized()) {
|
||||
try {
|
||||
pmix::finalize();
|
||||
@@ -112,6 +124,92 @@ PMIxPlugin::~PMIxPlugin()
|
||||
}
|
||||
}
|
||||
|
||||
auto PMIxPlugin::SubscribeForCommands() -> void
|
||||
{
|
||||
fCommands.Subscribe([this](const string& cmdStr, const pmix::proc& sender) {
|
||||
// LOG(info) << "PMIx Plugin received message: '" << cmdStr << "', from " << sender;
|
||||
|
||||
Cmds inCmds;
|
||||
inCmds.Deserialize(cmdStr, Format::JSON);
|
||||
|
||||
for (const auto& cmd : inCmds) {
|
||||
LOG(info) << "Received command type: '" << cmd->GetType() << "' from " << sender;
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state:
|
||||
fCommands.Send(Cmds(make<CurrentState>(fDeviceId, GetCurrentDeviceState()))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
break;
|
||||
case Type::change_state: {
|
||||
Transition transition = static_cast<ChangeState&>(*cmd).GetTransition();
|
||||
if (ChangeDeviceState(transition)) {
|
||||
fCommands.Send(
|
||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Ok, transition, GetCurrentDeviceState()))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
} else {
|
||||
fCommands.Send(
|
||||
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Failure, transition, GetCurrentDeviceState()))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fLastExternalController = sender.rank;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.insert(sender.rank);
|
||||
}
|
||||
|
||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState
|
||||
<< " to " << sender;
|
||||
Cmds outCmds(make<StateChangeSubscription>(fDeviceId, fProcess.rank, Result::Ok),
|
||||
make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
||||
fCommands.Send(outCmds.Serialize(Format::JSON), {sender});
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
fStateChangeSubscribers.erase(sender.rank);
|
||||
}
|
||||
fCommands.Send(Cmds(make<StateChangeUnsubscription>(fDeviceId, fProcess.rank, Result::Ok))
|
||||
.Serialize(Format::JSON),
|
||||
{sender});
|
||||
}
|
||||
break;
|
||||
case Type::state_change_exiting_received: {
|
||||
{
|
||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||
if (fLastExternalController == sender.rank) {
|
||||
fExitingAckedByLastExternalController = true;
|
||||
}
|
||||
}
|
||||
fExitingAcked.notify_one();
|
||||
}
|
||||
break;
|
||||
case Type::dump_config: {
|
||||
stringstream ss;
|
||||
for (const auto& k: GetPropertyKeys()) {
|
||||
ss << fDeviceId << ": " << k << " -> " << GetPropertyAsString(k) << "\n";
|
||||
}
|
||||
fCommands.Send(Cmds(make<Config>(fDeviceId, ss.str())).Serialize(Format::JSON),
|
||||
{sender});
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG(warn) << "Unexpected/unknown command received: " << cmdStr;
|
||||
LOG(warn) << "Origin: " << sender;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
auto PMIxPlugin::Init() -> pmix::proc
|
||||
{
|
||||
if (!pmix::initialized()) {
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -44,9 +44,10 @@ class PMIxPlugin : public Plugin
|
||||
pid_t fPid;
|
||||
std::string fPMIxClient;
|
||||
std::string fDeviceId;
|
||||
pmix::Commands fCommands;
|
||||
|
||||
std::set<uint32_t> fStateChangeSubscribers;
|
||||
// uint32_t fLastExternalController;
|
||||
uint32_t fLastExternalController;
|
||||
bool fExitingAckedByLastExternalController;
|
||||
std::condition_variable fExitingAcked;
|
||||
std::mutex fStateChangeSubscriberMutex;
|
||||
@@ -60,6 +61,7 @@ class PMIxPlugin : public Plugin
|
||||
auto Fence(const std::string& label) -> void;
|
||||
auto Lookup() -> void;
|
||||
|
||||
auto SubscribeForCommands() -> void;
|
||||
auto WaitForExitingAck() -> void;
|
||||
};
|
||||
|
||||
|
@@ -1,11 +1,12 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/States.h>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
@@ -28,6 +29,7 @@
|
||||
#include <vector>
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
const std::map<fair::mq::Transition, fair::mq::State> expected =
|
||||
@@ -44,6 +46,23 @@ const std::map<fair::mq::Transition, fair::mq::State> expected =
|
||||
{ fair::mq::Transition::End, fair::mq::State::Exiting }
|
||||
};
|
||||
|
||||
struct StateSubscription
|
||||
{
|
||||
pmix::Commands& fCommands;
|
||||
|
||||
explicit StateSubscription(pmix::Commands& commands)
|
||||
: fCommands(commands)
|
||||
{
|
||||
fCommands.Send(Cmds(make<SubscribeToStateChange>(600000)).Serialize(Format::JSON));
|
||||
}
|
||||
|
||||
~StateSubscription()
|
||||
{
|
||||
fCommands.Send(Cmds(make<UnsubscribeFromStateChange>()).Serialize(Format::JSON));
|
||||
this_thread::sleep_for(chrono::milliseconds(100)); // give PMIx a chance to complete request
|
||||
}
|
||||
};
|
||||
|
||||
struct MiniTopo
|
||||
{
|
||||
explicit MiniTopo(unsigned int n)
|
||||
@@ -122,6 +141,74 @@ int main(int argc, char* argv[])
|
||||
LOG(warn) << "pmix::fence() [pmix::init] OK";
|
||||
|
||||
MiniTopo topo(numDevices);
|
||||
pmix::Commands commands(process);
|
||||
|
||||
commands.Subscribe([&](const string& msg, const pmix::proc& sender) {
|
||||
// LOG(info) << "Received '" << msg << "' from " << sender;
|
||||
Cmds cmds;
|
||||
cmds.Deserialize(msg, Format::JSON);
|
||||
// cout << "Received " << cmds.Size() << " command(s) with total size of " << msg.length() << " bytes: " << endl;
|
||||
for (const auto& cmd : cmds) {
|
||||
// cout << " > " << cmd->GetType() << endl;
|
||||
switch (cmd->GetType()) {
|
||||
case Type::state_change: {
|
||||
cout << "Received state_change from " << static_cast<StateChange&>(*cmd).GetDeviceId() << ": " << static_cast<StateChange&>(*cmd).GetLastState() << "->" << static_cast<StateChange&>(*cmd).GetCurrentState() << endl;
|
||||
topo.Update(sender.rank, static_cast<StateChange&>(*cmd).GetCurrentState());
|
||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == fair::mq::State::Exiting) {
|
||||
commands.Send(Cmds(make<StateChangeExitingReceived>()).Serialize(Format::JSON), {sender});
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription:
|
||||
if (static_cast<StateChangeSubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change subscription failed for " << static_cast<StateChangeSubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription:
|
||||
if (static_cast<StateChangeUnsubscription&>(*cmd).GetResult() != Result::Ok) {
|
||||
cout << "State change unsubscription failed for " << static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId() << endl;
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
if (static_cast<TransitionStatus&>(*cmd).GetResult() == Result::Ok) {
|
||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " started to transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
} else {
|
||||
cout << "Device " << static_cast<TransitionStatus&>(*cmd).GetDeviceId() << " cannot transition with " << static_cast<TransitionStatus&>(*cmd).GetTransition() << endl;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Type::current_state:
|
||||
cout << "Device " << static_cast<CurrentState&>(*cmd).GetDeviceId() << " is in " << static_cast<CurrentState&>(*cmd).GetCurrentState() << " state" << endl;
|
||||
break;
|
||||
case Type::config:
|
||||
cout << "Received config for device " << static_cast<Config&>(*cmd).GetDeviceId() << ":\n" << static_cast<Config&>(*cmd).GetConfig() << endl;
|
||||
break;
|
||||
default:
|
||||
cout << "Unexpected/unknown command received: " << cmd->GetType() << endl;
|
||||
cout << "Origin: " << sender << endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
pmix::fence({all});
|
||||
LOG(warn) << "pmix::fence() [subscribed] OK";
|
||||
|
||||
StateSubscription stateSubscription(commands);
|
||||
|
||||
for (auto transition : { fair::mq::Transition::InitDevice,
|
||||
fair::mq::Transition::CompleteInit,
|
||||
fair::mq::Transition::Bind,
|
||||
fair::mq::Transition::Connect,
|
||||
fair::mq::Transition::InitTask,
|
||||
fair::mq::Transition::Run,
|
||||
fair::mq::Transition::Stop,
|
||||
fair::mq::Transition::ResetTask,
|
||||
fair::mq::Transition::ResetDevice,
|
||||
fair::mq::Transition::End }) {
|
||||
commands.Send(Cmds(make<ChangeState>(transition)).Serialize(Format::JSON));
|
||||
topo.WaitFor(expected.at(transition));
|
||||
}
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "Error: " << e.what();
|
||||
return EXIT_FAILURE;
|
||||
|
@@ -40,7 +40,7 @@ Config::Config(const string& name, Plugin::Version version, const string& mainta
|
||||
LOG(debug) << "channel-config: Parsing channel configuration";
|
||||
SetProperties(SuboptParser(GetProperty<vector<string>>("channel-config"), idForParser));
|
||||
} else {
|
||||
LOG(warn) << "fair::mq::plugins::Config: no channels configuration provided via --mq-config or --channel-config";
|
||||
LOG(info) << "fair::mq::plugins::Config: no channels configuration provided via --mq-config or --channel-config";
|
||||
}
|
||||
} catch (exception& e) {
|
||||
LOG(error) << e.what();
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <boost/program_options.hpp>
|
||||
#include <memory>
|
||||
|
||||
// to be implemented by the user to return a child class of fair::mq::Device
|
||||
// to be implemented by the user to return a child class of FairMQDevice
|
||||
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& config);
|
||||
|
||||
// to be implemented by the user to add custom command line options (or just with empty body)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
using FairMQDevicePtr = fair::mq::Device*;
|
||||
|
||||
// to be implemented by the user to return a child class of fair::mq::Device
|
||||
// to be implemented by the user to return a child class of FairMQDevice
|
||||
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& config);
|
||||
|
||||
// to be implemented by the user to add custom command line options (or just with empty body)
|
||||
|
223
fairmq/sdk/AsioAsyncOp.h
Normal file
223
fairmq/sdk/AsioAsyncOp.h
Normal file
@@ -0,0 +1,223 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_ASIOASYNCOP_H
|
||||
#define FAIR_MQ_SDK_ASIOASYNCOP_H
|
||||
|
||||
#include <asio/associated_allocator.hpp>
|
||||
#include <asio/associated_executor.hpp>
|
||||
#include <asio/executor_work_guard.hpp>
|
||||
#include <asio/dispatch.hpp>
|
||||
#include <asio/system_executor.hpp>
|
||||
#include <chrono>
|
||||
#include <exception>
|
||||
#include <fairmq/sdk/Error.h>
|
||||
#include <fairmq/sdk/Traits.h>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <system_error>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#include <fairlogger/Logger.h>
|
||||
#ifndef FAIR_LOG
|
||||
#define FAIR_LOG LOG
|
||||
#endif /* ifndef FAIR_LOG */
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
template<typename... SignatureArgTypes>
|
||||
struct AsioAsyncOpImplBase
|
||||
{
|
||||
virtual auto Complete(std::error_code, SignatureArgTypes...) -> void = 0;
|
||||
virtual auto IsCompleted() const -> bool = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* @tparam Executor1 Associated I/O executor, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_i_o_executor
|
||||
* @tparam Allocator1 Default allocation strategy, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
||||
*/
|
||||
template<typename Executor1, typename Allocator1, typename Handler, typename... SignatureArgTypes>
|
||||
struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
||||
{
|
||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
||||
using Allocator2 = typename asio::associated_allocator<Handler, Allocator1>::type;
|
||||
|
||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_completion_handler_executor
|
||||
using Executor2 = typename asio::associated_executor<Handler, Executor1>::type;
|
||||
|
||||
/// Ctor
|
||||
AsioAsyncOpImpl(const Executor1& ex1, Allocator1 alloc1, Handler&& handler)
|
||||
: fWork1(ex1)
|
||||
, fWork2(asio::get_associated_executor(handler, ex1))
|
||||
, fHandler(std::move(handler))
|
||||
, fAlloc1(std::move(alloc1))
|
||||
{}
|
||||
|
||||
auto GetAlloc2() const -> Allocator2 { return asio::get_associated_allocator(fHandler, fAlloc1); }
|
||||
auto GetEx2() const -> Executor2 { return asio::get_associated_executor(fWork2); }
|
||||
|
||||
auto Complete(std::error_code ec, SignatureArgTypes... args) -> void override
|
||||
{
|
||||
if (IsCompleted()) {
|
||||
throw RuntimeError("Async operation already completed");
|
||||
}
|
||||
|
||||
asio::dispatch(GetEx2(),
|
||||
[=, handler = std::move(fHandler)]() mutable {
|
||||
try {
|
||||
handler(ec, args...);
|
||||
} catch (const std::exception& e) {
|
||||
FAIR_LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
||||
} catch (...) {
|
||||
FAIR_LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
||||
}
|
||||
});
|
||||
|
||||
fWork1.reset();
|
||||
fWork2.reset();
|
||||
}
|
||||
|
||||
auto IsCompleted() const -> bool override
|
||||
{
|
||||
return !fWork1.owns_work() && !fWork2.owns_work();
|
||||
}
|
||||
|
||||
private:
|
||||
/// See https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.outstanding_work
|
||||
asio::executor_work_guard<Executor1> fWork1;
|
||||
asio::executor_work_guard<Executor2> fWork2;
|
||||
Handler fHandler;
|
||||
Allocator1 fAlloc1;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class AsioAsyncOp AsioAsyncOp.h <fairmq/sdk/AsioAsyncOp.h>
|
||||
* @tparam Executor Associated I/O executor, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.associated_i_o_executor
|
||||
* @tparam Allocator Default allocation strategy, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
||||
* @tparam CompletionSignature
|
||||
* @brief Interface for Asio-compliant asynchronous operation, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html
|
||||
*
|
||||
* @par Thread Safety
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Unsafe.
|
||||
*
|
||||
* primary template
|
||||
*/
|
||||
template<typename Executor, typename Allocator, typename CompletionSignature>
|
||||
struct AsioAsyncOp
|
||||
{
|
||||
};
|
||||
|
||||
/**
|
||||
* @tparam Executor See primary template
|
||||
* @tparam Allocator See primary template
|
||||
* @tparam SignatureReturnType Return type of CompletionSignature, see primary template
|
||||
* @tparam SignatureFirstArgType Type of first argument of CompletionSignature, see primary template
|
||||
* @tparam SignatureArgTypes Types of the rest of arguments of CompletionSignature
|
||||
*
|
||||
* partial specialization to deconstruct CompletionSignature
|
||||
*/
|
||||
template<typename Executor,
|
||||
typename Allocator,
|
||||
typename SignatureReturnType,
|
||||
typename SignatureFirstArgType,
|
||||
typename... SignatureArgTypes>
|
||||
struct AsioAsyncOp<Executor,
|
||||
Allocator,
|
||||
SignatureReturnType(SignatureFirstArgType, SignatureArgTypes...)>
|
||||
{
|
||||
static_assert(std::is_void<SignatureReturnType>::value,
|
||||
"return value of CompletionSignature must be void");
|
||||
static_assert(std::is_same<SignatureFirstArgType, std::error_code>::value,
|
||||
"first argument of CompletionSignature must be std::error_code");
|
||||
using Duration = std::chrono::milliseconds;
|
||||
|
||||
private:
|
||||
using Impl = AsioAsyncOpImplBase<SignatureArgTypes...>;
|
||||
using ImplPtr = std::unique_ptr<Impl, std::function<void(Impl*)>>;
|
||||
ImplPtr fImpl;
|
||||
|
||||
public:
|
||||
/// Default Ctor
|
||||
AsioAsyncOp()
|
||||
: fImpl(nullptr)
|
||||
{}
|
||||
|
||||
/// Ctor with handler
|
||||
template<typename Handler>
|
||||
AsioAsyncOp(Executor ex1, Allocator alloc1, Handler&& handler)
|
||||
: AsioAsyncOp()
|
||||
{
|
||||
// Async operation type to be allocated and constructed
|
||||
using Op = AsioAsyncOpImpl<Executor, Allocator, Handler, SignatureArgTypes...>;
|
||||
|
||||
// Create allocator for concrete op type
|
||||
// Allocator2, see https://www.boost.org/doc/libs/1_70_0/doc/html/boost_asio/reference/asynchronous_operations.html#boost_asio.reference.asynchronous_operations.allocation_of_intermediate_storage
|
||||
using OpAllocator =
|
||||
typename std::allocator_traits<typename Op::Allocator2>::template rebind_alloc<Op>;
|
||||
OpAllocator opAlloc;
|
||||
|
||||
// Allocate memory
|
||||
auto mem(std::allocator_traits<OpAllocator>::allocate(opAlloc, 1));
|
||||
|
||||
// Construct object
|
||||
auto ptr(new (mem) Op(std::move(ex1),
|
||||
std::move(alloc1),
|
||||
std::forward<Handler>(handler)));
|
||||
|
||||
// Assign ownership to this object
|
||||
fImpl = ImplPtr(ptr, [opAlloc](Impl* p) mutable {
|
||||
std::allocator_traits<OpAllocator>::deallocate(opAlloc, static_cast<Op*>(p), 1);
|
||||
});
|
||||
}
|
||||
|
||||
/// Ctor with handler #2
|
||||
template<typename Handler>
|
||||
AsioAsyncOp(Executor ex1, Handler&& handler)
|
||||
: AsioAsyncOp(std::move(ex1), Allocator(), std::forward<Handler>(handler))
|
||||
{}
|
||||
|
||||
/// Ctor with handler #3
|
||||
template<typename Handler>
|
||||
explicit AsioAsyncOp(Handler&& handler)
|
||||
: AsioAsyncOp(asio::system_executor(), std::forward<Handler>(handler))
|
||||
{}
|
||||
|
||||
auto IsCompleted() -> bool { return (fImpl == nullptr) || fImpl->IsCompleted(); }
|
||||
|
||||
auto Complete(std::error_code ec, SignatureArgTypes... args) -> void
|
||||
{
|
||||
if(IsCompleted()) {
|
||||
throw RuntimeError("Async operation already completed");
|
||||
}
|
||||
|
||||
fImpl->Complete(ec, args...);
|
||||
fImpl.reset(nullptr);
|
||||
}
|
||||
|
||||
auto Complete(SignatureArgTypes... args) -> void
|
||||
{
|
||||
Complete(std::error_code(), args...);
|
||||
}
|
||||
|
||||
auto Cancel(SignatureArgTypes... args) -> void
|
||||
{
|
||||
Complete(MakeErrorCode(ErrorCode::OperationCanceled), args...);
|
||||
}
|
||||
|
||||
auto Timeout(SignatureArgTypes... args) -> void
|
||||
{
|
||||
Complete(MakeErrorCode(ErrorCode::OperationTimeout), args...);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_ASIOASYNCOP_H */
|
73
fairmq/sdk/AsioBase.h
Normal file
73
fairmq/sdk/AsioBase.h
Normal file
@@ -0,0 +1,73 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_ASIOBASE_H
|
||||
#define FAIR_MQ_SDK_ASIOBASE_H
|
||||
|
||||
#include <asio/any_io_executor.hpp>
|
||||
#include <fairmq/sdk/Traits.h>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
using DefaultExecutor = asio::any_io_executor;
|
||||
using DefaultAllocator = std::allocator<int>;
|
||||
|
||||
/**
|
||||
* @class AsioBase AsioBase.h <fairmq/sdk/AsioBase.h>
|
||||
* @tparam Executor Associated I/O executor
|
||||
* @tparam Allocator Associated default allocator
|
||||
* @brief Base for creating Asio-enabled I/O objects
|
||||
*
|
||||
* @par Thread Safety
|
||||
* @e Distinct @e objects: Safe.@n
|
||||
* @e Shared @e objects: Unsafe.
|
||||
*/
|
||||
template<typename Executor, typename Allocator>
|
||||
class AsioBase
|
||||
{
|
||||
public:
|
||||
/// Member type of associated I/O executor
|
||||
using ExecutorType = Executor;
|
||||
/// Get associated I/O executor
|
||||
auto GetExecutor() const noexcept -> ExecutorType { return fExecutor; }
|
||||
|
||||
/// Member type of associated default allocator
|
||||
using AllocatorType = Allocator;
|
||||
/// Get associated default allocator
|
||||
auto GetAllocator() const noexcept -> AllocatorType { return fAllocator; }
|
||||
|
||||
/// NO default ctor
|
||||
AsioBase() = delete;
|
||||
|
||||
/// Construct with associated I/O executor
|
||||
explicit AsioBase(Executor ex, Allocator alloc)
|
||||
: fExecutor(std::move(ex))
|
||||
, fAllocator(std::move(alloc))
|
||||
{}
|
||||
|
||||
/// NOT copyable
|
||||
AsioBase(const AsioBase&) = delete;
|
||||
AsioBase& operator=(const AsioBase&) = delete;
|
||||
|
||||
/// movable
|
||||
AsioBase(AsioBase&&) noexcept = default;
|
||||
AsioBase& operator=(AsioBase&&) noexcept = default;
|
||||
|
||||
~AsioBase() = default;
|
||||
|
||||
private:
|
||||
ExecutorType fExecutor;
|
||||
AllocatorType fAllocator;
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_ASIOBASE_H */
|
117
fairmq/sdk/CMakeLists.txt
Normal file
117
fairmq/sdk/CMakeLists.txt
Normal file
@@ -0,0 +1,117 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
if(BUILD_TIDY_TOOL)
|
||||
include(FairMQTidy)
|
||||
endif()
|
||||
|
||||
#################
|
||||
# libFairMQ_SDK #
|
||||
#################
|
||||
configure_file(DDSInfo.h.in ${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h @ONLY)
|
||||
|
||||
set(target SDK)
|
||||
|
||||
set(SDK_PUBLIC_HEADER_FILES
|
||||
../SDK.h
|
||||
AsioAsyncOp.h
|
||||
AsioBase.h
|
||||
DDSAgent.h
|
||||
DDSCollection.h
|
||||
DDSEnvironment.h
|
||||
DDSSession.h
|
||||
DDSTask.h
|
||||
DDSTopology.h
|
||||
Error.h
|
||||
Topology.h
|
||||
Traits.h
|
||||
)
|
||||
|
||||
set(SDK_PRIVATE_HEADER_FILES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h
|
||||
)
|
||||
|
||||
set(SDK_SOURCE_FILES
|
||||
DDSEnvironment.cxx
|
||||
DDSSession.cxx
|
||||
DDSTopology.cxx
|
||||
Topology.cxx
|
||||
)
|
||||
|
||||
add_library(${target}
|
||||
${SDK_SOURCE_FILES}
|
||||
${SDK_PUBLIC_HEADER_FILES} # for IDE integration
|
||||
${SDK_PRIVATE_HEADER_FILES} # for IDE integration
|
||||
)
|
||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||
set_target_properties(${target} PROPERTIES LABELS coverage)
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
asio::asio
|
||||
Boost::boost
|
||||
Boost::filesystem
|
||||
FairLogger::FairLogger
|
||||
Threads::Threads
|
||||
Tools
|
||||
StateMachine
|
||||
Commands
|
||||
|
||||
PRIVATE
|
||||
DDS::dds_intercom_lib
|
||||
DDS::dds_tools_lib
|
||||
DDS::dds_topology_lib
|
||||
)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
OUTPUT_NAME FairMQ_${target}
|
||||
)
|
||||
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
|
||||
fairmq_target_tidy(TARGET ${target})
|
||||
endif()
|
||||
|
||||
###############
|
||||
# executables #
|
||||
###############
|
||||
add_executable(fairmq-dds-command-ui ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||
target_link_libraries(fairmq-dds-command-ui
|
||||
FairMQ
|
||||
Commands
|
||||
SDK
|
||||
StateMachine
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
SDK
|
||||
fairmq-dds-command-ui
|
||||
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
# preserve relative path and prepend fairmq
|
||||
foreach(HEADER IN LISTS SDK_PUBLIC_HEADER_FILES)
|
||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/sdk/${_path} _destination)
|
||||
install(FILES ${HEADER}
|
||||
DESTINATION ${_destination}
|
||||
)
|
||||
endforeach()
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/DDSInfo.h
|
||||
DESTINATION ${PROJECT_INSTALL_INCDIR}/sdk
|
||||
)
|
78
fairmq/sdk/DDSAgent.h
Normal file
78
fairmq/sdk/DDSAgent.h
Normal file
@@ -0,0 +1,78 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSSAGENT_H
|
||||
#define FAIR_MQ_SDK_DDSSAGENT_H
|
||||
|
||||
#include <fairmq/sdk/DDSSession.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DDSAgent <fairmq/sdk/DDSAgent.h>
|
||||
* @brief Represents a DDS agent
|
||||
*/
|
||||
class DDSAgent
|
||||
{
|
||||
public:
|
||||
using Id = uint64_t;
|
||||
using Pid = uint32_t;
|
||||
|
||||
explicit DDSAgent(DDSSession session,
|
||||
Id id,
|
||||
Pid pid,
|
||||
std::string path,
|
||||
std::string host,
|
||||
std::chrono::milliseconds startupTime,
|
||||
std::string username)
|
||||
: fSession(std::move(session))
|
||||
, fId(id)
|
||||
, fPid(pid)
|
||||
, fDDSPath(std::move(path))
|
||||
, fHost(std::move(host))
|
||||
, fStartupTime(startupTime)
|
||||
, fUsername(std::move(username))
|
||||
{}
|
||||
|
||||
DDSSession GetSession() const { return fSession; }
|
||||
Id GetId() const { return fId; }
|
||||
Pid GetPid() const { return fPid; }
|
||||
std::string GetHost() const { return fHost; }
|
||||
std::string GetDDSPath() const { return fDDSPath; }
|
||||
std::chrono::milliseconds GetStartupTime() const { return fStartupTime; }
|
||||
std::string GetUsername() const { return fUsername; }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSAgent& agent) -> std::ostream&
|
||||
{
|
||||
return os << "DDSAgent id: " << agent.fId
|
||||
<< ", pid: " << agent.fPid
|
||||
<< ", path: " << agent.fDDSPath
|
||||
<< ", host: " << agent.fHost
|
||||
<< ", startupTime: " << agent.fStartupTime.count()
|
||||
<< ", username: " << agent.fUsername;
|
||||
}
|
||||
|
||||
private:
|
||||
DDSSession fSession;
|
||||
Id fId;
|
||||
Pid fPid;
|
||||
std::string fDDSPath;
|
||||
std::string fHost;
|
||||
std::chrono::milliseconds fStartupTime;
|
||||
std::string fUsername;
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSSAGENT_H */
|
46
fairmq/sdk/DDSCollection.h
Normal file
46
fairmq/sdk/DDSCollection.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSCOLLECTION_H
|
||||
#define FAIR_MQ_SDK_DDSCOLLECTION_H
|
||||
|
||||
// #include <fairmq/sdk/DDSAgent.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DDSCollection <fairmq/sdk/DDSCollection.h>
|
||||
* @brief Represents a DDS collection
|
||||
*/
|
||||
class DDSCollection
|
||||
{
|
||||
public:
|
||||
using Id = std::uint64_t;
|
||||
|
||||
explicit DDSCollection(Id id)
|
||||
: fId(id)
|
||||
{}
|
||||
|
||||
Id GetId() const { return fId; }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSCollection& collection) -> std::ostream&
|
||||
{
|
||||
return os << "DDSCollection id: " << collection.fId;
|
||||
}
|
||||
|
||||
private:
|
||||
Id fId;
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSCOLLECTION_H */
|
86
fairmq/sdk/DDSEnvironment.cxx
Normal file
86
fairmq/sdk/DDSEnvironment.cxx
Normal file
@@ -0,0 +1,86 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "DDSEnvironment.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <dds/dds.h>
|
||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/tools/InstanceLimit.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
struct DDSEnvironment::Impl
|
||||
{
|
||||
explicit Impl(Path configHome)
|
||||
: fLocation(DDSInstallPrefix)
|
||||
, fConfigHome(std::move(configHome))
|
||||
{
|
||||
SetupPath();
|
||||
SetupConfigHome();
|
||||
}
|
||||
|
||||
auto SetupConfigHome() -> void
|
||||
{
|
||||
if (fConfigHome.empty()) {
|
||||
fConfigHome = GetEnv("HOME");
|
||||
} else {
|
||||
setenv("HOME", fConfigHome.c_str(), 1);
|
||||
}
|
||||
}
|
||||
|
||||
auto SetupPath() -> void
|
||||
{
|
||||
std::string path(GetEnv("PATH"));
|
||||
Path ddsExecDir = (fLocation == DDSInstallPrefix) ? DDSExecutableDir : fLocation / Path("bin");
|
||||
path = ddsExecDir.string() + std::string(":") + path;
|
||||
setenv("PATH", path.c_str(), 1);
|
||||
}
|
||||
|
||||
auto GetEnv(const std::string& key) const -> std::string
|
||||
{
|
||||
auto value = std::getenv(key.c_str());
|
||||
if (value) {
|
||||
return {value};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
struct Tag {};
|
||||
friend auto operator<<(std::ostream& os, Tag) -> std::ostream& { return os << "DDSEnvironment"; }
|
||||
tools::InstanceLimiter<Tag, 1> fCount;
|
||||
|
||||
Path fLocation;
|
||||
Path fConfigHome;
|
||||
};
|
||||
|
||||
DDSEnvironment::DDSEnvironment()
|
||||
: DDSEnvironment(Path())
|
||||
{}
|
||||
|
||||
DDSEnvironment::DDSEnvironment(Path configHome)
|
||||
: fImpl(std::make_shared<Impl>(std::move(configHome)))
|
||||
{}
|
||||
|
||||
auto DDSEnvironment::GetLocation() const -> Path { return fImpl->fLocation; }
|
||||
|
||||
auto DDSEnvironment::GetConfigHome() const -> Path { return fImpl->fConfigHome; }
|
||||
|
||||
auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&
|
||||
{
|
||||
return os << "$DDS_LOCATION: " << env.GetLocation() << ", "
|
||||
<< "$DDS_CONFIG_HOME: " << env.GetConfigHome() / DDSEnvironment::Path(".DDS");
|
||||
}
|
||||
|
||||
} // namespace fair::mq::sdk
|
44
fairmq/sdk/DDSEnvironment.h
Normal file
44
fairmq/sdk/DDSEnvironment.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSENVIRONMENT_H
|
||||
#define FAIR_MQ_SDK_DDSENVIRONMENT_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DDSEnvironment DDSSession.h <fairmq/sdk/DDSSession.h>
|
||||
* @brief Sets up the DDS environment (object helper)
|
||||
*/
|
||||
class DDSEnvironment
|
||||
{
|
||||
public:
|
||||
using Path = boost::filesystem::path;
|
||||
|
||||
DDSEnvironment();
|
||||
explicit DDSEnvironment(Path);
|
||||
|
||||
auto GetLocation() const -> Path;
|
||||
auto GetConfigHome() const -> Path;
|
||||
|
||||
friend auto operator<<(std::ostream& os, DDSEnvironment env) -> std::ostream&;
|
||||
private:
|
||||
struct Impl;
|
||||
std::shared_ptr<Impl> fImpl;
|
||||
};
|
||||
|
||||
using DDSEnv = DDSEnvironment;
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSENVIRONMENT_H */
|
29
fairmq/sdk/DDSInfo.h.in
Normal file
29
fairmq/sdk/DDSInfo.h.in
Normal file
@@ -0,0 +1,29 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSINFO_H
|
||||
#define FAIR_MQ_SDK_DDSINFO_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace dds::tools_api { class CSession; }
|
||||
namespace dds::topology_api { class CTopology; }
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
const std::string DDSVersion("@DDS_VERSION@");
|
||||
const std::string DDSInstallPrefix("@DDS_INSTALL_PREFIX@");
|
||||
const std::string DDSExecutableDir("@DDS_BINDIR@");
|
||||
const std::string DDSIncludeDir("@DDS_INCDIR@");
|
||||
const std::string DDSLibraryDir("@DDS_LIBDIR@");
|
||||
const std::string DDSPluginDir("@DDS_PLUGINDIR@");
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSINFO_H */
|
389
fairmq/sdk/DDSSession.cxx
Normal file
389
fairmq/sdk/DDSSession.cxx
Normal file
@@ -0,0 +1,389 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "DDSSession.h"
|
||||
|
||||
#include <boost/process.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <dds/dds.h>
|
||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/sdk/DDSAgent.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSTopology.h>
|
||||
#include <fairmq/tools/Semaphore.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
auto operator<<(std::ostream& os, DDSRMSPlugin plugin) -> std::ostream&
|
||||
{
|
||||
switch (plugin) {
|
||||
case DDSRMSPlugin::ssh:
|
||||
return os << "ssh";
|
||||
case DDSRMSPlugin::localhost:
|
||||
return os << "localhost";
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
auto operator>>(std::istream& is, DDSRMSPlugin& plugin) -> std::istream&
|
||||
{
|
||||
std::string value;
|
||||
if (is >> value) {
|
||||
if (value == "ssh") {
|
||||
plugin = DDSRMSPlugin::ssh;
|
||||
} else if (value == "localhost") {
|
||||
plugin = DDSRMSPlugin::localhost;
|
||||
} else {
|
||||
throw std::runtime_error("Unknown or unsupported DDSRMSPlugin");
|
||||
}
|
||||
}
|
||||
return is;
|
||||
}
|
||||
|
||||
struct DDSSession::Impl
|
||||
{
|
||||
explicit Impl(DDSEnvironment env)
|
||||
: fEnv(std::move(env))
|
||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
||||
, fSession(std::make_shared<dds::tools_api::CSession>())
|
||||
, fDDSCustomCmd(fDDSService)
|
||||
, fId(to_string(fSession->create()))
|
||||
, fStopOnDestruction(false)
|
||||
{
|
||||
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
||||
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
explicit Impl(Id existing, DDSEnvironment env)
|
||||
: fEnv(std::move(env))
|
||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
||||
, fSession(std::make_shared<dds::tools_api::CSession>())
|
||||
, fDDSCustomCmd(fDDSService)
|
||||
, fId(std::move(existing))
|
||||
, fStopOnDestruction(false)
|
||||
{
|
||||
fSession->attach(fId);
|
||||
|
||||
fDDSService.subscribeOnError([](const dds::intercom_api::EErrorCode errorCode, const std::string& msg) {
|
||||
std::cerr << "DDS error, error code: " << errorCode << ", error message: " << msg << std::endl;
|
||||
});
|
||||
}
|
||||
|
||||
explicit Impl(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env)
|
||||
: fEnv(std::move(env))
|
||||
, fRMSPlugin(DDSRMSPlugin::localhost)
|
||||
, fSession(std::move(nativeSession))
|
||||
, fDDSCustomCmd(fDDSService)
|
||||
, fId(to_string(fSession->getSessionID()))
|
||||
, fStopOnDestruction(false)
|
||||
{
|
||||
// Sanity check
|
||||
if (!fSession->IsRunning()) {
|
||||
throw std::runtime_error("Given CSession must be running");
|
||||
}
|
||||
}
|
||||
|
||||
~Impl()
|
||||
{
|
||||
if (fStopOnDestruction) {
|
||||
fSession->shutdown();
|
||||
}
|
||||
}
|
||||
|
||||
Impl() = delete;
|
||||
Impl(const Impl&) = delete;
|
||||
Impl& operator=(const Impl&) = delete;
|
||||
Impl(Impl&&) = delete;
|
||||
Impl& operator=(Impl&&) = delete;
|
||||
|
||||
DDSEnvironment fEnv;
|
||||
DDSRMSPlugin fRMSPlugin;
|
||||
Path fRMSConfig;
|
||||
std::shared_ptr<dds::tools_api::CSession> fSession;
|
||||
dds::intercom_api::CIntercomService fDDSService;
|
||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
||||
Id fId;
|
||||
bool fStopOnDestruction;
|
||||
};
|
||||
|
||||
DDSSession::DDSSession(DDSEnvironment env)
|
||||
: fImpl(std::make_shared<Impl>(std::move(env)))
|
||||
{}
|
||||
|
||||
DDSSession::DDSSession(Id existing, DDSEnvironment env)
|
||||
: fImpl(std::make_shared<Impl>(std::move(existing), std::move(env)))
|
||||
{}
|
||||
|
||||
DDSSession::DDSSession(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env)
|
||||
: fImpl(std::make_shared<Impl>(std::move(nativeSession), std::move(env)))
|
||||
{}
|
||||
|
||||
auto DDSSession::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
||||
|
||||
auto DDSSession::IsRunning() const -> bool { return fImpl->fSession->IsRunning(); }
|
||||
|
||||
auto DDSSession::GetId() const -> Id { return fImpl->fId; }
|
||||
|
||||
auto DDSSession::Stop() -> void { return fImpl->fSession->shutdown(); }
|
||||
|
||||
auto DDSSession::GetRMSPlugin() const -> DDSRMSPlugin { return fImpl->fRMSPlugin; }
|
||||
|
||||
auto DDSSession::SetRMSPlugin(DDSRMSPlugin plugin) -> void { fImpl->fRMSPlugin = plugin; }
|
||||
|
||||
auto DDSSession::GetRMSConfig() const -> Path { return fImpl->fRMSConfig; }
|
||||
|
||||
auto DDSSession::SetRMSConfig(Path configFile) const -> void
|
||||
{
|
||||
fImpl->fRMSConfig = std::move(configFile);
|
||||
}
|
||||
|
||||
auto DDSSession::IsStoppedOnDestruction() const -> bool { return fImpl->fStopOnDestruction; }
|
||||
|
||||
auto DDSSession::StopOnDestruction(bool stop) -> void { fImpl->fStopOnDestruction = stop; }
|
||||
|
||||
auto DDSSession::SubmitAgents(Quantity agents) -> void
|
||||
{
|
||||
// Requesting to submit 0 agents is not meaningful
|
||||
assert(agents > 0);
|
||||
|
||||
using namespace dds::tools_api;
|
||||
|
||||
SSubmitRequestData submitInfo;
|
||||
submitInfo.m_rms = tools::ToString(GetRMSPlugin());
|
||||
submitInfo.m_instances = 1;
|
||||
submitInfo.m_slots = agents; // TODO new api: get slots from agents
|
||||
submitInfo.m_config = GetRMSConfig().string();
|
||||
|
||||
tools::SharedSemaphore blocker;
|
||||
auto submitRequest = SSubmitRequest::makeRequest(submitInfo);
|
||||
submitRequest->setMessageCallback([](const SMessageResponseData& message){
|
||||
LOG(debug) << message.m_msg;
|
||||
});
|
||||
submitRequest->setDoneCallback([agents, blocker]() mutable {
|
||||
LOG(debug) << agents << " Agents submitted";
|
||||
blocker.Signal();
|
||||
});
|
||||
|
||||
fImpl->fSession->sendRequest<SSubmitRequest>(submitRequest);
|
||||
blocker.Wait();
|
||||
|
||||
WaitForIdleAgents(agents);
|
||||
}
|
||||
|
||||
auto DDSSession::RequestAgentCount() -> AgentCount
|
||||
{
|
||||
using namespace dds::tools_api;
|
||||
|
||||
SAgentCountRequest::response_t res;
|
||||
fImpl->fSession->syncSendRequest<SAgentCountRequest>(SAgentCountRequest::request_t(), res);
|
||||
|
||||
AgentCount count;
|
||||
count.active = res.m_activeSlotsCount;
|
||||
count.idle = res.m_idleSlotsCount;
|
||||
count.executing = res.m_executingSlotsCount;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
auto DDSSession::RequestAgentInfo() -> std::vector<DDSAgent>
|
||||
{
|
||||
using namespace dds::tools_api;
|
||||
|
||||
SAgentInfoRequest::responseVector_t res;
|
||||
fImpl->fSession->syncSendRequest<SAgentInfoRequest>(SAgentInfoRequest::request_t(), res);
|
||||
|
||||
std::vector<DDSAgent> agentInfo;
|
||||
agentInfo.reserve(res.size());
|
||||
for (const auto& a : res) {
|
||||
agentInfo.emplace_back(
|
||||
*this,
|
||||
a.m_agentID,
|
||||
a.m_agentPid,
|
||||
a.m_DDSPath,
|
||||
a.m_host,
|
||||
a.m_startUpTime,
|
||||
a.m_username
|
||||
// a.m_nSlots
|
||||
);
|
||||
}
|
||||
|
||||
return agentInfo;
|
||||
}
|
||||
|
||||
auto DDSSession::RequestTaskInfo() -> std::vector<DDSTask>
|
||||
{
|
||||
using namespace dds::tools_api;
|
||||
|
||||
SAgentInfoRequest::responseVector_t res;
|
||||
fImpl->fSession->syncSendRequest<SAgentInfoRequest>(SAgentInfoRequest::request_t(), res);
|
||||
|
||||
std::vector<DDSTask> taskInfo;
|
||||
taskInfo.reserve(res.size());
|
||||
for (auto& a : res) {
|
||||
//taskInfo.emplace_back(a.m_taskID, 0);
|
||||
(void)a;
|
||||
taskInfo.emplace_back(0, 0);
|
||||
}
|
||||
|
||||
return taskInfo;
|
||||
}
|
||||
|
||||
auto DDSSession::RequestCommanderInfo() -> CommanderInfo
|
||||
{
|
||||
using namespace dds::tools_api;
|
||||
|
||||
SCommanderInfoRequestData commanderInfo;
|
||||
tools::SharedSemaphore blocker;
|
||||
std::string error;
|
||||
auto commanderInfoRequest = SCommanderInfoRequest::makeRequest(commanderInfo);
|
||||
CommanderInfo info;
|
||||
commanderInfoRequest->setResponseCallback([&info](const SCommanderInfoResponseData& _response) {
|
||||
info.pid = _response.m_pid;
|
||||
info.activeTopologyName = _response.m_activeTopologyName;
|
||||
});
|
||||
commanderInfoRequest->setMessageCallback([&](const SMessageResponseData& _message) {
|
||||
if (_message.m_severity == dds::intercom_api::EMsgSeverity::error) {
|
||||
error = _message.m_msg;
|
||||
blocker.Signal();
|
||||
} else {
|
||||
LOG(debug) << _message.m_msg;
|
||||
}
|
||||
});
|
||||
commanderInfoRequest->setDoneCallback([blocker]() mutable { blocker.Signal(); });
|
||||
fImpl->fSession->sendRequest<SCommanderInfoRequest>(commanderInfoRequest);
|
||||
blocker.Wait();
|
||||
|
||||
if (!error.empty()) {
|
||||
throw std::runtime_error(error);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
auto DDSSession::WaitForExecutingAgents(Quantity minCount) -> void
|
||||
{
|
||||
auto count(RequestAgentCount());
|
||||
int interval(8);
|
||||
while (count.executing < minCount) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
|
||||
interval = std::min(256, interval * 2);
|
||||
count = RequestAgentCount();
|
||||
}
|
||||
}
|
||||
|
||||
auto DDSSession::WaitForIdleAgents(Quantity minCount) -> void
|
||||
{
|
||||
auto count(RequestAgentCount());
|
||||
int interval(8);
|
||||
while (count.idle < minCount) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(interval));
|
||||
interval = std::min(256, interval * 2);
|
||||
count = RequestAgentCount();
|
||||
}
|
||||
}
|
||||
|
||||
auto DDSSession::ActivateTopology(DDSTopology topo) -> void
|
||||
{
|
||||
using namespace dds::tools_api;
|
||||
|
||||
STopologyRequestData topologyInfo;
|
||||
topologyInfo.m_updateType = STopologyRequestData::EUpdateType::ACTIVATE;
|
||||
topologyInfo.m_topologyFile = topo.GetTopoFile().string();
|
||||
|
||||
tools::SharedSemaphore blocker;
|
||||
auto topologyRequest = STopologyRequest::makeRequest(topologyInfo);
|
||||
topologyRequest->setMessageCallback([](const SMessageResponseData& _message) {
|
||||
LOG(debug) << _message.m_msg;
|
||||
});
|
||||
topologyRequest->setDoneCallback([blocker]() mutable { blocker.Signal(); });
|
||||
fImpl->fSession->sendRequest<STopologyRequest>(topologyRequest);
|
||||
blocker.Wait();
|
||||
|
||||
WaitForExecutingAgents(topo.GetNumRequiredAgents());
|
||||
}
|
||||
|
||||
auto DDSSession::ActivateTopology(const Path& topoFile) -> void
|
||||
{
|
||||
ActivateTopology(DDSTopology(topoFile, GetEnv()));
|
||||
}
|
||||
|
||||
void DDSSession::StartDDSService() { fImpl->fDDSService.start(fImpl->fId); }
|
||||
|
||||
void DDSSession::SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)> cb)
|
||||
{
|
||||
fImpl->fDDSCustomCmd.subscribe(cb);
|
||||
// fImpl->fDDSCustomCmd.subscribeOnReply([](const std::string& reply) {
|
||||
// LOG(debug) << reply;
|
||||
// });
|
||||
}
|
||||
|
||||
void DDSSession::UnsubscribeFromCommands()
|
||||
{
|
||||
fImpl->fDDSCustomCmd.unsubscribe();
|
||||
}
|
||||
|
||||
void DDSSession::SendCommand(const std::string& cmd, const std::string& path /* = "" */) { fImpl->fDDSCustomCmd.send(cmd, path); }
|
||||
|
||||
void DDSSession::SendCommand(const std::string& cmd, DDSChannel::Id recipient)
|
||||
{
|
||||
fImpl->fDDSCustomCmd.send(cmd, std::to_string(recipient));
|
||||
}
|
||||
|
||||
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
||||
{
|
||||
return os << "$DDS_SESSION_ID: " << session.GetId();
|
||||
}
|
||||
|
||||
auto getMostRecentRunningDDSSession(DDSEnv env) -> DDSSession
|
||||
{
|
||||
boost::process::ipstream pipeStream;
|
||||
boost::process::child c("dds-session list all", boost::process::std_out > pipeStream);
|
||||
std::string lastLine;
|
||||
std::string currentLine;
|
||||
|
||||
while (pipeStream && std::getline(pipeStream, currentLine) && !currentLine.empty()) {
|
||||
lastLine = currentLine;
|
||||
}
|
||||
c.wait();
|
||||
std::string sessionId;
|
||||
|
||||
if (!lastLine.empty()) {
|
||||
std::vector<std::string> words;
|
||||
std::istringstream iss(lastLine);
|
||||
for (std::string s; iss >> s;) {
|
||||
if (s != "*") {
|
||||
words.push_back(s);
|
||||
}
|
||||
}
|
||||
if (words.back() == "RUNNING") {
|
||||
sessionId = words.front();
|
||||
}
|
||||
}
|
||||
|
||||
if (sessionId.empty()) {
|
||||
throw std::runtime_error("could not find most recent DDS session");
|
||||
}
|
||||
|
||||
return DDSSession(DDSSession::Id(sessionId), std::move(env));
|
||||
}
|
||||
|
||||
} // namespace fair::mq::sdk
|
118
fairmq/sdk/DDSSession.h
Normal file
118
fairmq/sdk/DDSSession.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSSESSION_H
|
||||
#define FAIR_MQ_SDK_DDSSESSION_H
|
||||
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
|
||||
#include <cstdint>
|
||||
#include <istream>
|
||||
#include <memory>
|
||||
#include <ostream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @enum DDSRMSPlugin DDSSession.h <fairmq/sdk/DDSSession.h>
|
||||
* @brief Supported DDS resource management system plugins
|
||||
*/
|
||||
enum class DDSRMSPlugin
|
||||
{
|
||||
localhost,
|
||||
ssh
|
||||
};
|
||||
auto operator<<(std::ostream& os, DDSRMSPlugin plugin) -> std::ostream&;
|
||||
auto operator>>(std::istream& is, DDSRMSPlugin& plugin) -> std::istream&;
|
||||
|
||||
class DDSTopology;
|
||||
class DDSAgent;
|
||||
|
||||
class DDSChannel
|
||||
{
|
||||
public:
|
||||
using Id = std::uint64_t;
|
||||
};
|
||||
|
||||
/**
|
||||
* @class DDSSession DDSSession.h <fairmq/sdk/DDSSession.h>
|
||||
* @brief Represents a DDS session
|
||||
*/
|
||||
class DDSSession
|
||||
{
|
||||
public:
|
||||
using Id = std::string;
|
||||
using Quantity = std::uint32_t;
|
||||
using Path = boost::filesystem::path;
|
||||
|
||||
explicit DDSSession(DDSEnvironment env = DDSEnvironment());
|
||||
explicit DDSSession(Id existing, DDSEnvironment env = DDSEnvironment());
|
||||
|
||||
/// @brief Construct with already existing native DDS API objects
|
||||
/// @param nativeSession Existing and initialized CSession (either via create() or attach())
|
||||
/// @param env Optional DDSEnv
|
||||
explicit DDSSession(std::shared_ptr<dds::tools_api::CSession> nativeSession, DDSEnv env = {});
|
||||
|
||||
auto GetEnv() const -> DDSEnvironment;
|
||||
auto GetId() const -> Id;
|
||||
auto GetRMSPlugin() const -> DDSRMSPlugin;
|
||||
auto SetRMSPlugin(DDSRMSPlugin) -> void;
|
||||
auto GetRMSConfig() const -> Path;
|
||||
auto SetRMSConfig(Path) const -> void;
|
||||
auto IsStoppedOnDestruction() const -> bool;
|
||||
auto StopOnDestruction(bool stop = true) -> void;
|
||||
auto IsRunning() const -> bool;
|
||||
auto SubmitAgents(Quantity agents) -> void;
|
||||
struct AgentCount {
|
||||
Quantity idle = 0;
|
||||
Quantity active = 0;
|
||||
Quantity executing = 0;
|
||||
};
|
||||
auto RequestAgentCount() -> AgentCount;
|
||||
auto RequestAgentInfo() -> std::vector<DDSAgent>;
|
||||
auto RequestTaskInfo() -> std::vector<DDSTask>;
|
||||
struct CommanderInfo {
|
||||
int pid = -1;
|
||||
std::string activeTopologyName;
|
||||
};
|
||||
auto RequestCommanderInfo() -> CommanderInfo;
|
||||
auto WaitForIdleAgents(Quantity) -> void;
|
||||
auto WaitForOnlyIdleAgents() -> void;
|
||||
auto WaitForExecutingAgents(Quantity) -> void;
|
||||
auto ActivateTopology(const Path& topoFile) -> void;
|
||||
auto ActivateTopology(DDSTopology) -> void;
|
||||
auto Stop() -> void;
|
||||
|
||||
void StartDDSService();
|
||||
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
||||
void UnsubscribeFromCommands();
|
||||
void SendCommand(const std::string&, const std::string& = "");
|
||||
void SendCommand(const std::string&, DDSChannel::Id);
|
||||
auto GetTaskId(DDSChannel::Id) const -> DDSTask::Id;
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::shared_ptr<Impl> fImpl;
|
||||
};
|
||||
|
||||
auto getMostRecentRunningDDSSession(DDSEnv env = {}) -> DDSSession;
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSSESSION_H */
|
49
fairmq/sdk/DDSTask.h
Normal file
49
fairmq/sdk/DDSTask.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSTASK_H
|
||||
#define FAIR_MQ_SDK_DDSTASK_H
|
||||
|
||||
#include <fairmq/sdk/DDSCollection.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <cstdint>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DDSTask <fairmq/sdk/DDSTask.h>
|
||||
* @brief Represents a DDS task
|
||||
*/
|
||||
class DDSTask
|
||||
{
|
||||
public:
|
||||
using Id = std::uint64_t;
|
||||
|
||||
explicit DDSTask(Id id, Id collectionId)
|
||||
: fId(id)
|
||||
, fCollectionId(collectionId)
|
||||
{}
|
||||
|
||||
Id GetId() const { return fId; }
|
||||
DDSCollection::Id GetCollectionId() const { return fCollectionId; }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const DDSTask& task) -> std::ostream&
|
||||
{
|
||||
return os << "DDSTask id: " << task.fId << ", collection id: " << task.fCollectionId;
|
||||
}
|
||||
|
||||
private:
|
||||
Id fId;
|
||||
DDSCollection::Id fCollectionId;
|
||||
};
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSTASK_H */
|
116
fairmq/sdk/DDSTopology.cxx
Normal file
116
fairmq/sdk/DDSTopology.cxx
Normal file
@@ -0,0 +1,116 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "DDSTopology.h"
|
||||
|
||||
#include <boost/range/iterator_range.hpp>
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <dds/dds.h>
|
||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <fairlogger/Logger.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
struct DDSTopology::Impl
|
||||
{
|
||||
explicit Impl(Path topoFile, DDSEnvironment env)
|
||||
: fEnv(std::move(env))
|
||||
, fTopoFile(std::move(topoFile))
|
||||
, fTopo(fTopoFile.string())
|
||||
{}
|
||||
|
||||
explicit Impl(dds::topology_api::CTopology nativeTopology, DDSEnvironment env)
|
||||
: fEnv(std::move(env))
|
||||
, fTopo(std::move(nativeTopology))
|
||||
{}
|
||||
|
||||
DDSEnvironment fEnv;
|
||||
Path fTopoFile;
|
||||
dds::topology_api::CTopology fTopo;
|
||||
};
|
||||
|
||||
DDSTopology::DDSTopology(Path topoFile, DDSEnvironment env)
|
||||
: fImpl(std::make_shared<Impl>(std::move(topoFile), std::move(env)))
|
||||
{}
|
||||
|
||||
DDSTopology::DDSTopology(dds::topology_api::CTopology nativeTopology, DDSEnv env)
|
||||
: fImpl(std::make_shared<Impl>(std::move(nativeTopology), std::move(env)))
|
||||
{}
|
||||
|
||||
auto DDSTopology::GetEnv() const -> DDSEnvironment { return fImpl->fEnv; }
|
||||
|
||||
auto DDSTopology::GetTopoFile() const -> Path
|
||||
{
|
||||
auto file(fImpl->fTopoFile);
|
||||
if (file.string().empty()) {
|
||||
throw std::runtime_error("DDS topology xml spec file unknown");
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
auto DDSTopology::GetNumRequiredAgents() const -> std::size_t
|
||||
{
|
||||
return fImpl->fTopo.getRequiredNofAgents();
|
||||
}
|
||||
|
||||
auto DDSTopology::GetTasks(const std::string& path /* = "" */) const -> std::vector<DDSTask>
|
||||
{
|
||||
std::vector<DDSTask> list;
|
||||
|
||||
dds::topology_api::STopoRuntimeTask::FilterIteratorPair_t itPair;
|
||||
if (path.empty()) {
|
||||
itPair = fImpl->fTopo.getRuntimeTaskIterator(nullptr); // passing nullptr will get all tasks
|
||||
} else {
|
||||
itPair = fImpl->fTopo.getRuntimeTaskIteratorMatchingPath(path);
|
||||
}
|
||||
auto tasks = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& task : tasks) {
|
||||
// LOG(debug) << "Found task with id: " << task.first << ", "
|
||||
// << "Path: " << task.second.m_taskPath << ", "
|
||||
// << "Collection id: " << task.second.m_taskCollectionId << ", "
|
||||
// << "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
||||
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
auto DDSTopology::GetCollections() const -> std::vector<DDSCollection>
|
||||
{
|
||||
std::vector<DDSCollection> list;
|
||||
|
||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(nullptr); // passing nullptr will get all collections
|
||||
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
||||
|
||||
for (const auto& c : collections) {
|
||||
LOG(debug) << "Found collection with id: " << c.first << ", "
|
||||
<< "Index: " << c.second.m_collectionIndex << ", "
|
||||
<< "Path: " << c.second.m_collectionPath;
|
||||
list.emplace_back(c.first);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
auto DDSTopology::GetName() const -> std::string { return fImpl->fTopo.getName(); }
|
||||
|
||||
auto operator<<(std::ostream& os, const DDSTopology& t) -> std::ostream&
|
||||
try {
|
||||
return os << "DDS topology: " << t.GetName() << " (loaded from " << t.GetTopoFile() << ")";
|
||||
} catch (std::runtime_error&) {
|
||||
return os << "DDS topology: " << t.GetName();
|
||||
}
|
||||
|
||||
} // namespace fair::mq::sdk
|
75
fairmq/sdk/DDSTopology.h
Normal file
75
fairmq/sdk/DDSTopology.h
Normal file
@@ -0,0 +1,75 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_DDSTOPOLOGY_H
|
||||
#define FAIR_MQ_SDK_DDSTOPOLOGY_H
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <fairmq/sdk/DDSCollection.h>
|
||||
#include <fairmq/sdk/DDSEnvironment.h>
|
||||
#include <fairmq/sdk/DDSInfo.h>
|
||||
#include <fairmq/sdk/DDSTask.h>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DDSTopology DDSTopology.h <fairmq/sdk/DDSTopology.h>
|
||||
* @brief Represents a DDS topology
|
||||
*/
|
||||
class DDSTopology
|
||||
{
|
||||
public:
|
||||
using Path = boost::filesystem::path;
|
||||
|
||||
DDSTopology() = delete;
|
||||
|
||||
/// @brief Construct from file
|
||||
/// @param topoFile DDS topology xml file
|
||||
/// @param env DDS environment
|
||||
explicit DDSTopology(Path topoFile, DDSEnvironment env = DDSEnvironment());
|
||||
|
||||
/// @brief Construct with already existing native DDS API objects
|
||||
/// @param nativeTopology Existing and initialized CTopology
|
||||
/// @param env Optional DDSEnv
|
||||
explicit DDSTopology(dds::topology_api::CTopology nativeTopology, DDSEnv env = {});
|
||||
|
||||
/// @brief Get associated DDS environment
|
||||
auto GetEnv() const -> DDSEnvironment;
|
||||
|
||||
/// @brief Get path to DDS topology xml, if it is known
|
||||
/// @throw std::runtime_error
|
||||
auto GetTopoFile() const -> Path;
|
||||
|
||||
/// @brief Get number of required agents for this topology
|
||||
auto GetNumRequiredAgents() const -> std::size_t;
|
||||
|
||||
/// @brief Get list of tasks in this topology, optionally matching provided path
|
||||
auto GetTasks(const std::string& = "") const -> std::vector<DDSTask>;
|
||||
|
||||
/// @brief Get list of tasks in this topology
|
||||
auto GetCollections() const -> std::vector<DDSCollection>;
|
||||
|
||||
/// @brief Get the name of the topology
|
||||
auto GetName() const -> std::string;
|
||||
|
||||
friend auto operator<<(std::ostream&, const DDSTopology&) -> std::ostream&;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
std::shared_ptr<Impl> fImpl;
|
||||
};
|
||||
|
||||
using DDSTopo = DDSTopology;
|
||||
|
||||
} // namespace fair::mq::sdk
|
||||
|
||||
#endif /* FAIR_MQ_SDK_DDSTOPOLOGY_H */
|
20
fairmq/sdk/Error.h
Normal file
20
fairmq/sdk/Error.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_ERROR_H
|
||||
#define FAIR_MQ_SDK_ERROR_H
|
||||
|
||||
#include <fairmq/Error.h>
|
||||
|
||||
namespace fair::mq::sdk {
|
||||
|
||||
using RuntimeError = fair::mq::RuntimeError;
|
||||
|
||||
} /* namespace fair::mq::sdk */
|
||||
|
||||
#endif /* FAIR_MQ_SDK_ERROR_H */
|
31
fairmq/sdk/Topology.cxx
Normal file
31
fairmq/sdk/Topology.cxx
Normal file
@@ -0,0 +1,31 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Topology.h"
|
||||
|
||||
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
#include <dds/dds.h>
|
||||
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
|
||||
/// @brief Helper to (Re)Construct a FairMQ topology based on already existing native DDS API objects
|
||||
/// @param nativeSession Existing and initialized CSession (either via create() or attach())
|
||||
/// @param nativeTopo Existing CTopology that is activated on the given nativeSession
|
||||
/// @param env Optional DDSEnv (needed primarily for unit testing)
|
||||
/// @param blockUntilConnected if true, ctor will wait for all tasks to confirm subscriptions
|
||||
auto MakeTopology(dds::topology_api::CTopology nativeTopo,
|
||||
std::shared_ptr<dds::tools_api::CSession> nativeSession,
|
||||
DDSEnv env,
|
||||
bool blockUntilConnected) -> Topology
|
||||
{
|
||||
return {DDSTopo(std::move(nativeTopo), env), DDSSession(std::move(nativeSession), env), blockUntilConnected};
|
||||
}
|
||||
|
||||
} // namespace fair::mq::sdk
|
1367
fairmq/sdk/Topology.h
Normal file
1367
fairmq/sdk/Topology.h
Normal file
File diff suppressed because it is too large
Load Diff
48
fairmq/sdk/Traits.h
Normal file
48
fairmq/sdk/Traits.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_TRAITS_H
|
||||
#define FAIR_MQ_SDK_TRAITS_H
|
||||
|
||||
#include <asio/associated_allocator.hpp>
|
||||
#include <asio/associated_executor.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace asio::detail {
|
||||
|
||||
/// Specialize to match our coding conventions
|
||||
template<typename T, typename Executor>
|
||||
struct associated_executor_impl<T,
|
||||
Executor,
|
||||
std::enable_if_t<is_executor<typename T::ExecutorType>::value>>
|
||||
{
|
||||
using type = typename T::ExecutorType;
|
||||
|
||||
static auto get(const T& obj, const Executor& /*ex = Executor()*/) noexcept -> type
|
||||
{
|
||||
return obj.GetExecutor();
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialize to match our coding conventions
|
||||
template<typename T, typename Allocator>
|
||||
struct associated_allocator_impl<T,
|
||||
Allocator,
|
||||
std::enable_if_t<T::AllocatorType>>
|
||||
{
|
||||
using type = typename T::AllocatorType;
|
||||
|
||||
static auto get(const T& obj, const Allocator& /*alloc = Allocator()*/) noexcept -> type
|
||||
{
|
||||
return obj.GetAllocator();
|
||||
}
|
||||
};
|
||||
|
||||
} /* namespace asio::detail */
|
||||
|
||||
#endif /* FAIR_MQ_SDK_TRAITS_H */
|
60
fairmq/sdk/commands/CMakeLists.txt
Normal file
60
fairmq/sdk/commands/CMakeLists.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set(target Commands)
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
||||
COMMAND $<TARGET_FILE:flatbuffers::flatc> -c -o ${CMAKE_CURRENT_BINARY_DIR} CommandsFormat.fbs
|
||||
COMMAND ${CMAKE_COMMAND} -E rename ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat_generated.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
# JSON serialization needs to see the .fbs file at run time, save it as constexpr string instead of locating/opening it every time
|
||||
file(STRINGS CommandsFormat.fbs tmp)
|
||||
list(JOIN tmp "\n" commands_format_def_fbs)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/CommandsFormatDef.h.in ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
||||
|
||||
add_library(${target} Commands.cxx Commands.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormat.h ${CMAKE_CURRENT_BINARY_DIR}/CommandsFormatDef.h)
|
||||
add_library(FairMQ::${target} ALIAS ${target})
|
||||
|
||||
set(_flatbuffers flatbuffers::flatbuffers_shared)
|
||||
if(NOT TARGET flatbuffers::flatbuffers_shared AND TARGET flatbuffers::flatbuffers)
|
||||
set(_flatbuffers flatbuffers::flatbuffers)
|
||||
endif()
|
||||
|
||||
target_link_libraries(${target}
|
||||
PUBLIC
|
||||
StateMachine
|
||||
Tools
|
||||
|
||||
PRIVATE
|
||||
${_flatbuffers}
|
||||
)
|
||||
target_compile_features(${target} PUBLIC cxx_std_17)
|
||||
set_target_properties(${target} PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
OUTPUT_NAME FairMQ${target}
|
||||
)
|
||||
|
||||
target_include_directories(${target}
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS ${target}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
install(FILES Commands.h
|
||||
DESTINATION ${PROJECT_INSTALL_INCDIR}/sdk/commands
|
||||
)
|
479
fairmq/sdk/commands/Commands.cxx
Normal file
479
fairmq/sdk/commands/Commands.cxx
Normal file
@@ -0,0 +1,479 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "Commands.h"
|
||||
|
||||
#include <fairmq/sdk/commands/CommandsFormatDef.h>
|
||||
#include <fairmq/sdk/commands/CommandsFormat.h>
|
||||
|
||||
#include <flatbuffers/idl.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace fair::mq::sdk::cmd
|
||||
{
|
||||
|
||||
array<Result, 2> fbResultToResult =
|
||||
{
|
||||
{
|
||||
Result::Ok,
|
||||
Result::Failure
|
||||
}
|
||||
};
|
||||
|
||||
array<FBResult, 2> resultToFBResult =
|
||||
{
|
||||
{
|
||||
FBResult::FBResult_Ok,
|
||||
FBResult::FBResult_Failure
|
||||
}
|
||||
};
|
||||
|
||||
array<string, 2> resultNames =
|
||||
{
|
||||
{
|
||||
"Ok",
|
||||
"Failure"
|
||||
}
|
||||
};
|
||||
|
||||
array<string, 17> typeNames =
|
||||
{
|
||||
{
|
||||
"CheckState",
|
||||
"ChangeState",
|
||||
"DumpConfig",
|
||||
"SubscribeToStateChange",
|
||||
"UnsubscribeFromStateChange",
|
||||
"StateChangeExitingReceived",
|
||||
"GetProperties",
|
||||
"SetProperties",
|
||||
"SubscriptionHeartbeat",
|
||||
|
||||
"CurrentState",
|
||||
"TransitionStatus",
|
||||
"Config",
|
||||
"StateChangeSubscription",
|
||||
"StateChangeUnsubscription",
|
||||
"StateChange",
|
||||
"Properties",
|
||||
"PropertiesSet"
|
||||
}
|
||||
};
|
||||
|
||||
array<fair::mq::State, 16> fbStateToMQState =
|
||||
{
|
||||
{
|
||||
fair::mq::State::Undefined,
|
||||
fair::mq::State::Ok,
|
||||
fair::mq::State::Error,
|
||||
fair::mq::State::Idle,
|
||||
fair::mq::State::InitializingDevice,
|
||||
fair::mq::State::Initialized,
|
||||
fair::mq::State::Binding,
|
||||
fair::mq::State::Bound,
|
||||
fair::mq::State::Connecting,
|
||||
fair::mq::State::DeviceReady,
|
||||
fair::mq::State::InitializingTask,
|
||||
fair::mq::State::Ready,
|
||||
fair::mq::State::Running,
|
||||
fair::mq::State::ResettingTask,
|
||||
fair::mq::State::ResettingDevice,
|
||||
fair::mq::State::Exiting
|
||||
}
|
||||
};
|
||||
|
||||
array<sdk::cmd::FBState, 16> mqStateToFBState =
|
||||
{
|
||||
{
|
||||
sdk::cmd::FBState_Undefined,
|
||||
sdk::cmd::FBState_Ok,
|
||||
sdk::cmd::FBState_Error,
|
||||
sdk::cmd::FBState_Idle,
|
||||
sdk::cmd::FBState_InitializingDevice,
|
||||
sdk::cmd::FBState_Initialized,
|
||||
sdk::cmd::FBState_Binding,
|
||||
sdk::cmd::FBState_Bound,
|
||||
sdk::cmd::FBState_Connecting,
|
||||
sdk::cmd::FBState_DeviceReady,
|
||||
sdk::cmd::FBState_InitializingTask,
|
||||
sdk::cmd::FBState_Ready,
|
||||
sdk::cmd::FBState_Running,
|
||||
sdk::cmd::FBState_ResettingTask,
|
||||
sdk::cmd::FBState_ResettingDevice,
|
||||
sdk::cmd::FBState_Exiting
|
||||
}
|
||||
};
|
||||
|
||||
array<fair::mq::Transition, 12> fbTransitionToMQTransition =
|
||||
{
|
||||
{
|
||||
fair::mq::Transition::Auto,
|
||||
fair::mq::Transition::InitDevice,
|
||||
fair::mq::Transition::CompleteInit,
|
||||
fair::mq::Transition::Bind,
|
||||
fair::mq::Transition::Connect,
|
||||
fair::mq::Transition::InitTask,
|
||||
fair::mq::Transition::Run,
|
||||
fair::mq::Transition::Stop,
|
||||
fair::mq::Transition::ResetTask,
|
||||
fair::mq::Transition::ResetDevice,
|
||||
fair::mq::Transition::End,
|
||||
fair::mq::Transition::ErrorFound
|
||||
}
|
||||
};
|
||||
|
||||
array<sdk::cmd::FBTransition, 12> mqTransitionToFBTransition =
|
||||
{
|
||||
{
|
||||
sdk::cmd::FBTransition_Auto,
|
||||
sdk::cmd::FBTransition_InitDevice,
|
||||
sdk::cmd::FBTransition_CompleteInit,
|
||||
sdk::cmd::FBTransition_Bind,
|
||||
sdk::cmd::FBTransition_Connect,
|
||||
sdk::cmd::FBTransition_InitTask,
|
||||
sdk::cmd::FBTransition_Run,
|
||||
sdk::cmd::FBTransition_Stop,
|
||||
sdk::cmd::FBTransition_ResetTask,
|
||||
sdk::cmd::FBTransition_ResetDevice,
|
||||
sdk::cmd::FBTransition_End,
|
||||
sdk::cmd::FBTransition_ErrorFound
|
||||
}
|
||||
};
|
||||
|
||||
array<FBCmd, 17> typeToFBCmd =
|
||||
{
|
||||
{
|
||||
FBCmd::FBCmd_check_state,
|
||||
FBCmd::FBCmd_change_state,
|
||||
FBCmd::FBCmd_dump_config,
|
||||
FBCmd::FBCmd_subscribe_to_state_change,
|
||||
FBCmd::FBCmd_unsubscribe_from_state_change,
|
||||
FBCmd::FBCmd_state_change_exiting_received,
|
||||
FBCmd::FBCmd_get_properties,
|
||||
FBCmd::FBCmd_set_properties,
|
||||
FBCmd::FBCmd_subscription_heartbeat,
|
||||
FBCmd::FBCmd_current_state,
|
||||
FBCmd::FBCmd_transition_status,
|
||||
FBCmd::FBCmd_config,
|
||||
FBCmd::FBCmd_state_change_subscription,
|
||||
FBCmd::FBCmd_state_change_unsubscription,
|
||||
FBCmd::FBCmd_state_change,
|
||||
FBCmd::FBCmd_properties,
|
||||
FBCmd::FBCmd_properties_set
|
||||
}
|
||||
};
|
||||
|
||||
array<Type, 17> fbCmdToType =
|
||||
{
|
||||
{
|
||||
Type::check_state,
|
||||
Type::change_state,
|
||||
Type::dump_config,
|
||||
Type::subscribe_to_state_change,
|
||||
Type::unsubscribe_from_state_change,
|
||||
Type::state_change_exiting_received,
|
||||
Type::get_properties,
|
||||
Type::set_properties,
|
||||
Type::subscription_heartbeat,
|
||||
Type::current_state,
|
||||
Type::transition_status,
|
||||
Type::config,
|
||||
Type::state_change_subscription,
|
||||
Type::state_change_unsubscription,
|
||||
Type::state_change,
|
||||
Type::properties,
|
||||
Type::properties_set
|
||||
}
|
||||
};
|
||||
|
||||
fair::mq::State GetMQState(const FBState state) { return fbStateToMQState.at(state); }
|
||||
FBState GetFBState(const fair::mq::State state) { return mqStateToFBState.at(static_cast<int>(state)); }
|
||||
fair::mq::Transition GetMQTransition(const FBTransition transition) { return fbTransitionToMQTransition.at(transition); }
|
||||
FBTransition GetFBTransition(const fair::mq::Transition transition) { return mqTransitionToFBTransition.at(static_cast<int>(transition)); }
|
||||
|
||||
Result GetResult(const FBResult result) { return fbResultToResult.at(result); }
|
||||
FBResult GetFBResult(const Result result) { return resultToFBResult.at(static_cast<int>(result)); }
|
||||
string GetResultName(const Result result) { return resultNames.at(static_cast<int>(result)); }
|
||||
string GetTypeName(const Type type) { return typeNames.at(static_cast<int>(type)); }
|
||||
|
||||
FBCmd GetFBCmd(const Type type) { return typeToFBCmd.at(static_cast<int>(type)); }
|
||||
|
||||
string Cmds::Serialize(const Format type) const
|
||||
{
|
||||
flatbuffers::FlatBufferBuilder fbb;
|
||||
vector<flatbuffers::Offset<FBCommand>> commandOffsets;
|
||||
|
||||
for (auto& cmd : fCmds) {
|
||||
flatbuffers::Offset<FBCommand> cmdOffset;
|
||||
unique_ptr<FBCommandBuilder> cmdBuilder; // delay the creation of the builder, because child strings need to be constructed first (which are conditional)
|
||||
|
||||
switch (cmd->GetType()) {
|
||||
case Type::check_state: {
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::change_state: {
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_transition(GetFBTransition(static_cast<ChangeState&>(*cmd).GetTransition()));
|
||||
}
|
||||
break;
|
||||
case Type::dump_config: {
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case Type::subscribe_to_state_change: {
|
||||
auto _cmd = static_cast<SubscribeToStateChange&>(*cmd);
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_interval(_cmd.GetInterval());
|
||||
}
|
||||
break;
|
||||
case Type::unsubscribe_from_state_change: {
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::state_change_exiting_received: {
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
}
|
||||
break;
|
||||
case Type::get_properties: {
|
||||
auto _cmd = static_cast<GetProperties&>(*cmd);
|
||||
auto query = fbb.CreateString(_cmd.GetQuery());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
||||
cmdBuilder->add_property_query(query);
|
||||
}
|
||||
break;
|
||||
case Type::set_properties: {
|
||||
auto _cmd = static_cast<SetProperties&>(*cmd);
|
||||
std::vector<flatbuffers::Offset<FBProperty>> propsVector;
|
||||
for (auto const& e : _cmd.GetProps()) {
|
||||
auto const key(fbb.CreateString(e.first));
|
||||
auto const val(fbb.CreateString(e.second));
|
||||
propsVector.push_back(CreateFBProperty(fbb, key, val));
|
||||
}
|
||||
auto props = fbb.CreateVector(propsVector);
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
||||
cmdBuilder->add_properties(props);
|
||||
}
|
||||
break;
|
||||
case Type::subscription_heartbeat: {
|
||||
auto _cmd = static_cast<SubscriptionHeartbeat&>(*cmd);
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_interval(_cmd.GetInterval());
|
||||
}
|
||||
break;
|
||||
case Type::current_state: {
|
||||
auto _cmd = static_cast<CurrentState&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
||||
}
|
||||
break;
|
||||
case Type::transition_status: {
|
||||
auto _cmd = static_cast<TransitionStatus&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||
cmdBuilder->add_transition(GetFBTransition(_cmd.GetTransition()));
|
||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
||||
}
|
||||
break;
|
||||
case Type::config: {
|
||||
auto _cmd = static_cast<Config&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
auto config = fbb.CreateString(_cmd.GetConfig());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_config_string(config);
|
||||
}
|
||||
break;
|
||||
case Type::state_change_subscription: {
|
||||
auto _cmd = static_cast<StateChangeSubscription&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::state_change_unsubscription: {
|
||||
auto _cmd = static_cast<StateChangeUnsubscription&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||
}
|
||||
break;
|
||||
case Type::state_change: {
|
||||
auto _cmd = static_cast<StateChange&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||
cmdBuilder->add_last_state(GetFBState(_cmd.GetLastState()));
|
||||
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
||||
}
|
||||
break;
|
||||
case Type::properties: {
|
||||
auto _cmd = static_cast<Properties&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
|
||||
std::vector<flatbuffers::Offset<FBProperty>> propsVector;
|
||||
for (const auto& e : _cmd.GetProps()) {
|
||||
auto key = fbb.CreateString(e.first);
|
||||
auto val = fbb.CreateString(e.second);
|
||||
auto prop = CreateFBProperty(fbb, key, val);
|
||||
propsVector.push_back(prop);
|
||||
}
|
||||
auto props = fbb.CreateVector(propsVector);
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||
cmdBuilder->add_properties(props);
|
||||
}
|
||||
break;
|
||||
case Type::properties_set: {
|
||||
auto _cmd = static_cast<PropertiesSet&>(*cmd);
|
||||
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||
cmdBuilder = make_unique<FBCommandBuilder>(fbb);
|
||||
cmdBuilder->add_device_id(deviceId);
|
||||
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
||||
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Serialize()");
|
||||
break;
|
||||
}
|
||||
|
||||
cmdBuilder->add_command_id(typeToFBCmd.at(static_cast<int>(cmd->GetType())));
|
||||
|
||||
cmdOffset = cmdBuilder->Finish();
|
||||
commandOffsets.push_back(cmdOffset);
|
||||
}
|
||||
|
||||
auto commands = fbb.CreateVector(commandOffsets);
|
||||
auto cmds = CreateFBCommands(fbb, commands);
|
||||
fbb.Finish(cmds);
|
||||
|
||||
if (type == Format::Binary) {
|
||||
return string(reinterpret_cast<char*>(fbb.GetBufferPointer()), fbb.GetSize());
|
||||
} else { // Type == Format::JSON
|
||||
flatbuffers::Parser parser;
|
||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
||||
throw CommandFormatError("Serialize couldn't parse commands format");
|
||||
}
|
||||
std::string json;
|
||||
if (!flatbuffers::GenerateText(parser, fbb.GetBufferPointer(), &json)) {
|
||||
throw CommandFormatError("Serialize couldn't serialize parsed data to JSON!");
|
||||
}
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
void Cmds::Deserialize(const string& str, const Format type)
|
||||
{
|
||||
fCmds.clear();
|
||||
|
||||
const flatbuffers::Vector<flatbuffers::Offset<FBCommand>>* cmds = nullptr;
|
||||
|
||||
flatbuffers::Parser parser;
|
||||
if (type == Format::Binary) {
|
||||
cmds = cmd::GetFBCommands(const_cast<char*>(str.c_str()))->commands();
|
||||
} else { // Type == Format::JSON
|
||||
if (!parser.Parse(commandsFormatDefFbs)) {
|
||||
throw CommandFormatError("Deserialize couldn't parse commands format");
|
||||
}
|
||||
if (!parser.Parse(str.c_str())) {
|
||||
throw CommandFormatError("Deserialize couldn't parse incoming JSON string");
|
||||
}
|
||||
cmds = cmd::GetFBCommands(parser.builder_.GetBufferPointer())->commands();
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < cmds->size(); ++i) {
|
||||
const fair::mq::sdk::cmd::FBCommand& cmdPtr = *(cmds->Get(i));
|
||||
switch (cmdPtr.command_id()) {
|
||||
case FBCmd_check_state:
|
||||
fCmds.emplace_back(make<CheckState>());
|
||||
break;
|
||||
case FBCmd_change_state:
|
||||
fCmds.emplace_back(make<ChangeState>(GetMQTransition(cmdPtr.transition())));
|
||||
break;
|
||||
case FBCmd_dump_config:
|
||||
fCmds.emplace_back(make<DumpConfig>());
|
||||
break;
|
||||
case FBCmd_subscribe_to_state_change:
|
||||
fCmds.emplace_back(make<SubscribeToStateChange>(cmdPtr.interval()));
|
||||
break;
|
||||
case FBCmd_unsubscribe_from_state_change:
|
||||
fCmds.emplace_back(make<UnsubscribeFromStateChange>());
|
||||
break;
|
||||
case FBCmd_state_change_exiting_received:
|
||||
fCmds.emplace_back(make<StateChangeExitingReceived>());
|
||||
break;
|
||||
case FBCmd_get_properties:
|
||||
fCmds.emplace_back(make<GetProperties>(cmdPtr.request_id(), cmdPtr.property_query()->str()));
|
||||
break;
|
||||
case FBCmd_set_properties: {
|
||||
std::vector<std::pair<std::string, std::string>> properties;
|
||||
auto props = cmdPtr.properties();
|
||||
for (unsigned int j = 0; j < props->size(); ++j) {
|
||||
properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str());
|
||||
}
|
||||
fCmds.emplace_back(make<SetProperties>(cmdPtr.request_id(), properties));
|
||||
} break;
|
||||
case FBCmd_subscription_heartbeat:
|
||||
fCmds.emplace_back(make<SubscriptionHeartbeat>(cmdPtr.interval()));
|
||||
break;
|
||||
case FBCmd_current_state:
|
||||
fCmds.emplace_back(make<CurrentState>(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state())));
|
||||
break;
|
||||
case FBCmd_transition_status:
|
||||
fCmds.emplace_back(make<TransitionStatus>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition()), GetMQState(cmdPtr.current_state())));
|
||||
break;
|
||||
case FBCmd_config:
|
||||
fCmds.emplace_back(make<Config>(cmdPtr.device_id()->str(), cmdPtr.config_string()->str()));
|
||||
break;
|
||||
case FBCmd_state_change_subscription:
|
||||
fCmds.emplace_back(make<StateChangeSubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_state_change_unsubscription:
|
||||
fCmds.emplace_back(make<StateChangeUnsubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
case FBCmd_state_change:
|
||||
fCmds.emplace_back(make<StateChange>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state())));
|
||||
break;
|
||||
case FBCmd_properties: {
|
||||
std::vector<std::pair<std::string, std::string>> properties;
|
||||
auto props = cmdPtr.properties();
|
||||
for (unsigned int j = 0; j < props->size(); ++j) {
|
||||
properties.emplace_back(props->Get(j)->key()->str(), props->Get(j)->value()->str());
|
||||
}
|
||||
fCmds.emplace_back(make<Properties>(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result()), properties));
|
||||
} break;
|
||||
case FBCmd_properties_set:
|
||||
fCmds.emplace_back(make<PropertiesSet>(cmdPtr.device_id()->str(), cmdPtr.request_id(), GetResult(cmdPtr.result())));
|
||||
break;
|
||||
default:
|
||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace fair::mq::sdk::cmd
|
414
fairmq/sdk/commands/Commands.h
Normal file
414
fairmq/sdk/commands/Commands.h
Normal file
@@ -0,0 +1,414 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_SDK_COMMANDFACTORY
|
||||
#define FAIR_MQ_SDK_COMMANDFACTORY
|
||||
|
||||
#include <fairmq/States.h>
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <stdexcept>
|
||||
#include <utility> // move
|
||||
|
||||
namespace fair::mq::sdk::cmd
|
||||
{
|
||||
|
||||
enum class Format : int {
|
||||
Binary,
|
||||
JSON
|
||||
};
|
||||
|
||||
enum class Result : int {
|
||||
Ok,
|
||||
Failure
|
||||
};
|
||||
|
||||
enum class Type : int
|
||||
{
|
||||
check_state, // args: { }
|
||||
change_state, // args: { transition }
|
||||
dump_config, // args: { }
|
||||
subscribe_to_state_change, // args: { }
|
||||
unsubscribe_from_state_change, // args: { }
|
||||
state_change_exiting_received, // args: { }
|
||||
get_properties, // args: { request_id, property_query }
|
||||
set_properties, // args: { request_id, properties }
|
||||
subscription_heartbeat, // args: { interval }
|
||||
|
||||
current_state, // args: { device_id, current_state }
|
||||
transition_status, // args: { device_id, task_id, Result, transition, current_state }
|
||||
config, // args: { device_id, config_string }
|
||||
state_change_subscription, // args: { device_id, task_id, Result }
|
||||
state_change_unsubscription, // args: { device_id, task_id, Result }
|
||||
state_change, // args: { device_id, task_id, last_state, current_state }
|
||||
properties, // args: { device_id, request_id, Result, properties }
|
||||
properties_set // args: { device_id, request_id, Result }
|
||||
};
|
||||
|
||||
struct Cmd
|
||||
{
|
||||
explicit Cmd(const Type type) : fType(type) {}
|
||||
virtual ~Cmd() = default;
|
||||
|
||||
Type GetType() const { return fType; }
|
||||
|
||||
private:
|
||||
Type fType;
|
||||
};
|
||||
|
||||
struct CheckState : Cmd
|
||||
{
|
||||
explicit CheckState() : Cmd(Type::check_state) {}
|
||||
};
|
||||
|
||||
struct ChangeState : Cmd
|
||||
{
|
||||
explicit ChangeState(Transition transition)
|
||||
: Cmd(Type::change_state)
|
||||
, fTransition(transition)
|
||||
{}
|
||||
|
||||
Transition GetTransition() const { return fTransition; }
|
||||
void SetTransition(Transition transition) { fTransition = transition; }
|
||||
|
||||
private:
|
||||
Transition fTransition;
|
||||
};
|
||||
|
||||
struct DumpConfig : Cmd
|
||||
{
|
||||
explicit DumpConfig() : Cmd(Type::dump_config) {}
|
||||
};
|
||||
|
||||
struct SubscribeToStateChange : Cmd
|
||||
{
|
||||
explicit SubscribeToStateChange(int64_t interval)
|
||||
: Cmd(Type::subscribe_to_state_change)
|
||||
, fInterval(interval)
|
||||
{}
|
||||
|
||||
int64_t GetInterval() const { return fInterval; }
|
||||
void SetInterval(int64_t interval) { fInterval = interval; }
|
||||
|
||||
private:
|
||||
int64_t fInterval;
|
||||
};
|
||||
|
||||
struct UnsubscribeFromStateChange : Cmd
|
||||
{
|
||||
explicit UnsubscribeFromStateChange() : Cmd(Type::unsubscribe_from_state_change) {}
|
||||
};
|
||||
|
||||
struct StateChangeExitingReceived : Cmd
|
||||
{
|
||||
explicit StateChangeExitingReceived() : Cmd(Type::state_change_exiting_received) {}
|
||||
};
|
||||
|
||||
struct GetProperties : Cmd
|
||||
{
|
||||
GetProperties(std::size_t request_id, std::string query)
|
||||
: Cmd(Type::get_properties)
|
||||
, fRequestId(request_id)
|
||||
, fQuery(std::move(query))
|
||||
{}
|
||||
|
||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
||||
auto GetQuery() const -> std::string { return fQuery; }
|
||||
auto SetQuery(std::string query) -> void { fQuery = std::move(query); }
|
||||
|
||||
private:
|
||||
std::size_t fRequestId;
|
||||
std::string fQuery;
|
||||
};
|
||||
|
||||
struct SetProperties : Cmd
|
||||
{
|
||||
SetProperties(std::size_t request_id, std::vector<std::pair<std::string, std::string>> properties)
|
||||
: Cmd(Type::set_properties)
|
||||
, fRequestId(request_id)
|
||||
, fProperties(std::move(properties))
|
||||
{}
|
||||
|
||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
||||
auto GetProps() const -> std::vector<std::pair<std::string, std::string>> { return fProperties; }
|
||||
auto SetProps(std::vector<std::pair<std::string, std::string>> properties) -> void { fProperties = std::move(properties); }
|
||||
|
||||
private:
|
||||
std::size_t fRequestId;
|
||||
std::vector<std::pair<std::string, std::string>> fProperties;
|
||||
};
|
||||
|
||||
struct SubscriptionHeartbeat : Cmd
|
||||
{
|
||||
explicit SubscriptionHeartbeat(int64_t interval)
|
||||
: Cmd(Type::subscription_heartbeat)
|
||||
, fInterval(interval)
|
||||
{}
|
||||
|
||||
int64_t GetInterval() const { return fInterval; }
|
||||
void SetInterval(int64_t interval) { fInterval = interval; }
|
||||
|
||||
private:
|
||||
int64_t fInterval;
|
||||
};
|
||||
|
||||
struct CurrentState : Cmd
|
||||
{
|
||||
explicit CurrentState(std::string id, State currentState)
|
||||
: Cmd(Type::current_state)
|
||||
, fDeviceId(std::move(id))
|
||||
, fCurrentState(currentState)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
||||
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
fair::mq::State fCurrentState;
|
||||
};
|
||||
|
||||
struct TransitionStatus : Cmd
|
||||
{
|
||||
explicit TransitionStatus(std::string deviceId, const uint64_t taskId, const Result result, const Transition transition, State currentState)
|
||||
: Cmd(Type::transition_status)
|
||||
, fDeviceId(std::move(deviceId))
|
||||
, fTaskId(taskId)
|
||||
, fResult(result)
|
||||
, fTransition(transition)
|
||||
, fCurrentState(currentState)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
uint64_t GetTaskId() const { return fTaskId; }
|
||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
Transition GetTransition() const { return fTransition; }
|
||||
void SetTransition(const Transition transition) { fTransition = transition; }
|
||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
||||
void SetCurrentState(fair::mq::State state) { fCurrentState = state; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
uint64_t fTaskId;
|
||||
Result fResult;
|
||||
Transition fTransition;
|
||||
fair::mq::State fCurrentState;
|
||||
};
|
||||
|
||||
struct Config : Cmd
|
||||
{
|
||||
explicit Config(std::string id, std::string config)
|
||||
: Cmd(Type::config)
|
||||
, fDeviceId(std::move(id))
|
||||
, fConfig(std::move(config))
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
std::string GetConfig() const { return fConfig; }
|
||||
void SetConfig(const std::string& config) { fConfig = config; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
std::string fConfig;
|
||||
};
|
||||
|
||||
struct StateChangeSubscription : Cmd
|
||||
{
|
||||
explicit StateChangeSubscription(std::string id, const uint64_t taskId, const Result result)
|
||||
: Cmd(Type::state_change_subscription)
|
||||
, fDeviceId(std::move(id))
|
||||
, fTaskId(taskId)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
uint64_t GetTaskId() const { return fTaskId; }
|
||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
uint64_t fTaskId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct StateChangeUnsubscription : Cmd
|
||||
{
|
||||
explicit StateChangeUnsubscription(std::string id, const uint64_t taskId, const Result result)
|
||||
: Cmd(Type::state_change_unsubscription)
|
||||
, fDeviceId(std::move(id))
|
||||
, fTaskId(taskId)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
uint64_t GetTaskId() const { return fTaskId; }
|
||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
||||
Result GetResult() const { return fResult; }
|
||||
void SetResult(const Result result) { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
uint64_t fTaskId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
struct StateChange : Cmd
|
||||
{
|
||||
explicit StateChange(std::string deviceId, const uint64_t taskId, const State lastState, const State currentState)
|
||||
: Cmd(Type::state_change)
|
||||
, fDeviceId(std::move(deviceId))
|
||||
, fTaskId(taskId)
|
||||
, fLastState(lastState)
|
||||
, fCurrentState(currentState)
|
||||
{}
|
||||
|
||||
std::string GetDeviceId() const { return fDeviceId; }
|
||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
||||
uint64_t GetTaskId() const { return fTaskId; }
|
||||
void SetTaskId(const uint64_t taskId) { fTaskId = taskId; }
|
||||
fair::mq::State GetLastState() const { return fLastState; }
|
||||
void SetLastState(const fair::mq::State state) { fLastState = state; }
|
||||
fair::mq::State GetCurrentState() const { return fCurrentState; }
|
||||
void SetCurrentState(const fair::mq::State state) { fCurrentState = state; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
uint64_t fTaskId;
|
||||
fair::mq::State fLastState;
|
||||
fair::mq::State fCurrentState;
|
||||
};
|
||||
|
||||
struct Properties : Cmd
|
||||
{
|
||||
Properties(std::string deviceId, std::size_t requestId, const Result result, std::vector<std::pair<std::string, std::string>> properties)
|
||||
: Cmd(Type::properties)
|
||||
, fDeviceId(std::move(deviceId))
|
||||
, fRequestId(requestId)
|
||||
, fResult(result)
|
||||
, fProperties(std::move(properties))
|
||||
{}
|
||||
|
||||
auto GetDeviceId() const -> std::string { return fDeviceId; }
|
||||
auto SetDeviceId(std::string deviceId) -> void { fDeviceId = std::move(deviceId); }
|
||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
||||
auto GetResult() const -> Result { return fResult; }
|
||||
auto SetResult(Result result) -> void { fResult = result; }
|
||||
auto GetProps() const -> std::vector<std::pair<std::string, std::string>> { return fProperties; }
|
||||
auto SetProps(std::vector<std::pair<std::string, std::string>> properties) -> void { fProperties = std::move(properties); }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
std::size_t fRequestId;
|
||||
Result fResult;
|
||||
std::vector<std::pair<std::string, std::string>> fProperties;
|
||||
};
|
||||
|
||||
struct PropertiesSet : Cmd {
|
||||
PropertiesSet(std::string deviceId, std::size_t requestId, Result result)
|
||||
: Cmd(Type::properties_set)
|
||||
, fDeviceId(std::move(deviceId))
|
||||
, fRequestId(requestId)
|
||||
, fResult(result)
|
||||
{}
|
||||
|
||||
auto GetDeviceId() const -> std::string { return fDeviceId; }
|
||||
auto SetDeviceId(std::string deviceId) -> void { fDeviceId = std::move(deviceId); }
|
||||
auto GetRequestId() const -> std::size_t { return fRequestId; }
|
||||
auto SetRequestId(std::size_t requestId) -> void { fRequestId = requestId; }
|
||||
auto GetResult() const -> Result { return fResult; }
|
||||
auto SetResult(Result result) -> void { fResult = result; }
|
||||
|
||||
private:
|
||||
std::string fDeviceId;
|
||||
std::size_t fRequestId;
|
||||
Result fResult;
|
||||
};
|
||||
|
||||
template<typename C, typename... Args>
|
||||
std::unique_ptr<Cmd> make(Args&&... args)
|
||||
{
|
||||
return std::make_unique<C>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
struct Cmds
|
||||
{
|
||||
using container = std::vector<std::unique_ptr<Cmd>>;
|
||||
struct CommandFormatError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
explicit Cmds() = default;
|
||||
|
||||
template<typename... Rest>
|
||||
explicit Cmds(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
||||
{
|
||||
Unpack(std::forward<std::unique_ptr<Cmd>&&>(first), std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
void Add(std::unique_ptr<Cmd>&& cmd) { fCmds.emplace_back(std::move(cmd)); }
|
||||
|
||||
template<typename C, typename... Args>
|
||||
void Add(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<Cmd, C>::value, "Only types derived from fair::mq::cmd::Cmd are allowed");
|
||||
Add(make<C>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
Cmd& At(size_t i) { return *(fCmds.at(i)); }
|
||||
|
||||
size_t Size() const { return fCmds.size(); }
|
||||
void Reset() { fCmds.clear(); }
|
||||
|
||||
std::string Serialize(const Format type = Format::Binary) const;
|
||||
void Deserialize(const std::string&, const Format type = Format::Binary);
|
||||
|
||||
private:
|
||||
container fCmds;
|
||||
|
||||
void Unpack() {}
|
||||
|
||||
template <class... Rest>
|
||||
void Unpack(std::unique_ptr<Cmd>&& first, Rest&&... rest)
|
||||
{
|
||||
fCmds.emplace_back(std::move(first));
|
||||
Unpack(std::forward<Rest>(rest)...);
|
||||
}
|
||||
|
||||
public:
|
||||
using iterator = container::iterator;
|
||||
using const_iterator = container::const_iterator;
|
||||
|
||||
auto begin() -> decltype(fCmds.begin()) { return fCmds.begin(); }
|
||||
auto end() -> decltype(fCmds.end()) { return fCmds.end(); }
|
||||
auto cbegin() -> decltype(fCmds.cbegin()) { return fCmds.cbegin(); }
|
||||
auto cend() -> decltype(fCmds.cend()) { return fCmds.cend(); }
|
||||
};
|
||||
|
||||
std::string GetResultName(const Result result);
|
||||
std::string GetTypeName(const Type type);
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const Result& result) { return os << GetResultName(result); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const Type& type) { return os << GetTypeName(type); }
|
||||
|
||||
} // namespace fair::mq::sdk::cmd
|
||||
|
||||
#endif /* FAIR_MQ_SDK_COMMANDFACTORY */
|
89
fairmq/sdk/commands/CommandsFormat.fbs
Normal file
89
fairmq/sdk/commands/CommandsFormat.fbs
Normal file
@@ -0,0 +1,89 @@
|
||||
namespace fair.mq.sdk.cmd;
|
||||
|
||||
enum FBResult:byte {
|
||||
Ok,
|
||||
Failure
|
||||
}
|
||||
|
||||
enum FBState:byte {
|
||||
Undefined,
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
}
|
||||
|
||||
enum FBTransition:byte {
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound
|
||||
}
|
||||
|
||||
table FBProperty {
|
||||
key:string;
|
||||
value:string;
|
||||
}
|
||||
|
||||
enum FBCmd:byte {
|
||||
check_state, // args: { }
|
||||
change_state, // args: { transition }
|
||||
dump_config, // args: { }
|
||||
subscribe_to_state_change, // args: { interval }
|
||||
unsubscribe_from_state_change, // args: { }
|
||||
state_change_exiting_received, // args: { }
|
||||
get_properties, // args: { request_id, property_query }
|
||||
set_properties, // args: { request_id, properties }
|
||||
subscription_heartbeat, // args: { interval }
|
||||
|
||||
current_state, // args: { device_id, current_state }
|
||||
transition_status, // args: { device_id, task_id, Result, transition, current_state }
|
||||
config, // args: { device_id, config_string }
|
||||
state_change_subscription, // args: { device_id, task_id, Result }
|
||||
state_change_unsubscription, // args: { device_id, task_id, Result }
|
||||
state_change, // args: { device_id, task_id, last_state, current_state }
|
||||
properties, // args: { device_id, request_id, Result, properties }
|
||||
properties_set // args: { device_id, request_id, Result }
|
||||
}
|
||||
|
||||
table FBCommand {
|
||||
command_id:FBCmd;
|
||||
device_id:string;
|
||||
task_id:uint64;
|
||||
request_id:uint64;
|
||||
interval:int64;
|
||||
state:FBState;
|
||||
transition:FBTransition;
|
||||
result:FBResult;
|
||||
config_string:string;
|
||||
last_state:FBState;
|
||||
current_state:FBState;
|
||||
debug:string;
|
||||
properties:[FBProperty];
|
||||
property_query:string;
|
||||
}
|
||||
|
||||
table FBCommands {
|
||||
commands:[FBCommand];
|
||||
}
|
||||
|
||||
root_type FBCommands;
|
18
fairmq/sdk/commands/CommandsFormatDef.h.in
Normal file
18
fairmq/sdk/commands/CommandsFormatDef.h.in
Normal file
@@ -0,0 +1,18 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace fair::mq::sdk
|
||||
{
|
||||
namespace cmd {
|
||||
|
||||
constexpr auto commandsFormatDefFbs = R"(@commands_format_def_fbs@)";
|
||||
|
||||
} // namespace cmd
|
||||
} // namespace fair::mq::sdk
|
256
fairmq/sdk/runDDSCommandUI.cxx
Normal file
256
fairmq/sdk/runDDSCommandUI.cxx
Normal file
@@ -0,0 +1,256 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <fairmq/sdk/commands/Commands.h>
|
||||
#include <fairmq/States.h>
|
||||
#include <fairmq/SDK.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
#include <termios.h> // raw mode console input
|
||||
#include <unistd.h>
|
||||
#include <condition_variable>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq;
|
||||
using namespace fair::mq::sdk;
|
||||
using namespace fair::mq::sdk::cmd;
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
struct TerminalConfig
|
||||
{
|
||||
explicit TerminalConfig()
|
||||
{
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag &= ~ICANON; // disable canonical input
|
||||
// t.c_lflag &= ~ECHO; // do not echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
|
||||
~TerminalConfig()
|
||||
{
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag |= ICANON; // re-enable canonical input
|
||||
// t.c_lflag |= ECHO; // echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
};
|
||||
|
||||
void printControlsHelp()
|
||||
{
|
||||
cout << "Use keys to control the devices:" << endl;
|
||||
cout << "[c] check states, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
||||
cout << "To quit press Ctrl+C" << endl;
|
||||
}
|
||||
|
||||
void handleCommand(const string& command, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||
{
|
||||
std::pair<std::error_code, fair::mq::sdk::TopologyState> changeStateResult;
|
||||
|
||||
if (command == "c") {
|
||||
cout << "> checking state of the devices" << endl;
|
||||
auto const result = topo.GetCurrentState();
|
||||
bool error = false;
|
||||
for (const auto& d : result) {
|
||||
cout << d.taskId << " : " << d.state << endl;
|
||||
if (d.state == sdk::DeviceState::Error) {
|
||||
error = true;
|
||||
}
|
||||
}
|
||||
if (error) {
|
||||
throw runtime_error("Some of the devices are in the Error state");
|
||||
}
|
||||
return;
|
||||
} else if (command == "o") {
|
||||
cout << "> dumping config of " << (path.empty() ? "all" : path) << endl;
|
||||
// TODO: extend this regex to return all properties, once command size limitation is removed.
|
||||
auto const result = topo.GetProperties("^(session|id)$", path, std::chrono::milliseconds(timeout));
|
||||
if (result.first != std::error_code()) {
|
||||
cout << "ERROR: GetProperties failed for '" << path << "': " << result.first.message() << endl;
|
||||
throw runtime_error(tools::ToString("GetProperties failed for '", path, "': ", result.first.message()));
|
||||
}
|
||||
for (const auto& d : result.second.devices) {
|
||||
for (auto const& p : d.second.props) {
|
||||
cout << d.first << ": " << p.first << " : " << p.second << endl;
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else if (command == "p") {
|
||||
if (pKey.empty() || pVal.empty()) {
|
||||
cout << "cannot send property with empty key and/or value! given key: '" << pKey << "', value: '" << pVal << "'." << endl;
|
||||
throw runtime_error(tools::ToString("cannot send property with empty key and/or value! given key: '", pKey, "', value: '", pVal, "'."));
|
||||
}
|
||||
const DeviceProperties props{{pKey, pVal}};
|
||||
cout << "> setting properties --> " << (path.empty() ? "all" : path) << endl;
|
||||
auto const result = topo.SetProperties(props, path);
|
||||
if (result.first != std::error_code()) {
|
||||
cout << "ERROR: SetProperties failed for '" << path << "': " << result.first.message() << endl;
|
||||
throw runtime_error(tools::ToString("SetProperties failed for '", path, "': ", result.first.message()));
|
||||
}
|
||||
// give dds time to complete request
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
return;
|
||||
} else if (command == "i") {
|
||||
cout << "> initiating InitDevice transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::InitDevice, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "k") {
|
||||
cout << "> initiating CompleteInit transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::CompleteInit, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "b") {
|
||||
cout << "> initiating Bind transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::Bind, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "x") {
|
||||
cout << "> initiating Connect transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::Connect, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "j") {
|
||||
cout << "> initiating InitTask transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::InitTask, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "r") {
|
||||
cout << "> initiating Run transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::Run, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "s") {
|
||||
cout << "> initiating Stop transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::Stop, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "t") {
|
||||
cout << "> initiating ResetTask transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::ResetTask, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "d") {
|
||||
cout << "> initiating ResetDevice transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::ResetDevice, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "q") {
|
||||
cout << "> initiating End transition --> " << (path.empty() ? "all" : path) << endl;
|
||||
changeStateResult = topo.ChangeState(TopologyTransition::End, path, std::chrono::milliseconds(timeout));
|
||||
} else if (command == "h") {
|
||||
cout << "> help" << endl;
|
||||
printControlsHelp();
|
||||
return;
|
||||
} else {
|
||||
cout << "\033[01;32mInvalid input: [" << command << "]\033[0m" << endl;
|
||||
printControlsHelp();
|
||||
throw runtime_error(tools::ToString("\033[01;32mInvalid input: [", command, "]\033[0m"));
|
||||
}
|
||||
if (changeStateResult.first != std::error_code()) {
|
||||
cout << "ERROR: ChangeState failed for '" << path << "': " << changeStateResult.first.message() << endl;
|
||||
throw runtime_error(tools::ToString("ERROR: ChangeState failed for '", path, "': ", changeStateResult.first.message()));
|
||||
}
|
||||
}
|
||||
|
||||
void sendCommand(const string& commandIn, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||
{
|
||||
if (!commandIn.empty()) {
|
||||
handleCommand(commandIn, path, timeout, topo, pKey, pVal);
|
||||
return;
|
||||
}
|
||||
|
||||
char c = 0;
|
||||
string command;
|
||||
TerminalConfig tconfig;
|
||||
|
||||
printControlsHelp();
|
||||
cin >> c;
|
||||
command = c;
|
||||
|
||||
while (true) {
|
||||
try {
|
||||
handleCommand(command, path, timeout, topo, pKey, pVal);
|
||||
} catch(exception& e) {
|
||||
cout << "Error: " << e.what() << endl;
|
||||
}
|
||||
cin >> c;
|
||||
command = c;
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
try {
|
||||
string sessionID;
|
||||
string topoFile;
|
||||
|
||||
string command;
|
||||
string path;
|
||||
string targetState;
|
||||
string pKey;
|
||||
string pVal;
|
||||
unsigned int timeout = 0;
|
||||
|
||||
fair::Logger::SetConsoleSeverity("debug");
|
||||
fair::Logger::SetConsoleColor(true);
|
||||
|
||||
bpo::options_description options("Common options");
|
||||
|
||||
auto envSessionId = getenv("DDS_SESSION_ID");
|
||||
if (envSessionId) {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->default_value(envSessionId), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
} else {
|
||||
options.add_options()("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||
}
|
||||
|
||||
auto envTopoFile = getenv("FAIRMQ_DDS_TOPO_FILE");
|
||||
if (envTopoFile) {
|
||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->default_value(envTopoFile), "DDS topology file path");
|
||||
} else {
|
||||
options.add_options()("topology-file,f", bpo::value<string>(&topoFile)->required(), "DDS topology file path");
|
||||
}
|
||||
|
||||
options.add_options()
|
||||
("command,c", bpo::value<string>(&command)->default_value(""), "Command character")
|
||||
("path,p", bpo::value<string>(&path)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
||||
("property-key", bpo::value<string>(&pKey)->default_value(""), "property key to be used with 'p' command")
|
||||
("property-value", bpo::value<string>(&pVal)->default_value(""), "property value to be used with 'p' command")
|
||||
("wait-for-state,w", bpo::value<string>(&targetState)->default_value(""), "Wait until targeted FairMQ devices reach the given state")
|
||||
("timeout,t", bpo::value<unsigned int>(&timeout)->default_value(0), "Timeout in milliseconds when waiting for a device state (0 - wait infinitely)")
|
||||
("help,h", "Produce help message");
|
||||
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
||||
cout << "Commands: [c] check state, [o] dump config, [h] help, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device, [k] complete init, [b] bind, [x] connect, [p] set property" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bpo::notify(vm);
|
||||
|
||||
DDSEnvironment env;
|
||||
DDSSession session(sessionID, env);
|
||||
DDSTopology ddsTopo(DDSTopology::Path(topoFile), env);
|
||||
|
||||
Topology topo(ddsTopo, session, true);
|
||||
|
||||
if (!targetState.empty()) {
|
||||
if (!command.empty()) {
|
||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
||||
}
|
||||
size_t pos = targetState.find("->");
|
||||
cout << "> waiting for " << (path.empty() ? "all" : path) << " to reach " << targetState << endl;
|
||||
if (pos == string::npos) {
|
||||
/* auto ec = */topo.WaitForState(GetState(targetState), path, std::chrono::milliseconds(timeout));
|
||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
||||
} else {
|
||||
/* auto ec = */topo.WaitForState(GetState(targetState.substr(0, pos)), GetState(targetState.substr(pos + 2)), path, std::chrono::milliseconds(timeout));
|
||||
// cout << "WaitForState(" << targetState << ") result: " << ec.message() << endl;
|
||||
}
|
||||
} else {
|
||||
sendCommand(command, path, timeout, topo, pKey, pVal);
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
} catch (exception& e) {
|
||||
cerr << "Error: " << e.what() << endl;
|
||||
return EXIT_FAILURE;
|
||||
}
|
@@ -207,22 +207,22 @@ class Manager
|
||||
|
||||
fEventCounter = fManagementSegment.find<EventCounter>(unique_instance).first;
|
||||
if (fEventCounter) {
|
||||
LOG(debug) << "event counter found: " << fEventCounter->fCount;
|
||||
LOG(trace) << "event counter found: " << fEventCounter->fCount;
|
||||
} else {
|
||||
LOG(debug) << "no event counter found, creating one and initializing with 0";
|
||||
LOG(trace) << "no event counter found, creating one and initializing with 0";
|
||||
fEventCounter = fManagementSegment.construct<EventCounter>(unique_instance)(0);
|
||||
LOG(debug) << "initialized event counter with: " << fEventCounter->fCount;
|
||||
LOG(trace) << "initialized event counter with: " << fEventCounter->fCount;
|
||||
}
|
||||
|
||||
fDeviceCounter = fManagementSegment.find<DeviceCounter>(unique_instance).first;
|
||||
if (fDeviceCounter) {
|
||||
LOG(debug) << "device counter found, with value of " << fDeviceCounter->fCount << ". incrementing.";
|
||||
LOG(trace) << "device counter found, with value of " << fDeviceCounter->fCount << ". incrementing.";
|
||||
(fDeviceCounter->fCount)++;
|
||||
LOG(debug) << "incremented device counter, now: " << fDeviceCounter->fCount;
|
||||
LOG(trace) << "incremented device counter, now: " << fDeviceCounter->fCount;
|
||||
} else {
|
||||
LOG(debug) << "no device counter found, creating one and initializing with 1";
|
||||
LOG(trace) << "no device counter found, creating one and initializing with 1";
|
||||
fDeviceCounter = fManagementSegment.construct<DeviceCounter>(unique_instance)(1);
|
||||
LOG(debug) << "initialized device counter with: " << fDeviceCounter->fCount;
|
||||
LOG(trace) << "initialized device counter with: " << fDeviceCounter->fCount;
|
||||
}
|
||||
|
||||
fShmSegments = fManagementSegment.find_or_construct<Uint16SegmentInfoHashMap>(unique_instance)(fShmVoidAlloc);
|
||||
@@ -265,10 +265,10 @@ class Manager
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG(debug) << "Created/opened shared memory segment '" << "fmq_" << fShmId << "_m_" << fSegmentId << "'."
|
||||
<< " Size: " << boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Available: " << boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Allocation algorithm: " << allocationAlgorithm;
|
||||
LOG(debug) << (createdSegment ? "Created" : "Opened") << " managed shared memory segment " << "fmq_" << fShmId << "_m_" << fSegmentId
|
||||
<< ". Size: " << boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Available: " << boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId)) << " bytes."
|
||||
<< " Allocation algorithm: " << allocationAlgorithm;
|
||||
} catch (interprocess_exception& bie) {
|
||||
LOG(error) << "Failed to create/open shared memory segment '" << "fmq_" << fShmId << "_m_" << fSegmentId << "': " << bie.what();
|
||||
throw TransportError(tools::ToString("Failed to create/open shared memory segment '", "fmq_", fShmId, "_m_", fSegmentId, "': ", bie.what()));
|
||||
@@ -395,20 +395,26 @@ class Manager
|
||||
|
||||
const uint16_t id = cfg.id.value();
|
||||
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
|
||||
UnmanagedRegion* region = nullptr;
|
||||
bool newRegionCreated = false;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
auto res = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, size, false, cfg));
|
||||
newRegionCreated = res.second;
|
||||
|
||||
auto it = fRegions.find(id);
|
||||
if (it != fRegions.end()) {
|
||||
region = it->second.get();
|
||||
if (region->fControlling) {
|
||||
LOG(error) << "Unmanaged Region with id " << id << " already exists. Only unique IDs per session are allowed.";
|
||||
throw TransportError(tools::ToString("Unmanaged Region with id ", id, " already exists. Only unique IDs per session are allowed."));
|
||||
}
|
||||
|
||||
LOG(debug) << "Unmanaged region (view) already present, promoting to controller";
|
||||
region->BecomeController(cfg);
|
||||
} else {
|
||||
auto res = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, size, true, cfg));
|
||||
region = res.first->second.get();
|
||||
}
|
||||
// LOG(debug) << "Created region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
||||
|
||||
if (!newRegionCreated) {
|
||||
region->fRemote = false; // TODO: this should be more clear, refactor it.
|
||||
}
|
||||
|
||||
// start ack receiver only if a callback has been provided.
|
||||
if (callback || bulkCallback) {
|
||||
region->SetCallbacks(callback, bulkCallback);
|
||||
@@ -429,7 +435,7 @@ class Manager
|
||||
}
|
||||
}
|
||||
|
||||
UnmanagedRegion* GetRegion(uint16_t id)
|
||||
UnmanagedRegion* GetRegionFromCache(uint16_t id)
|
||||
{
|
||||
// NOTE: gcc optimizations. Prevent loading tls addresses many times in the fast path
|
||||
const auto &lTlCache = fTlRegionCache;
|
||||
@@ -443,41 +449,39 @@ class Manager
|
||||
}
|
||||
}
|
||||
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
// slow path: check invalidation
|
||||
if (lTlCacheGen != fRegionsGen) {
|
||||
fTlRegionCache.fRegionsTLCache.clear();
|
||||
}
|
||||
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
auto* lRegion = GetRegionUnsafe(id, shmLock);
|
||||
auto* lRegion = GetRegion(id);
|
||||
fTlRegionCache.fRegionsTLCache.emplace_back(std::make_tuple(lRegion, id, fShmId64));
|
||||
fTlRegionCache.fRegionsTLCacheGen = fRegionsGen;
|
||||
return lRegion;
|
||||
}
|
||||
|
||||
UnmanagedRegion* GetRegionUnsafe(uint16_t id, boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex>& lockedShmLock)
|
||||
UnmanagedRegion* GetRegion(uint16_t id)
|
||||
{
|
||||
// remote region could actually be a local one if a message originates from this device (has been sent out and returned)
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
auto it = fRegions.find(id);
|
||||
if (it != fRegions.end()) {
|
||||
return it->second.get();
|
||||
} else {
|
||||
try {
|
||||
// get region info
|
||||
RegionInfo regionInfo = fShmRegions->at(id);
|
||||
// safe to unlock now - no shm container accessed after this
|
||||
lockedShmLock.unlock();
|
||||
RegionConfig cfg;
|
||||
cfg.id = id;
|
||||
cfg.creationFlags = regionInfo.fCreationFlags;
|
||||
cfg.path = regionInfo.fPath.c_str();
|
||||
// get region info
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
RegionInfo regionInfo = fShmRegions->at(id);
|
||||
cfg.id = id;
|
||||
cfg.creationFlags = regionInfo.fCreationFlags;
|
||||
cfg.path = regionInfo.fPath.c_str();
|
||||
}
|
||||
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
||||
|
||||
auto r = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, 0, true, std::move(cfg)));
|
||||
auto r = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, 0, false, std::move(cfg)));
|
||||
r.first->second->InitializeQueues();
|
||||
r.first->second->StartAckSender();
|
||||
lockedShmLock.lock();
|
||||
return r.first->second.get();
|
||||
} catch (std::out_of_range& oor) {
|
||||
LOG(error) << "Could not get remote region with id '" << id << "'. Does the region creator run with the same session id?";
|
||||
@@ -493,10 +497,10 @@ class Manager
|
||||
void RemoveRegion(uint16_t id)
|
||||
{
|
||||
try {
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
fRegions.at(id)->StopAcks();
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
if (fRegions.at(id)->RemoveOnDestruction()) {
|
||||
fShmRegions->at(id).fDestroyed = true;
|
||||
(fEventCounter->fCount)++;
|
||||
@@ -512,44 +516,73 @@ class Manager
|
||||
std::vector<fair::mq::RegionInfo> GetRegionInfo()
|
||||
{
|
||||
std::vector<fair::mq::RegionInfo> result;
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
std::map<uint64_t, RegionConfig> regionCfgs;
|
||||
|
||||
for (const auto& e : *fShmSegments) {
|
||||
// make sure any segments in the session are found
|
||||
GetSegment(e.first);
|
||||
try {
|
||||
{
|
||||
boost::interprocess::scoped_lock<boost::interprocess::interprocess_mutex> shmLock(*fShmMtx);
|
||||
|
||||
for (const auto& [segmentId, segmentInfo] : *fShmSegments) {
|
||||
// make sure any segments in the session are found
|
||||
GetSegment(segmentId);
|
||||
try {
|
||||
fair::mq::RegionInfo info;
|
||||
info.managed = true;
|
||||
info.id = segmentId;
|
||||
info.event = RegionEvent::created;
|
||||
info.ptr = boost::apply_visitor(SegmentAddress(), fSegments.at(segmentId));
|
||||
info.size = boost::apply_visitor(SegmentSize(), fSegments.at(segmentId));
|
||||
result.push_back(info);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
LOG(error) << "could not find segment with id " << segmentId;
|
||||
LOG(error) << oor.what();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& [regionId, regionInfo] : *fShmRegions) {
|
||||
fair::mq::RegionInfo info;
|
||||
info.managed = true;
|
||||
info.id = e.first;
|
||||
info.event = RegionEvent::created;
|
||||
info.ptr = boost::apply_visitor(SegmentAddress(), fSegments.at(e.first));
|
||||
info.size = boost::apply_visitor(SegmentSize(), fSegments.at(e.first));
|
||||
info.managed = false;
|
||||
info.id = regionId;
|
||||
info.flags = regionInfo.fUserFlags;
|
||||
info.event = regionInfo.fDestroyed ? RegionEvent::destroyed : RegionEvent::created;
|
||||
if (info.event == RegionEvent::created) {
|
||||
RegionConfig cfg;
|
||||
cfg.id = info.id;
|
||||
cfg.creationFlags = regionInfo.fCreationFlags;
|
||||
cfg.path = regionInfo.fPath.c_str();
|
||||
regionCfgs.emplace(info.id, cfg);
|
||||
// fill the ptr+size info after shmLock is released, to avoid constructing local region under it
|
||||
} else {
|
||||
info.ptr = nullptr;
|
||||
info.size = 0;
|
||||
}
|
||||
result.push_back(info);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
LOG(error) << "could not find segment with id " << e.first;
|
||||
LOG(error) << oor.what();
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& e : *fShmRegions) {
|
||||
fair::mq::RegionInfo info;
|
||||
info.managed = false;
|
||||
info.id = e.first;
|
||||
info.flags = e.second.fUserFlags;
|
||||
info.event = e.second.fDestroyed ? RegionEvent::destroyed : RegionEvent::created;
|
||||
if (info.event == RegionEvent::created) {
|
||||
auto region = GetRegionUnsafe(info.id, shmLock);
|
||||
if (region) {
|
||||
// do another iteration outside of shm lock, to fill ptr+size of unmanaged regions
|
||||
for (auto& info : result) {
|
||||
if (!info.managed && info.event == RegionEvent::created) {
|
||||
auto cfgIt = regionCfgs.find(info.id);
|
||||
if (cfgIt != regionCfgs.end()) {
|
||||
UnmanagedRegion* region = nullptr;
|
||||
std::lock_guard<std::mutex> lock(fLocalRegionsMtx);
|
||||
auto it = fRegions.find(info.id);
|
||||
if (it != fRegions.end()) {
|
||||
region = it->second.get();
|
||||
} else {
|
||||
auto r = fRegions.emplace(cfgIt->first, std::make_unique<UnmanagedRegion>(fShmId, 0, false, cfgIt->second));
|
||||
region = r.first->second.get();
|
||||
region->InitializeQueues();
|
||||
region->StartAckSender();
|
||||
}
|
||||
|
||||
info.ptr = region->GetData();
|
||||
info.size = region->GetSize();
|
||||
} else {
|
||||
throw std::runtime_error(tools::ToString("GetRegionInfo() could not get region with id '", info.id, "'"));
|
||||
info.ptr = nullptr;
|
||||
info.size = 0;
|
||||
}
|
||||
} else {
|
||||
info.ptr = nullptr;
|
||||
info.size = 0;
|
||||
}
|
||||
result.push_back(info);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@@ -195,7 +195,7 @@ class Message final : public fair::mq::Message
|
||||
fLocalPtr = nullptr;
|
||||
}
|
||||
} else {
|
||||
fRegionPtr = fManager.GetRegion(fMeta.fRegionId);
|
||||
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
||||
if (fRegionPtr) {
|
||||
fLocalPtr = reinterpret_cast<char*>(fRegionPtr->GetData()) + fMeta.fHandle;
|
||||
} else {
|
||||
@@ -365,7 +365,7 @@ class Message final : public fair::mq::Message
|
||||
void ReleaseUnmanagedRegionBlock()
|
||||
{
|
||||
if (!fRegionPtr) {
|
||||
fRegionPtr = fManager.GetRegion(fMeta.fRegionId);
|
||||
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
||||
}
|
||||
|
||||
if (fRegionPtr) {
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include <boost/interprocess/ipc/message_queue.hpp>
|
||||
|
||||
#include <csignal>
|
||||
#include <cstdio>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
@@ -533,6 +534,88 @@ unsigned long Monitor::GetFreeMemory(const SessionId& sessionId, uint16_t segmen
|
||||
return GetFreeMemory(shmId, segmentId);
|
||||
}
|
||||
|
||||
bool Monitor::SegmentIsPresent(const ShmId& shmId, uint16_t segmentId)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
try {
|
||||
bipc::managed_shared_memory managementSegment(bipc::open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
||||
Uint16SegmentInfoHashMap* shmSegments = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||
|
||||
if (!shmSegments) {
|
||||
LOG(error) << "Found management segment, but could not locate segment info";
|
||||
return false;
|
||||
}
|
||||
|
||||
auto it = shmSegments->find(segmentId);
|
||||
if (it != shmSegments->end()) {
|
||||
try {
|
||||
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||
RBTreeBestFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
||||
} else {
|
||||
SimpleSeqFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
||||
}
|
||||
} catch (bie&) {
|
||||
LOG(error) << "Could not find segment with id '" << segmentId << "' for shmId '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(error) << "Could not find segment info for segment id '" << segmentId << "' for shmId '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
} catch (bie&) {
|
||||
LOG(error) << "Could not find management segment for shmid '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Monitor::SegmentIsPresent(const SessionId& sessionId, uint16_t segmentId)
|
||||
{
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
return SegmentIsPresent(shmId, segmentId);
|
||||
}
|
||||
|
||||
bool Monitor::RegionIsPresent(const ShmId& shmId, uint16_t regionId)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
try {
|
||||
bipc::managed_shared_memory managementSegment(bipc::open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
||||
Uint16RegionInfoHashMap* shmRegions = managementSegment.find<Uint16RegionInfoHashMap>(bipc::unique_instance).first;
|
||||
|
||||
if (!shmRegions) {
|
||||
LOG(error) << "Found management segment, but could not locate region info";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string regionFileName("fmq_" + shmId.shmId + "_rg_" + to_string(regionId));
|
||||
|
||||
auto it = shmRegions->find(regionId);
|
||||
if (it != shmRegions->end()) {
|
||||
try {
|
||||
if (it->second.fPath.empty()) {
|
||||
shared_memory_object object(open_only, regionFileName.c_str(), read_only);
|
||||
}
|
||||
} catch (bie&) {
|
||||
LOG(error) << "Could not find region with id '" << regionId << "' for shmId '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(error) << "Could not find region info for region id '" << regionId << "' for shmId '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
} catch (bie&) {
|
||||
LOG(error) << "Could not find management segment for shmid '" << shmId.shmId << "'";
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
bool Monitor::RegionIsPresent(const SessionId& sessionId, uint16_t regionId)
|
||||
{
|
||||
ShmId shmId{makeShmIdStr(sessionId.sessionId)};
|
||||
return RegionIsPresent(shmId, regionId);
|
||||
}
|
||||
|
||||
void Monitor::PrintHelp()
|
||||
{
|
||||
LOG(info) << "controls: [x] close memory, "
|
||||
@@ -587,7 +670,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmIdT,
|
||||
string path = info.fPath.c_str();
|
||||
int flags = info.fCreationFlags;
|
||||
if (verbose) {
|
||||
LOG(info) << "Found RegionInfo with path: '" << path << "', flags: " << flags << ", fDestroyed: " << info.fDestroyed << ".";
|
||||
LOG(info) << "Found UnmanagedRegion with id: " << id << ", path: '" << path << "', flags: " << flags << ", fDestroyed: " << info.fDestroyed << ".";
|
||||
}
|
||||
if (!path.empty()) {
|
||||
result.emplace_back(Remove<bipc::file_mapping>(path + "fmq_" + shmId + "_rg_" + to_string(id), verbose));
|
||||
|
@@ -119,7 +119,7 @@ class Monitor
|
||||
/// @param sessionId session id
|
||||
static std::unordered_map<uint16_t, std::vector<BufferDebugInfo>> GetDebugInfo(const SessionId& sessionId);
|
||||
/// @brief Returns the amount of free memory in the specified segment
|
||||
/// @param sessionId shmem id
|
||||
/// @param shmId shmem id
|
||||
/// @param segmentId segment id
|
||||
/// @throws MonitorError
|
||||
static unsigned long GetFreeMemory(const ShmId& shmId, uint16_t segmentId);
|
||||
@@ -128,6 +128,23 @@ class Monitor
|
||||
/// @param segmentId segment id
|
||||
/// @throws MonitorError
|
||||
static unsigned long GetFreeMemory(const SessionId& sessionId, uint16_t segmentId);
|
||||
/// @brief Checks if a given segment can be opened
|
||||
/// @param shmId shmem id
|
||||
/// @param segmentId segment id
|
||||
static bool SegmentIsPresent(const ShmId& shmId, uint16_t segmentId);
|
||||
/// @brief Checks if a given segment can be opened
|
||||
/// @param sessionId session id
|
||||
/// @param segmentId segment id
|
||||
static bool SegmentIsPresent(const SessionId& sessionId, uint16_t segmentId);
|
||||
/// @brief Checks if a given region can be opened
|
||||
/// @param shmId shmem id
|
||||
/// @param regionId region id
|
||||
static bool RegionIsPresent(const ShmId& shmId, uint16_t regionId);
|
||||
/// @brief Checks if a given region can be opened
|
||||
/// @param sessionId session id
|
||||
/// @param regionId region id
|
||||
static bool RegionIsPresent(const SessionId& sessionId, uint16_t regionId);
|
||||
|
||||
|
||||
static bool PrintShm(const ShmId& shmId);
|
||||
static void ListAll(const std::string& path);
|
||||
|
@@ -44,19 +44,19 @@ struct UnmanagedRegion
|
||||
friend class Monitor;
|
||||
|
||||
UnmanagedRegion(const std::string& shmId, uint16_t id, uint64_t size)
|
||||
: UnmanagedRegion(shmId, size, false, makeRegionConfig(id))
|
||||
: UnmanagedRegion(shmId, size, true, makeRegionConfig(id))
|
||||
{}
|
||||
|
||||
UnmanagedRegion(const std::string& shmId, uint64_t size, RegionConfig cfg)
|
||||
: UnmanagedRegion(shmId, size, false, std::move(cfg))
|
||||
: UnmanagedRegion(shmId, size, true, std::move(cfg))
|
||||
{}
|
||||
|
||||
UnmanagedRegion(const std::string& shmId, RegionConfig cfg)
|
||||
: UnmanagedRegion(shmId, cfg.size, false, std::move(cfg))
|
||||
: UnmanagedRegion(shmId, cfg.size, true, std::move(cfg))
|
||||
{}
|
||||
|
||||
UnmanagedRegion(const std::string& shmId, uint64_t size, bool remote, RegionConfig cfg)
|
||||
: fRemote(remote)
|
||||
UnmanagedRegion(const std::string& shmId, uint64_t size, bool controlling, RegionConfig cfg)
|
||||
: fControlling(controlling)
|
||||
, fRemoveOnDestruction(cfg.removeOnDestruction)
|
||||
, fLinger(cfg.linger)
|
||||
, fStopAcks(false)
|
||||
@@ -73,11 +73,15 @@ struct UnmanagedRegion
|
||||
|
||||
// TODO: refactor this
|
||||
cfg.size = size;
|
||||
const uint16_t id = cfg.id.value();
|
||||
bool created = false;
|
||||
|
||||
LOG(debug) << "UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
||||
|
||||
if (!cfg.path.empty()) {
|
||||
fName = std::string(cfg.path + fName);
|
||||
|
||||
if (!fRemote) {
|
||||
if (fControlling) {
|
||||
// create a file
|
||||
std::filebuf fbuf;
|
||||
if (fbuf.open(fName, std::ios_base::in | std::ios_base::out | std::ios_base::trunc | std::ios_base::binary)) {
|
||||
@@ -92,23 +96,30 @@ struct UnmanagedRegion
|
||||
if (!fFile) {
|
||||
LOG(error) << "Failed to initialize file: " << fName;
|
||||
LOG(error) << "errno: " << errno << ": " << strerror(errno);
|
||||
throw std::runtime_error(tools::ToString("Failed to initialize file for shared memory region: ", strerror(errno)));
|
||||
throw TransportError(tools::ToString("Failed to initialize file for shared memory region: ", strerror(errno)));
|
||||
}
|
||||
fFileMapping = file_mapping(fName.c_str(), read_write);
|
||||
LOG(debug) << "shmem: initialized file: " << fName;
|
||||
LOG(debug) << "UnmanagedRegion(): initialized file: " << fName;
|
||||
fRegion = mapped_region(fFileMapping, read_write, 0, size, 0, cfg.creationFlags);
|
||||
} else {
|
||||
try {
|
||||
// if opening fails, create
|
||||
try {
|
||||
fShmemObject = shared_memory_object(open_only, fName.c_str(), read_write);
|
||||
created = false;
|
||||
} catch (interprocess_exception& e) {
|
||||
LOG(debug) << "Could not open " << (remote ? "remote" : "local") << " shared_memory_object for region id '" << cfg.id.value() << "': " << e.what() << ", creating...";
|
||||
fShmemObject = shared_memory_object(create_only, fName.c_str(), read_write);
|
||||
fShmemObject.truncate(size);
|
||||
if (fControlling) {
|
||||
LOG(debug) << "Could not open controlling shared_memory_object for region " << id << ": " << e.what() << ", creating...";
|
||||
fShmemObject = shared_memory_object(create_only, fName.c_str(), read_write);
|
||||
fShmemObject.truncate(size);
|
||||
created = true;
|
||||
} else {
|
||||
LOG(error) << "Could not open view for shared_memory_object for region " << id << ": " << e.what();
|
||||
throw TransportError(tools::ToString("Could not open view for shared_memory_object for region ", id, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
} catch (interprocess_exception& e) {
|
||||
LOG(error) << "Failed " << (remote ? "opening" : "creating") << " shared_memory_object for region id '" << cfg.id.value() << "': " << e.what();
|
||||
LOG(error) << "Failed initializing shared_memory_object for region id " << id << ": " << e.what();
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -119,27 +130,27 @@ struct UnmanagedRegion
|
||||
throw TransportError(tools::ToString("Created/opened region size (", fRegion.get_size(), ") does not match configured size (", size, ")"));
|
||||
}
|
||||
} catch (interprocess_exception& e) {
|
||||
LOG(error) << "Failed mapping shared_memory_object for region id '" << cfg.id.value() << "': " << e.what();
|
||||
LOG(error) << "Failed mapping shared_memory_object for region id " << id << ": " << e.what();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.lock) {
|
||||
LOG(debug) << "Locking region " << cfg.id.value() << "...";
|
||||
LOG(debug) << "Locking region " << id << "...";
|
||||
Lock();
|
||||
LOG(debug) << "Successfully locked region " << cfg.id.value() << ".";
|
||||
LOG(debug) << "Successfully locked region " << id << ".";
|
||||
}
|
||||
if (cfg.zero) {
|
||||
LOG(debug) << "Zeroing free memory of region " << cfg.id.value() << "...";
|
||||
LOG(debug) << "Zeroing free memory of region " << id << "...";
|
||||
Zero();
|
||||
LOG(debug) << "Successfully zeroed free memory of region " << cfg.id.value() << ".";
|
||||
LOG(debug) << "Successfully zeroed free memory of region " << id << ".";
|
||||
}
|
||||
|
||||
if (!remote) {
|
||||
if (fControlling && created) {
|
||||
Register(shmId, cfg);
|
||||
}
|
||||
|
||||
LOG(trace) << "shmem: initialized region: " << fName << " (" << (remote ? "remote" : "local") << ")";
|
||||
LOG(debug) << (created ? "Created" : "Opened") << " unmanaged shared memory region: " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
||||
}
|
||||
|
||||
UnmanagedRegion() = delete;
|
||||
@@ -149,6 +160,13 @@ struct UnmanagedRegion
|
||||
UnmanagedRegion& operator=(const UnmanagedRegion&) = delete;
|
||||
UnmanagedRegion& operator=(UnmanagedRegion&&) = delete;
|
||||
|
||||
void BecomeController(RegionConfig& cfg)
|
||||
{
|
||||
fControlling = true;
|
||||
fLinger = cfg.linger;
|
||||
fRemoveOnDestruction = cfg.removeOnDestruction;
|
||||
}
|
||||
|
||||
void Zero()
|
||||
{
|
||||
memset(fRegion.get_address(), 0x00, fRegion.get_size());
|
||||
@@ -171,6 +189,7 @@ struct UnmanagedRegion
|
||||
|
||||
~UnmanagedRegion()
|
||||
{
|
||||
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
||||
fStopAcks = true;
|
||||
|
||||
if (fAcksSender.joinable()) {
|
||||
@@ -178,7 +197,7 @@ struct UnmanagedRegion
|
||||
fAcksSender.join();
|
||||
}
|
||||
|
||||
if (!fRemote) {
|
||||
if (fControlling) {
|
||||
if (fAcksReceiver.joinable()) {
|
||||
fAcksReceiver.join();
|
||||
}
|
||||
@@ -204,14 +223,14 @@ struct UnmanagedRegion
|
||||
fclose(fFile);
|
||||
}
|
||||
} else {
|
||||
// LOG(debug) << "Region queue '" << fQueueName << "' is remote, no cleanup necessary";
|
||||
// LOG(debug) << "Region queue '" << fQueueName << "' is viewer, no cleanup necessary";
|
||||
}
|
||||
|
||||
// LOG(debug) << "Region '" << fName << "' (" << (fRemote ? "remote" : "local") << ") destructed.";
|
||||
// LOG(debug) << "Region '" << fName << "' (" << (fControlling ? "controller" : "viewer") << ") destructed.";
|
||||
}
|
||||
|
||||
private:
|
||||
bool fRemote;
|
||||
bool fControlling;
|
||||
bool fRemoveOnDestruction;
|
||||
uint32_t fLinger;
|
||||
std::atomic<bool> fStopAcks;
|
||||
@@ -243,6 +262,7 @@ struct UnmanagedRegion
|
||||
static void Register(const std::string& shmId, const RegionConfig& cfg)
|
||||
{
|
||||
using namespace boost::interprocess;
|
||||
LOG(debug) << "Registering unmanaged shared memory region with id " << cfg.id.value();
|
||||
managed_shared_memory mngSegment(open_or_create, std::string("fmq_" + shmId + "_mng").c_str(), kManagementSegmentSize);
|
||||
VoidAlloc alloc(mngSegment.get_segment_manager());
|
||||
|
||||
@@ -250,10 +270,14 @@ struct UnmanagedRegion
|
||||
|
||||
EventCounter* eventCounter = mngSegment.find_or_construct<EventCounter>(unique_instance)(0);
|
||||
|
||||
bool newShmRegionCreated = shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, alloc)).second;
|
||||
if (newShmRegionCreated) {
|
||||
(eventCounter->fCount)++;
|
||||
auto it = shmRegions->find(cfg.id.value());
|
||||
if (it != shmRegions->end()) {
|
||||
LOG(error) << "Unmanaged Region with id " << cfg.id.value() << " has already been registered. Only unique IDs per session are allowed.";
|
||||
throw TransportError(tools::ToString("Unmanaged Region with id ", cfg.id.value(), " has already been registered. Only unique IDs per session are allowed."));
|
||||
}
|
||||
|
||||
shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, alloc)).second;
|
||||
(eventCounter->fCount)++;
|
||||
}
|
||||
|
||||
void SetCallbacks(RegionCallback callback, RegionBulkCallback bulkCallback)
|
||||
|
@@ -40,9 +40,9 @@ class UnmanagedRegionImpl final : public fair::mq::UnmanagedRegion
|
||||
, fRegion(nullptr)
|
||||
, fRegionId(0)
|
||||
{
|
||||
auto result = fManager.CreateRegion(size, callback, bulkCallback, std::move(cfg));
|
||||
fRegion = result.first;
|
||||
fRegionId = result.second;
|
||||
auto [regionPtr, regionId] = fManager.CreateRegion(size, callback, bulkCallback, std::move(cfg));
|
||||
fRegion = regionPtr;
|
||||
fRegionId = regionId;
|
||||
}
|
||||
|
||||
UnmanagedRegionImpl(const UnmanagedRegionImpl&) = delete;
|
||||
|
@@ -14,6 +14,7 @@
|
||||
#include <clang/ASTMatchers/ASTMatchers.h>
|
||||
#include <clang/Basic/Diagnostic.h>
|
||||
#include <llvm/Support/Casting.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace fair::mq::tidy {
|
||||
|
||||
@@ -26,7 +27,7 @@ struct ModernizeNonNamespacedTypes
|
||||
|
||||
// https://clang.llvm.org/docs/LibASTMatchersReference.html
|
||||
finder.addMatcher(
|
||||
typeLoc(loc(qualType(hasDeclaration(namedDecl(matchesName("::FairMQ")).bind("decl")))))
|
||||
typeLoc(loc(qualType(hasDeclaration(namedDecl(matchesName("FairMQ.*")).bind("decl")))))
|
||||
.bind("loc"),
|
||||
&fCallback);
|
||||
}
|
||||
@@ -43,22 +44,29 @@ struct ModernizeNonNamespacedTypes
|
||||
if (auto const type_alias_decl = m.Nodes.getNodeAs<TypeAliasDecl>("decl")) {
|
||||
auto const underlying_type(type_alias_decl->getUnderlyingType());
|
||||
|
||||
// auto ldecl_ctx(type_loc->getType()getLexicalDeclContext());
|
||||
// std::stringstream s;
|
||||
// while (ldecl_ctx) {
|
||||
// s << "." << ldecl_ctx->getDeclKindName();
|
||||
// if (ldecl_ctx->isNamespace()) {
|
||||
// s << dyn_cast<NamespaceDecl>(ldecl_ctx)->getNameAsString();
|
||||
// }
|
||||
// ldecl_ctx = ldecl_ctx->getLexicalParent();
|
||||
// }
|
||||
|
||||
if (underlying_type.getAsString().rfind("fair::mq::", 0) == 0) {
|
||||
auto& diag_engine(m.Context->getDiagnostics());
|
||||
auto const location(type_loc->getBeginLoc());
|
||||
if (location.isValid()) {
|
||||
auto builder(diag_engine.Report(
|
||||
location,
|
||||
diag_engine.getCustomDiagID(
|
||||
DiagnosticsEngine::Warning,
|
||||
"Modernize non-namespaced type %0 with %1. [%2]")));
|
||||
builder << named_decl;
|
||||
builder << underlying_type;
|
||||
builder << "fairmq-modernize-nonnamespaced-types";
|
||||
auto builder(
|
||||
diag_engine.Report(type_loc->getBeginLoc(),
|
||||
diag_engine.getCustomDiagID(
|
||||
DiagnosticsEngine::Warning,
|
||||
"Modernize non-namespaced type %0 with %1. [%2]")));
|
||||
builder << named_decl;
|
||||
builder << underlying_type;
|
||||
builder << "fairmq-modernize-nonnamespaced-types";
|
||||
|
||||
builder.AddFixItHint(FixItHint::CreateReplacement(
|
||||
type_loc->getSourceRange(), underlying_type.getAsString()));
|
||||
}
|
||||
builder.AddFixItHint(FixItHint::CreateReplacement(
|
||||
type_loc->getSourceRange(), underlying_type.getAsString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -77,8 +77,8 @@ execute_result execute(const string& cmd, const string& prefix, const string& in
|
||||
bp::async_pipe errorPipe(ios);
|
||||
|
||||
const string delimiter = "\n";
|
||||
ba::deadline_timer inputTimer(ios, boost::posix_time::milliseconds(1000)); // NOLINT
|
||||
ba::deadline_timer signalTimer(ios, boost::posix_time::milliseconds(2000)); // NOLINT
|
||||
ba::deadline_timer inputTimer(ios, boost::posix_time::milliseconds(100)); // NOLINT
|
||||
ba::deadline_timer signalTimer(ios, boost::posix_time::milliseconds(400)); // NOLINT
|
||||
|
||||
// child process
|
||||
bp::child c(cmd, bp::std_out > outputPipe, bp::std_err > errorPipe, bp::std_in < inputPipe);
|
||||
|
@@ -194,16 +194,13 @@ inline auto getMonitorEvent(void* monitorSocket) -> int
|
||||
|
||||
// Second frame in message contains event address
|
||||
assertm(zmq_msg_more(&msg), "A second frame is pending"); // NOLINT
|
||||
zmq_msg_close(&msg);
|
||||
zmq_msg_t msg2;
|
||||
zmq_msg_init(&msg2);
|
||||
zmq_msg_init(&msg);
|
||||
{
|
||||
[[maybe_unused]] auto const rc = zmq_msg_recv(&msg2, monitorSocket, 0);
|
||||
[[maybe_unused]] auto const rc = zmq_msg_recv(&msg, monitorSocket, 0);
|
||||
assertm(rc >= 0, "second monitor event frame successfully received"); // NOLINT
|
||||
}
|
||||
assertm(!zmq_msg_more(&msg2), "No more frames are pending"); // NOLINT
|
||||
assertm(!zmq_msg_more(&msg), "No more frames are pending"); // NOLINT
|
||||
// No unpacking of the event address needed for now
|
||||
zmq_msg_close(&msg2);
|
||||
|
||||
return event;
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
@@ -65,7 +65,7 @@ add_testsuite(Protocols
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
@@ -78,7 +78,7 @@ add_testsuite(Parts
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parts
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(Message
|
||||
@@ -90,7 +90,7 @@ add_testsuite(Message
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/message
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
@@ -104,7 +104,7 @@ add_testsuite(Region
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/region
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
@@ -127,7 +127,7 @@ add_testsuite(Device
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/device
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
set(VERSION_MAJOR 1)
|
||||
@@ -151,7 +151,7 @@ set(VERSION_MINOR 2)
|
||||
set(VERSION_PATCH 0)
|
||||
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/helper/plugins/dummy2.h.in ${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy2.h)
|
||||
add_testlib(fairmq-plugin-test_dummy2
|
||||
add_testlib(FairMQPlugin_test_dummy2
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/helper/plugins/dummy2.h
|
||||
helper/plugins/dummy2.cxx
|
||||
@@ -171,8 +171,8 @@ add_testsuite(Plugins
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS FairMQPlugin_test_dummy fairmq-plugin-test_dummy2
|
||||
TIMEOUT 20
|
||||
DEPENDS FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(PluginsPrelinked
|
||||
@@ -180,10 +180,10 @@ add_testsuite(PluginsPrelinked
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
plugins/_plugin_manager_prelink.cxx
|
||||
|
||||
LINKS FairMQ FairMQPlugin_test_dummy fairmq-plugin-test_dummy2
|
||||
LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(PluginServices
|
||||
@@ -196,7 +196,7 @@ add_testsuite(PluginServices
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(EventManager
|
||||
@@ -207,7 +207,7 @@ add_testsuite(EventManager
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(Properties
|
||||
@@ -219,7 +219,7 @@ add_testsuite(Properties
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
# add_testsuite(StateMachine
|
||||
@@ -241,7 +241,7 @@ add_testsuite(Tools
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(Channel
|
||||
@@ -252,7 +252,7 @@ add_testsuite(Channel
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(Transport
|
||||
@@ -265,7 +265,7 @@ add_testsuite(Transport
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
@@ -277,7 +277,7 @@ add_testsuite(Poller
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
@@ -289,6 +289,59 @@ add_testsuite(MemoryResources
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 20
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
if(BUILD_SDK)
|
||||
# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdk/test_topo.xml
|
||||
# ${CMAKE_BINARY_DIR}/test_topo.xml)
|
||||
# add_testsuite(SDK
|
||||
# SOURCES
|
||||
# ${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
# sdk/_async_op.cxx
|
||||
# sdk/_dds.cxx
|
||||
# sdk/_topology.cxx
|
||||
# sdk/Fixtures.h
|
||||
#
|
||||
# LINKS
|
||||
# SDK
|
||||
# Tools
|
||||
# DDS::dds_topology_lib
|
||||
# DDS::dds_tools_lib
|
||||
# INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
# ${CMAKE_CURRENT_BINARY_DIR}
|
||||
# TIMEOUT 30
|
||||
# ${definitions}
|
||||
# )
|
||||
|
||||
if(DDS_TESTS)
|
||||
foreach(i RANGE 1 ${DDS_TESTS})
|
||||
add_test(NAME DDSToolsAPIStabilityTest_${i}
|
||||
COMMAND ${CMAKE_CURRENT_BINARY_DIR}/testsuite_SDK --gtest_filter=TopologyHelper.MakeTopology --gtest_also_run_disabled_tests
|
||||
)
|
||||
set_tests_properties(DDSToolsAPIStabilityTest_${i} PROPERTIES TIMEOUT 10)
|
||||
endforeach()
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/DDSToolsAPIStabilityTest.cmake.in
|
||||
${CMAKE_BINARY_DIR}/DDSToolsAPIStabilityTest.cmake
|
||||
@ONLY
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(BUILD_SDK_COMMANDS)
|
||||
add_testsuite(Commands
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
commands/_commands.cxx
|
||||
|
||||
LINKS
|
||||
Commands
|
||||
StateMachine
|
||||
Tools
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 30
|
||||
${definitions}
|
||||
)
|
||||
endif()
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user