mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-17 18:41:46 +00:00
Compare commits
85 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
960b612d80 | ||
|
e1a113aabe | ||
|
5721ea9510 | ||
|
330687772f | ||
|
7cbd154344 | ||
|
036561ab38 | ||
|
274ba5ec00 | ||
|
c5efd3e4a6 | ||
|
0a5820c07f | ||
|
5788daa410 | ||
|
46014118f0 | ||
|
adc4688f9b | ||
|
c3127f22e5 | ||
|
926ee743ed | ||
|
c7b1304a2c | ||
|
32764e1b12 | ||
|
96348b8462 | ||
|
cd83efadea | ||
|
38eb9d22e4 | ||
|
a20ac7af08 | ||
|
24aabdb854 | ||
|
539b088ade | ||
|
b05782af16 | ||
|
3a8f34efaa | ||
|
8160edfd04 | ||
|
3d4cd02812 | ||
|
0ae53fd7d9 | ||
|
a545bee3b1 | ||
|
f00519b99b | ||
|
41fc27d504 | ||
|
811d1b8973 | ||
|
ced67d8952 | ||
|
8123a6ecab | ||
|
beff0af51b | ||
|
21835cc104 | ||
|
334d81a1ab | ||
|
c1719eb285 | ||
|
fcd1022997 | ||
|
e221242f9a | ||
|
e853d121bf | ||
|
14d6d717a3 | ||
|
119cbe37f1 | ||
|
0e72a9bf54 | ||
|
3785fd9ff9 | ||
|
278cd62049 | ||
|
6c63b01cfe | ||
|
66acde2a69 | ||
|
19ab8bba3b | ||
|
be524d838a | ||
|
92af823135 | ||
|
50dacbcdde | ||
|
264a178424 | ||
|
1c8ad03f3c | ||
|
25658370fa | ||
|
f42945b3a3 | ||
|
9544de0647 | ||
|
d608abf31c | ||
|
15de80cfd3 | ||
|
f2da29a650 | ||
|
c180300303 | ||
|
9f8a3553ba | ||
|
692ec4e997 | ||
|
b6d9c949ae | ||
|
b6791856f9 | ||
|
a1e0814a92 | ||
|
38bb14e556 | ||
|
7187953604 | ||
|
c290c16896 | ||
|
fd2bac3e22 | ||
|
8e3f25851c | ||
|
ce937ca03e | ||
|
684e711b8b | ||
|
5b5fecc994 | ||
|
462a93b58b | ||
|
a2cff5b7bb | ||
|
b2e027478e | ||
|
e6dede492e | ||
|
f195eeac66 | ||
|
4d1e7b9cdb | ||
|
50be386191 | ||
|
f31be6d7a1 | ||
|
5607d47664 | ||
|
0f4595b8c1 | ||
|
b0b271d1f4 | ||
|
073f5e5c0e |
@@ -1,3 +1,3 @@
|
|||||||
---
|
---
|
||||||
Checks: '*,-google-*,-fuchsia-*,-cert-*,-llvm-header-guard,-readability-named-parameter,-misc-non-private-member-variables-in-classes,-*-magic-numbers,-llvm-include-order,-hicpp-no-array-decay,-performance-unnecessary-value-param,-cppcoreguidelines-pro-bounds-array-to-pointer-decay'
|
Checks: '*,-google-*,-fuchsia-*,-cert-*,-llvm-header-guard,-readability-named-parameter,-misc-non-private-member-variables-in-classes,-*-magic-numbers,-llvm-include-order,-hicpp-no-array-decay,-performance-unnecessary-value-param,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-modernize-use-trailing-return-type,-readability-redundant-member-init'
|
||||||
HeaderFilterRegex: '/(fairmq/)'
|
HeaderFilterRegex: '/(fairmq/)'
|
||||||
|
@@ -6,8 +6,8 @@
|
|||||||
# copied verbatim in the file "LICENSE" #
|
# copied verbatim in the file "LICENSE" #
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.11 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.12 FATAL_ERROR)
|
||||||
cmake_policy(VERSION 3.11...3.15)
|
cmake_policy(VERSION 3.12...3.15)
|
||||||
|
|
||||||
# Project ######################################################################
|
# Project ######################################################################
|
||||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
@@ -18,7 +18,7 @@ get_git_version()
|
|||||||
project(FairMQ VERSION ${PROJECT_VERSION} LANGUAGES CXX)
|
project(FairMQ VERSION ${PROJECT_VERSION} LANGUAGES CXX)
|
||||||
message(STATUS "${BWhite}${PROJECT_NAME}${CR} ${PROJECT_GIT_VERSION} from ${PROJECT_DATE}")
|
message(STATUS "${BWhite}${PROJECT_NAME}${CR} ${PROJECT_GIT_VERSION} from ${PROJECT_DATE}")
|
||||||
|
|
||||||
if(BUILD_OFI_TRANSPORT OR BUILD_SDK)
|
if(BUILD_OFI_TRANSPORT OR BUILD_SDK OR BUILD_PMIX_PLUGIN)
|
||||||
set(PROJECT_MIN_CXX_STANDARD 14)
|
set(PROJECT_MIN_CXX_STANDARD 14)
|
||||||
else()
|
else()
|
||||||
set(PROJECT_MIN_CXX_STANDARD 11)
|
set(PROJECT_MIN_CXX_STANDARD 11)
|
||||||
@@ -44,7 +44,7 @@ fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
|
|||||||
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
|
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
|
||||||
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
|
||||||
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
|
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."
|
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
|
||||||
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
|
||||||
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
|
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
|
||||||
@@ -85,21 +85,15 @@ if(BUILD_NANOMSG_TRANSPORT)
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_SDK)
|
|
||||||
set(required_dds_version 2.5.46)
|
|
||||||
else()
|
|
||||||
set(required_dds_version 2.4)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_SDK_COMMANDS)
|
if(BUILD_SDK_COMMANDS)
|
||||||
find_package2(PRIVATE Flatbuffers REQUIRED)
|
find_package2(PRIVATE Flatbuffers REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
|
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
|
||||||
find_package2(PRIVATE DDS REQUIRED
|
find_package2(PRIVATE DDS REQUIRED
|
||||||
VERSION ${required_dds_version}
|
VERSION 3.0
|
||||||
)
|
)
|
||||||
set(DDS_Boost_COMPONENTS system log log_setup)
|
set(DDS_Boost_COMPONENTS system log log_setup regex filesystem thread)
|
||||||
set(DDS_Boost_VERSION 1.67)
|
set(DDS_Boost_VERSION 1.67)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
@@ -403,9 +397,9 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
||||||
if(BUILD_PMIX_PLUGIN)
|
if(BUILD_PMIX_PLUGIN)
|
||||||
set(pmix_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
set(pmix_summary "${BGreen}YES${CR} EXPERIMENTAL (requires C++14) (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
||||||
else()
|
else()
|
||||||
set(pmix_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_PMIX_PLUGIN=ON${CR})")
|
set(pmix_summary "${BRed} NO${CR} EXPERIMENTAL (requires C++14) (default, enable with ${BMagenta}-DBUILD_PMIX_PLUGIN=ON${CR})")
|
||||||
endif()
|
endif()
|
||||||
message(STATUS " ${BWhite}pmix_plugin${CR} ${pmix_summary}")
|
message(STATUS " ${BWhite}pmix_plugin${CR} ${pmix_summary}")
|
||||||
if(BUILD_EXAMPLES)
|
if(BUILD_EXAMPLES)
|
||||||
|
@@ -4,6 +4,7 @@ Eulisse, Giulio
|
|||||||
Karabowicz, Radoslaw
|
Karabowicz, Radoslaw
|
||||||
Kretz, Matthias <kretz@kde.org>
|
Kretz, Matthias <kretz@kde.org>
|
||||||
Krzewicki, Mikolaj
|
Krzewicki, Mikolaj
|
||||||
|
Lebedev, Andrey
|
||||||
Mrnjavac, Teo <teo.m@cern.ch>
|
Mrnjavac, Teo <teo.m@cern.ch>
|
||||||
Neskovic, Gvozden
|
Neskovic, Gvozden
|
||||||
Richter, Matthias
|
Richter, Matthias
|
||||||
|
2
Dart.sh
2
Dart.sh
@@ -65,7 +65,7 @@ if [ "$1" == "alfa_ci" ]; then
|
|||||||
export ctest_model=Experimental
|
export ctest_model=Experimental
|
||||||
elif [ "$1" == "codecov" ]; then
|
elif [ "$1" == "codecov" ]; then
|
||||||
export ctest_model=Profile
|
export ctest_model=Profile
|
||||||
export do_codecov_upload=1
|
export do_codecov_upload=0
|
||||||
else
|
else
|
||||||
export ctest_model=$1
|
export ctest_model=$1
|
||||||
fi
|
fi
|
||||||
|
@@ -143,15 +143,17 @@ macro(set_fairmq_defaults)
|
|||||||
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
|
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
|
||||||
|
|
||||||
# Configure build types
|
# Configure build types
|
||||||
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "Experimental" "AdressSan" "ThreadSan")
|
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "Experimental" "AddressSan" "ThreadSan")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wshadow -Wall -Wextra")
|
set(_warnings "-Wshadow -Wall -Wextra -Wpedantic")
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g ${_warnings}")
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
||||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${_warnings} -DNDEBUG")
|
||||||
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
|
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g ${_warnings}")
|
||||||
set(CMAKE_CXX_FLAGS_PROFILE "-g3 -Wshadow -Wall -Wextra -fno-inline -ftest-coverage -fprofile-arcs")
|
set(CMAKE_CXX_FLAGS_PROFILE "-g3 ${_warnings} -fno-inline -ftest-coverage -fprofile-arcs")
|
||||||
set(CMAKE_CXX_FLAGS_EXPERIMENTAL "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
set(CMAKE_CXX_FLAGS_EXPERIMENTAL "-O2 -g ${_warnings} -DNDEBUG")
|
||||||
set(CMAKE_CXX_FLAGS_ADRESSSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=address -fno-omit-frame-pointer")
|
set(CMAKE_CXX_FLAGS_ADDRESSSAN "-O2 -g ${_warnings} -fsanitize=address -fno-omit-frame-pointer")
|
||||||
set(CMAKE_CXX_FLAGS_THREADSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=thread")
|
set(CMAKE_CXX_FLAGS_THREADSAN "-O2 -g ${_warnings} -fsanitize=thread")
|
||||||
|
unset(_warnings)
|
||||||
|
|
||||||
if(CMAKE_GENERATOR STREQUAL "Ninja" AND
|
if(CMAKE_GENERATOR STREQUAL "Ninja" AND
|
||||||
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
|
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
|
||||||
@@ -522,7 +524,7 @@ macro(fairmq_build_option option description)
|
|||||||
if(${__requires_condition__})
|
if(${__requires_condition__})
|
||||||
else()
|
else()
|
||||||
if(${option})
|
if(${option})
|
||||||
message(WARNING "Cannot enable build option ${option}, depending option is not set: ${__requires_condition__}")
|
message(FATAL_ERROR "Cannot enable build option ${option}, depending option is not set: ${__requires_condition__}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
@@ -16,6 +16,8 @@ add_subdirectory(multiple-channels)
|
|||||||
if(BUILD_NANOMSG_TRANSPORT)
|
if(BUILD_NANOMSG_TRANSPORT)
|
||||||
add_subdirectory(multiple-transports)
|
add_subdirectory(multiple-transports)
|
||||||
endif()
|
endif()
|
||||||
|
add_subdirectory(n-m)
|
||||||
|
add_subdirectory(qc)
|
||||||
add_subdirectory(readout)
|
add_subdirectory(readout)
|
||||||
add_subdirectory(region)
|
add_subdirectory(region)
|
||||||
add_subdirectory(req-rep)
|
add_subdirectory(req-rep)
|
||||||
|
@@ -6,41 +6,50 @@ Set of FairMQ examples. More examples that combine FairMQ with FairRoot can be f
|
|||||||
|
|
||||||
A simple topology of two devices - **Sampler** and **Sink**. **Sampler** sends data to **Sink** with the **PUSH-PULL** pattern.
|
A simple topology of two devices - **Sampler** and **Sink**. **Sampler** sends data to **Sink** with the **PUSH-PULL** pattern.
|
||||||
|
|
||||||
|
|
||||||
## 1-n-1
|
## 1-n-1
|
||||||
|
|
||||||
A simple topology of three device types - **Sampler**, **Processor** and **Sink**. **Sampler** sends data to one or more **Processor**s, who modify the data and send it to one **Sink**. Transport with the **PUSH-PULL** pattern. The example also shows the configuration via JSON files, as oposed to `--channel-config` that is used by other examples.
|
A simple topology of three device types - **Sampler**, **Processor** and **Sink**. **Sampler** sends data to one or more **Processor**s, who modify the data and send it to one **Sink**. Transport with the **PUSH-PULL** pattern. The example also shows the configuration via JSON files, as oposed to `--channel-config` that is used by other examples.
|
||||||
|
|
||||||
|
## Built-in devices
|
||||||
|
|
||||||
## DDS
|
Usage of generic devies provided with FairMQ.
|
||||||
|
|
||||||
This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to those of Example 2, but now it can be easily distributed on different computing nodes without the need for manual reconfiguration of the devices.
|
|
||||||
|
|
||||||
|
|
||||||
## Copy & Push
|
## Copy & Push
|
||||||
|
|
||||||
A topology consisting of one **Sampler** and two **Sink**s. The **Sampler** uses the `Copy` method to send the same data to both sinks with the **PUSH-PULL** pattern. In countrary to the **PUB-SUB** pattern, this ensures that all receivers are connected and no data is lost, but requires additional channels to be configured.
|
A topology consisting of one **Sampler** and two **Sink**s. The **Sampler** uses the `Copy` method to send the same data to both sinks with the **PUSH-PULL** pattern. In countrary to the **PUB-SUB** pattern, this ensures that all receivers are connected and no data is lost, but requires additional channels to be configured.
|
||||||
|
|
||||||
|
## DDS
|
||||||
|
|
||||||
## Request & Reply
|
This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to those of Example 2, but now it can be easily distributed on different computing nodes without the need for manual reconfiguration of the devices.
|
||||||
|
|
||||||
This topology contains two devices that communicate with each other via the **REQ-REP** pettern. Bidirectional communication via a single socket.
|
## Multipart
|
||||||
|
|
||||||
|
This example shows how to send a multipart message from one device to the other. (two parts message parts - header and body).
|
||||||
|
|
||||||
## Multiple Channels
|
## Multiple Channels
|
||||||
|
|
||||||
This example demonstrates how to work with multiple channels and multiplex between them.
|
This example demonstrates how to work with multiple channels and multiplex between them.
|
||||||
|
|
||||||
|
## Multiple Transports
|
||||||
## Sending Multipart messages
|
|
||||||
|
|
||||||
This example shows how to send a multipart message from one device to the other. (two parts message parts - header and body).
|
|
||||||
|
|
||||||
|
|
||||||
## Multiple Transports example
|
|
||||||
|
|
||||||
This examples shows how to combine different channel transports (zeromq/nanomsg/shmem) inside of one device and/or topology.
|
This examples shows how to combine different channel transports (zeromq/nanomsg/shmem) inside of one device and/or topology.
|
||||||
|
|
||||||
## Region example
|
## n-m
|
||||||
|
|
||||||
|
A topology consisting of three layers of devices: synchronizer -> n * senders -> m * receivers.
|
||||||
|
|
||||||
|
## QC
|
||||||
|
|
||||||
|
A topology consisting of 4 devices - Sampler, QCDispatcher, QCTask and Sink. The data flows from Sampler through QCDispatcher to Sink. On demand - by setting the corresponding configuration property - the QCDispatcher device will duplicate the data to the QCTask device. The property is set by the topology controller, in this example this is the `fairmq-dds-command-ui` utility.
|
||||||
|
|
||||||
|
## Readout
|
||||||
|
|
||||||
|
Two example topologies of setups to be distributed to two kinds of nodes - detector readout node and processing node. Detector readout node contains readout process, data builder and data sender (and optionally an additional processor), while processing node contains data receiver devices. communication within readout nodes is done via unmanaged region through shared memory transport.
|
||||||
|
|
||||||
|
## Region
|
||||||
|
|
||||||
This example demonstrates the use of a more advanced feature - UnmanagedRegion, that can be used to create a buffer through one of FairMQ transports. The contents of this buffer are managed by the user, who can also create messages out of sub-buffers of the created buffer. Such feature can be interesting in environments that have special requirements by the hardware that writes the data, to keep the transfer efficient (e.g. shared memory).
|
This example demonstrates the use of a more advanced feature - UnmanagedRegion, that can be used to create a buffer through one of FairMQ transports. The contents of this buffer are managed by the user, who can also create messages out of sub-buffers of the created buffer. Such feature can be interesting in environments that have special requirements by the hardware that writes the data, to keep the transfer efficient (e.g. shared memory).
|
||||||
|
|
||||||
|
## Request & Reply
|
||||||
|
|
||||||
|
This topology contains two devices that communicate with each other via the **REQ-REP** pettern. Bidirectional communication via a single socket.
|
||||||
|
@@ -7,12 +7,12 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
add_library(ExampleDDSLib STATIC
|
add_library(ExampleDDSLib STATIC
|
||||||
"Sampler.cxx"
|
"Sampler.cxx"
|
||||||
"Sampler.h"
|
"Sampler.h"
|
||||||
"Processor.cxx"
|
"Processor.cxx"
|
||||||
"Processor.h"
|
"Processor.h"
|
||||||
"Sink.cxx"
|
"Sink.cxx"
|
||||||
"Sink.h"
|
"Sink.h"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(ExampleDDSLib PUBLIC FairMQ)
|
target_link_libraries(ExampleDDSLib PUBLIC FairMQ)
|
||||||
@@ -28,12 +28,7 @@ target_link_libraries(fairmq-ex-dds-sink PRIVATE ExampleDDSLib)
|
|||||||
|
|
||||||
add_custom_target(ExampleDDS DEPENDS fairmq-ex-dds-sampler fairmq-ex-dds-processor fairmq-ex-dds-sink)
|
add_custom_target(ExampleDDS DEPENDS fairmq-ex-dds-sampler fairmq-ex-dds-processor fairmq-ex-dds-sink)
|
||||||
|
|
||||||
if(DDS_VERSION VERSION_LESS 2.5.25)
|
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||||
set(WAIT_COMMAND "dds-info --wait-for-idle-agents")
|
|
||||||
else()
|
|
||||||
set(WAIT_COMMAND "dds-info --idle-count --wait")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||||
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-dds-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml @ONLY)
|
||||||
@@ -44,24 +39,24 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CUR
|
|||||||
|
|
||||||
# test
|
# test
|
||||||
if(DDS_FOUND)
|
if(DDS_FOUND)
|
||||||
add_test(NAME Example.DDS.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh localhost)
|
add_test(NAME Example.DDS.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh localhost)
|
||||||
set_tests_properties(Example.DDS.localhost PROPERTIES
|
set_tests_properties(Example.DDS.localhost PROPERTIES
|
||||||
TIMEOUT 15
|
TIMEOUT 15
|
||||||
RUN_SERIAL true
|
RUN_SERIAL true
|
||||||
PASS_REGULAR_EXPRESSION "Example successful"
|
PASS_REGULAR_EXPRESSION "Example successful"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# install
|
# install
|
||||||
|
|
||||||
install(
|
install(
|
||||||
TARGETS
|
TARGETS
|
||||||
fairmq-ex-dds-sampler
|
fairmq-ex-dds-sampler
|
||||||
fairmq-ex-dds-processor
|
fairmq-ex-dds-processor
|
||||||
fairmq-ex-dds-sink
|
fairmq-ex-dds-sink
|
||||||
|
|
||||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
# configure run script with different executable paths for build and for install directories
|
# configure run script with different executable paths for build and for install directories
|
||||||
@@ -73,30 +68,30 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-dds-env.sh ${CMAKE_CURRENT_
|
|||||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install @ONLY)
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install @ONLY)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology.xml_install
|
||||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
RENAME ex-dds-topology.xml
|
RENAME ex-dds-topology.xml
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-topology-infinite.xml_install
|
||||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
RENAME ex-dds-topology-infinite.xml
|
RENAME ex-dds-topology-infinite.xml
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-dds-hosts.cfg
|
||||||
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-dds-env.sh_install
|
||||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
RENAME fairmq-ex-dds-env.sh
|
RENAME fairmq-ex-dds-env.sh
|
||||||
)
|
)
|
||||||
|
|
||||||
install(
|
install(
|
||||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-dds.sh_install
|
||||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
RENAME fairmq-start-ex-dds.sh
|
RENAME fairmq-start-ex-dds.sh
|
||||||
)
|
)
|
||||||
|
@@ -9,3 +9,8 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
export PATH=@BIN_DIR@:$PATH
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
OS=$(uname -s 2>&1)
|
||||||
|
if [ "$OS" == "Darwin" ]; then
|
||||||
|
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||||
|
fi
|
||||||
|
@@ -30,52 +30,49 @@ echo "SESSION ID: ${DDS_SESSION_ID}"
|
|||||||
|
|
||||||
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||||
|
|
||||||
requiredNofAgents=12
|
requiredNofSlots=12
|
||||||
if [[ "$plugin" == "ssh" ]]; then
|
if [[ "$plugin" == "ssh" ]]; then
|
||||||
dds-submit -r ${plugin} -c @DATA_DIR@/ex-dds-hosts.cfg
|
dds-submit -r ${plugin} -c @DATA_DIR@/ex-dds-hosts.cfg
|
||||||
else
|
else
|
||||||
dds-submit -r ${plugin} -n ${requiredNofAgents}
|
dds-submit -r ${plugin} --slots ${requiredNofSlots}
|
||||||
fi
|
fi
|
||||||
echo "...waiting for ${requiredNofAgents} idle agents..."
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
@WAIT_COMMAND@ ${requiredNofAgents}
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
topologyFile=@DATA_DIR@/ex-dds-topology.xml
|
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-dds-topology.xml
|
||||||
echo "TOPOLOGY FILE: ${topologyFile}"
|
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||||
# TODO Uncomment once DDS 2.6 is released
|
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||||
# echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${topologyFile})"
|
|
||||||
|
|
||||||
# TODO Uncomment once DDS 2.6 is released
|
dds-info --active-topology
|
||||||
# dds-info --active-topology
|
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||||
dds-topology --activate ${topologyFile}
|
dds-info --active-topology
|
||||||
# dds-info --active-topology
|
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||||
# dds-info --wait-for-executing-agents ${requiredNofAgents}
|
dds-info --executing-count --wait ${requiredNofSlots}
|
||||||
sleep 1
|
|
||||||
|
|
||||||
echo "------------------------"
|
echo "------------------------"
|
||||||
echo "...waiting for Topology to finish..."
|
echo "...waiting for Topology to finish..."
|
||||||
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||||
fairmq-dds-command-ui -w "IDLE" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -w "IDLE"
|
||||||
fairmq-dds-command-ui -c i -w "INITIALIZING DEVICE" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c i
|
||||||
fairmq-dds-command-ui -c k -w "INITIALIZED" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c k
|
||||||
fairmq-dds-command-ui -c b -w "BOUND" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c b
|
||||||
fairmq-dds-command-ui -c x -w "DEVICE READY" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c x
|
||||||
fairmq-dds-command-ui -c j -w "READY" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c j
|
||||||
fairmq-dds-command-ui -c r
|
fairmq-dds-command-ui -c r
|
||||||
sampler_and_sink="main/(Sampler|Sink)"
|
sampler_and_sink="main/(Sampler|Sink).*"
|
||||||
fairmq-dds-command-ui -p $sampler_and_sink -w "RUNNING->READY" -n 2
|
fairmq-dds-command-ui -w "RUNNING->READY" -p $sampler_and_sink
|
||||||
echo "...$sampler_and_sink are READY, sending shutdown..."
|
echo "...$sampler_and_sink are READY, sending shutdown..."
|
||||||
fairmq-dds-command-ui -c s -w "RUNNING->READY" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c s
|
||||||
fairmq-dds-command-ui -c t -w "DEVICE READY" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c t
|
||||||
fairmq-dds-command-ui -c d -w "IDLE" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c d
|
||||||
fairmq-dds-command-ui -c q -w "EXITING" -n ${requiredNofAgents}
|
fairmq-dds-command-ui -c q
|
||||||
echo "...waiting for ${requiredNofAgents} idle agents..."
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
@WAIT_COMMAND@ ${requiredNofAgents}
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
echo "------------------------"
|
echo "------------------------"
|
||||||
|
|
||||||
# TODO Uncomment once DDS 2.6 is released
|
dds-info --active-topology
|
||||||
# dds-info --active-topology
|
|
||||||
dds-topology --stop
|
dds-topology --stop
|
||||||
# dds-info --active-topology
|
dds-info --active-topology
|
||||||
|
|
||||||
dds-agent-cmd getlog -a
|
dds-agent-cmd getlog -a
|
||||||
logDir="${wrkDir}/logs"
|
logDir="${wrkDir}/logs"
|
||||||
|
@@ -20,7 +20,7 @@ SAMPLER+=" --verbosity veryhigh"
|
|||||||
SAMPLER+=" --session $SESSION"
|
SAMPLER+=" --session $SESSION"
|
||||||
SAMPLER+=" --max-iterations 1"
|
SAMPLER+=" --max-iterations 1"
|
||||||
SAMPLER+=" --control static --color false"
|
SAMPLER+=" --control static --color false"
|
||||||
SAMPLER+=" --channel-config name=data,type=pair,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
|
SAMPLER+=" --channel-config name=data,type=pair,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555,linger=1000"
|
||||||
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
|
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
|
||||||
SAMPLER_PID=$!
|
SAMPLER_PID=$!
|
||||||
|
|
||||||
|
99
examples/n-m/CMakeLists.txt
Normal file
99
examples/n-m/CMakeLists.txt
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright (C) 2014 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" #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-n-m-synchronizer runSynchronizer.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-n-m-synchronizer PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-n-m-sender runSender.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-n-m-sender PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-n-m-receiver runReceiver.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-n-m-receiver PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_custom_target(ExampleNM DEPENDS fairmq-ex-n-m-synchronizer fairmq-ex-n-m-sender fairmq-ex-n-m-receiver)
|
||||||
|
|
||||||
|
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||||
|
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||||
|
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-pair-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-n-m-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh @ONLY)
|
||||||
|
|
||||||
|
# test
|
||||||
|
if(DDS_FOUND)
|
||||||
|
add_test(NAME Example.N-M.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh localhost)
|
||||||
|
set_tests_properties(Example.N-M.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||||
|
add_test(NAME Example.N-M-pair.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh localhost)
|
||||||
|
set_tests_properties(Example.N-M-pair.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# install
|
||||||
|
install(
|
||||||
|
TARGETS
|
||||||
|
fairmq-ex-n-m-synchronizer
|
||||||
|
fairmq-ex-n-m-sender
|
||||||
|
fairmq-ex-n-m-receiver
|
||||||
|
|
||||||
|
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# configure run script with different executable paths for build and for install directories
|
||||||
|
set(BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||||
|
set(DATA_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-n-m-pair-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-n-m-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-n-m-pair-dds.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh_install @ONLY)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-topology.xml_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
|
RENAME ex-n-m-topology.xml
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-n-m-pair-topology.xml_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
|
RENAME ex-n-m-pair-topology.xml
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-n-m-env.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-ex-n-m-env.sh
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-start-ex-n-m.sh
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-start-ex-n-m-pair.sh
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-dds.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-start-ex-n-m-dds.sh
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-n-m-pair-dds.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-start-ex-n-m-pair-dds.sh
|
||||||
|
)
|
24
examples/n-m/Header.h
Normal file
24
examples/n-m/Header.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 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_EXAMPLE_N_M_HEADER_H
|
||||||
|
#define FAIR_MQ_EXAMPLE_N_M_HEADER_H
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace example_n_m
|
||||||
|
{
|
||||||
|
|
||||||
|
struct Header
|
||||||
|
{
|
||||||
|
std::uint16_t id;
|
||||||
|
int senderIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace example_n_m
|
||||||
|
|
||||||
|
#endif /* FAIR_MQ_EXAMPLE_N_M_HEADER_H */
|
4
examples/n-m/README.md
Normal file
4
examples/n-m/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
N-M
|
||||||
|
==========================
|
||||||
|
|
||||||
|
A topology consisting of three layers of devices: synchronizer -> sender(s) -> receiver(s). Senders distribute data to receivers based on the data id contained in the message from the synchronizer (same id goes to the same receiver from every sender). The senders send the data in a non-blocking fashion - if queue is full or receiver is down, data is discarded. Two configurations are provided - one using push/pull channels between senders/receivers, another using pair channels. In push/pull case there is only one receiving channel on the receiver device. In pair case there are as many receiver (sub-)channels as there are senders.
|
44
examples/n-m/ex-n-m-pair-topology.xml
Normal file
44
examples/n-m/ex-n-m-pair-topology.xml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<topology name="myTopology">
|
||||||
|
|
||||||
|
<var name="numSenders" value="3" />
|
||||||
|
<var name="numReceivers" value="4" />
|
||||||
|
|
||||||
|
<property name="fmqchan_sync" />
|
||||||
|
<property name="fmqchan_data" />
|
||||||
|
|
||||||
|
<decltask name="Synchronizer">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-synchronizer --id sync --rate 100 --color false -P dds --channel-config name=sync,type=pub,method=bind</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_sync</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="Sender">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-sender --id sender%taskIndex% --timeframe-size 100000 --num-receivers ${numReceivers} --color false -P dds --channel-config name=sync,type=sub,method=connect name=data,type=pair,method=connect,numSockets=${numReceivers} --dds-i data:%taskIndex%</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="read">fmqchan_sync</id>
|
||||||
|
<name access="read">fmqchan_data</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="Receiver">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-receiver --id receiver%taskIndex% --num-senders ${numSenders} --color false -P dds --max-timeframes 10 --channel-config name=data,type=pair,method=bind,numSockets=${numSenders}</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_data</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<main name="main">
|
||||||
|
<task>Synchronizer</task>
|
||||||
|
<group name="Senders" n="${numSenders}">
|
||||||
|
<task>Sender</task>
|
||||||
|
</group>
|
||||||
|
<group name="Receivers" n="${numReceivers}">
|
||||||
|
<task>Receiver</task>
|
||||||
|
</group>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</topology>
|
44
examples/n-m/ex-n-m-topology.xml
Normal file
44
examples/n-m/ex-n-m-topology.xml
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
<topology name="myTopology">
|
||||||
|
|
||||||
|
<var name="numSenders" value="3" />
|
||||||
|
<var name="numReceivers" value="4" />
|
||||||
|
|
||||||
|
<property name="fmqchan_sync" />
|
||||||
|
<property name="fmqchan_data" />
|
||||||
|
|
||||||
|
<decltask name="Synchronizer">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-synchronizer --id sync --rate 100 --color false -P dds --channel-config name=sync,type=pub,method=bind</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_sync</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="Sender">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-sender --id sender%taskIndex% --timeframe-size 100000 --num-receivers ${numReceivers} --color false -P dds --channel-config name=sync,type=sub,method=connect name=data,type=push,method=connect,numSockets=${numReceivers}</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="read">fmqchan_sync</id>
|
||||||
|
<name access="read">fmqchan_data</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="Receiver">
|
||||||
|
<exe reachable="true">fairmq-ex-n-m-receiver --id receiver%taskIndex% --num-senders ${numSenders} --color false -P dds --max-timeframes 10 --channel-config name=data,type=pull,method=bind</exe>
|
||||||
|
<env reachable="false">fairmq-ex-n-m-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_data</id>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<main name="main">
|
||||||
|
<task>Synchronizer</task>
|
||||||
|
<group name="Senders" n="${numSenders}">
|
||||||
|
<task>Sender</task>
|
||||||
|
</group>
|
||||||
|
<group name="Receivers" n="${numReceivers}">
|
||||||
|
<task>Receiver</task>
|
||||||
|
</group>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</topology>
|
16
examples/n-m/fairmq-ex-n-m-env.sh
Executable file
16
examples/n-m/fairmq-ex-n-m-env.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 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" #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
OS=$(uname -s 2>&1)
|
||||||
|
if [ "$OS" == "Darwin" ]; then
|
||||||
|
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||||
|
fi
|
76
examples/n-m/fairmq-start-ex-n-m-dds.sh.in
Executable file
76
examples/n-m/fairmq-start-ex-n-m-dds.sh.in
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 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 -e
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
dds-session stop $1
|
||||||
|
echo "CLEANUP PERFORMED"
|
||||||
|
}
|
||||||
|
|
||||||
|
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
exec 5>&1
|
||||||
|
output=$(dds-session start | tee >(cat - >&5))
|
||||||
|
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||||
|
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||||
|
|
||||||
|
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||||
|
|
||||||
|
requiredNofSlots=8
|
||||||
|
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-n-m-topology.xml
|
||||||
|
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||||
|
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||||
|
dds-info --active-topology
|
||||||
|
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||||
|
dds-info --executing-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
echo "------------------------"
|
||||||
|
echo "...waiting for Topology to finish..."
|
||||||
|
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||||
|
fairmq-dds-command-ui -w "IDLE"
|
||||||
|
fairmq-dds-command-ui -c i
|
||||||
|
fairmq-dds-command-ui -c k
|
||||||
|
fairmq-dds-command-ui -c b
|
||||||
|
fairmq-dds-command-ui -c x
|
||||||
|
fairmq-dds-command-ui -c j
|
||||||
|
fairmq-dds-command-ui -c r
|
||||||
|
receivers="main/Receivers.*"
|
||||||
|
fairmq-dds-command-ui -w "RUNNING->READY" -p $receivers
|
||||||
|
echo "All receivers transitioned from RUNNING to READY"
|
||||||
|
fairmq-dds-command-ui -c s
|
||||||
|
fairmq-dds-command-ui -c t
|
||||||
|
fairmq-dds-command-ui -c d
|
||||||
|
fairmq-dds-command-ui -c q
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
echo "------------------------"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --stop
|
||||||
|
dds-info --active-topology
|
||||||
|
|
||||||
|
dds-agent-cmd getlog -a
|
||||||
|
logDir="${wrkDir}/logs"
|
||||||
|
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||||
|
echo "AGENT LOG FILES IN: ${logDir}"
|
||||||
|
|
||||||
|
# This string is used by ctest to detect success
|
||||||
|
echo "Example successful :)"
|
||||||
|
|
||||||
|
# Cleanup function is called by EXIT trap
|
76
examples/n-m/fairmq-start-ex-n-m-pair-dds.sh.in
Executable file
76
examples/n-m/fairmq-start-ex-n-m-pair-dds.sh.in
Executable file
@@ -0,0 +1,76 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 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 -e
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
dds-session stop $1
|
||||||
|
echo "CLEANUP PERFORMED"
|
||||||
|
}
|
||||||
|
|
||||||
|
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
exec 5>&1
|
||||||
|
output=$(dds-session start | tee >(cat - >&5))
|
||||||
|
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||||
|
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||||
|
|
||||||
|
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||||
|
|
||||||
|
requiredNofSlots=8
|
||||||
|
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-n-m-pair-topology.xml
|
||||||
|
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||||
|
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||||
|
dds-info --active-topology
|
||||||
|
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||||
|
dds-info --executing-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
echo "------------------------"
|
||||||
|
echo "...waiting for Topology to finish..."
|
||||||
|
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||||
|
fairmq-dds-command-ui -w "IDLE"
|
||||||
|
fairmq-dds-command-ui -c i
|
||||||
|
fairmq-dds-command-ui -c k
|
||||||
|
fairmq-dds-command-ui -c b
|
||||||
|
fairmq-dds-command-ui -c x
|
||||||
|
fairmq-dds-command-ui -c j
|
||||||
|
fairmq-dds-command-ui -c r
|
||||||
|
receivers="main/Receivers.*"
|
||||||
|
fairmq-dds-command-ui -w "RUNNING->READY" -p $receivers
|
||||||
|
echo "All receivers transitioned from RUNNING to READY"
|
||||||
|
fairmq-dds-command-ui -c s
|
||||||
|
fairmq-dds-command-ui -c t
|
||||||
|
fairmq-dds-command-ui -c d
|
||||||
|
fairmq-dds-command-ui -c q
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
echo "------------------------"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --stop
|
||||||
|
dds-info --active-topology
|
||||||
|
|
||||||
|
dds-agent-cmd getlog -a
|
||||||
|
logDir="${wrkDir}/logs"
|
||||||
|
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||||
|
echo "AGENT LOG FILES IN: ${logDir}"
|
||||||
|
|
||||||
|
# This string is used by ctest to detect success
|
||||||
|
echo "Example successful :)"
|
||||||
|
|
||||||
|
# Cleanup function is called by EXIT trap
|
60
examples/n-m/fairmq-start-ex-n-m-pair.sh.in
Executable file
60
examples/n-m/fairmq-start-ex-n-m-pair.sh.in
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
SYNC="fairmq-ex-n-m-synchronizer"
|
||||||
|
SYNC+=" --id Sync"
|
||||||
|
SYNC+=" --channel-config name=sync,type=pub,method=bind,address=tcp://localhost:8010"
|
||||||
|
SYNC+=" --rate 100"
|
||||||
|
xterm -geometry 80x25+0+0 -hold -e $SYNC &
|
||||||
|
|
||||||
|
SENDER0="fairmq-ex-n-m-sender"
|
||||||
|
SENDER0+=" --id Sender1"
|
||||||
|
SENDER0+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER0+=" name=data,type=pair,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||||
|
SENDER0+=" --sender-index 0"
|
||||||
|
SENDER0+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER0+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+0 -hold -e $SENDER0 &
|
||||||
|
|
||||||
|
SENDER1="fairmq-ex-n-m-sender"
|
||||||
|
SENDER1+=" --id Sender2"
|
||||||
|
SENDER1+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER1+=" name=data,type=pair,method=connect,address=tcp://localhost:8031,address=tcp://localhost:8032,address=tcp://localhost:8033,address=tcp://localhost:8034"
|
||||||
|
SENDER1+=" --sender-index 1"
|
||||||
|
SENDER1+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER1+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+350 -hold -e $SENDER1 &
|
||||||
|
|
||||||
|
SENDER2="fairmq-ex-n-m-sender"
|
||||||
|
SENDER2+=" --id Sender3"
|
||||||
|
SENDER2+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER2+=" name=data,type=pair,method=connect,address=tcp://localhost:8041,address=tcp://localhost:8042,address=tcp://localhost:8043,address=tcp://localhost:8044"
|
||||||
|
SENDER2+=" --sender-index 2"
|
||||||
|
SENDER2+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER2+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+700 -hold -e $SENDER2 &
|
||||||
|
|
||||||
|
RECEIVER0="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER0+=" --id Receiver1"
|
||||||
|
RECEIVER0+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8021,address=tcp://localhost:8031,address=tcp://localhost:8041"
|
||||||
|
RECEIVER0+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+0 -hold -e $RECEIVER0 &
|
||||||
|
|
||||||
|
RECEIVER1="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER1+=" --id Receiver2"
|
||||||
|
RECEIVER1+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8022,address=tcp://localhost:8032,address=tcp://localhost:8042"
|
||||||
|
RECEIVER1+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+350 -hold -e $RECEIVER1 &
|
||||||
|
|
||||||
|
RECEIVER2="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER2+=" --id Receiver3"
|
||||||
|
RECEIVER2+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8023,address=tcp://localhost:8033,address=tcp://localhost:8043"
|
||||||
|
RECEIVER2+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+700 -hold -e $RECEIVER2 &
|
||||||
|
|
||||||
|
RECEIVER3="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER3+=" --id Receiver4"
|
||||||
|
RECEIVER3+=" --channel-config name=data,type=pair,method=bind,address=tcp://localhost:8024,address=tcp://localhost:8034,address=tcp://localhost:8044"
|
||||||
|
RECEIVER3+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+1050 -hold -e $RECEIVER3 &
|
60
examples/n-m/fairmq-start-ex-n-m.sh.in
Executable file
60
examples/n-m/fairmq-start-ex-n-m.sh.in
Executable file
@@ -0,0 +1,60 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
SYNC="fairmq-ex-n-m-synchronizer"
|
||||||
|
SYNC+=" --id Sync"
|
||||||
|
SYNC+=" --channel-config name=sync,type=pub,method=bind,address=tcp://localhost:8010"
|
||||||
|
SYNC+=" --rate 100"
|
||||||
|
xterm -geometry 80x25+0+0 -hold -e $SYNC &
|
||||||
|
|
||||||
|
SENDER0="fairmq-ex-n-m-sender"
|
||||||
|
SENDER0+=" --id Sender1"
|
||||||
|
SENDER0+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER0+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||||
|
SENDER0+=" --sender-index 0"
|
||||||
|
SENDER0+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER0+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+0 -hold -e $SENDER0 &
|
||||||
|
|
||||||
|
SENDER1="fairmq-ex-n-m-sender"
|
||||||
|
SENDER1+=" --id Sender2"
|
||||||
|
SENDER1+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER1+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||||
|
SENDER1+=" --sender-index 1"
|
||||||
|
SENDER1+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER1+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+350 -hold -e $SENDER1 &
|
||||||
|
|
||||||
|
SENDER2="fairmq-ex-n-m-sender"
|
||||||
|
SENDER2+=" --id Sender3"
|
||||||
|
SENDER2+=" --channel-config name=sync,type=sub,method=connect,address=tcp://localhost:8010"
|
||||||
|
SENDER2+=" name=data,type=push,method=connect,address=tcp://localhost:8021,address=tcp://localhost:8022,address=tcp://localhost:8023,address=tcp://localhost:8024"
|
||||||
|
SENDER2+=" --sender-index 2"
|
||||||
|
SENDER2+=" --subtimeframe-size 1000000"
|
||||||
|
SENDER2+=" --num-receivers 4"
|
||||||
|
xterm -geometry 80x25+500+700 -hold -e $SENDER2 &
|
||||||
|
|
||||||
|
RECEIVER0="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER0+=" --id Receiver1"
|
||||||
|
RECEIVER0+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8021"
|
||||||
|
RECEIVER0+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+0 -hold -e $RECEIVER0 &
|
||||||
|
|
||||||
|
RECEIVER1="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER1+=" --id Receiver2"
|
||||||
|
RECEIVER1+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8022"
|
||||||
|
RECEIVER1+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+350 -hold -e $RECEIVER1 &
|
||||||
|
|
||||||
|
RECEIVER2="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER2+=" --id Receiver3"
|
||||||
|
RECEIVER2+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8023"
|
||||||
|
RECEIVER2+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+700 -hold -e $RECEIVER2 &
|
||||||
|
|
||||||
|
RECEIVER3="fairmq-ex-n-m-receiver"
|
||||||
|
RECEIVER3+=" --id Receiver4"
|
||||||
|
RECEIVER3+=" --channel-config name=data,type=pull,method=bind,address=tcp://localhost:8024"
|
||||||
|
RECEIVER3+=" --num-senders 3"
|
||||||
|
xterm -geometry 80x25+1000+1050 -hold -e $RECEIVER3 &
|
119
examples/n-m/runReceiver.cxx
Normal file
119
examples/n-m/runReceiver.cxx
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* 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, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include "Header.h"
|
||||||
|
|
||||||
|
#include <FairMQDevice.h>
|
||||||
|
#include <runFairMQDevice.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <chrono>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace example_n_m;
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
|
struct TFBuffer
|
||||||
|
{
|
||||||
|
FairMQParts parts;
|
||||||
|
chrono::steady_clock::time_point start;
|
||||||
|
chrono::steady_clock::time_point end;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Receiver : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Receiver()
|
||||||
|
: fBuffer()
|
||||||
|
, fDiscardedSet()
|
||||||
|
, fNumSenders(0)
|
||||||
|
, fBufferTimeoutInMs(5000)
|
||||||
|
, fMaxTimeframes(0)
|
||||||
|
, fTimeframeCounter(0)
|
||||||
|
{
|
||||||
|
OnData("data", &Receiver::HandleData);
|
||||||
|
}
|
||||||
|
|
||||||
|
~Receiver() = default;
|
||||||
|
|
||||||
|
void InitTask() override
|
||||||
|
{
|
||||||
|
fNumSenders = GetConfig()->GetValue<int>("num-senders");
|
||||||
|
fBufferTimeoutInMs = GetConfig()->GetValue<int>("buffer-timeout");
|
||||||
|
fMaxTimeframes = GetConfig()->GetValue<int>("max-timeframes");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool HandleData(FairMQParts& parts, int /* index */)
|
||||||
|
{
|
||||||
|
Header& h = *(static_cast<Header*>(parts.At(0)->GetData()));
|
||||||
|
// LOG(info) << "Received sub-time frame #" << h.id << " from Sender" << h.senderIndex;
|
||||||
|
|
||||||
|
if (fDiscardedSet.find(h.id) == fDiscardedSet.end()) {
|
||||||
|
if (fBuffer.find(h.id) == fBuffer.end()) {
|
||||||
|
// if this is the first part with this ID, save the receive time.
|
||||||
|
fBuffer[h.id].start = chrono::steady_clock::now();
|
||||||
|
}
|
||||||
|
// if the received ID has not previously been discarded, store the data part in the buffer
|
||||||
|
fBuffer[h.id].parts.AddPart(move(parts.At(1)));
|
||||||
|
} else {
|
||||||
|
// if received ID has been previously discarded.
|
||||||
|
LOG(debug) << "Received part from an already discarded timeframe with id " << h.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fBuffer[h.id].parts.Size() == fNumSenders) {
|
||||||
|
LOG(info) << "Successfully completed timeframe #" << h.id;
|
||||||
|
fBuffer.erase(h.id);
|
||||||
|
|
||||||
|
if (fMaxTimeframes > 0 && ++fTimeframeCounter >= fMaxTimeframes) {
|
||||||
|
LOG(info) << "Reached configured maximum number of timeframes (" << fMaxTimeframes << "). Exiting RUNNING state.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscardIncompleteTimeframes()
|
||||||
|
{
|
||||||
|
auto it = fBuffer.begin();
|
||||||
|
while (it != fBuffer.end()) {
|
||||||
|
if (chrono::duration_cast<chrono::milliseconds>(chrono::steady_clock::now() - (it->second).start).count() > fBufferTimeoutInMs) {
|
||||||
|
LOG(debug) << "Timeframe #" << it->first << " incomplete after " << fBufferTimeoutInMs << " milliseconds, discarding";
|
||||||
|
fDiscardedSet.insert(it->first);
|
||||||
|
fBuffer.erase(it++);
|
||||||
|
LOG(debug) << "Number of discarded timeframes: " << fDiscardedSet.size();
|
||||||
|
} else {
|
||||||
|
// LOG(info) << "Timeframe #" << it->first << " within timeout, buffering...";
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unordered_map<uint16_t, TFBuffer> fBuffer;
|
||||||
|
unordered_set<uint16_t> fDiscardedSet;
|
||||||
|
|
||||||
|
int fNumSenders;
|
||||||
|
int fBufferTimeoutInMs;
|
||||||
|
int fMaxTimeframes;
|
||||||
|
int fTimeframeCounter;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addCustomOptions(bpo::options_description& options)
|
||||||
|
{
|
||||||
|
options.add_options()
|
||||||
|
("buffer-timeout", bpo::value<int>()->default_value(1000), "Buffer timeout in milliseconds")
|
||||||
|
("num-senders", bpo::value<int>()->required(), "Number of senders")
|
||||||
|
("max-timeframes", bpo::value<int>()->default_value(0), "Maximum number of timeframes to receive (0 - unlimited)");
|
||||||
|
}
|
||||||
|
|
||||||
|
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Receiver(); }
|
79
examples/n-m/runSender.cxx
Normal file
79
examples/n-m/runSender.cxx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* 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, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include "Header.h"
|
||||||
|
|
||||||
|
#include <FairMQDevice.h>
|
||||||
|
#include <runFairMQDevice.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace example_n_m;
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
|
class Sender : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sender()
|
||||||
|
: fNumReceivers(0)
|
||||||
|
, fIndex(0)
|
||||||
|
, fSubtimeframeSize(10000)
|
||||||
|
{}
|
||||||
|
|
||||||
|
~Sender() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void InitTask() override
|
||||||
|
{
|
||||||
|
fIndex = GetConfig()->GetProperty<int>("sender-index");
|
||||||
|
fSubtimeframeSize = GetConfig()->GetProperty<int>("subtimeframe-size");
|
||||||
|
fNumReceivers = GetConfig()->GetProperty<int>("num-receivers");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run() override
|
||||||
|
{
|
||||||
|
FairMQChannel& dataInChannel = fChannels.at("sync").at(0);
|
||||||
|
|
||||||
|
while (!NewStatePending()) {
|
||||||
|
Header h;
|
||||||
|
FairMQMessagePtr id(NewMessage());
|
||||||
|
if (dataInChannel.Receive(id) > 0) {
|
||||||
|
h.id = *(static_cast<uint16_t*>(id->GetData()));
|
||||||
|
h.senderIndex = fIndex;
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
FairMQParts parts;
|
||||||
|
parts.AddPart(NewSimpleMessage(h));
|
||||||
|
parts.AddPart(NewMessage(fSubtimeframeSize));
|
||||||
|
|
||||||
|
uint64_t currentDataId = h.id;
|
||||||
|
int direction = currentDataId % fNumReceivers;
|
||||||
|
|
||||||
|
if (Send(parts, "data", direction, 0) < 0) {
|
||||||
|
LOG(debug) << "Failed to queue Subtimeframe #" << currentDataId << " to Receiver[" << direction << "]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int fNumReceivers;
|
||||||
|
unsigned int fIndex;
|
||||||
|
int fSubtimeframeSize;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addCustomOptions(bpo::options_description& options)
|
||||||
|
{
|
||||||
|
options.add_options()
|
||||||
|
("sender-index", bpo::value<int>()->default_value(0), "Sender Index")
|
||||||
|
("subtimeframe-size", bpo::value<int>()->default_value(1000), "Subtimeframe size in bytes")
|
||||||
|
("num-receivers", bpo::value<int>()->required(), "Number of EPNs");
|
||||||
|
}
|
||||||
|
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Sender(); }
|
46
examples/n-m/runSynchronizer.cxx
Normal file
46
examples/n-m/runSynchronizer.cxx
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* 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, *
|
||||||
|
* copied verbatim in the file "LICENSE" *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include <FairMQDevice.h>
|
||||||
|
#include <runFairMQDevice.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
|
class Synchronizer : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Synchronizer()
|
||||||
|
: fTimeframeId(0)
|
||||||
|
{}
|
||||||
|
~Synchronizer() = default;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool ConditionalRun() override
|
||||||
|
{
|
||||||
|
FairMQMessagePtr msg(NewSimpleMessage(fTimeframeId));
|
||||||
|
|
||||||
|
if (Send(msg, "sync") > 0) {
|
||||||
|
if (++fTimeframeId == UINT16_MAX - 1) {
|
||||||
|
fTimeframeId = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t fTimeframeId;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addCustomOptions(bpo::options_description& /* options */) {}
|
||||||
|
FairMQDevice* getDevice(const FairMQProgOptions& /* config */) { return new Synchronizer(); }
|
71
examples/qc/CMakeLists.txt
Normal file
71
examples/qc/CMakeLists.txt
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
################################################################################
|
||||||
|
# Copyright (C) 2014 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" #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-qc-sampler runSampler.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-qc-sampler PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-qc-dispatcher runQCDispatcher.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-qc-dispatcher PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-qc-task runQCTask.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-qc-task PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_executable(fairmq-ex-qc-sink runSink.cxx)
|
||||||
|
target_link_libraries(fairmq-ex-qc-sink PRIVATE FairMQ)
|
||||||
|
|
||||||
|
add_custom_target(ExampleQC DEPENDS fairmq-ex-qc-sampler fairmq-ex-qc-dispatcher fairmq-ex-qc-task fairmq-ex-qc-sink)
|
||||||
|
|
||||||
|
list(JOIN Boost_LIBRARY_DIRS ":" LIB_DIR)
|
||||||
|
set(BIN_DIR ${CMAKE_CURRENT_BINARY_DIR}:${CMAKE_BINARY_DIR}/fairmq/plugins/DDS)
|
||||||
|
set(DATA_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-qc-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-qc-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-qc.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh @ONLY)
|
||||||
|
|
||||||
|
# test
|
||||||
|
if(DDS_FOUND)
|
||||||
|
add_test(NAME Example.QC.localhost COMMAND ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh localhost)
|
||||||
|
set_tests_properties(Example.QC.localhost PROPERTIES TIMEOUT 15 RUN_SERIAL true PASS_REGULAR_EXPRESSION "Example successful")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# install
|
||||||
|
install(
|
||||||
|
TARGETS
|
||||||
|
fairmq-ex-qc-sampler
|
||||||
|
fairmq-ex-qc-dispatcher
|
||||||
|
fairmq-ex-qc-task
|
||||||
|
fairmq-ex-qc-sink
|
||||||
|
|
||||||
|
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
|
||||||
|
# configure run script with different executable paths for build and for install directories
|
||||||
|
set(BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||||
|
set(DATA_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-qc-topology.xml ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-ex-qc-env.sh ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh_install @ONLY)
|
||||||
|
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-qc.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh_install @ONLY)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-qc-topology.xml_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_DATADIR}
|
||||||
|
RENAME ex-qc-topology.xml
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-ex-qc-env.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-ex-qc-env.sh
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-qc.sh_install
|
||||||
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
RENAME fairmq-start-ex-qc.sh
|
||||||
|
)
|
4
examples/qc/README.md
Normal file
4
examples/qc/README.md
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
QC
|
||||||
|
==
|
||||||
|
|
||||||
|
A topology consisting of 4 devices - Sampler, QCDispatcher, QCTask and Sink. The data flows from Sampler through QCDispatcher to Sink. On demand - by setting the corresponding configuration property - the QCDispatcher device will duplicate the data to the QCTask device. The property is set by the topology controller, in this example this is the `fairmq-dds-command-ui` utility.
|
48
examples/qc/ex-qc-topology.xml
Normal file
48
examples/qc/ex-qc-topology.xml
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
<topology name="ExampleQC">
|
||||||
|
|
||||||
|
<property name="fmqchan_data1" />
|
||||||
|
<property name="fmqchan_data2" />
|
||||||
|
<property name="fmqchan_qc" />
|
||||||
|
|
||||||
|
<decltask name="Sampler">
|
||||||
|
<exe>fairmq-ex-qc-sampler --color false --channel-config name=data1,type=push,method=bind -P dds --max-iterations 1000</exe>
|
||||||
|
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_data1</name>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="QCDispatcher">
|
||||||
|
<exe>fairmq-ex-qc-dispatcher --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect name=qc,type=push,method=connect -P dds</exe>
|
||||||
|
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="read">fmqchan_data1</name>
|
||||||
|
<name access="read">fmqchan_data2</name>
|
||||||
|
<name access="read">fmqchan_qc</name>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="QCTask">
|
||||||
|
<exe>fairmq-ex-qc-task --color false --channel-config name=qc,type=pull,method=bind -P dds</exe>
|
||||||
|
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_qc</name>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<decltask name="Sink">
|
||||||
|
<exe>fairmq-ex-qc-sink --color false --channel-config name=data2,type=pull,method=bind -P dds --max-iterations 1000</exe>
|
||||||
|
<env reachable="false">fairmq-ex-qc-env.sh</env>
|
||||||
|
<properties>
|
||||||
|
<name access="write">fmqchan_data2</name>
|
||||||
|
</properties>
|
||||||
|
</decltask>
|
||||||
|
|
||||||
|
<main name="main">
|
||||||
|
<task>Sampler</task>
|
||||||
|
<task>QCDispatcher</task>
|
||||||
|
<task>QCTask</task>
|
||||||
|
<task>Sink</task>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
</topology>
|
16
examples/qc/fairmq-ex-qc-env.sh
Executable file
16
examples/qc/fairmq-ex-qc-env.sh
Executable file
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 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" #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
OS=$(uname -s 2>&1)
|
||||||
|
if [ "$OS" == "Darwin" ]; then
|
||||||
|
export DYLD_LIBRARY_PATH=@LIB_DIR@:$DYLD_LIBRARY_PATH
|
||||||
|
fi
|
82
examples/qc/fairmq-start-ex-qc.sh.in
Executable file
82
examples/qc/fairmq-start-ex-qc.sh.in
Executable file
@@ -0,0 +1,82 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# 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" #
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# fairmq-start-ex-qc.sh -> submit agents with localhost plugin
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cleanup() {
|
||||||
|
dds-session stop $1
|
||||||
|
echo "CLEANUP PERFORMED"
|
||||||
|
}
|
||||||
|
|
||||||
|
source @DDS_INSTALL_PREFIX@/DDS_env.sh
|
||||||
|
export PATH=@BIN_DIR@:$PATH
|
||||||
|
|
||||||
|
exec 5>&1
|
||||||
|
output=$(dds-session start | tee >(cat - >&5))
|
||||||
|
export DDS_SESSION_ID=$(echo ${output} | grep "DDS session ID: " | cut -d' ' -f4)
|
||||||
|
echo "SESSION ID: ${DDS_SESSION_ID}"
|
||||||
|
|
||||||
|
trap "cleanup ${DDS_SESSION_ID}" EXIT
|
||||||
|
|
||||||
|
requiredNofSlots=4
|
||||||
|
dds-submit -r localhost --slots ${requiredNofSlots}
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
export FAIRMQ_DDS_TOPO_FILE=@DATA_DIR@/ex-qc-topology.xml
|
||||||
|
echo "TOPOLOGY FILE: ${FAIRMQ_DDS_TOPO_FILE}"
|
||||||
|
echo "TOPOLOGY NAME: $(dds-topology --disable-validation --topology-name ${FAIRMQ_DDS_TOPO_FILE})"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --activate ${FAIRMQ_DDS_TOPO_FILE}
|
||||||
|
dds-info --active-topology
|
||||||
|
echo "...waiting for ${requiredNofSlots} executing slots..."
|
||||||
|
dds-info --executing-count --wait ${requiredNofSlots}
|
||||||
|
|
||||||
|
echo "------------------------"
|
||||||
|
echo "...waiting for Topology to finish..."
|
||||||
|
# TODO Retrieve number of devices from DDS topology API instead of having the user pass it explicitely
|
||||||
|
fairmq-dds-command-ui -w "IDLE"
|
||||||
|
fairmq-dds-command-ui -c i
|
||||||
|
fairmq-dds-command-ui -c k
|
||||||
|
fairmq-dds-command-ui -c b
|
||||||
|
fairmq-dds-command-ui -c x
|
||||||
|
fairmq-dds-command-ui -c j
|
||||||
|
allexceptqctasks="main/(Sampler|QCDispatcher|Sink)"
|
||||||
|
fairmq-dds-command-ui -c r -p $allexceptqctasks
|
||||||
|
qctask="main/QCTask.*"
|
||||||
|
qcdispatcher="main/QCDispatcher.*"
|
||||||
|
fairmq-dds-command-ui -c p --property-key qc --property-value active -p $qcdispatcher
|
||||||
|
fairmq-dds-command-ui -c r -p $qctask
|
||||||
|
fairmq-dds-command-ui -w "RUNNING->READY" -p $qctask
|
||||||
|
echo "...$qctask received data and transitioned to READY, sending shutdown..."
|
||||||
|
fairmq-dds-command-ui -c s
|
||||||
|
fairmq-dds-command-ui -c t
|
||||||
|
fairmq-dds-command-ui -c d
|
||||||
|
fairmq-dds-command-ui -c q
|
||||||
|
echo "...waiting for ${requiredNofSlots} idle slots..."
|
||||||
|
dds-info --idle-count --wait ${requiredNofSlots}
|
||||||
|
echo "------------------------"
|
||||||
|
|
||||||
|
dds-info --active-topology
|
||||||
|
dds-topology --stop
|
||||||
|
dds-info --active-topology
|
||||||
|
|
||||||
|
dds-agent-cmd getlog -a
|
||||||
|
logDir="${wrkDir}/logs"
|
||||||
|
for file in $(find "${logDir}" -name "*.tar.gz"); do tar -xf ${file} -C "${logDir}" ; done
|
||||||
|
echo "AGENT LOG FILES IN: ${logDir}"
|
||||||
|
|
||||||
|
# This string is used by ctest to detect success
|
||||||
|
echo "Example successful :)"
|
||||||
|
|
||||||
|
# Cleanup function is called by EXIT trap
|
59
examples/qc/runQCDispatcher.cxx
Normal file
59
examples/qc/runQCDispatcher.cxx
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 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 "runFairMQDevice.h"
|
||||||
|
#include "FairMQDevice.h"
|
||||||
|
|
||||||
|
class QCDispatcher : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QCDispatcher()
|
||||||
|
: fDoQC(false)
|
||||||
|
{
|
||||||
|
OnData("data1", &QCDispatcher::HandleData);
|
||||||
|
}
|
||||||
|
|
||||||
|
void InitTask() override
|
||||||
|
{
|
||||||
|
GetConfig()->Subscribe<std::string>("qcdevice", [&](const std::string& key, std::string value) {
|
||||||
|
if (key == "qc") {
|
||||||
|
if (value == "active") {
|
||||||
|
fDoQC.store(true);
|
||||||
|
} else if (value == "inactive") {
|
||||||
|
fDoQC.store(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool HandleData(FairMQMessagePtr& msg, int)
|
||||||
|
{
|
||||||
|
if (fDoQC.load() == true) {
|
||||||
|
FairMQMessagePtr msgCopy(NewMessage());
|
||||||
|
msgCopy->Copy(*msg);
|
||||||
|
if (Send(msg, "qc") < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Send(msg, "data2") < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetTask() override { GetConfig()->Unsubscribe<std::string>("qcdevice"); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::atomic<bool> fDoQC;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addCustomOptions(boost::program_options::options_description& /*options*/) {}
|
||||||
|
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new QCDispatcher(); }
|
26
examples/qc/runQCTask.cxx
Normal file
26
examples/qc/runQCTask.cxx
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 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 "runFairMQDevice.h"
|
||||||
|
#include "FairMQDevice.h"
|
||||||
|
|
||||||
|
class QCTask : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QCTask()
|
||||||
|
{
|
||||||
|
OnData("qc", [](FairMQMessagePtr& /*msg*/, int) {
|
||||||
|
LOG(info) << "received data";
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
void addCustomOptions(bpo::options_description& /*options*/) {}
|
||||||
|
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new QCTask(); }
|
36
examples/qc/runSampler.cxx
Normal file
36
examples/qc/runSampler.cxx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 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 "runFairMQDevice.h"
|
||||||
|
#include "FairMQDevice.h"
|
||||||
|
|
||||||
|
#include <thread> // this_thread::sleep_for
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
|
class Sampler : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sampler() {}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool ConditionalRun()
|
||||||
|
{
|
||||||
|
FairMQMessagePtr msg(NewMessage(1000));
|
||||||
|
|
||||||
|
if (Send(msg, "data1") < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
void addCustomOptions(bpo::options_description&) {}
|
||||||
|
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new Sampler(); }
|
25
examples/qc/runSink.cxx
Normal file
25
examples/qc/runSink.cxx
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014 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 "runFairMQDevice.h"
|
||||||
|
#include "FairMQDevice.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class Sink : public FairMQDevice
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Sink() { OnData("data2", &Sink::HandleData); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool HandleData(FairMQMessagePtr& /*msg*/, int /*index*/) { return true; }
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
void addCustomOptions(bpo::options_description&) {}
|
||||||
|
FairMQDevicePtr getDevice(const fair::mq::ProgOptions& /*config*/) { return new Sink(); }
|
@@ -35,6 +35,14 @@ void Sampler::InitTask()
|
|||||||
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
||||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||||
|
|
||||||
|
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
|
||||||
|
LOG(warn) << ">>>" << info.event;
|
||||||
|
LOG(warn) << "id: " << info.id;
|
||||||
|
LOG(warn) << "ptr: " << info.ptr;
|
||||||
|
LOG(warn) << "size: " << info.size;
|
||||||
|
LOG(warn) << "flags: " << info.flags;
|
||||||
|
});
|
||||||
|
|
||||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
|
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
|
||||||
0,
|
0,
|
||||||
10000000,
|
10000000,
|
||||||
@@ -82,6 +90,7 @@ void Sampler::ResetTask()
|
|||||||
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
|
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
|
||||||
}
|
}
|
||||||
fRegion.reset();
|
fRegion.reset();
|
||||||
|
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
Sampler::~Sampler()
|
Sampler::~Sampler()
|
||||||
|
@@ -29,6 +29,13 @@ void Sink::InitTask()
|
|||||||
{
|
{
|
||||||
// Get the fMaxIterations value from the command line options (via fConfig)
|
// Get the fMaxIterations value from the command line options (via fConfig)
|
||||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||||
|
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
|
||||||
|
LOG(warn) << ">>>" << info.event;
|
||||||
|
LOG(warn) << "id: " << info.id;
|
||||||
|
LOG(warn) << "ptr: " << info.ptr;
|
||||||
|
LOG(warn) << "size: " << info.size;
|
||||||
|
LOG(warn) << "flags: " << info.flags;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Sink::Run()
|
void Sink::Run()
|
||||||
@@ -50,6 +57,11 @@ void Sink::Run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Sink::ResetTask()
|
||||||
|
{
|
||||||
|
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
|
||||||
|
}
|
||||||
|
|
||||||
Sink::~Sink()
|
Sink::~Sink()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@@ -31,6 +31,7 @@ class Sink : public FairMQDevice
|
|||||||
protected:
|
protected:
|
||||||
virtual void Run();
|
virtual void Run();
|
||||||
virtual void InitTask();
|
virtual void InitTask();
|
||||||
|
virtual void ResetTask();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t fMaxIterations;
|
uint64_t fMaxIterations;
|
||||||
|
@@ -19,6 +19,7 @@ SAMPLER+=" --id sampler1"
|
|||||||
SAMPLER+=" --transport $transport"
|
SAMPLER+=" --transport $transport"
|
||||||
SAMPLER+=" --severity debug"
|
SAMPLER+=" --severity debug"
|
||||||
SAMPLER+=" --session $SESSION"
|
SAMPLER+=" --session $SESSION"
|
||||||
|
SAMPLER+=" --verbosity veryhigh"
|
||||||
SAMPLER+=" --control static --color false"
|
SAMPLER+=" --control static --color false"
|
||||||
SAMPLER+=" --max-iterations 1"
|
SAMPLER+=" --max-iterations 1"
|
||||||
SAMPLER+=" --msg-size $msgSize"
|
SAMPLER+=" --msg-size $msgSize"
|
||||||
|
@@ -6,16 +6,6 @@
|
|||||||
# copied verbatim in the file "LICENSE" #
|
# copied verbatim in the file "LICENSE" #
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
####################
|
|
||||||
# external plugins #
|
|
||||||
####################
|
|
||||||
if(BUILD_DDS_PLUGIN)
|
|
||||||
add_subdirectory(plugins/DDS)
|
|
||||||
endif()
|
|
||||||
if(BUILD_PMIX_PLUGIN)
|
|
||||||
add_subdirectory(plugins/PMIx)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(BUILD_FAIRMQ OR BUILD_SDK)
|
if(BUILD_FAIRMQ OR BUILD_SDK)
|
||||||
###########
|
###########
|
||||||
# Version #
|
# Version #
|
||||||
@@ -58,6 +48,12 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
|
|||||||
${TOOLS_PUBLIC_HEADER_FILES}
|
${TOOLS_PUBLIC_HEADER_FILES}
|
||||||
)
|
)
|
||||||
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||||
|
# workaround https://github.com/boostorg/asio/commit/43874d5497414c67655d901e48c939ef01337edb
|
||||||
|
if( Boost_VERSION VERSION_LESS 1.69
|
||||||
|
AND CMAKE_CXX_COMPILER_ID STREQUAL AppleClang
|
||||||
|
AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 10.0.1)
|
||||||
|
target_compile_definitions(${target} PUBLIC BOOST_ASIO_HAS_STD_STRING_VIEW)
|
||||||
|
endif()
|
||||||
target_include_directories(${target}
|
target_include_directories(${target}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||||
@@ -186,11 +182,11 @@ if(BUILD_FAIRMQ)
|
|||||||
plugins/Builtin.h
|
plugins/Builtin.h
|
||||||
plugins/config/Config.h
|
plugins/config/Config.h
|
||||||
plugins/Control.h
|
plugins/Control.h
|
||||||
shmem/FairMQMessageSHM.h
|
shmem/Message.h
|
||||||
shmem/FairMQPollerSHM.h
|
shmem/Poller.h
|
||||||
shmem/FairMQUnmanagedRegionSHM.h
|
shmem/UnmanagedRegion.h
|
||||||
shmem/FairMQSocketSHM.h
|
shmem/Socket.h
|
||||||
shmem/FairMQTransportFactorySHM.h
|
shmem/TransportFactory.h
|
||||||
shmem/Common.h
|
shmem/Common.h
|
||||||
shmem/Manager.h
|
shmem/Manager.h
|
||||||
shmem/Region.h
|
shmem/Region.h
|
||||||
@@ -247,11 +243,10 @@ if(BUILD_FAIRMQ)
|
|||||||
SuboptParser.cxx
|
SuboptParser.cxx
|
||||||
plugins/config/Config.cxx
|
plugins/config/Config.cxx
|
||||||
plugins/Control.cxx
|
plugins/Control.cxx
|
||||||
shmem/FairMQMessageSHM.cxx
|
shmem/Message.cxx
|
||||||
shmem/FairMQPollerSHM.cxx
|
shmem/Poller.cxx
|
||||||
shmem/FairMQUnmanagedRegionSHM.cxx
|
shmem/Socket.cxx
|
||||||
shmem/FairMQSocketSHM.cxx
|
shmem/TransportFactory.cxx
|
||||||
shmem/FairMQTransportFactorySHM.cxx
|
|
||||||
shmem/Manager.cxx
|
shmem/Manager.cxx
|
||||||
shmem/Region.cxx
|
shmem/Region.cxx
|
||||||
zeromq/FairMQMessageZMQ.cxx
|
zeromq/FairMQMessageZMQ.cxx
|
||||||
@@ -467,3 +462,13 @@ endif()
|
|||||||
if(BUILD_SDK)
|
if(BUILD_SDK)
|
||||||
add_subdirectory(sdk)
|
add_subdirectory(sdk)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
####################
|
||||||
|
# external plugins #
|
||||||
|
####################
|
||||||
|
if(BUILD_DDS_PLUGIN)
|
||||||
|
add_subdirectory(plugins/DDS)
|
||||||
|
endif()
|
||||||
|
if(BUILD_PMIX_PLUGIN)
|
||||||
|
add_subdirectory(plugins/PMIx)
|
||||||
|
endif()
|
||||||
|
@@ -75,7 +75,7 @@ void DeviceRunner::SubscribeForConfigChange()
|
|||||||
fair::Logger::SetConsoleColor(val);
|
fair::Logger::SetConsoleColor(val);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
fConfig.Subscribe<string>("device-runner", [&](const std::string& key, const std::string val) {
|
fConfig.Subscribe<string>("device-runner", [&](const std::string& key, const std::string& val) {
|
||||||
if (key == "severity") {
|
if (key == "severity") {
|
||||||
fair::Logger::SetConsoleSeverity(val);
|
fair::Logger::SetConsoleSeverity(val);
|
||||||
} else if (key == "file-severity") {
|
} else if (key == "file-severity") {
|
||||||
|
@@ -20,7 +20,7 @@ using namespace std;
|
|||||||
using namespace fair::mq;
|
using namespace fair::mq;
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T& ifNotFound) noexcept
|
T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T& ifNotFound)
|
||||||
{
|
{
|
||||||
if (m.count(k)) {
|
if (m.count(k)) {
|
||||||
return boost::any_cast<T>(m.at(k));
|
return boost::any_cast<T>(m.at(k));
|
||||||
@@ -133,26 +133,37 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan, const string& newName)
|
|||||||
|
|
||||||
FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
|
FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
|
||||||
{
|
{
|
||||||
fTransportFactory = nullptr;
|
if (this == &chan) {
|
||||||
fTransportType = chan.fTransportType;
|
return *this;
|
||||||
fSocket = nullptr;
|
}
|
||||||
fName = chan.fName;
|
|
||||||
fType = chan.fType;
|
{
|
||||||
fMethod = chan.fMethod;
|
// TODO: replace this with std::scoped_lock (c++17)
|
||||||
fAddress = chan.fAddress;
|
lock(fMtx, chan.fMtx);
|
||||||
fSndBufSize = chan.fSndBufSize;
|
lock_guard<mutex> lock1(fMtx, adopt_lock);
|
||||||
fRcvBufSize = chan.fRcvBufSize;
|
lock_guard<mutex> lock2(chan.fMtx, adopt_lock);
|
||||||
fSndKernelSize = chan.fSndKernelSize;
|
|
||||||
fRcvKernelSize = chan.fRcvKernelSize;
|
fTransportFactory = nullptr;
|
||||||
fLinger = chan.fLinger;
|
fTransportType = chan.fTransportType;
|
||||||
fRateLogging = chan.fRateLogging;
|
fSocket = nullptr;
|
||||||
fPortRangeMin = chan.fPortRangeMin;
|
fName = chan.fName;
|
||||||
fPortRangeMax = chan.fPortRangeMax;
|
fType = chan.fType;
|
||||||
fAutoBind = chan.fAutoBind;
|
fMethod = chan.fMethod;
|
||||||
fIsValid = false;
|
fAddress = chan.fAddress;
|
||||||
fMultipart = chan.fMultipart;
|
fSndBufSize = chan.fSndBufSize;
|
||||||
fModified = chan.fModified;
|
fRcvBufSize = chan.fRcvBufSize;
|
||||||
fReset = false;
|
fSndKernelSize = chan.fSndKernelSize;
|
||||||
|
fRcvKernelSize = chan.fRcvKernelSize;
|
||||||
|
fLinger = chan.fLinger;
|
||||||
|
fRateLogging = chan.fRateLogging;
|
||||||
|
fPortRangeMin = chan.fPortRangeMin;
|
||||||
|
fPortRangeMax = chan.fPortRangeMax;
|
||||||
|
fAutoBind = chan.fAutoBind;
|
||||||
|
fIsValid = false;
|
||||||
|
fMultipart = chan.fMultipart;
|
||||||
|
fModified = chan.fModified;
|
||||||
|
fReset = false;
|
||||||
|
}
|
||||||
|
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
@@ -340,6 +340,11 @@ class FairMQChannel
|
|||||||
return Transport()->CreateUnmanagedRegion(size, callback, path, flags);
|
return Transport()->CreateUnmanagedRegion(size, callback, path, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
|
||||||
|
{
|
||||||
|
return Transport()->CreateUnmanagedRegion(size, userFlags, callback, path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
|
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
|
||||||
static constexpr const char* DefaultTransportName = "default";
|
static constexpr const char* DefaultTransportName = "default";
|
||||||
static constexpr const char* DefaultName = "";
|
static constexpr const char* DefaultName = "";
|
||||||
|
@@ -299,10 +299,15 @@ void FairMQDevice::InitWrapper()
|
|||||||
// if binding address is not specified, try getting it from the configured network interface
|
// if binding address is not specified, try getting it from the configured network interface
|
||||||
if (subChannel.fAddress == "unspecified" || subChannel.fAddress == "") {
|
if (subChannel.fAddress == "unspecified" || subChannel.fAddress == "") {
|
||||||
// if the configured network interface is default, get its name from the default route
|
// if the configured network interface is default, get its name from the default route
|
||||||
if (networkInterface == "default") {
|
try {
|
||||||
networkInterface = tools::getDefaultRouteNetworkInterface();
|
if (networkInterface == "default") {
|
||||||
|
networkInterface = tools::getDefaultRouteNetworkInterface();
|
||||||
|
}
|
||||||
|
subChannel.fAddress = "tcp://" + tools::getInterfaceIP(networkInterface) + ":1";
|
||||||
|
} catch(const tools::DefaultRouteDetectionError& e) {
|
||||||
|
LOG(debug) << "binding on tcp://*:1";
|
||||||
|
subChannel.fAddress = "tcp://*:1";
|
||||||
}
|
}
|
||||||
subChannel.fAddress = "tcp://" + tools::getInterfaceIP(networkInterface) + ":1";
|
|
||||||
}
|
}
|
||||||
// fill the uninitialized list
|
// fill the uninitialized list
|
||||||
fUninitializedBindingChannels.push_back(&subChannel);
|
fUninitializedBindingChannels.push_back(&subChannel);
|
||||||
|
@@ -217,17 +217,47 @@ class FairMQDevice
|
|||||||
}
|
}
|
||||||
|
|
||||||
// creates unamanaged region with the default device transport
|
// creates unamanaged region with the default device transport
|
||||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
|
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size,
|
||||||
|
FairMQRegionCallback callback = nullptr,
|
||||||
|
const std::string& path = "",
|
||||||
|
int flags = 0)
|
||||||
{
|
{
|
||||||
return Transport()->CreateUnmanagedRegion(size, callback);
|
return Transport()->CreateUnmanagedRegion(size, callback, path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates unamanaged region with the default device transport
|
||||||
|
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size,
|
||||||
|
const int64_t userFlags,
|
||||||
|
FairMQRegionCallback callback = nullptr,
|
||||||
|
const std::string& path = "",
|
||||||
|
int flags = 0)
|
||||||
|
{
|
||||||
|
return Transport()->CreateUnmanagedRegion(size, userFlags, callback, path, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
// creates unmanaged region with the transport of the specified channel
|
// creates unmanaged region with the transport of the specified channel
|
||||||
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0)
|
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel,
|
||||||
|
int index,
|
||||||
|
const size_t size,
|
||||||
|
FairMQRegionCallback callback = nullptr,
|
||||||
|
const std::string& path = "",
|
||||||
|
int flags = 0)
|
||||||
{
|
{
|
||||||
return GetChannel(channel, index).NewUnmanagedRegion(size, callback, path, flags);
|
return GetChannel(channel, index).NewUnmanagedRegion(size, callback, path, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creates unmanaged region with the transport of the specified channel
|
||||||
|
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel,
|
||||||
|
int index,
|
||||||
|
const size_t size,
|
||||||
|
const int64_t userFlags,
|
||||||
|
FairMQRegionCallback callback = nullptr,
|
||||||
|
const std::string& path = "",
|
||||||
|
int flags = 0)
|
||||||
|
{
|
||||||
|
return GetChannel(channel, index).NewUnmanagedRegion(size, userFlags, callback, path, flags);
|
||||||
|
}
|
||||||
|
|
||||||
template<typename ...Ts>
|
template<typename ...Ts>
|
||||||
FairMQPollerPtr NewPoller(const Ts&... inputs)
|
FairMQPollerPtr NewPoller(const Ts&... inputs)
|
||||||
{
|
{
|
||||||
|
@@ -31,8 +31,8 @@ namespace fair
|
|||||||
namespace mq
|
namespace mq
|
||||||
{
|
{
|
||||||
|
|
||||||
using PollerPtr = std::unique_ptr<FairMQPoller>;
|
using Poller = FairMQPoller;
|
||||||
|
using PollerPtr = FairMQPollerPtr;
|
||||||
struct PollerError : std::runtime_error { using std::runtime_error::runtime_error; };
|
struct PollerError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||||
|
|
||||||
} /* namespace mq */
|
} /* namespace mq */
|
||||||
|
@@ -22,7 +22,7 @@ class FairMQSocket
|
|||||||
FairMQSocket() {}
|
FairMQSocket() {}
|
||||||
FairMQSocket(FairMQTransportFactory* fac): fTransport(fac) {}
|
FairMQSocket(FairMQTransportFactory* fac): fTransport(fac) {}
|
||||||
|
|
||||||
virtual std::string GetId() = 0;
|
virtual std::string GetId() const = 0;
|
||||||
|
|
||||||
virtual bool Bind(const std::string& address) = 0;
|
virtual bool Bind(const std::string& address) = 0;
|
||||||
virtual bool Connect(const std::string& address) = 0;
|
virtual bool Connect(const std::string& address) = 0;
|
||||||
|
@@ -7,8 +7,8 @@
|
|||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <FairMQTransportFactory.h>
|
#include <FairMQTransportFactory.h>
|
||||||
|
#include <fairmq/shmem/TransportFactory.h>
|
||||||
#include <zeromq/FairMQTransportFactoryZMQ.h>
|
#include <zeromq/FairMQTransportFactoryZMQ.h>
|
||||||
#include <shmem/FairMQTransportFactorySHM.h>
|
|
||||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||||
#include <nanomsg/FairMQTransportFactoryNN.h>
|
#include <nanomsg/FairMQTransportFactoryNN.h>
|
||||||
#endif /* BUILD_NANOMSG_TRANSPORT */
|
#endif /* BUILD_NANOMSG_TRANSPORT */
|
||||||
@@ -17,50 +17,46 @@
|
|||||||
#endif
|
#endif
|
||||||
#include <FairMQLogger.h>
|
#include <FairMQLogger.h>
|
||||||
#include <fairmq/tools/Unique.h>
|
#include <fairmq/tools/Unique.h>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
FairMQTransportFactory::FairMQTransportFactory(const std::string& id)
|
using namespace std;
|
||||||
|
|
||||||
|
FairMQTransportFactory::FairMQTransportFactory(const string& id)
|
||||||
: fkId(id)
|
: fkId(id)
|
||||||
{
|
{}
|
||||||
}
|
|
||||||
|
|
||||||
auto FairMQTransportFactory::CreateTransportFactory(const std::string& type, const std::string& id, const fair::mq::ProgOptions* config) -> std::shared_ptr<FairMQTransportFactory>
|
auto FairMQTransportFactory::CreateTransportFactory(const string& type,
|
||||||
|
const string& id,
|
||||||
|
const fair::mq::ProgOptions* config)
|
||||||
|
-> shared_ptr<FairMQTransportFactory>
|
||||||
{
|
{
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
auto finalId = id;
|
auto finalId = id;
|
||||||
|
|
||||||
// Generate uuid if empty
|
// Generate uuid if empty
|
||||||
if (finalId == "")
|
if (finalId == "") {
|
||||||
{
|
|
||||||
finalId = fair::mq::tools::Uuid();
|
finalId = fair::mq::tools::Uuid();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == "zeromq")
|
if (type == "zeromq") {
|
||||||
{
|
|
||||||
return make_shared<FairMQTransportFactoryZMQ>(finalId, config);
|
return make_shared<FairMQTransportFactoryZMQ>(finalId, config);
|
||||||
}
|
} else if (type == "shmem") {
|
||||||
else if (type == "shmem")
|
return make_shared<fair::mq::shmem::TransportFactory>(finalId, config);
|
||||||
{
|
|
||||||
return make_shared<FairMQTransportFactorySHM>(finalId, config);
|
|
||||||
}
|
}
|
||||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||||
else if (type == "nanomsg")
|
else if (type == "nanomsg") {
|
||||||
{
|
|
||||||
return make_shared<FairMQTransportFactoryNN>(finalId, config);
|
return make_shared<FairMQTransportFactoryNN>(finalId, config);
|
||||||
}
|
}
|
||||||
#endif /* BUILD_NANOMSG_TRANSPORT */
|
#endif /* BUILD_NANOMSG_TRANSPORT */
|
||||||
#ifdef BUILD_OFI_TRANSPORT
|
#ifdef BUILD_OFI_TRANSPORT
|
||||||
else if (type == "ofi")
|
else if (type == "ofi") {
|
||||||
{
|
|
||||||
return make_shared<fair::mq::ofi::TransportFactory>(finalId, config);
|
return make_shared<fair::mq::ofi::TransportFactory>(finalId, config);
|
||||||
}
|
}
|
||||||
#endif /* BUILD_OFI_TRANSPORT */
|
#endif /* BUILD_OFI_TRANSPORT */
|
||||||
else
|
else {
|
||||||
{
|
LOG(error) << "Unavailable transport requested: "
|
||||||
LOG(error) << "Unavailable transport requested: " << "\"" << type << "\"" << ". Available are: "
|
<< "\"" << type << "\""
|
||||||
|
<< ". Available are: "
|
||||||
<< "\"zeromq\""
|
<< "\"zeromq\""
|
||||||
<< "\"shmem\""
|
<< "\"shmem\""
|
||||||
#ifdef BUILD_NANOMSG_TRANSPORT
|
#ifdef BUILD_NANOMSG_TRANSPORT
|
||||||
|
@@ -61,20 +61,46 @@ class FairMQTransportFactory
|
|||||||
/// @param obj optional helper pointer that can be used in the callback
|
/// @param obj optional helper pointer that can be used in the callback
|
||||||
/// @return pointer to FairMQMessage
|
/// @return pointer to FairMQMessage
|
||||||
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||||
|
/// @brief create a message with the buffer located within the corresponding unmanaged region
|
||||||
|
/// @param unmanagedRegion the unmanaged region that this message buffer belongs to
|
||||||
|
/// @param data message buffer (must be within the region - checked at runtime by the transport)
|
||||||
|
/// @param size size of the message
|
||||||
|
/// @param hint optional parameter, returned to the user in the FairMQRegionCallback
|
||||||
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
|
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
|
||||||
|
|
||||||
/// Create a socket
|
/// @brief Create a socket
|
||||||
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
|
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
|
||||||
|
|
||||||
/// Create a poller for a single channel (all subchannels)
|
/// @brief Create a poller for a single channel (all subchannels)
|
||||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
|
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
|
||||||
/// Create a poller for specific channels
|
/// @brief Create a poller for specific channels
|
||||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
|
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
|
||||||
/// Create a poller for specific channels (all subchannels)
|
/// @brief Create a poller for specific channels (all subchannels)
|
||||||
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
|
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
|
||||||
|
|
||||||
|
/// @brief Create new UnmanagedRegion
|
||||||
|
/// @param size size of the region
|
||||||
|
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
|
||||||
|
/// @param path optional parameter to pass to the underlying transport
|
||||||
|
/// @param flags optional parameter to pass to the underlying transport
|
||||||
|
/// @return pointer to UnmanagedRegion
|
||||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const = 0;
|
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const = 0;
|
||||||
|
/// @brief Create new UnmanagedRegion
|
||||||
|
/// @param size size of the region
|
||||||
|
/// @param userFlags flags to be stored with the region, have no effect on the transport, but can be retrieved from the region by the user
|
||||||
|
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
|
||||||
|
/// @param path optional parameter to pass to the underlying transport
|
||||||
|
/// @param flags optional parameter to pass to the underlying transport
|
||||||
|
/// @return pointer to UnmanagedRegion
|
||||||
|
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const = 0;
|
||||||
|
|
||||||
|
/// @brief Subscribe to region events (creation, destruction, ...)
|
||||||
|
/// @param callback the callback that is called when a region event occurs
|
||||||
|
virtual void SubscribeToRegionEvents(FairMQRegionEventCallback callback) = 0;
|
||||||
|
/// @brief Unsubscribe from region events
|
||||||
|
virtual void UnsubscribeFromRegionEvents() = 0;
|
||||||
|
|
||||||
|
virtual std::vector<FairMQRegionInfo> GetRegionInfo() = 0;
|
||||||
|
|
||||||
/// Get transport type
|
/// Get transport type
|
||||||
virtual fair::mq::Transport GetType() const = 0;
|
virtual fair::mq::Transport GetType() const = 0;
|
||||||
@@ -137,6 +163,7 @@ namespace fair
|
|||||||
namespace mq
|
namespace mq
|
||||||
{
|
{
|
||||||
|
|
||||||
|
using TransportFactory = FairMQTransportFactory;
|
||||||
struct TransportFactoryError : std::runtime_error { using std::runtime_error::runtime_error; };
|
struct TransportFactoryError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||||
|
|
||||||
} /* namespace mq */
|
} /* namespace mq */
|
||||||
|
@@ -12,8 +12,24 @@
|
|||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <memory> // std::unique_ptr
|
#include <memory> // std::unique_ptr
|
||||||
#include <functional> // std::function
|
#include <functional> // std::function
|
||||||
|
#include <ostream> // std::ostream
|
||||||
|
|
||||||
|
enum class FairMQRegionEvent : int
|
||||||
|
{
|
||||||
|
created,
|
||||||
|
destroyed
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FairMQRegionInfo {
|
||||||
|
uint64_t id; // id of the region
|
||||||
|
void* ptr; // pointer to the start of the region
|
||||||
|
size_t size; // region size
|
||||||
|
int64_t flags; // custom flags set by the creator
|
||||||
|
FairMQRegionEvent event;
|
||||||
|
};
|
||||||
|
|
||||||
using FairMQRegionCallback = std::function<void(void*, size_t, void*)>;
|
using FairMQRegionCallback = std::function<void(void*, size_t, void*)>;
|
||||||
|
using FairMQRegionEventCallback = std::function<void(FairMQRegionInfo)>;
|
||||||
|
|
||||||
class FairMQUnmanagedRegion
|
class FairMQUnmanagedRegion
|
||||||
{
|
{
|
||||||
@@ -26,12 +42,26 @@ class FairMQUnmanagedRegion
|
|||||||
|
|
||||||
using FairMQUnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
|
using FairMQUnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& os, const FairMQRegionEvent& event)
|
||||||
|
{
|
||||||
|
if (event == FairMQRegionEvent::created) {
|
||||||
|
return os << "created";
|
||||||
|
} else {
|
||||||
|
return os << "destroyed";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace fair
|
namespace fair
|
||||||
{
|
{
|
||||||
namespace mq
|
namespace mq
|
||||||
{
|
{
|
||||||
|
|
||||||
using UnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
|
using RegionCallback = FairMQRegionCallback;
|
||||||
|
using RegionEventCallback = FairMQRegionEventCallback;
|
||||||
|
using RegionEvent = FairMQRegionEvent;
|
||||||
|
using RegionInfo = FairMQRegionInfo;
|
||||||
|
using UnmanagedRegion = FairMQUnmanagedRegion;
|
||||||
|
using UnmanagedRegionPtr = FairMQUnmanagedRegionPtr;
|
||||||
|
|
||||||
} /* namespace mq */
|
} /* namespace mq */
|
||||||
} /* namespace fair */
|
} /* namespace fair */
|
||||||
|
@@ -60,7 +60,7 @@ FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targe
|
|||||||
container.data(),
|
container.data(),
|
||||||
containerSizeBytes);
|
containerSizeBytes);
|
||||||
return message;
|
return message;
|
||||||
};
|
}
|
||||||
|
|
||||||
} /* namespace mq */
|
} /* namespace mq */
|
||||||
} /* namespace fair */
|
} /* namespace fair */
|
||||||
|
@@ -18,5 +18,5 @@
|
|||||||
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t /*alignment*/)
|
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t /*alignment*/)
|
||||||
{
|
{
|
||||||
return setMessage(factory->CreateMessage(bytes));
|
return setMessage(factory->CreateMessage(bytes));
|
||||||
};
|
}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2017-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
@@ -8,15 +8,20 @@
|
|||||||
|
|
||||||
#include <fairmq/Plugin.h>
|
#include <fairmq/Plugin.h>
|
||||||
#include <FairMQLogger.h>
|
#include <FairMQLogger.h>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
fair::mq::Plugin::Plugin(const string name, const Version version, const string maintainer, const string homepage, PluginServices* pluginServices)
|
fair::mq::Plugin::Plugin(string name,
|
||||||
: fkName{name}
|
Version version,
|
||||||
|
string maintainer,
|
||||||
|
string homepage,
|
||||||
|
PluginServices* pluginServices)
|
||||||
|
: fkName(std::move(name))
|
||||||
, fkVersion(version)
|
, fkVersion(version)
|
||||||
, fkMaintainer{maintainer}
|
, fkMaintainer(std::move(maintainer))
|
||||||
, fkHomepage{homepage}
|
, fkHomepage(std::move(homepage))
|
||||||
, fPluginServices{pluginServices}
|
, fPluginServices(pluginServices)
|
||||||
{
|
{
|
||||||
LOG(debug) << "Loaded plugin: " << *this;
|
LOG(debug) << "Loaded plugin: " << *this;
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2017-2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
@@ -44,7 +44,11 @@ class Plugin
|
|||||||
using Version = tools::Version;
|
using Version = tools::Version;
|
||||||
|
|
||||||
Plugin() = delete;
|
Plugin() = delete;
|
||||||
Plugin(const std::string name, const Version version, const std::string maintainer, const std::string homepage, PluginServices* pluginServices);
|
Plugin(std::string name,
|
||||||
|
Version version,
|
||||||
|
std::string maintainer,
|
||||||
|
std::string homepage,
|
||||||
|
PluginServices* pluginServices);
|
||||||
|
|
||||||
Plugin(const Plugin&) = delete;
|
Plugin(const Plugin&) = delete;
|
||||||
Plugin operator=(const Plugin&) = delete;
|
Plugin operator=(const Plugin&) = delete;
|
||||||
@@ -60,10 +64,10 @@ class Plugin
|
|||||||
friend auto operator!=(const Plugin& lhs, const Plugin& rhs) -> bool { return !(lhs == rhs); }
|
friend auto operator!=(const Plugin& lhs, const Plugin& rhs) -> bool { return !(lhs == rhs); }
|
||||||
friend auto operator<<(std::ostream& os, const Plugin& p) -> std::ostream&
|
friend auto operator<<(std::ostream& os, const Plugin& p) -> std::ostream&
|
||||||
{
|
{
|
||||||
return os << "'" << p.GetName() << "', "
|
return os << "'" << p.GetName() << "', "
|
||||||
<< "version '" << p.GetVersion() << "', "
|
<< "version '" << p.GetVersion() << "', "
|
||||||
<< "maintainer '" << p.GetMaintainer() << "', "
|
<< "maintainer '" << p.GetMaintainer() << "', "
|
||||||
<< "homepage '" << p.GetHomepage() << "'";
|
<< "homepage '" << p.GetHomepage() << "'";
|
||||||
}
|
}
|
||||||
static auto NoProgramOptions() -> ProgOptions { return boost::none; }
|
static auto NoProgramOptions() -> ProgOptions { return boost::none; }
|
||||||
|
|
||||||
@@ -80,7 +84,6 @@ class Plugin
|
|||||||
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
|
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
|
||||||
auto ReleaseDeviceControl() -> void { fPluginServices->ReleaseDeviceControl(fkName); };
|
auto ReleaseDeviceControl() -> void { fPluginServices->ReleaseDeviceControl(fkName); };
|
||||||
auto ChangeDeviceState(const DeviceStateTransition next) -> bool { return fPluginServices->ChangeDeviceState(fkName, next); }
|
auto ChangeDeviceState(const DeviceStateTransition next) -> bool { return fPluginServices->ChangeDeviceState(fkName, next); }
|
||||||
void TransitionDeviceStateTo(const DeviceState state) { return fPluginServices->TransitionDeviceStateTo(fkName, state); }
|
|
||||||
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
|
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
|
||||||
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
|
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
|
||||||
|
|
||||||
|
@@ -28,6 +28,8 @@ using boost::optional;
|
|||||||
|
|
||||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "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>();
|
||||||
|
|
||||||
fair::mq::PluginManager::PluginManager()
|
fair::mq::PluginManager::PluginManager()
|
||||||
: fSearchPaths{}
|
: fSearchPaths{}
|
||||||
, fPluginFactories()
|
, fPluginFactories()
|
||||||
|
@@ -80,7 +80,7 @@ class PluginManager
|
|||||||
auto ForEachPluginProgOptions(std::function<void (boost::program_options::options_description)> func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } }
|
auto ForEachPluginProgOptions(std::function<void (boost::program_options::options_description)> func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = fair::mq::tools::make_unique<PluginServices>(std::forward<Args>(args)...); };
|
auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = fair::mq::tools::make_unique<PluginServices>(std::forward<Args>(args)...); }
|
||||||
|
|
||||||
auto WaitForPluginsToReleaseDeviceControl() -> void { fPluginServices->WaitForReleaseDeviceControl(); }
|
auto WaitForPluginsToReleaseDeviceControl() -> void { fPluginServices->WaitForReleaseDeviceControl(); }
|
||||||
|
|
||||||
@@ -97,6 +97,7 @@ class PluginManager
|
|||||||
using fair::mq::tools::ToString;
|
using fair::mq::tools::ToString;
|
||||||
|
|
||||||
auto lib = shared_library{std::forward<Args>(args)...};
|
auto lib = shared_library{std::forward<Args>(args)...};
|
||||||
|
fgDLLKeepAlive.push_back(lib);
|
||||||
|
|
||||||
fPluginFactories[pluginName] = import_alias<PluginFactory>(
|
fPluginFactories[pluginName] = import_alias<PluginFactory>(
|
||||||
shared_library{lib},
|
shared_library{lib},
|
||||||
@@ -117,6 +118,7 @@ class PluginManager
|
|||||||
|
|
||||||
static const std::string fgkLibPrefix;
|
static const std::string fgkLibPrefix;
|
||||||
std::vector<boost::filesystem::path> fSearchPaths;
|
std::vector<boost::filesystem::path> fSearchPaths;
|
||||||
|
static std::vector<boost::dll::shared_library> fgDLLKeepAlive;
|
||||||
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
||||||
std::unique_ptr<PluginServices> fPluginServices;
|
std::unique_ptr<PluginServices> fPluginServices;
|
||||||
std::map<std::string, std::unique_ptr<Plugin>> fPlugins;
|
std::map<std::string, std::unique_ptr<Plugin>> fPlugins;
|
||||||
|
@@ -28,22 +28,6 @@ auto PluginServices::ChangeDeviceState(const string& controller, const DeviceSta
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PluginServices::TransitionDeviceStateTo(const std::string& controller, DeviceState state)
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fDeviceControllerMutex};
|
|
||||||
|
|
||||||
if (!fDeviceController) fDeviceController = controller;
|
|
||||||
|
|
||||||
if (fDeviceController == controller) {
|
|
||||||
fDevice.TransitionTo(state);
|
|
||||||
} else {
|
|
||||||
throw DeviceControlError{tools::ToString(
|
|
||||||
"Plugin '", controller, "' is not allowed to change device states. ",
|
|
||||||
"Currently, plugin '", *fDeviceController, "' has taken control."
|
|
||||||
)};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto PluginServices::TakeDeviceControl(const string& controller) -> void
|
auto PluginServices::TakeDeviceControl(const string& controller) -> void
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lock{fDeviceControllerMutex};
|
lock_guard<mutex> lock{fDeviceControllerMutex};
|
||||||
|
@@ -124,8 +124,6 @@ class PluginServices
|
|||||||
/// If the device control role has not been taken yet, calling this function will take over control implicitely.
|
/// If the device control role has not been taken yet, calling this function will take over control implicitely.
|
||||||
auto ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool;
|
auto ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool;
|
||||||
|
|
||||||
void TransitionDeviceStateTo(const std::string& controller, DeviceState state);
|
|
||||||
|
|
||||||
/// @brief Subscribe with a callback to device state changes
|
/// @brief Subscribe with a callback to device state changes
|
||||||
/// @param subscriber id
|
/// @param subscriber id
|
||||||
/// @param callback
|
/// @param callback
|
||||||
|
@@ -62,7 +62,7 @@ ValInfo ConvertVarValToValInfo(const po::variable_value& v)
|
|||||||
} catch (out_of_range& oor) {
|
} catch (out_of_range& oor) {
|
||||||
return {string("[unidentified_type]"), string("[unidentified_type]"), origin};
|
return {string("[unidentified_type]"), string("[unidentified_type]"), origin};
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
string ConvertVarValToString(const po::variable_value& v)
|
string ConvertVarValToString(const po::variable_value& v)
|
||||||
{
|
{
|
||||||
@@ -443,4 +443,4 @@ void ProgOptions::PrintOptionsRaw() const
|
|||||||
|
|
||||||
|
|
||||||
} // namespace mq
|
} // namespace mq
|
||||||
} // namespace fair
|
} // namespace fair
|
||||||
|
@@ -79,7 +79,9 @@ struct Machine_ : public state_machine_def<Machine_>
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Machine_()
|
Machine_()
|
||||||
: fLastTransitionResult(true)
|
: fState(State::Ok)
|
||||||
|
, fNewState(State::Ok)
|
||||||
|
, fLastTransitionResult(true)
|
||||||
, fNewStatePending(false)
|
, fNewStatePending(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2018-2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
||||||
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
||||||
#define FAIRMQ_LICENSE "LGPL-3.0"
|
#define FAIRMQ_LICENSE "LGPL-3.0"
|
||||||
#define FAIRMQ_COPYRIGHT "2012-2019 GSI"
|
#define FAIRMQ_COPYRIGHT "2012-2020 GSI"
|
||||||
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||||
|
|
||||||
#endif // FAIR_MQ_VERSION_H
|
#endif // FAIR_MQ_VERSION_H
|
||||||
|
@@ -91,11 +91,6 @@ FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const str
|
|||||||
LOG(debug) << "Created socket " << GetId();
|
LOG(debug) << "Created socket " << GetId();
|
||||||
}
|
}
|
||||||
|
|
||||||
string FairMQSocketNN::GetId()
|
|
||||||
{
|
|
||||||
return fId;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FairMQSocketNN::Bind(const string& address)
|
bool FairMQSocketNN::Bind(const string& address)
|
||||||
{
|
{
|
||||||
// LOG(info) << "bind socket " << fId << " on " << address;
|
// LOG(info) << "bind socket " << fId << " on " << address;
|
||||||
|
@@ -23,7 +23,7 @@ class FairMQSocketNN final : public FairMQSocket
|
|||||||
FairMQSocketNN(const FairMQSocketNN&) = delete;
|
FairMQSocketNN(const FairMQSocketNN&) = delete;
|
||||||
FairMQSocketNN operator=(const FairMQSocketNN&) = delete;
|
FairMQSocketNN operator=(const FairMQSocketNN&) = delete;
|
||||||
|
|
||||||
std::string GetId() override;
|
std::string GetId() const override { return fId; }
|
||||||
|
|
||||||
bool Bind(const std::string& address) override;
|
bool Bind(const std::string& address) override;
|
||||||
bool Connect(const std::string& address) override;
|
bool Connect(const std::string& address) override;
|
||||||
|
@@ -70,6 +70,11 @@ FairMQUnmanagedRegionPtr FairMQTransportFactoryNN::CreateUnmanagedRegion(const s
|
|||||||
return unique_ptr<FairMQUnmanagedRegion>(new FairMQUnmanagedRegionNN(size, callback, path, flags));
|
return unique_ptr<FairMQUnmanagedRegion>(new FairMQUnmanagedRegionNN(size, callback, path, flags));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FairMQUnmanagedRegionPtr FairMQTransportFactoryNN::CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback, const std::string& path /* = "" */, int flags /* = 0 */) const
|
||||||
|
{
|
||||||
|
return unique_ptr<FairMQUnmanagedRegion>(new FairMQUnmanagedRegionNN(size, userFlags, callback, path, flags));
|
||||||
|
}
|
||||||
|
|
||||||
fair::mq::Transport FairMQTransportFactoryNN::GetType() const
|
fair::mq::Transport FairMQTransportFactoryNN::GetType() const
|
||||||
{
|
{
|
||||||
return fTransportType;
|
return fTransportType;
|
||||||
|
@@ -37,6 +37,11 @@ class FairMQTransportFactoryNN final : public FairMQTransportFactory
|
|||||||
FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const override;
|
FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const override;
|
||||||
|
|
||||||
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0) const override;
|
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0) const override;
|
||||||
|
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const override;
|
||||||
|
|
||||||
|
void SubscribeToRegionEvents(FairMQRegionEventCallback /* callback */) override { LOG(error) << "SubscribeToRegionEvents not yet implemented for nanomsg"; }
|
||||||
|
void UnsubscribeFromRegionEvents() override { LOG(error) << "UnsubscribeFromRegionEvents not yet implemented for nanomsg"; }
|
||||||
|
std::vector<FairMQRegionInfo> GetRegionInfo() override { LOG(error) << "GetRegionInfo not yet implemented for nanomsg, returning empty vector"; return std::vector<FairMQRegionInfo>(); }
|
||||||
|
|
||||||
fair::mq::Transport GetType() const override;
|
fair::mq::Transport GetType() const override;
|
||||||
|
|
||||||
|
@@ -18,6 +18,13 @@ FairMQUnmanagedRegionNN::FairMQUnmanagedRegionNN(const size_t size, FairMQRegion
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FairMQUnmanagedRegionNN::FairMQUnmanagedRegionNN(const size_t size, const int64_t /*userFlags*/, FairMQRegionCallback callback, const std::string& /*path = "" */, int /*flags = 0 */)
|
||||||
|
: fBuffer(malloc(size))
|
||||||
|
, fSize(size)
|
||||||
|
, fCallback(callback)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
void* FairMQUnmanagedRegionNN::GetData() const
|
void* FairMQUnmanagedRegionNN::GetData() const
|
||||||
{
|
{
|
||||||
return fBuffer;
|
return fBuffer;
|
||||||
|
@@ -20,6 +20,8 @@ class FairMQUnmanagedRegionNN final : public FairMQUnmanagedRegion
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
FairMQUnmanagedRegionNN(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0);
|
FairMQUnmanagedRegionNN(const size_t size, FairMQRegionCallback callback, const std::string& path = "", int flags = 0);
|
||||||
|
FairMQUnmanagedRegionNN(const size_t size, const int64_t userFlags, FairMQRegionCallback callback, const std::string& path = "", int flags = 0);
|
||||||
|
|
||||||
FairMQUnmanagedRegionNN(const FairMQUnmanagedRegionNN&) = delete;
|
FairMQUnmanagedRegionNN(const FairMQUnmanagedRegionNN&) = delete;
|
||||||
FairMQUnmanagedRegionNN operator=(const FairMQUnmanagedRegionNN&) = delete;
|
FairMQUnmanagedRegionNN operator=(const FairMQUnmanagedRegionNN&) = delete;
|
||||||
|
|
||||||
@@ -34,4 +36,4 @@ class FairMQUnmanagedRegionNN final : public FairMQUnmanagedRegion
|
|||||||
FairMQRegionCallback fCallback;
|
FairMQRegionCallback fCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* FAIRMQUNMANAGEDREGIONNN_H_ */
|
#endif /* FAIRMQUNMANAGEDREGIONNN_H_ */
|
||||||
|
@@ -43,7 +43,7 @@ class Socket final : public fair::mq::Socket
|
|||||||
Socket(const Socket&) = delete;
|
Socket(const Socket&) = delete;
|
||||||
Socket operator=(const Socket&) = delete;
|
Socket operator=(const Socket&) = delete;
|
||||||
|
|
||||||
auto GetId() -> std::string { return fId; }
|
auto GetId() const -> std::string override { return fId; }
|
||||||
|
|
||||||
auto Bind(const std::string& address) -> bool override;
|
auto Bind(const std::string& address) -> bool override;
|
||||||
auto Connect(const std::string& address) -> bool override;
|
auto Connect(const std::string& address) -> bool override;
|
||||||
|
@@ -90,6 +90,11 @@ auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, FairMQRegion
|
|||||||
throw runtime_error{"Not yet implemented UMR."};
|
throw runtime_error{"Not yet implemented UMR."};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto TransportFactory::CreateUnmanagedRegion(const size_t /*size*/, const int64_t /*userFlags*/, FairMQRegionCallback /*callback*/, const std::string& /* path = "" */, int /* flags = 0 */) const -> UnmanagedRegionPtr
|
||||||
|
{
|
||||||
|
throw runtime_error{"Not yet implemented UMR."};
|
||||||
|
}
|
||||||
|
|
||||||
auto TransportFactory::GetType() const -> Transport
|
auto TransportFactory::GetType() const -> Transport
|
||||||
{
|
{
|
||||||
return Transport::OFI;
|
return Transport::OFI;
|
||||||
|
@@ -46,7 +46,12 @@ class TransportFactory final : public FairMQTransportFactory
|
|||||||
auto CreatePoller(const std::vector<FairMQChannel*>& channels) const -> PollerPtr override;
|
auto CreatePoller(const std::vector<FairMQChannel*>& channels) const -> PollerPtr override;
|
||||||
auto CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const -> PollerPtr override;
|
auto CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const -> PollerPtr override;
|
||||||
|
|
||||||
auto CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const -> UnmanagedRegionPtr override;
|
auto CreateUnmanagedRegion(const size_t size, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const -> UnmanagedRegionPtr override;
|
||||||
|
auto CreateUnmanagedRegion(const size_t size, int64_t userFlags, RegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const -> UnmanagedRegionPtr override;
|
||||||
|
|
||||||
|
void SubscribeToRegionEvents(RegionEventCallback /* callback */) override { LOG(error) << "SubscribeToRegionEvents not yet implemented for OFI"; }
|
||||||
|
void UnsubscribeFromRegionEvents() override { LOG(error) << "UnsubscribeFromRegionEvents not yet implemented for OFI"; }
|
||||||
|
std::vector<FairMQRegionInfo> GetRegionInfo() override { LOG(error) << "GetRegionInfo not yet implemented for OFI, returning empty vector"; return std::vector<FairMQRegionInfo>(); }
|
||||||
|
|
||||||
auto GetType() const -> Transport override;
|
auto GetType() const -> Transport override;
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@ set_target_properties(${plugin} PROPERTIES
|
|||||||
|
|
||||||
set(exe fairmq-dds-command-ui)
|
set(exe fairmq-dds-command-ui)
|
||||||
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runDDSCommandUI.cxx)
|
||||||
target_link_libraries(${exe} FairMQ Commands StateMachine DDS::dds_intercom_lib DDS::dds_protocol_lib)
|
target_link_libraries(${exe} FairMQ Commands SDK StateMachine)
|
||||||
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
install(TARGETS ${plugin} ${exe}
|
install(TARGETS ${plugin} ${exe}
|
||||||
|
@@ -8,8 +8,6 @@
|
|||||||
|
|
||||||
#include "DDS.h"
|
#include "DDS.h"
|
||||||
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
|
||||||
|
|
||||||
#include <fairmq/tools/Strings.h>
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
#include <boost/algorithm/string/join.hpp>
|
#include <boost/algorithm/string/join.hpp>
|
||||||
@@ -37,30 +35,18 @@ DDS::DDS(const string& name,
|
|||||||
const string& homepage,
|
const string& homepage,
|
||||||
PluginServices* pluginServices)
|
PluginServices* pluginServices)
|
||||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||||
, fTransitions({"INIT DEVICE",
|
, fDDSTaskId(dds::env_prop<dds::task_id>())
|
||||||
"COMPLETE INIT",
|
|
||||||
"BIND",
|
|
||||||
"CONNECT",
|
|
||||||
"INIT TASK",
|
|
||||||
"RUN",
|
|
||||||
"STOP",
|
|
||||||
"RESET TASK",
|
|
||||||
"RESET DEVICE",
|
|
||||||
"END"})
|
|
||||||
, fCurrentState(DeviceState::Idle)
|
, fCurrentState(DeviceState::Idle)
|
||||||
, fLastState(DeviceState::Idle)
|
, fLastState(DeviceState::Idle)
|
||||||
, fDeviceTerminationRequested(false)
|
, fDeviceTerminationRequested(false)
|
||||||
, fLastExternalController(0)
|
, fLastExternalController(0)
|
||||||
, fExitingAckedByLastExternalController(false)
|
, fExitingAckedByLastExternalController(false)
|
||||||
, fHeartbeatInterval(100)
|
|
||||||
, fUpdatesAllowed(false)
|
, fUpdatesAllowed(false)
|
||||||
, fWorkGuard(fWorkerQueue.get_executor())
|
, fWorkGuard(fWorkerQueue.get_executor())
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
TakeDeviceControl();
|
TakeDeviceControl();
|
||||||
|
|
||||||
fHeartbeatThread = thread(&DDS::HeartbeatSender, this);
|
|
||||||
|
|
||||||
string deviceId(GetProperty<string>("id"));
|
string deviceId(GetProperty<string>("id"));
|
||||||
if (deviceId.empty()) {
|
if (deviceId.empty()) {
|
||||||
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
SetProperty<string>("id", dds::env_prop<dds::task_path>());
|
||||||
@@ -71,15 +57,13 @@ DDS::DDS(const string& name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto control = GetProperty<string>("control");
|
auto control = GetProperty<string>("control");
|
||||||
bool staticMode(false);
|
|
||||||
if (control == "static") {
|
if (control == "static") {
|
||||||
LOG(debug) << "Running DDS controller: static";
|
LOG(error) << "DDS Plugin: static mode is not supported";
|
||||||
staticMode = true;
|
throw invalid_argument("DDS Plugin: static mode is not supported");
|
||||||
} else if (control == "dynamic" || control == "external" || control == "interactive") {
|
} else if (control == "dynamic" || control == "external" || control == "interactive") {
|
||||||
LOG(debug) << "Running DDS controller: external";
|
LOG(debug) << "Running DDS controller: external";
|
||||||
} else {
|
} else {
|
||||||
LOG(error) << "Unrecognized control mode '" << control << "' requested. " << "Ignoring and falling back to static control mode.";
|
LOG(error) << "Unrecognized control mode '" << control << "' requested. " << "Ignoring and starting in external control mode.";
|
||||||
staticMode = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SubscribeForCustomCommands();
|
SubscribeForCustomCommands();
|
||||||
@@ -87,17 +71,23 @@ DDS::DDS(const string& name,
|
|||||||
|
|
||||||
// subscribe to device state changes, pushing new state changes into the event queue
|
// subscribe to device state changes, pushing new state changes into the event queue
|
||||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
||||||
fStateQueue.Push(newState);
|
|
||||||
switch (newState) {
|
switch (newState) {
|
||||||
case DeviceState::Bound:
|
case DeviceState::Bound: {
|
||||||
// Receive addresses of connecting channels from DDS
|
// Receive addresses of connecting channels from DDS
|
||||||
// and propagate addresses of bound channels to DDS.
|
// and propagate addresses of bound channels to DDS.
|
||||||
FillChannelContainers();
|
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
|
// publish bound addresses via DDS at keys corresponding to the channel
|
||||||
// prefixes, e.g. 'data' in data[i]
|
// prefixes, e.g. 'data' in data[i]
|
||||||
PublishBoundChannels();
|
PublishBoundChannels();
|
||||||
break;
|
} break;
|
||||||
case DeviceState::ResettingDevice: {
|
case DeviceState::ResettingDevice: {
|
||||||
{
|
{
|
||||||
lock_guard<mutex> lk(fUpdateMutex);
|
lock_guard<mutex> lk(fUpdateMutex);
|
||||||
@@ -105,36 +95,45 @@ DDS::DDS(const string& name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
EmptyChannelContainers();
|
EmptyChannelContainers();
|
||||||
break;
|
} break;
|
||||||
}
|
case DeviceState::Exiting: {
|
||||||
case DeviceState::Exiting:
|
if (!fControllerThread.joinable()) {
|
||||||
|
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
||||||
|
}
|
||||||
fWorkGuard.reset();
|
fWorkGuard.reset();
|
||||||
fDeviceTerminationRequested = true;
|
fDeviceTerminationRequested = true;
|
||||||
UnsubscribeFromDeviceStateChange();
|
UnsubscribeFromDeviceStateChange();
|
||||||
ReleaseDeviceControl();
|
ReleaseDeviceControl();
|
||||||
break;
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
using namespace sdk::cmd;
|
||||||
|
auto now = chrono::steady_clock::now();
|
||||||
string id = GetProperty<string>("id");
|
string id = GetProperty<string>("id");
|
||||||
fLastState = fCurrentState;
|
fLastState = fCurrentState;
|
||||||
fCurrentState = newState;
|
fCurrentState = newState;
|
||||||
using namespace sdk::cmd;
|
|
||||||
for (auto subscriberId : fStateChangeSubscribers) {
|
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
|
||||||
|
|
||||||
Cmds cmds(make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||||
fDDS.Send(cmds.Serialize(), to_string(subscriberId));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (staticMode) {
|
StartWorkerThread();
|
||||||
fControllerThread = thread(&DDS::StaticControl, this);
|
|
||||||
} else {
|
|
||||||
StartWorkerThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
fDDS.Start();
|
fDDS.Start();
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
} catch (PluginServices::DeviceControlError& e) {
|
||||||
@@ -160,30 +159,10 @@ auto DDS::StartWorkerThread() -> void
|
|||||||
auto DDS::WaitForExitingAck() -> void
|
auto DDS::WaitForExitingAck() -> void
|
||||||
{
|
{
|
||||||
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
||||||
fExitingAcked.wait_for(
|
auto timeout = GetProperty<unsigned int>("wait-for-exiting-ack-timeout");
|
||||||
lock,
|
fExitingAcked.wait_for(lock, chrono::milliseconds(timeout), [this]() {
|
||||||
chrono::milliseconds(GetProperty<unsigned int>("wait-for-exiting-ack-timeout")),
|
return fExitingAckedByLastExternalController || fStateChangeSubscribers.empty();
|
||||||
[this]() { return fExitingAckedByLastExternalController; });
|
});
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::StaticControl() -> void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
TransitionDeviceStateTo(DeviceState::Running);
|
|
||||||
|
|
||||||
// wait until stop signal
|
|
||||||
unique_lock<mutex> lock(fStopMutex);
|
|
||||||
while (!fDeviceTerminationRequested) {
|
|
||||||
fStopCondition.wait_for(lock, chrono::seconds(1));
|
|
||||||
}
|
|
||||||
LOG(debug) << "Stopping DDS plugin static controller";
|
|
||||||
} catch (DeviceErrorState&) {
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
} catch (exception& e) {
|
|
||||||
ReleaseDeviceControl();
|
|
||||||
LOG(error) << "Error: " << e.what() << "\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDS::FillChannelContainers() -> void
|
auto DDS::FillChannelContainers() -> void
|
||||||
@@ -202,9 +181,7 @@ auto DDS::FillChannelContainers() -> void
|
|||||||
} else if (GetProperty<string>(methodKey) == "connect") {
|
} else if (GetProperty<string>(methodKey) == "connect") {
|
||||||
fConnectingChans.insert(make_pair(c.first, DDSConfig()));
|
fConnectingChans.insert(make_pair(c.first, DDSConfig()));
|
||||||
LOG(debug) << "preparing to connect: " << c.first << " with " << c.second << " sub-channels.";
|
LOG(debug) << "preparing to connect: " << c.first << " with " << c.second << " sub-channels.";
|
||||||
for (int i = 0; i < c.second; ++i) {
|
fConnectingChans.at(c.first).fNumSubChannels = c.second;
|
||||||
fConnectingChans.at(c.first).fSubChannelAddresses.push_back(string());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
LOG(error) << "Cannot update address configuration. Channel method (bind/connect) not specified.";
|
LOG(error) << "Cannot update address configuration. Channel method (bind/connect) not specified.";
|
||||||
return;
|
return;
|
||||||
@@ -251,11 +228,6 @@ auto DDS::FillChannelContainers() -> void
|
|||||||
LOG(debug) << "dds-i-n: adding " << chanName << " -> i: " << i << " n: " << n;
|
LOG(debug) << "dds-i-n: adding " << chanName << " -> i: " << i << " n: " << n;
|
||||||
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
fIofN.insert(make_pair(chanName, IofN(i, n)));
|
||||||
}
|
}
|
||||||
{
|
|
||||||
lock_guard<mutex> lk(fUpdateMutex);
|
|
||||||
fUpdatesAllowed = true;
|
|
||||||
}
|
|
||||||
fUpdateCondition.notify_one();
|
|
||||||
} catch (const exception& e) {
|
} catch (const exception& e) {
|
||||||
LOG(error) << "Error filling channel containers: " << e.what();
|
LOG(error) << "Error filling channel containers: " << e.what();
|
||||||
}
|
}
|
||||||
@@ -281,6 +253,12 @@ auto DDS::SubscribeForConnectingChannels() -> void
|
|||||||
unique_lock<mutex> lk(fUpdateMutex);
|
unique_lock<mutex> lk(fUpdateMutex);
|
||||||
fUpdateCondition.wait(lk, [&]{ return fUpdatesAllowed; });
|
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;
|
string val = value;
|
||||||
// check if it is to handle as one out of multiple values
|
// check if it is to handle as one out of multiple values
|
||||||
auto it = fIofN.find(channelName);
|
auto it = fIofN.find(channelName);
|
||||||
@@ -310,19 +288,16 @@ auto DDS::SubscribeForConnectingChannels() -> void
|
|||||||
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
fConnectingChans.at(channelName).fDDSValues.insert({senderTaskID, val.c_str()});
|
||||||
}
|
}
|
||||||
|
|
||||||
// update channels and remove them from unfinished container
|
for (const auto& mi : fConnectingChans) {
|
||||||
for (auto mi = fConnectingChans.begin(); mi != fConnectingChans.end(); /* no increment */) {
|
if (mi.second.fNumSubChannels == mi.second.fDDSValues.size()) {
|
||||||
if (mi->second.fSubChannelAddresses.size() == mi->second.fDDSValues.size()) {
|
int i = 0;
|
||||||
// when multiple subChannels are used, their order on every device should be the same, irregardless of arrival order from DDS.
|
for (const auto& e : mi.second.fDDSValues) {
|
||||||
sort(mi->second.fSubChannelAddresses.begin(), mi->second.fSubChannelAddresses.end());
|
auto result = UpdateProperty<string>(string{"chans." + mi.first + "." + to_string(i) + ".address"}, e.second);
|
||||||
auto it3 = mi->second.fDDSValues.begin();
|
if (!result) {
|
||||||
for (unsigned int i = 0; i < mi->second.fSubChannelAddresses.size(); ++i) {
|
LOG(error) << "UpdateProperty failed for: " << "chans." << mi.first << "." << to_string(i) << ".address" << " - property does not exist";
|
||||||
SetProperty<string>(string{"chans." + mi->first + "." + to_string(i) + ".address"}, it3->second);
|
}
|
||||||
++it3;
|
++i;
|
||||||
}
|
}
|
||||||
fConnectingChans.erase(mi++);
|
|
||||||
} else {
|
|
||||||
++mi;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (const exception& e) {
|
} catch (const exception& e) {
|
||||||
@@ -341,124 +316,133 @@ auto DDS::PublishBoundChannels() -> void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDS::HeartbeatSender() -> void
|
|
||||||
{
|
|
||||||
using namespace sdk::cmd;
|
|
||||||
string id = GetProperty<string>("id");
|
|
||||||
|
|
||||||
while (!fDeviceTerminationRequested) {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
|
||||||
|
|
||||||
for (const auto subscriberId : fHeartbeatSubscribers) {
|
|
||||||
fDDS.Send(Cmds(make<Heartbeat>(id)).Serialize(), to_string(subscriberId));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(fHeartbeatInterval));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDS::SubscribeForCustomCommands() -> void
|
auto DDS::SubscribeForCustomCommands() -> void
|
||||||
{
|
{
|
||||||
using namespace sdk::cmd;
|
|
||||||
LOG(debug) << "Subscribing for DDS custom commands.";
|
LOG(debug) << "Subscribing for DDS custom commands.";
|
||||||
|
|
||||||
string id = GetProperty<string>("id");
|
string id = GetProperty<string>("id");
|
||||||
|
|
||||||
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
fDDS.SubscribeCustomCmd([id, this](const string& cmdStr, const string& cond, uint64_t senderId) {
|
||||||
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
// LOG(info) << "Received command: '" << cmdStr << "' from " << senderId;
|
||||||
|
sdk::cmd::Cmds inCmds;
|
||||||
Cmds inCmds;
|
|
||||||
inCmds.Deserialize(cmdStr);
|
inCmds.Deserialize(cmdStr);
|
||||||
|
|
||||||
for (const auto& cmd : inCmds) {
|
for (const auto& cmd : inCmds) {
|
||||||
switch (cmd->GetType()) {
|
HandleCmd(id, *cmd, cond, senderId);
|
||||||
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, Result::Ok, transition));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
} else {
|
|
||||||
Cmds outCmds(make<TransitionStatus>(id, Result::Failure, transition));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(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::subscribe_to_heartbeats: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
|
||||||
fHeartbeatSubscribers.insert(senderId);
|
|
||||||
}
|
|
||||||
Cmds outCmds(make<HeartbeatSubscription>(id, Result::Ok));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_heartbeats: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fHeartbeatSubscriberMutex};
|
|
||||||
fHeartbeatSubscribers.erase(senderId);
|
|
||||||
}
|
|
||||||
Cmds outCmds(make<HeartbeatUnsubscription>(id, Result::Ok));
|
|
||||||
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: {
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.insert(senderId);
|
|
||||||
if (!fControllerThread.joinable()) {
|
|
||||||
fControllerThread = thread(&DDS::WaitForExitingAck, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
LOG(debug) << "Publishing state-change: " << fLastState << "->" << fCurrentState << " to " << senderId;
|
|
||||||
|
|
||||||
Cmds outCmds(make<StateChangeSubscription>(id, Result::Ok), make<StateChange>(id, dds::env_prop<dds::task_id>(), fLastState, fCurrentState));
|
|
||||||
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_state_change: {
|
|
||||||
{
|
|
||||||
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
|
||||||
fStateChangeSubscribers.erase(senderId);
|
|
||||||
}
|
|
||||||
Cmds outCmds(make<StateChangeUnsubscription>(id, Result::Ok));
|
|
||||||
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
LOG(warn) << "Unexpected/unknown command received: " << cmdStr;
|
|
||||||
LOG(warn) << "Origin: " << senderId;
|
|
||||||
LOG(warn) << "Destination: " << cond;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
fDDS.Send(outCmds.Serialize(), to_string(senderId));
|
||||||
|
} else {
|
||||||
|
Cmds outCmds(make<TransitionStatus>(id, fDDSTaskId, Result::Failure, transition));
|
||||||
|
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()
|
DDS::~DDS()
|
||||||
{
|
{
|
||||||
UnsubscribeFromDeviceStateChange();
|
UnsubscribeFromDeviceStateChange();
|
||||||
@@ -468,10 +452,6 @@ DDS::~DDS()
|
|||||||
fControllerThread.join();
|
fControllerThread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHeartbeatThread.joinable()) {
|
|
||||||
fHeartbeatThread.join();
|
|
||||||
}
|
|
||||||
|
|
||||||
fWorkGuard.reset();
|
fWorkGuard.reset();
|
||||||
if (fWorkerThread.joinable()) {
|
if (fWorkerThread.joinable()) {
|
||||||
fWorkerThread.join();
|
fWorkerThread.join();
|
||||||
|
@@ -12,9 +12,9 @@
|
|||||||
#include <fairmq/Plugin.h>
|
#include <fairmq/Plugin.h>
|
||||||
#include <fairmq/StateQueue.h>
|
#include <fairmq/StateQueue.h>
|
||||||
#include <fairmq/Version.h>
|
#include <fairmq/Version.h>
|
||||||
|
#include <fairmq/sdk/commands/Commands.h>
|
||||||
|
|
||||||
#include <DDS/dds_env_prop.h>
|
#include <dds/dds.h>
|
||||||
#include <DDS/dds_intercom.h>
|
|
||||||
|
|
||||||
#include <boost/asio/executor.hpp>
|
#include <boost/asio/executor.hpp>
|
||||||
#include <boost/asio/executor_work_guard.hpp>
|
#include <boost/asio/executor_work_guard.hpp>
|
||||||
@@ -24,11 +24,12 @@
|
|||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <set>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <map>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <utility> // pair
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace fair
|
namespace fair
|
||||||
@@ -41,16 +42,16 @@ namespace plugins
|
|||||||
struct DDSConfig
|
struct DDSConfig
|
||||||
{
|
{
|
||||||
// container of sub channel addresses
|
// container of sub channel addresses
|
||||||
std::vector<std::string> fSubChannelAddresses;
|
unsigned int fNumSubChannels;
|
||||||
// dds values for the channel
|
// dds values for the channel
|
||||||
std::unordered_map<uint64_t, std::string> fDDSValues;
|
std::map<uint64_t, std::string> fDDSValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DDSSubscription
|
struct DDSSubscription
|
||||||
{
|
{
|
||||||
DDSSubscription()
|
DDSSubscription()
|
||||||
: fDDSCustomCmd(fService)
|
: fDDSCustomCmd(fService)
|
||||||
, fDDSKeyValue(fService)
|
, fDDSKeyValue(fService)
|
||||||
{
|
{
|
||||||
LOG(debug) << "$DDS_TASK_PATH: " << dds::env_prop<dds::task_path>();
|
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_GROUP_NAME: " << dds::env_prop<dds::group_name>();
|
||||||
@@ -133,7 +134,6 @@ class DDS : public Plugin
|
|||||||
~DDS();
|
~DDS();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
auto StaticControl() -> void;
|
|
||||||
auto WaitForExitingAck() -> void;
|
auto WaitForExitingAck() -> void;
|
||||||
auto StartWorkerThread() -> void;
|
auto StartWorkerThread() -> void;
|
||||||
|
|
||||||
@@ -143,10 +143,10 @@ class DDS : public Plugin
|
|||||||
auto SubscribeForConnectingChannels() -> void;
|
auto SubscribeForConnectingChannels() -> void;
|
||||||
auto PublishBoundChannels() -> void;
|
auto PublishBoundChannels() -> void;
|
||||||
auto SubscribeForCustomCommands() -> void;
|
auto SubscribeForCustomCommands() -> void;
|
||||||
|
auto HandleCmd(const std::string& id, sdk::cmd::Cmd& cmd, const std::string& cond, uint64_t senderId) -> void;
|
||||||
auto HeartbeatSender() -> void;
|
|
||||||
|
|
||||||
DDSSubscription fDDS;
|
DDSSubscription fDDS;
|
||||||
|
size_t fDDSTaskId;
|
||||||
|
|
||||||
std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
|
std::unordered_map<std::string, std::vector<std::string>> fBindingChans;
|
||||||
std::unordered_map<std::string, DDSConfig> fConnectingChans;
|
std::unordered_map<std::string, DDSConfig> fConnectingChans;
|
||||||
@@ -154,29 +154,17 @@ class DDS : public Plugin
|
|||||||
std::unordered_map<std::string, int> fI;
|
std::unordered_map<std::string, int> fI;
|
||||||
std::unordered_map<std::string, IofN> fIofN;
|
std::unordered_map<std::string, IofN> fIofN;
|
||||||
|
|
||||||
std::mutex fStopMutex;
|
|
||||||
std::condition_variable fStopCondition;
|
|
||||||
|
|
||||||
const std::set<std::string> fTransitions;
|
|
||||||
|
|
||||||
std::thread fControllerThread;
|
std::thread fControllerThread;
|
||||||
DeviceState fCurrentState, fLastState;
|
DeviceState fCurrentState, fLastState;
|
||||||
fair::mq::StateQueue fStateQueue;
|
|
||||||
|
|
||||||
std::atomic<bool> fDeviceTerminationRequested;
|
std::atomic<bool> fDeviceTerminationRequested;
|
||||||
|
|
||||||
std::set<uint64_t> fHeartbeatSubscribers;
|
std::unordered_map<uint64_t, std::pair<std::chrono::steady_clock::time_point, int64_t>> fStateChangeSubscribers;
|
||||||
std::mutex fHeartbeatSubscriberMutex;
|
|
||||||
|
|
||||||
std::set<uint64_t> fStateChangeSubscribers;
|
|
||||||
uint64_t fLastExternalController;
|
uint64_t fLastExternalController;
|
||||||
bool fExitingAckedByLastExternalController;
|
bool fExitingAckedByLastExternalController;
|
||||||
std::condition_variable fExitingAcked;
|
std::condition_variable fExitingAcked;
|
||||||
std::mutex fStateChangeSubscriberMutex;
|
std::mutex fStateChangeSubscriberMutex;
|
||||||
|
|
||||||
std::thread fHeartbeatThread;
|
|
||||||
std::chrono::milliseconds fHeartbeatInterval;
|
|
||||||
|
|
||||||
bool fUpdatesAllowed;
|
bool fUpdatesAllowed;
|
||||||
std::mutex fUpdateMutex;
|
std::mutex fUpdateMutex;
|
||||||
std::condition_variable fUpdateCondition;
|
std::condition_variable fUpdateCondition;
|
||||||
|
@@ -8,23 +8,23 @@
|
|||||||
|
|
||||||
#include <fairmq/sdk/commands/Commands.h>
|
#include <fairmq/sdk/commands/Commands.h>
|
||||||
#include <fairmq/States.h>
|
#include <fairmq/States.h>
|
||||||
|
#include <fairmq/SDK.h>
|
||||||
#include <DDS/dds_intercom.h>
|
|
||||||
|
|
||||||
#include <boost/program_options.hpp>
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <termios.h> // raw mode console input
|
||||||
|
#include <unistd.h>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <termios.h> // raw mode console input
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace dds::intercom_api;
|
using namespace fair::mq;
|
||||||
|
using namespace fair::mq::sdk;
|
||||||
using namespace fair::mq::sdk::cmd;
|
using namespace fair::mq::sdk::cmd;
|
||||||
namespace bpo = boost::program_options;
|
namespace bpo = boost::program_options;
|
||||||
|
|
||||||
@@ -49,272 +49,176 @@ struct TerminalConfig
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateSubscription
|
|
||||||
{
|
|
||||||
const string& fTopologyPath;
|
|
||||||
CCustomCmd& fDdsCustomCmd;
|
|
||||||
|
|
||||||
explicit StateSubscription(const string& topologyPath, CCustomCmd& ddsCustomCmd)
|
|
||||||
: fTopologyPath(topologyPath)
|
|
||||||
, fDdsCustomCmd(ddsCustomCmd)
|
|
||||||
{
|
|
||||||
fDdsCustomCmd.send(Cmds(make<SubscribeToStateChange>()).Serialize(), fTopologyPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
~StateSubscription() {
|
|
||||||
fDdsCustomCmd.send(Cmds(make<UnsubscribeFromStateChange>()).Serialize(), fTopologyPath);
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void printControlsHelp()
|
void printControlsHelp()
|
||||||
{
|
{
|
||||||
cout << "Use keys to control the devices:" << endl;
|
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" << 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;
|
cout << "To quit press Ctrl+C" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendCommand(const string& commandIn, const string& topologyPath, CCustomCmd& ddsCustomCmd) {
|
void handleCommand(const string& command, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||||
|
{
|
||||||
|
if (command == "c") {
|
||||||
|
cout << "> checking state of the devices" << endl;
|
||||||
|
auto const result = topo.GetCurrentState();
|
||||||
|
for (const auto& d : result) {
|
||||||
|
cout << d.taskId << " : " << d.state << endl;
|
||||||
|
}
|
||||||
|
} else if (command == "o") {
|
||||||
|
cout << "> dumping config of the devices (" << 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));
|
||||||
|
for (const auto& d : result.second.devices) {
|
||||||
|
for (auto const& p : d.second.props) {
|
||||||
|
cout << d.first << ": " << p.first << " : " << p.second << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (command == "p") {
|
||||||
|
if (pKey == "" || pVal == "") {
|
||||||
|
cout << "cannot send property with empty key and/or value! given key: '" << pKey << "', value: '" << pVal << "'." << endl;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const DeviceProperties props{{pKey, pVal}};
|
||||||
|
cout << "> sending property (" << path << ")" << endl;
|
||||||
|
topo.SetProperties(props, path);
|
||||||
|
// give dds time to complete request
|
||||||
|
this_thread::sleep_for(chrono::milliseconds(100));
|
||||||
|
} else if (command == "i") {
|
||||||
|
cout << "> init devices (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::InitDevice, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "k") {
|
||||||
|
cout << "> complete init (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::CompleteInit, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "b") {
|
||||||
|
cout << "> bind devices (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::Bind, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "x") {
|
||||||
|
cout << "> connect devices (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::Connect, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "j") {
|
||||||
|
cout << "> init tasks (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::InitTask, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "r") {
|
||||||
|
cout << "> run tasks (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::Run, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "s") {
|
||||||
|
cout << "> stop devices (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::Stop, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "t") {
|
||||||
|
cout << "> reset tasks (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::ResetTask, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "d") {
|
||||||
|
cout << "> reset devices (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::ResetDevice, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "q") {
|
||||||
|
cout << "> end (" << path << ")" << endl;
|
||||||
|
topo.ChangeState(TopologyTransition::End, path, std::chrono::milliseconds(timeout));
|
||||||
|
} else if (command == "h") {
|
||||||
|
cout << "> help" << endl;
|
||||||
|
printControlsHelp();
|
||||||
|
} else {
|
||||||
|
cout << "\033[01;32mInvalid input: [" << command << "]\033[0m" << endl;
|
||||||
|
printControlsHelp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendCommand(const string& commandIn, const string& path, unsigned int timeout, Topology& topo, const string& pKey, const string& pVal)
|
||||||
|
{
|
||||||
|
if (commandIn != "") {
|
||||||
|
handleCommand(commandIn, path, timeout, topo, pKey, pVal);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
char c;
|
char c;
|
||||||
string command(commandIn);
|
string command;
|
||||||
TerminalConfig tconfig;
|
TerminalConfig tconfig;
|
||||||
|
|
||||||
if (command == "") {
|
printControlsHelp();
|
||||||
printControlsHelp();
|
cin >> c;
|
||||||
|
command = c;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
handleCommand(command, path, timeout, topo, pKey, pVal);
|
||||||
cin >> c;
|
cin >> c;
|
||||||
command = c;
|
command = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
|
||||||
if (command == "c") {
|
|
||||||
cout << "> checking state of the devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<CheckState>()).Serialize(), topologyPath);
|
|
||||||
} else if (command == "o") {
|
|
||||||
cout << "> dumping config of the devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<DumpConfig>()).Serialize(), topologyPath);
|
|
||||||
} else if (command == "i") {
|
|
||||||
cout << "> init devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitDevice)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "k") {
|
|
||||||
cout << "> complete init" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::CompleteInit)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "b") {
|
|
||||||
cout << "> bind devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Bind)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "x") {
|
|
||||||
cout << "> connect devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Connect)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "j") {
|
|
||||||
cout << "> init tasks" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::InitTask)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "r") {
|
|
||||||
cout << "> run tasks" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Run)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "s") {
|
|
||||||
cout << "> stop devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::Stop)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "t") {
|
|
||||||
cout << "> reset tasks" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetTask)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "d") {
|
|
||||||
cout << "> reset devices" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::ResetDevice)).Serialize(), topologyPath);
|
|
||||||
} else if (command == "h") {
|
|
||||||
cout << "> help" << endl;
|
|
||||||
printControlsHelp();
|
|
||||||
} else if (command == "q") {
|
|
||||||
cout << "> end" << endl;
|
|
||||||
ddsCustomCmd.send(Cmds(make<ChangeState>(fair::mq::Transition::End)).Serialize(), topologyPath);
|
|
||||||
} else {
|
|
||||||
cout << "\033[01;32mInvalid input: [" << c << "]\033[0m" << endl;
|
|
||||||
printControlsHelp();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (commandIn != "") {
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
|
||||||
break;
|
|
||||||
} else {
|
|
||||||
cin >> c;
|
|
||||||
command = c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct WaitMode
|
|
||||||
{
|
|
||||||
explicit WaitMode(const string& targetState)
|
|
||||||
: fTransitionedCount(0)
|
|
||||||
{
|
|
||||||
if (targetState != "") {
|
|
||||||
size_t n = targetState.find("->");
|
|
||||||
if (n == string::npos) {
|
|
||||||
fTargetStatePair.first = fair::mq::State::Ok;
|
|
||||||
fTargetStatePair.second = fair::mq::GetState(targetState);
|
|
||||||
} else {
|
|
||||||
fTargetStatePair.first = fair::mq::GetState(targetState.substr(0, n));
|
|
||||||
fTargetStatePair.second = fair::mq::GetState(targetState.substr(n + 2));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Run(const chrono::milliseconds& timeout, const string& topologyPath, CCustomCmd& ddsCustomCmd, unsigned int numDevices, const string& command = "")
|
|
||||||
{
|
|
||||||
StateSubscription stateSubscription(topologyPath, ddsCustomCmd);
|
|
||||||
|
|
||||||
if (command != "") {
|
|
||||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO once DDS provides an API to retrieve actual number of tasks, use it here
|
|
||||||
auto condition = [&] {
|
|
||||||
bool res = fTransitionedCount == numDevices;
|
|
||||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
|
||||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.second << ", condition check: " << res << endl;
|
|
||||||
} else {
|
|
||||||
cout << "Waiting for " << numDevices << " devices to reach " << fTargetStatePair.first << "->" << fTargetStatePair.second << ", condition check: " << res << endl;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
};
|
|
||||||
|
|
||||||
unique_lock<mutex> lock(fMtx);
|
|
||||||
|
|
||||||
if (timeout > chrono::milliseconds(0)) {
|
|
||||||
if (!fCV.wait_for(lock, timeout, condition)) {
|
|
||||||
throw runtime_error("timeout");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fCV.wait(lock, condition);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cout << "WaitMode.Run() finished" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CountStates(fair::mq::State lastState, fair::mq::State currentState)
|
|
||||||
{
|
|
||||||
{
|
|
||||||
unique_lock<mutex> lock(fMtx);
|
|
||||||
if (fTargetStatePair.first == fair::mq::State::Ok) {
|
|
||||||
if (fTargetStatePair.second == currentState) {
|
|
||||||
fTransitionedCount++;
|
|
||||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for single value" << endl;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (fTargetStatePair.first == lastState && fTargetStatePair.second == currentState) {
|
|
||||||
fTransitionedCount++;
|
|
||||||
// cout << "fTransitionedCount = " << fTransitionedCount << " for double value" << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fCV.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
mutex fMtx;
|
|
||||||
condition_variable fCV;
|
|
||||||
pair<fair::mq::State, fair::mq::State> fTargetStatePair;
|
|
||||||
unsigned int fTransitionedCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
{
|
try {
|
||||||
try {
|
string sessionID;
|
||||||
string sessionID;
|
string topoFile;
|
||||||
string command;
|
|
||||||
string topologyPath;
|
|
||||||
string targetState;
|
|
||||||
unsigned int timeout;
|
|
||||||
unsigned int numDevices(0);
|
|
||||||
|
|
||||||
bpo::options_description options("Common options");
|
string command;
|
||||||
|
string path;
|
||||||
|
string targetState;
|
||||||
|
string pKey;
|
||||||
|
string pVal;
|
||||||
|
unsigned int timeout;
|
||||||
|
|
||||||
auto envSessionId = getenv("DDS_SESSION_ID");
|
fair::Logger::SetConsoleSeverity("debug");
|
||||||
if (envSessionId) {
|
fair::Logger::SetConsoleColor(true);
|
||||||
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)");
|
|
||||||
}
|
|
||||||
|
|
||||||
options.add_options()
|
bpo::options_description options("Common options");
|
||||||
("command,c", bpo::value<string> (&command)->default_value(""), "Command character")
|
|
||||||
("path,p", bpo::value<string> (&topologyPath)->default_value(""), "DDS Topology path to send command to (empty - send to all tasks)")
|
|
||||||
("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)")
|
|
||||||
("number-devices,n", bpo::value<unsigned int> (&numDevices)->default_value(0), "Number of devices (will be removed in the future)")
|
|
||||||
("help,h", "Produce help message");
|
|
||||||
|
|
||||||
bpo::variables_map vm;
|
auto envSessionId = getenv("DDS_SESSION_ID");
|
||||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
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)");
|
||||||
if (vm.count("help")) {
|
} else {
|
||||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
options.add_options()("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID (overrides any value in env var $DDS_SESSION_ID)");
|
||||||
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" << endl;
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
bpo::notify(vm);
|
|
||||||
|
|
||||||
WaitMode waitMode(targetState);
|
|
||||||
|
|
||||||
CIntercomService service;
|
|
||||||
CCustomCmd ddsCustomCmd(service);
|
|
||||||
|
|
||||||
service.subscribeOnError([](const EErrorCode errorCode, const string& errorMsg) {
|
|
||||||
cerr << "DDS error received: error code: " << errorCode << ", error message: " << errorMsg << endl;
|
|
||||||
});
|
|
||||||
|
|
||||||
// subscribe to receive messages from DDS
|
|
||||||
ddsCustomCmd.subscribe([&](const string& msg, const string& /*condition*/, uint64_t senderId) {
|
|
||||||
Cmds cmds;
|
|
||||||
cmds.Deserialize(msg);
|
|
||||||
// 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;
|
|
||||||
if (static_cast<StateChange&>(*cmd).GetCurrentState() == fair::mq::State::Exiting) {
|
|
||||||
ddsCustomCmd.send(Cmds(make<StateChangeExitingReceived>()).Serialize(), to_string(senderId));
|
|
||||||
}
|
|
||||||
waitMode.CountStates(static_cast<StateChange&>(*cmd).GetLastState(), static_cast<StateChange&>(*cmd).GetCurrentState());
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
default:
|
|
||||||
cout << "Unexpected/unknown command received: " << cmd->GetType() << endl;
|
|
||||||
cout << "Origin: " << senderId << endl;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
service.start(sessionID);
|
|
||||||
|
|
||||||
if (targetState == "") {
|
|
||||||
sendCommand(command, topologyPath, ddsCustomCmd);
|
|
||||||
} else {
|
|
||||||
waitMode.Run(chrono::milliseconds(timeout), topologyPath, ddsCustomCmd, numDevices, command);
|
|
||||||
}
|
|
||||||
|
|
||||||
ddsCustomCmd.unsubscribe();
|
|
||||||
} catch (exception& e) {
|
|
||||||
cerr << "Error: " << e.what() << endl;
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
if (targetState != "") {
|
||||||
|
if (command != "") {
|
||||||
|
sendCommand(command, path, timeout, topo, pKey, pVal);
|
||||||
|
}
|
||||||
|
size_t pos = targetState.find("->");
|
||||||
|
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;
|
return EXIT_SUCCESS;
|
||||||
|
} catch (exception& e) {
|
||||||
|
cerr << "Error: " << e.what() << endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
@@ -10,9 +10,10 @@ set(plugin FairMQPlugin_pmix)
|
|||||||
add_library(${plugin} SHARED
|
add_library(${plugin} SHARED
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/PMIxPlugin.cxx
|
${CMAKE_CURRENT_SOURCE_DIR}/PMIxPlugin.cxx
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/PMIxPlugin.h
|
${CMAKE_CURRENT_SOURCE_DIR}/PMIxPlugin.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/PMIxCommands.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/PMIx.hpp
|
${CMAKE_CURRENT_SOURCE_DIR}/PMIx.hpp
|
||||||
)
|
)
|
||||||
target_link_libraries(${plugin} FairMQ PMIx::libpmix)
|
target_link_libraries(${plugin} PUBLIC FairMQ PMIx::libpmix PRIVATE Commands)
|
||||||
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
target_include_directories(${plugin} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
set_target_properties(${plugin} PROPERTIES
|
set_target_properties(${plugin} PROPERTIES
|
||||||
CXX_VISIBILITY_PRESET hidden
|
CXX_VISIBILITY_PRESET hidden
|
||||||
@@ -20,7 +21,12 @@ set_target_properties(${plugin} PROPERTIES
|
|||||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||||
)
|
)
|
||||||
|
|
||||||
install(TARGETS ${plugin}
|
set(exe fairmq-pmix-command-ui)
|
||||||
|
add_executable(${exe} ${CMAKE_CURRENT_SOURCE_DIR}/runPMIxCommandUI.cxx)
|
||||||
|
target_link_libraries(${exe} FairMQ Commands StateMachine PMIx::libpmix)
|
||||||
|
target_include_directories(${exe} PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||||
|
|
||||||
|
install(TARGETS ${plugin} ${exe}
|
||||||
EXPORT ${PROJECT_EXPORT_SET}
|
EXPORT ${PROJECT_EXPORT_SET}
|
||||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
@@ -9,17 +9,18 @@
|
|||||||
#ifndef PMIX_HPP
|
#ifndef PMIX_HPP
|
||||||
#define PMIX_HPP
|
#define PMIX_HPP
|
||||||
|
|
||||||
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <pmix.h>
|
#include <pmix.h>
|
||||||
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <string.h>
|
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <FairMQLogger.h>
|
|
||||||
|
|
||||||
// C++ PMIx v2.2 API
|
// C++ PMIx v2.2 API
|
||||||
namespace pmix
|
namespace pmix
|
||||||
@@ -69,7 +70,7 @@ struct proc : pmix_proc_t
|
|||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const proc& p)
|
friend std::ostream& operator<<(std::ostream& os, const proc& p)
|
||||||
{
|
{
|
||||||
return os << "nspace=" << p.nspace << ",rank=" << p.rank;
|
return os << p.nspace << "_" << p.rank;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +81,6 @@ struct value : pmix_value_t
|
|||||||
|
|
||||||
value(const value& rhs)
|
value(const value& rhs)
|
||||||
{
|
{
|
||||||
LOG(warn) << "copy ctor";
|
|
||||||
status rc;
|
status rc;
|
||||||
auto lhs(static_cast<pmix_value_t*>(this));
|
auto lhs(static_cast<pmix_value_t*>(this));
|
||||||
PMIX_VALUE_XFER(rc, lhs, static_cast<pmix_value_t*>(const_cast<value*>(&rhs)));
|
PMIX_VALUE_XFER(rc, lhs, static_cast<pmix_value_t*>(const_cast<value*>(&rhs)));
|
||||||
@@ -111,6 +111,11 @@ struct value : pmix_value_t
|
|||||||
{
|
{
|
||||||
PMIX_VALUE_LOAD(static_cast<pmix_value_t*>(this), &val, PMIX_INT);
|
PMIX_VALUE_LOAD(static_cast<pmix_value_t*>(this), &val, PMIX_INT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
explicit value(pmix_data_array_t* val)
|
||||||
|
{
|
||||||
|
PMIX_VALUE_LOAD(static_cast<pmix_value_t*>(this), val, PMIX_DATA_ARRAY);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct info : pmix_info_t
|
struct info : pmix_info_t
|
||||||
@@ -134,9 +139,15 @@ struct info : pmix_info_t
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::ostream& operator<<(std::ostream& os, const info& p)
|
friend std::ostream& operator<<(std::ostream& os, const info& i)
|
||||||
{
|
{
|
||||||
return os << "key=" << p.key << ",value='" << p.value.data.string << "'";
|
return os << "key=" << i.key << ",value='" << i.value.data.string << "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
info(const info& rhs)
|
||||||
|
{
|
||||||
|
PMIX_INFO_XFER(static_cast<pmix_info_t*>(this),
|
||||||
|
static_cast<pmix_info_t*>(const_cast<info*>(&rhs)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -144,6 +155,7 @@ struct pdata : pmix_pdata_t
|
|||||||
{
|
{
|
||||||
pdata() { PMIX_PDATA_CONSTRUCT(static_cast<pmix_pdata_t*>(this)); }
|
pdata() { PMIX_PDATA_CONSTRUCT(static_cast<pmix_pdata_t*>(this)); }
|
||||||
~pdata() { PMIX_PDATA_DESTRUCT(static_cast<pmix_pdata_t*>(this)); }
|
~pdata() { PMIX_PDATA_DESTRUCT(static_cast<pmix_pdata_t*>(this)); }
|
||||||
|
|
||||||
pdata(const pdata& rhs)
|
pdata(const pdata& rhs)
|
||||||
{
|
{
|
||||||
PMIX_PDATA_XFER(static_cast<pmix_pdata_t*>(this),
|
PMIX_PDATA_XFER(static_cast<pmix_pdata_t*>(this),
|
||||||
@@ -171,7 +183,7 @@ auto init(const std::vector<info>& info = {}) -> proc
|
|||||||
|
|
||||||
auto initialized() -> bool { return !!PMIx_Initialized(); }
|
auto initialized() -> bool { return !!PMIx_Initialized(); }
|
||||||
|
|
||||||
auto get_version() -> const char* { return PMIx_Get_version(); }
|
auto get_version() -> std::string { return {PMIx_Get_version()}; }
|
||||||
|
|
||||||
auto finalize(const std::vector<info>& info = {}) -> void
|
auto finalize(const std::vector<info>& info = {}) -> void
|
||||||
{
|
{
|
||||||
@@ -213,6 +225,92 @@ auto lookup(std::vector<pdata>& pdata, const std::vector<info>& info = {}) -> vo
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string get_info(const std::string& name, pmix::proc& process)
|
||||||
|
{
|
||||||
|
pmix_value_t* v;
|
||||||
|
|
||||||
|
pmix::status rc = PMIx_Get(&process, name.c_str(), nullptr, 0, &v);
|
||||||
|
if (rc == PMIX_SUCCESS) {
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
switch (v->type) {
|
||||||
|
case PMIX_SIZE: ss << static_cast<size_t>(v->data.size) << " (size_t)"; break;
|
||||||
|
case PMIX_INT: ss << static_cast<int>(v->data.integer) << " (int)"; break;
|
||||||
|
case PMIX_INT8: ss << static_cast<int8_t>(v->data.int8) << " (int8_t)"; break;
|
||||||
|
case PMIX_INT16: ss << static_cast<int16_t>(v->data.int16) << " (int16_t)"; break;
|
||||||
|
case PMIX_INT32: ss << static_cast<int32_t>(v->data.int32) << " (int32_t)"; break;
|
||||||
|
case PMIX_INT64: ss << static_cast<int64_t>(v->data.int64) << " (int64_t)"; break;
|
||||||
|
case PMIX_UINT: ss << static_cast<unsigned int>(v->data.uint) << " (unsigned int)"; break;
|
||||||
|
case PMIX_UINT8: ss << static_cast<uint8_t>(v->data.uint8) << " (uint8_t)"; break;
|
||||||
|
case PMIX_UINT16: ss << static_cast<uint16_t>(v->data.uint16) << " (uint16_t)"; break;
|
||||||
|
case PMIX_UINT32: ss << static_cast<uint32_t>(v->data.uint32) << " (uint32_t)"; break;
|
||||||
|
case PMIX_UINT64: ss << static_cast<uint64_t>(v->data.uint64) << " (uint64_t)"; break;
|
||||||
|
case PMIX_FLOAT: ss << static_cast<float>(v->data.fval) << " (float)"; break;
|
||||||
|
case PMIX_DOUBLE: ss << static_cast<double>(v->data.dval) << " (double)"; break;
|
||||||
|
case PMIX_PID: ss << static_cast<pid_t>(v->data.pid) << " (pid_t)"; break;
|
||||||
|
case PMIX_STRING: ss << static_cast<char*>(v->data.string) << " (string)"; break;
|
||||||
|
case PMIX_PROC_RANK: ss << static_cast<uint32_t>(v->data.rank) << " (pmix_rank_t)"; break;
|
||||||
|
case PMIX_PROC: ss << "proc.nspace: " << static_cast<pmix_proc_t*>(v->data.proc)->nspace
|
||||||
|
<< ", proc.rank: " << static_cast<pmix_proc_t*>(v->data.proc)->rank << " (pmix_proc_t*)"; break;
|
||||||
|
default:
|
||||||
|
ss << "unknown type: " << v->type;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ss.str();
|
||||||
|
} else if (rc == PMIX_ERR_NOT_FOUND) {
|
||||||
|
// LOG(error) << "PMIx_Get failed: PMIX_ERR_NOT_FOUND";
|
||||||
|
return "";
|
||||||
|
} else {
|
||||||
|
// LOG(error) << "PMIx_Get failed: " << rc;
|
||||||
|
return "<undefined>";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string get_value_str(const pmix_value_t& v)
|
||||||
|
{
|
||||||
|
switch (v.type) {
|
||||||
|
case PMIX_BOOL: return std::to_string(static_cast<bool>(v.data.flag));
|
||||||
|
case PMIX_SIZE: return std::to_string(static_cast<size_t>(v.data.size));
|
||||||
|
case PMIX_INT: return std::to_string(static_cast<int>(v.data.integer));
|
||||||
|
case PMIX_INT8: return std::to_string(static_cast<int8_t>(v.data.int8));
|
||||||
|
case PMIX_INT16: return std::to_string(static_cast<int16_t>(v.data.int16));
|
||||||
|
case PMIX_INT32: return std::to_string(static_cast<int32_t>(v.data.int32));
|
||||||
|
case PMIX_INT64: return std::to_string(static_cast<int64_t>(v.data.int64));
|
||||||
|
case PMIX_UINT: return std::to_string(static_cast<unsigned int>(v.data.uint));
|
||||||
|
case PMIX_UINT8: return std::to_string(static_cast<uint8_t>(v.data.uint8));
|
||||||
|
case PMIX_UINT16: return std::to_string(static_cast<uint16_t>(v.data.uint16));
|
||||||
|
case PMIX_UINT32: return std::to_string(static_cast<uint32_t>(v.data.uint32));
|
||||||
|
case PMIX_UINT64: return std::to_string(static_cast<uint64_t>(v.data.uint64));
|
||||||
|
case PMIX_FLOAT: return std::to_string(static_cast<float>(v.data.fval));
|
||||||
|
case PMIX_DOUBLE: return std::to_string(static_cast<double>(v.data.dval));
|
||||||
|
case PMIX_PID: return std::to_string(static_cast<pid_t>(v.data.pid));
|
||||||
|
case PMIX_STRING: return static_cast<char*>(v.data.string);
|
||||||
|
case PMIX_PROC_RANK: return std::to_string(static_cast<uint32_t>(v.data.rank));
|
||||||
|
case PMIX_POINTER: { std::stringstream ss; ss << static_cast<void*>(v.data.ptr); return ss.str(); }
|
||||||
|
case PMIX_DATA_ARRAY: {
|
||||||
|
if (v.data.darray->type == PMIX_PROC) {
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "[";
|
||||||
|
for (size_t i = 0; i < v.data.darray->size; ++i) {
|
||||||
|
ss << static_cast<pmix_proc_t*>(static_cast<pmix_data_array_t*>(v.data.darray)->array)[0].nspace;
|
||||||
|
ss << "_";
|
||||||
|
ss << static_cast<pmix_proc_t*>(static_cast<pmix_data_array_t*>(v.data.darray)->array)[0].rank;
|
||||||
|
|
||||||
|
if (i < v.data.darray->size - 1) {
|
||||||
|
ss << ",";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ss << "]";
|
||||||
|
return ss.str();
|
||||||
|
} else {
|
||||||
|
return "UNKNOWN TYPE IN DATA ARRAY";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: return "UNKNOWN TYPE";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace pmix */
|
} /* namespace pmix */
|
||||||
|
|
||||||
#endif /* PMIX_HPP */
|
#endif /* PMIX_HPP */
|
||||||
|
291
fairmq/plugins/PMIx/PMIxCommands.h
Normal file
291
fairmq/plugins/PMIx/PMIxCommands.h
Normal file
@@ -0,0 +1,291 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* 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 PMIXCOMMANDS_H
|
||||||
|
#define PMIXCOMMANDS_H
|
||||||
|
|
||||||
|
#include "PMIx.hpp"
|
||||||
|
|
||||||
|
#include <FairMQLogger.h>
|
||||||
|
#include <fairmq/tools/Semaphore.h>
|
||||||
|
#include <fairmq/tools/CppSTL.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace pmix
|
||||||
|
{
|
||||||
|
|
||||||
|
std::array<std::string, 47> typeNames =
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"PMIX_UNDEF",
|
||||||
|
"PMIX_BOOL",
|
||||||
|
"PMIX_BYTE",
|
||||||
|
"PMIX_STRING",
|
||||||
|
"PMIX_SIZE",
|
||||||
|
"PMIX_PID",
|
||||||
|
"PMIX_INT",
|
||||||
|
"PMIX_INT8",
|
||||||
|
"PMIX_INT16",
|
||||||
|
"PMIX_INT32",
|
||||||
|
"PMIX_INT64",
|
||||||
|
"PMIX_UINT",
|
||||||
|
"PMIX_UINT8",
|
||||||
|
"PMIX_UINT16",
|
||||||
|
"PMIX_UINT32",
|
||||||
|
"PMIX_UINT64",
|
||||||
|
"PMIX_FLOAT",
|
||||||
|
"PMIX_DOUBLE",
|
||||||
|
"PMIX_TIMEVAL",
|
||||||
|
"PMIX_TIME",
|
||||||
|
"PMIX_STATUS",
|
||||||
|
"PMIX_VALUE",
|
||||||
|
"PMIX_PROC",
|
||||||
|
"PMIX_APP",
|
||||||
|
"PMIX_INFO",
|
||||||
|
"PMIX_PDATA",
|
||||||
|
"PMIX_BUFFER",
|
||||||
|
"PMIX_BYTE_OBJECT",
|
||||||
|
"PMIX_KVAL",
|
||||||
|
"PMIX_MODEX",
|
||||||
|
"PMIX_PERSIST",
|
||||||
|
"PMIX_POINTER",
|
||||||
|
"PMIX_SCOPE",
|
||||||
|
"PMIX_DATA_RANGE",
|
||||||
|
"PMIX_COMMAND",
|
||||||
|
"PMIX_INFO_DIRECTIVES",
|
||||||
|
"PMIX_DATA_TYPE",
|
||||||
|
"PMIX_PROC_STATE",
|
||||||
|
"PMIX_PROC_INFO",
|
||||||
|
"PMIX_DATA_ARRAY",
|
||||||
|
"PMIX_PROC_RANK",
|
||||||
|
"PMIX_QUERY",
|
||||||
|
"PMIX_COMPRESSED_STRING",
|
||||||
|
"PMIX_ALLOC_DIRECTIVE",
|
||||||
|
"PMIX_INFO_ARRAY",
|
||||||
|
"PMIX_IOF_CHANNEL",
|
||||||
|
"PMIX_ENVAR"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class Command : int
|
||||||
|
{
|
||||||
|
general = PMIX_EXTERNAL_ERR_BASE,
|
||||||
|
error = PMIX_EXTERNAL_ERR_BASE - 1
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Commands
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Commands(const proc& process)
|
||||||
|
: fProcess(process)
|
||||||
|
, fSubscribed(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~Commands()
|
||||||
|
{
|
||||||
|
Unsubscribe();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Subscribe(std::function<void(const std::string& msg, const proc& sender)> callback)
|
||||||
|
{
|
||||||
|
using namespace std::placeholders;
|
||||||
|
|
||||||
|
LOG(debug) << "PMIxCommands: Subscribing...";
|
||||||
|
|
||||||
|
fCallback = callback;
|
||||||
|
std::array<pmix::status, 1> codes;
|
||||||
|
codes[0] = static_cast<int>(pmix::Command::general);
|
||||||
|
|
||||||
|
PMIX_INFO_LOAD(&(fInfos[0]), PMIX_EVENT_RETURN_OBJECT, this, PMIX_POINTER);
|
||||||
|
|
||||||
|
PMIx_Register_event_handler(codes.data(), codes.size(),
|
||||||
|
fInfos.data(), fInfos.size(),
|
||||||
|
&Commands::Handler,
|
||||||
|
&Commands::EventHandlerRegistration,
|
||||||
|
this);
|
||||||
|
fBlocker.Wait();
|
||||||
|
LOG(debug) << "PMIxCommands: Subscribing complete!";
|
||||||
|
}
|
||||||
|
|
||||||
|
void Unsubscribe()
|
||||||
|
{
|
||||||
|
if (fSubscribed) {
|
||||||
|
LOG(debug) << "PMIxCommands: Unsubscribing...";
|
||||||
|
PMIx_Deregister_event_handler(fHandlerRef, &Commands::EventHandlerDeregistration, this);
|
||||||
|
fBlocker.Wait();
|
||||||
|
LOG(debug) << "PMIxCommands: Unsubscribing complete!";
|
||||||
|
} else {
|
||||||
|
LOG(debug) << "Unsubscribe() is called while no subscription is active";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Holder
|
||||||
|
{
|
||||||
|
Holder() : fData(nullptr) {}
|
||||||
|
~Holder() { PMIX_DATA_ARRAY_FREE(fData); }
|
||||||
|
|
||||||
|
std::vector<pmix::info> fInfos;
|
||||||
|
pmix_data_array_t* fData;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Send(const std::string& msg)
|
||||||
|
{
|
||||||
|
std::vector<pmix::info>* infos = new std::vector<pmix::info>();
|
||||||
|
infos->emplace_back("fairmq.cmd", msg);
|
||||||
|
PMIx_Notify_event(static_cast<int>(pmix::Command::general),
|
||||||
|
&fProcess,
|
||||||
|
PMIX_RANGE_NAMESPACE,
|
||||||
|
infos->data(), infos->size(),
|
||||||
|
&Commands::OpCompleteCallback<std::vector<pmix::info>>,
|
||||||
|
infos);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(const std::string& msg, rank rank)
|
||||||
|
{
|
||||||
|
pmix::proc destination(fProcess);
|
||||||
|
destination.rank = rank;
|
||||||
|
Send(msg, {destination});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Send(const std::string& msg, const std::vector<proc>& destination)
|
||||||
|
{
|
||||||
|
std::unique_ptr<Holder> holder = fair::mq::tools::make_unique<Holder>();
|
||||||
|
|
||||||
|
PMIX_DATA_ARRAY_CREATE(holder->fData, destination.size(), PMIX_PROC);
|
||||||
|
memcpy(holder->fData->array, destination.data(), destination.size() * sizeof(pmix_proc_t));
|
||||||
|
// LOG(warn) << "OLOG: " << msg << " > " << static_cast<pmix_proc_t*>(holder->fData->array)[0].nspace << ": " << static_cast<pmix_proc_t*>(holder->fData->array)[0].rank;
|
||||||
|
holder->fInfos.emplace_back(PMIX_EVENT_CUSTOM_RANGE, holder->fData);
|
||||||
|
// LOG(warn) << msg << " // packed range: " << static_cast<pmix_proc_t*>(static_cast<pmix_data_array_t*>(holder->fInfos.at(0).value.data.darray)->array)[0].nspace << "_" << static_cast<pmix_proc_t*>(static_cast<pmix_data_array_t*>(holder->fInfos.at(0).value.data.darray)->array)[0].rank;
|
||||||
|
// LOG(warn) << msg << " // packed range.type: " << pmix::typeNames.at(holder->fInfos.at(0).value.type);
|
||||||
|
// LOG(warn) << msg << " // packed range.array.type: " << pmix::typeNames.at(static_cast<pmix_data_array_t*>(holder->fInfos.at(0).value.data.darray)->type);
|
||||||
|
// LOG(warn) << msg << " // packed range.array.size: " << static_cast<pmix_data_array_t*>(holder->fInfos.at(0).value.data.darray)->size;
|
||||||
|
// LOG(warn) << holder->fInfos.size();
|
||||||
|
holder->fInfos.emplace_back("fairmq.cmd", msg);
|
||||||
|
// LOG(warn) << msg << " // packed msg: " << holder->fInfos.at(1).value.data.string;
|
||||||
|
// LOG(warn) << msg << " // packed msg.type: " << pmix::typeNames.at(holder->fInfos.at(1).value.type);
|
||||||
|
// LOG(warn) << holder->fInfos.size();
|
||||||
|
|
||||||
|
PMIx_Notify_event(static_cast<int>(pmix::Command::general),
|
||||||
|
&fProcess,
|
||||||
|
PMIX_RANGE_CUSTOM,
|
||||||
|
holder->fInfos.data(), holder->fInfos.size(),
|
||||||
|
&Commands::OpCompleteCallback<Holder>,
|
||||||
|
holder.get());
|
||||||
|
holder.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static void EventHandlerRegistration(pmix_status_t s, size_t handlerRef, void* obj)
|
||||||
|
{
|
||||||
|
if (s == PMIX_SUCCESS) {
|
||||||
|
LOG(debug) << "Successfully registered event handler, reference = " << static_cast<unsigned long>(handlerRef);
|
||||||
|
static_cast<Commands*>(obj)->fHandlerRef = handlerRef;
|
||||||
|
static_cast<Commands*>(obj)->fSubscribed = true;
|
||||||
|
} else {
|
||||||
|
LOG(error) << "Could not register PMIx event handler, status = " << s;
|
||||||
|
}
|
||||||
|
static_cast<Commands*>(obj)->fBlocker.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void EventHandlerDeregistration(pmix_status_t s, void* obj)
|
||||||
|
{
|
||||||
|
if (s == PMIX_SUCCESS) {
|
||||||
|
LOG(debug) << "Successfully deregistered event handler, reference = " << static_cast<Commands*>(obj)->fHandlerRef;
|
||||||
|
static_cast<Commands*>(obj)->fSubscribed = false;
|
||||||
|
} else {
|
||||||
|
LOG(error) << "Could not deregister PMIx event handler, reference = " << static_cast<Commands*>(obj)->fHandlerRef << ", status = " << s;
|
||||||
|
}
|
||||||
|
static_cast<Commands*>(obj)->fBlocker.Signal();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
static void OpCompleteCallback(pmix_status_t s, void* data)
|
||||||
|
{
|
||||||
|
if (s == PMIX_SUCCESS) {
|
||||||
|
// LOG(info) << "Operation completed successfully";
|
||||||
|
} else {
|
||||||
|
LOG(error) << "Could not complete operation, status = " << s;
|
||||||
|
}
|
||||||
|
if (data) {
|
||||||
|
// LOG(warn) << "Destroying event data...";
|
||||||
|
delete static_cast<T*>(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Handler(size_t handlerId,
|
||||||
|
pmix_status_t s,
|
||||||
|
const pmix_proc_t* src,
|
||||||
|
pmix_info_t info[], size_t ninfo,
|
||||||
|
pmix_info_t[] /* results */, size_t nresults,
|
||||||
|
pmix_event_notification_cbfunc_fn_t cbfunc,
|
||||||
|
void* cbdata)
|
||||||
|
{
|
||||||
|
std::stringstream ss;
|
||||||
|
ss << "Event handler called with "
|
||||||
|
<< "status: " << s << ", "
|
||||||
|
<< "source: " << src->nspace << "_" << src->rank << ", "
|
||||||
|
<< "ninfo: " << ninfo << ", "
|
||||||
|
<< "nresults: " << nresults << ", "
|
||||||
|
<< "handlerId: " << handlerId;
|
||||||
|
|
||||||
|
std::string msg;
|
||||||
|
|
||||||
|
Commands* obj = nullptr;
|
||||||
|
|
||||||
|
if (ninfo > 0) {
|
||||||
|
ss << ":\n";
|
||||||
|
for (size_t i = 0; i < ninfo; ++i) {
|
||||||
|
ss << " [" << i << "]: key: '" << info[i].key
|
||||||
|
<< "', value: '" << pmix::get_value_str(info[i].value)
|
||||||
|
<< "', value.type: '" << pmix::typeNames.at(info[i].value.type)
|
||||||
|
<< "', flags: " << info[i].flags;
|
||||||
|
|
||||||
|
if (std::strcmp(info[i].key, "fairmq.cmd") == 0) {
|
||||||
|
msg = pmix::get_value_str(info[i].value);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::strcmp(info[i].key, PMIX_EVENT_RETURN_OBJECT) == 0) {
|
||||||
|
obj = static_cast<Commands*>(info[i].value.data.ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (i < ninfo - 1) {
|
||||||
|
ss << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (obj != nullptr) {
|
||||||
|
if (static_cast<Commands*>(obj)->fProcess.rank != src->rank) {
|
||||||
|
// LOG(warn) << ss.str();
|
||||||
|
static_cast<Commands*>(obj)->fCallback(msg, proc(const_cast<char*>(src->nspace), rank(src->rank)));
|
||||||
|
} else {
|
||||||
|
// LOG(trace) << "suppressing message from itself";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
LOG(ERROR) << "ERROR";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbfunc != nullptr) {
|
||||||
|
cbfunc(PMIX_SUCCESS, nullptr, 0, nullptr, nullptr, cbdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const proc& fProcess;
|
||||||
|
size_t fHandlerRef;
|
||||||
|
std::function<void(const std::string& msg, const proc& sender)> fCallback;
|
||||||
|
std::array<pmix_info_t, 1> fInfos;
|
||||||
|
bool fSubscribed;
|
||||||
|
fair::mq::tools::SharedSemaphore fBlocker;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* namespace pmix */
|
||||||
|
|
||||||
|
#endif /* PMIXCOMMANDS_H */
|
@@ -8,8 +8,15 @@
|
|||||||
|
|
||||||
#include "PMIxPlugin.h"
|
#include "PMIxPlugin.h"
|
||||||
|
|
||||||
|
#include <fairmq/sdk/commands/Commands.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
|
|
||||||
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <cstdint> // UINT32_MAX
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace fair::mq::sdk::cmd;
|
||||||
|
|
||||||
namespace fair
|
namespace fair
|
||||||
{
|
{
|
||||||
@@ -18,47 +25,99 @@ namespace mq
|
|||||||
namespace plugins
|
namespace plugins
|
||||||
{
|
{
|
||||||
|
|
||||||
PMIxPlugin::PMIxPlugin(const std::string& name,
|
PMIxPlugin::PMIxPlugin(const string& name,
|
||||||
const Plugin::Version version,
|
const Plugin::Version version,
|
||||||
const std::string& maintainer,
|
const string& maintainer,
|
||||||
const std::string& homepage,
|
const string& homepage,
|
||||||
PluginServices* pluginServices)
|
PluginServices* pluginServices)
|
||||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||||
|
, fProcess(Init())
|
||||||
, fPid(getpid())
|
, fPid(getpid())
|
||||||
|
, fPMIxClient(tools::ToString("PMIx client(pid=", fPid, ") "))
|
||||||
|
, fDeviceId(string(fProcess.nspace) + "_" + to_string(fProcess.rank))
|
||||||
|
, fCommands(fProcess)
|
||||||
|
, fLastExternalController(UINT32_MAX)
|
||||||
|
, fExitingAckedByLastExternalController(false)
|
||||||
|
, fCurrentState(DeviceState::Idle)
|
||||||
|
, fLastState(DeviceState::Idle)
|
||||||
{
|
{
|
||||||
Init();
|
TakeDeviceControl();
|
||||||
SetProperty<std::string>("id", std::string(fProc.nspace) + "_" + std::to_string(fProc.rank));
|
LOG(debug) << PMIxClient() << "pmix::init() OK: " << fProcess << ", version=" << pmix::get_version();
|
||||||
Fence();
|
SetProperty<string>("id", fDeviceId);
|
||||||
|
|
||||||
SubscribeToDeviceStateChange([&](DeviceState newState) {
|
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;
|
||||||
|
|
||||||
|
// job level infos
|
||||||
|
// LOG(info) << "PMIX_SESSION_ID: " << pmix::getInfo(PMIX_SESSION_ID, fProcess);
|
||||||
|
// LOG(info) << "PMIX_UNIV_SIZE: " << pmix::getInfo(PMIX_UNIV_SIZE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_JOB_SIZE: " << pmix::getInfo(PMIX_JOB_SIZE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_JOB_NUM_APPS: " << pmix::getInfo(PMIX_JOB_NUM_APPS, fProcess);
|
||||||
|
// LOG(info) << "PMIX_APP_SIZE: " << pmix::getInfo(PMIX_APP_SIZE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_MAX_PROCS: " << pmix::getInfo(PMIX_MAX_PROCS, fProcess);
|
||||||
|
// LOG(info) << "PMIX_NUM_NODES: " << pmix::getInfo(PMIX_NUM_NODES, fProcess);
|
||||||
|
// LOG(info) << "PMIX_CLUSTER_ID: " << pmix::getInfo(PMIX_CLUSTER_ID, fProcess);
|
||||||
|
// LOG(info) << "PMIX_NSPACE: " << pmix::getInfo(PMIX_NSPACE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_JOBID: " << pmix::getInfo(PMIX_JOBID, fProcess);
|
||||||
|
// LOG(info) << "PMIX_NODE_LIST: " << pmix::getInfo(PMIX_NODE_LIST, fProcess);
|
||||||
|
// LOG(info) << "PMIX_ALLOCATED_NODELIST: " << pmix::getInfo(PMIX_ALLOCATED_NODELIST, fProcess);
|
||||||
|
// LOG(info) << "PMIX_NPROC_OFFSET: " << pmix::getInfo(PMIX_NPROC_OFFSET, fProcess);
|
||||||
|
// LOG(info) << "PMIX_LOCALLDR: " << pmix::getInfo(PMIX_LOCALLDR, fProcess);
|
||||||
|
// LOG(info) << "PMIX_APPLDR: " << pmix::getInfo(PMIX_APPLDR, fProcess);
|
||||||
|
|
||||||
|
// // per-node information
|
||||||
|
// LOG(info) << "PMIX_NODE_SIZE: " << pmix::getInfo(PMIX_NODE_SIZE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_LOCAL_SIZE: " << pmix::getInfo(PMIX_LOCAL_SIZE, fProcess);
|
||||||
|
// LOG(info) << "PMIX_AVAIL_PHYS_MEMORY: " << pmix::getInfo(PMIX_AVAIL_PHYS_MEMORY, fProcess);
|
||||||
|
|
||||||
|
// // per-process information
|
||||||
|
// LOG(info) << "PMIX_PROCID: " << pmix::getInfo(PMIX_PROCID, fProcess);
|
||||||
|
// LOG(info) << "PMIX_APPNUM: " << pmix::getInfo(PMIX_APPNUM, fProcess);
|
||||||
|
// LOG(info) << "PMIX_LOCAL_RANK: " << pmix::getInfo(PMIX_LOCAL_RANK, fProcess);
|
||||||
|
// LOG(info) << "PMIX_NODE_RANK: " << pmix::getInfo(PMIX_NODE_RANK, fProcess);
|
||||||
|
// LOG(info) << "PMIX_RANK: " << pmix::getInfo(PMIX_RANK, fProcess);
|
||||||
|
// LOG(info) << "PMIX_GLOBAL_RANK: " << pmix::getInfo(PMIX_GLOBAL_RANK, fProcess);
|
||||||
|
// LOG(info) << "PMIX_APP_RANK: " << pmix::getInfo(PMIX_APP_RANK, fProcess);
|
||||||
|
|
||||||
|
SubscribeToDeviceStateChange([this](DeviceState newState) {
|
||||||
switch (newState) {
|
switch (newState) {
|
||||||
case DeviceState::Idle:
|
case DeviceState::Bound:
|
||||||
Fence();
|
Publish();
|
||||||
break;
|
break;
|
||||||
case DeviceState::Bound:
|
case DeviceState::Connecting:
|
||||||
Publish();
|
Lookup();
|
||||||
Fence();
|
break;
|
||||||
break;
|
case DeviceState::Exiting:
|
||||||
case DeviceState::Connecting:
|
ReleaseDeviceControl();
|
||||||
Lookup();
|
UnsubscribeFromDeviceStateChange();
|
||||||
break;
|
break;
|
||||||
case DeviceState::DeviceReady:
|
default:
|
||||||
Fence();
|
break;
|
||||||
break;
|
}
|
||||||
case DeviceState::Ready:
|
|
||||||
Fence();
|
lock_guard<mutex> lock{fStateChangeSubscriberMutex};
|
||||||
break;
|
fLastState = fCurrentState;
|
||||||
case DeviceState::Exiting:
|
fCurrentState = newState;
|
||||||
UnsubscribeFromDeviceStateChange();
|
for (auto subscriberId : fStateChangeSubscribers) {
|
||||||
break;
|
LOG(debug) << "Publishing state-change: " << fLastState << "->" << newState << " to " << subscriberId;
|
||||||
default:
|
Cmds cmds(make<StateChange>(fDeviceId, 0, fLastState, fCurrentState));
|
||||||
break;
|
fCommands.Send(cmds.Serialize(Format::JSON), static_cast<pmix::rank>(subscriberId));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
PMIxPlugin::~PMIxPlugin()
|
PMIxPlugin::~PMIxPlugin()
|
||||||
{
|
{
|
||||||
|
LOG(debug) << "Destroying PMIxPlugin";
|
||||||
|
ReleaseDeviceControl();
|
||||||
|
fCommands.Unsubscribe();
|
||||||
while (pmix::initialized()) {
|
while (pmix::initialized()) {
|
||||||
try {
|
try {
|
||||||
pmix::finalize();
|
pmix::finalize();
|
||||||
@@ -69,33 +128,112 @@ PMIxPlugin::~PMIxPlugin()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PMIxPlugin::PMIxClient() const -> std::string
|
auto PMIxPlugin::SubscribeForCommands() -> void
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
fCommands.Subscribe([this](const string& cmdStr, const pmix::proc& sender) {
|
||||||
ss << "PMIx client(pid=" << fPid << ") ";
|
// LOG(info) << "PMIx Plugin received message: '" << cmdStr << "', from " << sender;
|
||||||
return ss.str();
|
|
||||||
|
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))
|
||||||
|
.Serialize(Format::JSON),
|
||||||
|
{sender});
|
||||||
|
} else {
|
||||||
|
fCommands.Send(
|
||||||
|
Cmds(make<TransitionStatus>(fDeviceId, 0, Result::Failure, transition))
|
||||||
|
.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() -> void
|
auto PMIxPlugin::Init() -> pmix::proc
|
||||||
{
|
{
|
||||||
if (!pmix::initialized()) {
|
if (!pmix::initialized()) {
|
||||||
fProc = pmix::init();
|
return pmix::init();
|
||||||
LOG(debug) << PMIxClient() << "pmix::init() OK: " << fProc
|
} else {
|
||||||
<< ",version=" << pmix::get_version();
|
throw runtime_error("trying to initialize PMIx while it is already initialized");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PMIxPlugin::Publish() -> void
|
auto PMIxPlugin::Publish() -> void
|
||||||
{
|
{
|
||||||
auto channels(GetChannelInfo());
|
auto channels(GetChannelInfo());
|
||||||
std::vector<pmix::info> info;
|
vector<pmix::info> info;
|
||||||
|
|
||||||
for (const auto& c : channels) {
|
for (const auto& c : channels) {
|
||||||
std::string methodKey{"chans." + c.first + "." + std::to_string(c.second - 1) + ".method"};
|
string methodKey("chans." + c.first + "." + to_string(c.second - 1) + ".method");
|
||||||
if (GetProperty<std::string>(methodKey) == "bind") {
|
if (GetProperty<string>(methodKey) == "bind") {
|
||||||
for (int i = 0; i < c.second; ++i) {
|
for (int i = 0; i < c.second; ++i) {
|
||||||
std::string addressKey{"chans." + c.first + "." + std::to_string(i) + ".address"};
|
string addressKey("chans." + c.first + "." + to_string(i) + ".address");
|
||||||
info.emplace_back(addressKey, GetProperty<std::string>(addressKey));
|
info.emplace_back(addressKey, GetProperty<string>(addressKey));
|
||||||
LOG(debug) << PMIxClient() << info.back();
|
LOG(debug) << PMIxClient() << info.back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,32 +241,37 @@ auto PMIxPlugin::Publish() -> void
|
|||||||
|
|
||||||
if (info.size() > 0) {
|
if (info.size() > 0) {
|
||||||
pmix::publish(info);
|
pmix::publish(info);
|
||||||
LOG(debug) << PMIxClient() << "pmix::publish() OK: published "
|
LOG(debug) << PMIxClient() << "pmix::publish() OK: published " << info.size()
|
||||||
<< info.size() << " binding channels.";
|
<< " binding channels.";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PMIxPlugin::Fence() -> void
|
auto PMIxPlugin::Fence() -> void
|
||||||
{
|
{
|
||||||
pmix::proc all(fProc);
|
pmix::proc all(fProcess);
|
||||||
all.rank = pmix::rank::wildcard;
|
all.rank = pmix::rank::wildcard;
|
||||||
|
|
||||||
pmix::fence({all});
|
pmix::fence({all});
|
||||||
LOG(debug) << PMIxClient() << "pmix::fence() OK";
|
}
|
||||||
|
|
||||||
|
auto PMIxPlugin::Fence(const std::string& label) -> void
|
||||||
|
{
|
||||||
|
Fence(label);
|
||||||
|
LOG(debug) << PMIxClient() << "pmix::fence() [" << label << "] OK";
|
||||||
}
|
}
|
||||||
|
|
||||||
auto PMIxPlugin::Lookup() -> void
|
auto PMIxPlugin::Lookup() -> void
|
||||||
{
|
{
|
||||||
auto channels(GetChannelInfo());
|
auto channels(GetChannelInfo());
|
||||||
for (const auto& c : channels) {
|
for (const auto& c : channels) {
|
||||||
std::string methodKey{"chans." + c.first + "." + std::to_string(c.second - 1) + ".method"};
|
string methodKey("chans." + c.first + "." + to_string(c.second - 1) + ".method");
|
||||||
if (GetProperty<std::string>(methodKey) == "connect") {
|
if (GetProperty<string>(methodKey) == "connect") {
|
||||||
for (int i = 0; i < c.second; ++i) {
|
for (int i = 0; i < c.second; ++i) {
|
||||||
std::vector<pmix::pdata> pdata;
|
vector<pmix::pdata> pdata;
|
||||||
std::string addressKey{"chans." + c.first + "." + std::to_string(i) + ".address"};
|
string addressKey("chans." + c.first + "." + to_string(i) + ".address");
|
||||||
pdata.emplace_back();
|
pdata.emplace_back();
|
||||||
pdata.back().set_key(addressKey);
|
pdata.back().set_key(addressKey);
|
||||||
std::vector<pmix::info> info;
|
vector<pmix::info> info;
|
||||||
info.emplace_back(PMIX_WAIT, static_cast<int>(pdata.size()));
|
info.emplace_back(PMIX_WAIT, static_cast<int>(pdata.size()));
|
||||||
|
|
||||||
if (pdata.size() > 0) {
|
if (pdata.size() > 0) {
|
||||||
@@ -141,11 +284,11 @@ auto PMIxPlugin::Lookup() -> void
|
|||||||
LOG(debug) << PMIxClient() << "pmix::lookup() not found: key=" << p.key;
|
LOG(debug) << PMIxClient() << "pmix::lookup() not found: key=" << p.key;
|
||||||
} else if (p.value.type == PMIX_STRING) {
|
} else if (p.value.type == PMIX_STRING) {
|
||||||
LOG(debug) << PMIxClient() << "pmix::lookup() found:"
|
LOG(debug) << PMIxClient() << "pmix::lookup() found:"
|
||||||
<< " key=" << p.key << ",value=" << p.value.data.string;
|
<< " key=" << p.key << ",value=" << p.value.data.string;
|
||||||
SetProperty<std::string>(p.key, p.value.data.string);
|
SetProperty<string>(p.key, p.value.data.string);
|
||||||
} else {
|
} else {
|
||||||
LOG(debug) << PMIxClient() << "pmix::lookup() wrong type returned: "
|
LOG(debug) << PMIxClient() << "pmix::lookup() wrong type returned: "
|
||||||
<< "key=" << p.key << ",type=" << p.value.type;
|
<< "key=" << p.key << ",type=" << p.value.type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -153,6 +296,14 @@ auto PMIxPlugin::Lookup() -> void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto PMIxPlugin::WaitForExitingAck() -> void
|
||||||
|
{
|
||||||
|
unique_lock<mutex> lock(fStateChangeSubscriberMutex);
|
||||||
|
fExitingAcked.wait_for(lock, chrono::milliseconds(1000), [this]() {
|
||||||
|
return fExitingAckedByLastExternalController;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace plugins */
|
} /* namespace plugins */
|
||||||
} /* namespace mq */
|
} /* namespace mq */
|
||||||
} /* namespace fair */
|
} /* namespace fair */
|
||||||
|
@@ -10,6 +10,7 @@
|
|||||||
#define FAIR_MQ_PLUGINS_PMIX
|
#define FAIR_MQ_PLUGINS_PMIX
|
||||||
|
|
||||||
#include "PMIx.hpp"
|
#include "PMIx.hpp"
|
||||||
|
#include "PMIxCommands.h"
|
||||||
|
|
||||||
#include <fairmq/Plugin.h>
|
#include <fairmq/Plugin.h>
|
||||||
#include <fairmq/Version.h>
|
#include <fairmq/Version.h>
|
||||||
@@ -39,23 +40,40 @@ class PMIxPlugin : public Plugin
|
|||||||
const std::string& homepage,
|
const std::string& homepage,
|
||||||
PluginServices* pluginServices);
|
PluginServices* pluginServices);
|
||||||
~PMIxPlugin();
|
~PMIxPlugin();
|
||||||
auto PMIxClient() const -> std::string;
|
|
||||||
|
auto PMIxClient() const -> std::string { return fPMIxClient; };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pmix::proc fProc;
|
pmix::proc fProcess;
|
||||||
pid_t fPid;
|
pid_t fPid;
|
||||||
|
std::string fPMIxClient;
|
||||||
|
std::string fDeviceId;
|
||||||
|
pmix::Commands fCommands;
|
||||||
|
|
||||||
auto Init() -> void;
|
std::set<uint32_t> fStateChangeSubscribers;
|
||||||
|
uint32_t fLastExternalController;
|
||||||
|
bool fExitingAckedByLastExternalController;
|
||||||
|
std::condition_variable fExitingAcked;
|
||||||
|
std::mutex fStateChangeSubscriberMutex;
|
||||||
|
|
||||||
|
DeviceState fCurrentState;
|
||||||
|
DeviceState fLastState;
|
||||||
|
|
||||||
|
auto Init() -> pmix::proc;
|
||||||
auto Publish() -> void;
|
auto Publish() -> void;
|
||||||
auto Fence() -> void;
|
auto Fence() -> void;
|
||||||
|
auto Fence(const std::string& label) -> void;
|
||||||
auto Lookup() -> void;
|
auto Lookup() -> void;
|
||||||
|
|
||||||
|
auto SubscribeForCommands() -> void;
|
||||||
|
auto WaitForExitingAck() -> void;
|
||||||
};
|
};
|
||||||
|
|
||||||
Plugin::ProgOptions PMIxProgramOptions()
|
Plugin::ProgOptions PMIxProgramOptions()
|
||||||
{
|
{
|
||||||
boost::program_options::options_description options{"PMIx Plugin"};
|
boost::program_options::options_description options("PMIx Plugin");
|
||||||
options.add_options()(
|
options.add_options()
|
||||||
"pmix-dummy", boost::program_options::value<int>()->default_value(0), "Dummy.");
|
("pmix-dummy", boost::program_options::value<int>()->default_value(0), "Dummy.");
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
218
fairmq/plugins/PMIx/runPMIxCommandUI.cxx
Normal file
218
fairmq/plugins/PMIx/runPMIxCommandUI.cxx
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "PMIx.hpp"
|
||||||
|
#include "PMIxCommands.h"
|
||||||
|
|
||||||
|
#include <boost/program_options.hpp>
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <iostream>
|
||||||
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
#include <termios.h> // raw mode console input
|
||||||
|
#include <thread>
|
||||||
|
#include <utility>
|
||||||
|
#include <unistd.h>
|
||||||
|
#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 =
|
||||||
|
{
|
||||||
|
{ fair::mq::Transition::InitDevice, fair::mq::State::InitializingDevice },
|
||||||
|
{ fair::mq::Transition::CompleteInit, fair::mq::State::Initialized },
|
||||||
|
{ fair::mq::Transition::Bind, fair::mq::State::Bound },
|
||||||
|
{ fair::mq::Transition::Connect, fair::mq::State::DeviceReady },
|
||||||
|
{ fair::mq::Transition::InitTask, fair::mq::State::Ready },
|
||||||
|
{ fair::mq::Transition::Run, fair::mq::State::Running },
|
||||||
|
{ fair::mq::Transition::Stop, fair::mq::State::Ready },
|
||||||
|
{ fair::mq::Transition::ResetTask, fair::mq::State::DeviceReady },
|
||||||
|
{ fair::mq::Transition::ResetDevice, fair::mq::State::Idle },
|
||||||
|
{ 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)
|
||||||
|
: fState(n, fair::mq::State::Ok)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void WaitFor(const fair::mq::State state)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lk(fMtx);
|
||||||
|
|
||||||
|
fCV.wait(lk, [&](){
|
||||||
|
unsigned int count = std::count_if(fState.cbegin(), fState.cend(), [=](const auto& s) {
|
||||||
|
return s == state;
|
||||||
|
});
|
||||||
|
|
||||||
|
bool result = count == fState.size();
|
||||||
|
cout << "expecting " << state << " for " << fState.size() << " devices, found " << count << ", condition: " << result << endl;
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Update(uint32_t rank, const fair::mq::State state)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lk(fMtx);
|
||||||
|
fState.at(rank - 1) = state;
|
||||||
|
}
|
||||||
|
fCV.notify_one();
|
||||||
|
} catch (const std::exception& e) {
|
||||||
|
LOG(error) << "Exception in Update: " << e.what();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
vector<fair::mq::State> fState;
|
||||||
|
std::mutex fMtx;
|
||||||
|
std::condition_variable fCV;
|
||||||
|
};
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
unsigned int numDevices;
|
||||||
|
|
||||||
|
bpo::options_description options("Common options");
|
||||||
|
options.add_options()
|
||||||
|
("number-devices,n", bpo::value<unsigned int>(&numDevices)->default_value(0), "Number of devices (will be removed in the future)")
|
||||||
|
("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" << endl;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
bpo::notify(vm);
|
||||||
|
|
||||||
|
fair::Logger::SetConsoleSeverity(fair::Severity::debug);
|
||||||
|
fair::Logger::SetConsoleColor(true);
|
||||||
|
fair::Logger::SetVerbosity(fair::Verbosity::low);
|
||||||
|
|
||||||
|
pmix::proc process;
|
||||||
|
|
||||||
|
if (!pmix::initialized()) {
|
||||||
|
process = pmix::init();
|
||||||
|
LOG(warn) << "pmix::init() OK: " << process << ", version=" << pmix::get_version();
|
||||||
|
}
|
||||||
|
|
||||||
|
pmix::proc all(process);
|
||||||
|
all.rank = pmix::rank::wildcard;
|
||||||
|
pmix::fence({all});
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
LOG(warn) << "exiting";
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
@@ -6,6 +6,8 @@ maxIterations="0"
|
|||||||
msgSize="1000000"
|
msgSize="1000000"
|
||||||
transport="zeromq"
|
transport="zeromq"
|
||||||
affinity="false"
|
affinity="false"
|
||||||
|
multipart="false"
|
||||||
|
numParts="1"
|
||||||
affinitySamp=""
|
affinitySamp=""
|
||||||
affinitySink=""
|
affinitySink=""
|
||||||
|
|
||||||
@@ -26,6 +28,14 @@ if [[ $4 =~ ^[a-z]+$ ]]; then
|
|||||||
affinity=$4
|
affinity=$4
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [[ $5 =~ ^[a-z]+$ ]]; then
|
||||||
|
multipart=$5
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $6 =~ ^[0-9]+$ ]]; then
|
||||||
|
numParts=$6
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
echo "Starting benchmark with following settings:"
|
echo "Starting benchmark with following settings:"
|
||||||
|
|
||||||
@@ -58,7 +68,8 @@ SAMPLER+=" --id bsampler1"
|
|||||||
SAMPLER+=" --transport $transport"
|
SAMPLER+=" --transport $transport"
|
||||||
SAMPLER+=" --severity debug"
|
SAMPLER+=" --severity debug"
|
||||||
SAMPLER+=" --msg-size $msgSize"
|
SAMPLER+=" --msg-size $msgSize"
|
||||||
SAMPLER+=" --num-parts 1"
|
SAMPLER+=" --multipart $multipart"
|
||||||
|
SAMPLER+=" --num-parts $numParts"
|
||||||
# SAMPLER+=" --msg-rate 1000"
|
# SAMPLER+=" --msg-rate 1000"
|
||||||
SAMPLER+=" --max-iterations $maxIterations"
|
SAMPLER+=" --max-iterations $maxIterations"
|
||||||
SAMPLER+=" --channel-config name=data,type=pair,method=bind,address=tcp://127.0.0.1:5555"
|
SAMPLER+=" --channel-config name=data,type=pair,method=bind,address=tcp://127.0.0.1:5555"
|
||||||
@@ -73,7 +84,7 @@ SINK+=" --id sink1"
|
|||||||
#SINK+=" --control static"
|
#SINK+=" --control static"
|
||||||
SINK+=" --transport $transport"
|
SINK+=" --transport $transport"
|
||||||
SINK+=" --severity debug"
|
SINK+=" --severity debug"
|
||||||
SINK+=" --multipart false"
|
SINK+=" --multipart $multipart"
|
||||||
SINK+=" --max-iterations $maxIterations"
|
SINK+=" --max-iterations $maxIterations"
|
||||||
SINK+=" --channel-config name=data,type=pair,method=connect,address=tcp://127.0.0.1:5555"
|
SINK+=" --channel-config name=data,type=pair,method=connect,address=tcp://127.0.0.1:5555"
|
||||||
xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK &
|
xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK &
|
||||||
|
@@ -15,7 +15,6 @@
|
|||||||
#include <asio/system_executor.hpp>
|
#include <asio/system_executor.hpp>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
#include <fairmq/sdk/Error.h>
|
#include <fairmq/sdk/Error.h>
|
||||||
#include <fairmq/sdk/Traits.h>
|
#include <fairmq/sdk/Traits.h>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -24,6 +23,11 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <fairlogger/Logger.h>
|
||||||
|
#ifndef FAIR_LOG
|
||||||
|
#define FAIR_LOG LOG
|
||||||
|
#endif /* ifndef FAIR_LOG */
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
namespace sdk {
|
namespace sdk {
|
||||||
@@ -49,7 +53,7 @@ struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
|||||||
using Executor2 = typename asio::associated_executor<Handler, Executor1>::type;
|
using Executor2 = typename asio::associated_executor<Handler, Executor1>::type;
|
||||||
|
|
||||||
/// Ctor
|
/// Ctor
|
||||||
AsioAsyncOpImpl(const Executor1& ex1, Allocator1&& alloc1, Handler&& handler)
|
AsioAsyncOpImpl(const Executor1& ex1, Allocator1 alloc1, Handler&& handler)
|
||||||
: fWork1(ex1)
|
: fWork1(ex1)
|
||||||
, fWork2(asio::get_associated_executor(handler, ex1))
|
, fWork2(asio::get_associated_executor(handler, ex1))
|
||||||
, fHandler(std::move(handler))
|
, fHandler(std::move(handler))
|
||||||
@@ -70,9 +74,9 @@ struct AsioAsyncOpImpl : AsioAsyncOpImplBase<SignatureArgTypes...>
|
|||||||
try {
|
try {
|
||||||
handler(ec, args...);
|
handler(ec, args...);
|
||||||
} catch (const std::exception& e) {
|
} catch (const std::exception& e) {
|
||||||
LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
FAIR_LOG(error) << "Uncaught exception in AsioAsyncOp completion handler: " << e.what();
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
FAIR_LOG(error) << "Unknown uncaught exception in AsioAsyncOp completion handler.";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GetAlloc2());
|
GetAlloc2());
|
||||||
@@ -149,7 +153,7 @@ struct AsioAsyncOp<Executor,
|
|||||||
|
|
||||||
/// Ctor with handler
|
/// Ctor with handler
|
||||||
template<typename Handler>
|
template<typename Handler>
|
||||||
AsioAsyncOp(Executor&& ex1, Allocator&& alloc1, Handler&& handler)
|
AsioAsyncOp(Executor ex1, Allocator alloc1, Handler&& handler)
|
||||||
: AsioAsyncOp()
|
: AsioAsyncOp()
|
||||||
{
|
{
|
||||||
// Async operation type to be allocated and constructed
|
// Async operation type to be allocated and constructed
|
||||||
@@ -165,8 +169,8 @@ struct AsioAsyncOp<Executor,
|
|||||||
auto mem(std::allocator_traits<OpAllocator>::allocate(opAlloc, 1));
|
auto mem(std::allocator_traits<OpAllocator>::allocate(opAlloc, 1));
|
||||||
|
|
||||||
// Construct object
|
// Construct object
|
||||||
auto ptr(new (mem) Op(std::forward<Executor>(ex1),
|
auto ptr(new (mem) Op(std::move(ex1),
|
||||||
std::forward<Allocator>(alloc1),
|
std::move(alloc1),
|
||||||
std::forward<Handler>(handler)));
|
std::forward<Handler>(handler)));
|
||||||
|
|
||||||
// Assign ownership to this object
|
// Assign ownership to this object
|
||||||
@@ -177,8 +181,8 @@ struct AsioAsyncOp<Executor,
|
|||||||
|
|
||||||
/// Ctor with handler #2
|
/// Ctor with handler #2
|
||||||
template<typename Handler>
|
template<typename Handler>
|
||||||
AsioAsyncOp(Executor&& ex1, Handler&& handler)
|
AsioAsyncOp(Executor ex1, Handler&& handler)
|
||||||
: AsioAsyncOp(std::forward<Executor>(ex1), Allocator(), std::forward<Handler>(handler))
|
: AsioAsyncOp(std::move(ex1), Allocator(), std::forward<Handler>(handler))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
/// Ctor with handler #3
|
/// Ctor with handler #3
|
||||||
|
@@ -33,32 +33,24 @@ class DDSAgent
|
|||||||
explicit DDSAgent(DDSSession session,
|
explicit DDSAgent(DDSSession session,
|
||||||
Id id,
|
Id id,
|
||||||
Pid pid,
|
Pid pid,
|
||||||
std::string state,
|
|
||||||
std::string path,
|
std::string path,
|
||||||
std::string host,
|
std::string host,
|
||||||
bool lobbyLeader,
|
|
||||||
std::chrono::milliseconds startupTime,
|
std::chrono::milliseconds startupTime,
|
||||||
Id taskId,
|
|
||||||
std::string username)
|
std::string username)
|
||||||
: fSession(std::move(session))
|
: fSession(std::move(session))
|
||||||
, fId(id)
|
, fId(id)
|
||||||
, fPid(pid)
|
, fPid(pid)
|
||||||
, fState(std::move(state))
|
|
||||||
, fDDSPath(std::move(path))
|
, fDDSPath(std::move(path))
|
||||||
, fHost(std::move(host))
|
, fHost(std::move(host))
|
||||||
, fLobbyLeader(lobbyLeader)
|
|
||||||
, fStartupTime(startupTime)
|
, fStartupTime(startupTime)
|
||||||
, fTaskId(taskId)
|
|
||||||
, fUsername(std::move(username))
|
, fUsername(std::move(username))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
DDSSession GetSession() const { return fSession; }
|
DDSSession GetSession() const { return fSession; }
|
||||||
Id GetId() const { return fId; }
|
Id GetId() const { return fId; }
|
||||||
Pid GetPid() const { return fPid; }
|
Pid GetPid() const { return fPid; }
|
||||||
std::string GetState() const { return fState; }
|
|
||||||
std::string GetHost() const { return fHost; }
|
std::string GetHost() const { return fHost; }
|
||||||
std::string GetDDSPath() const { return fDDSPath; }
|
std::string GetDDSPath() const { return fDDSPath; }
|
||||||
bool IsLobbyLeader() const { return fLobbyLeader; }
|
|
||||||
std::chrono::milliseconds GetStartupTime() const { return fStartupTime; }
|
std::chrono::milliseconds GetStartupTime() const { return fStartupTime; }
|
||||||
std::string GetUsername() const { return fUsername; }
|
std::string GetUsername() const { return fUsername; }
|
||||||
|
|
||||||
@@ -66,12 +58,9 @@ class DDSAgent
|
|||||||
{
|
{
|
||||||
return os << "DDSAgent id: " << agent.fId
|
return os << "DDSAgent id: " << agent.fId
|
||||||
<< ", pid: " << agent.fPid
|
<< ", pid: " << agent.fPid
|
||||||
<< ", state: " << agent.fState
|
|
||||||
<< ", path: " << agent.fDDSPath
|
<< ", path: " << agent.fDDSPath
|
||||||
<< ", host: " << agent.fHost
|
<< ", host: " << agent.fHost
|
||||||
<< ", lobbyLeader: " << agent.fLobbyLeader
|
|
||||||
<< ", startupTime: " << agent.fStartupTime.count()
|
<< ", startupTime: " << agent.fStartupTime.count()
|
||||||
<< ", taskId: " << agent.fTaskId
|
|
||||||
<< ", username: " << agent.fUsername;
|
<< ", username: " << agent.fUsername;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,12 +68,9 @@ class DDSAgent
|
|||||||
DDSSession fSession;
|
DDSSession fSession;
|
||||||
Id fId;
|
Id fId;
|
||||||
Pid fPid;
|
Pid fPid;
|
||||||
std::string fState;
|
|
||||||
std::string fDDSPath;
|
std::string fDDSPath;
|
||||||
std::string fHost;
|
std::string fHost;
|
||||||
bool fLobbyLeader;
|
|
||||||
std::chrono::milliseconds fStartupTime;
|
std::chrono::milliseconds fStartupTime;
|
||||||
Id fTaskId;
|
|
||||||
std::string fUsername;
|
std::string fUsername;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@@ -8,15 +8,11 @@
|
|||||||
|
|
||||||
#include "DDSEnvironment.h"
|
#include "DDSEnvironment.h"
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <dds/dds.h>
|
||||||
|
#include <fairlogger/Logger.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
#include <fairmq/sdk/DDSInfo.h>
|
#include <fairmq/sdk/DDSInfo.h>
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
|
||||||
|
|
||||||
#include <DDS/Tools.h>
|
|
||||||
#include <DDS/dds_intercom.h>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
@@ -59,12 +55,17 @@ struct DDSEnvironment::Impl
|
|||||||
setenv("HOME", fConfigHome.c_str(), 1);
|
setenv("HOME", fConfigHome.c_str(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::istringstream cmd;
|
std::stringstream cmd;
|
||||||
cmd.str("DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
#ifdef __APPLE__
|
||||||
"if [ -z \"$DDS_CFG\" ]; then\n"
|
// On macOS System Integrity Protection might filter out the DYLD_LIBRARY_PATH, so we pass it
|
||||||
" mkdir -p \"$HOME/.DDS\"\n"
|
// through explicitely here.
|
||||||
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
cmd << "export " << fgLdVar << "=" << GetEnv(fgLdVar) << "\n";
|
||||||
"fi");
|
#endif
|
||||||
|
cmd << "DDS_CFG=`dds-user-defaults --ignore-default-sid -p`\n"
|
||||||
|
"if [ -z \"$DDS_CFG\" ]; then\n"
|
||||||
|
" mkdir -p \"$HOME/.DDS\"\n"
|
||||||
|
" dds-user-defaults --ignore-default-sid -d -c \"$HOME/.DDS/DDS.cfg\"\n"
|
||||||
|
"fi\n";
|
||||||
std::system(cmd.str().c_str());
|
std::system(cmd.str().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,20 +77,23 @@ struct DDSEnvironment::Impl
|
|||||||
setenv("PATH", path.c_str(), 1);
|
setenv("PATH", path.c_str(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto SetupDynamicLoader() -> void
|
auto GenerateDDSLibDir() const -> Path
|
||||||
{
|
{
|
||||||
#ifdef __APPLE__
|
return {(fLocation == DDSInstallPrefix) ? DDSLibraryDir : fLocation / Path("lib")};
|
||||||
std::string ldVar("DYLD_LIBRARY_PATH");
|
|
||||||
#else
|
|
||||||
std::string ldVar("LD_LIBRARY_PATH");
|
|
||||||
#endif
|
|
||||||
std::string ld(GetEnv(ldVar));
|
|
||||||
Path ddsLibDir = (fLocation == DDSInstallPrefix) ? DDSLibraryDir : fLocation / Path("lib");
|
|
||||||
ld = ddsLibDir.string() + std::string(":") + ld;
|
|
||||||
setenv(ldVar.c_str(), ld.c_str(), 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto GetEnv(const std::string& key) -> std::string
|
auto SetupDynamicLoader() -> void
|
||||||
|
{
|
||||||
|
std::string ld(GetEnv(fgLdVar));
|
||||||
|
if (ld.empty()) {
|
||||||
|
ld = GenerateDDSLibDir().string();
|
||||||
|
} else {
|
||||||
|
ld = GenerateDDSLibDir().string() + std::string(":") + ld;
|
||||||
|
}
|
||||||
|
setenv(fgLdVar.c_str(), ld.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto GetEnv(const std::string& key) const -> std::string
|
||||||
{
|
{
|
||||||
auto value = std::getenv(key.c_str());
|
auto value = std::getenv(key.c_str());
|
||||||
if (value) {
|
if (value) {
|
||||||
@@ -104,6 +108,11 @@ struct DDSEnvironment::Impl
|
|||||||
|
|
||||||
Path fLocation;
|
Path fLocation;
|
||||||
Path fConfigHome;
|
Path fConfigHome;
|
||||||
|
#ifdef __APPLE__
|
||||||
|
std::string const fgLdVar = "DYLD_LIBRARY_PATH";
|
||||||
|
#else
|
||||||
|
std::string const fgLdVar = "LD_LIBRARY_PATH";
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
DDSEnvironment::DDSEnvironment()
|
DDSEnvironment::DDSEnvironment()
|
||||||
|
@@ -8,11 +8,11 @@
|
|||||||
|
|
||||||
#include "DDSSession.h"
|
#include "DDSSession.h"
|
||||||
|
|
||||||
#include <DDS/Tools.h>
|
|
||||||
#include <boost/process.hpp>
|
#include <boost/process.hpp>
|
||||||
#include <boost/uuid/uuid_io.hpp>
|
#include <boost/uuid/uuid_io.hpp>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <dds/dds.h>
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
#include <fairmq/sdk/DDSAgent.h>
|
#include <fairmq/sdk/DDSAgent.h>
|
||||||
@@ -135,8 +135,6 @@ struct DDSSession::Impl
|
|||||||
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
dds::intercom_api::CCustomCmd fDDSCustomCmd;
|
||||||
Id fId;
|
Id fId;
|
||||||
bool fStopOnDestruction;
|
bool fStopOnDestruction;
|
||||||
mutable std::mutex fMtx;
|
|
||||||
std::unordered_map<DDSChannel::Id, DDSTask::Id> fTaskIdByChannelIdMap;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
DDSSession::DDSSession(DDSEnvironment env)
|
DDSSession::DDSSession(DDSEnvironment env)
|
||||||
@@ -183,7 +181,8 @@ auto DDSSession::SubmitAgents(Quantity agents) -> void
|
|||||||
|
|
||||||
SSubmitRequestData submitInfo;
|
SSubmitRequestData submitInfo;
|
||||||
submitInfo.m_rms = tools::ToString(GetRMSPlugin());
|
submitInfo.m_rms = tools::ToString(GetRMSPlugin());
|
||||||
submitInfo.m_instances = agents;
|
submitInfo.m_instances = 1;
|
||||||
|
submitInfo.m_slots = agents; // TODO new api: get slots from agents
|
||||||
submitInfo.m_config = GetRMSConfig().string();
|
submitInfo.m_config = GetRMSConfig().string();
|
||||||
|
|
||||||
tools::SharedSemaphore blocker;
|
tools::SharedSemaphore blocker;
|
||||||
@@ -210,9 +209,9 @@ auto DDSSession::RequestAgentCount() -> AgentCount
|
|||||||
fImpl->fSession->syncSendRequest<SAgentCountRequest>(SAgentCountRequest::request_t(), res);
|
fImpl->fSession->syncSendRequest<SAgentCountRequest>(SAgentCountRequest::request_t(), res);
|
||||||
|
|
||||||
AgentCount count;
|
AgentCount count;
|
||||||
count.active = res.m_activeAgentsCount;
|
count.active = res.m_activeSlotsCount;
|
||||||
count.idle = res.m_idleAgentsCount;
|
count.idle = res.m_idleSlotsCount;
|
||||||
count.executing = res.m_executingAgentsCount;
|
count.executing = res.m_executingSlotsCount;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
@@ -231,13 +230,11 @@ auto DDSSession::RequestAgentInfo() -> std::vector<DDSAgent>
|
|||||||
*this,
|
*this,
|
||||||
a.m_agentID,
|
a.m_agentID,
|
||||||
a.m_agentPid,
|
a.m_agentPid,
|
||||||
a.m_agentState,
|
|
||||||
a.m_DDSPath,
|
a.m_DDSPath,
|
||||||
a.m_host,
|
a.m_host,
|
||||||
a.m_lobbyLeader,
|
|
||||||
a.m_startUpTime,
|
a.m_startUpTime,
|
||||||
a.m_taskID,
|
|
||||||
a.m_username
|
a.m_username
|
||||||
|
// a.m_nSlots
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -254,7 +251,9 @@ auto DDSSession::RequestTaskInfo() -> std::vector<DDSTask>
|
|||||||
std::vector<DDSTask> taskInfo;
|
std::vector<DDSTask> taskInfo;
|
||||||
taskInfo.reserve(res.size());
|
taskInfo.reserve(res.size());
|
||||||
for (auto& a : res) {
|
for (auto& a : res) {
|
||||||
taskInfo.emplace_back(a.m_taskID, 0);
|
//taskInfo.emplace_back(a.m_taskID, 0);
|
||||||
|
(void)a;
|
||||||
|
taskInfo.emplace_back(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return taskInfo;
|
return taskInfo;
|
||||||
@@ -354,25 +353,13 @@ void DDSSession::UnsubscribeFromCommands()
|
|||||||
fImpl->fDDSCustomCmd.unsubscribe();
|
fImpl->fDDSCustomCmd.unsubscribe();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DDSSession::SendCommand(const std::string& cmd) { fImpl->fDDSCustomCmd.send(cmd, ""); }
|
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)
|
void DDSSession::SendCommand(const std::string& cmd, DDSChannel::Id recipient)
|
||||||
{
|
{
|
||||||
fImpl->fDDSCustomCmd.send(cmd, std::to_string(recipient));
|
fImpl->fDDSCustomCmd.send(cmd, std::to_string(recipient));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDSSession::UpdateChannelToTaskAssociation(DDSChannel::Id channelId, DDSTask::Id taskId) -> void
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(fImpl->fMtx);
|
|
||||||
fImpl->fTaskIdByChannelIdMap[channelId] = taskId;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto DDSSession::GetTaskId(DDSChannel::Id channelId) const -> DDSTask::Id
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lk(fImpl->fMtx);
|
|
||||||
return fImpl->fTaskIdByChannelIdMap.at(channelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&
|
||||||
{
|
{
|
||||||
return os << "$DDS_SESSION_ID: " << session.GetId();
|
return os << "$DDS_SESSION_ID: " << session.GetId();
|
||||||
|
@@ -101,9 +101,8 @@ class DDSSession
|
|||||||
void StartDDSService();
|
void StartDDSService();
|
||||||
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
void SubscribeToCommands(std::function<void(const std::string& msg, const std::string& condition, uint64_t senderId)>);
|
||||||
void UnsubscribeFromCommands();
|
void UnsubscribeFromCommands();
|
||||||
void SendCommand(const std::string&);
|
void SendCommand(const std::string&, const std::string& = "");
|
||||||
void SendCommand(const std::string&, DDSChannel::Id);
|
void SendCommand(const std::string&, DDSChannel::Id);
|
||||||
auto UpdateChannelToTaskAssociation(DDSChannel::Id, DDSTask::Id) -> void;
|
|
||||||
auto GetTaskId(DDSChannel::Id) const -> DDSTask::Id;
|
auto GetTaskId(DDSChannel::Id) const -> DDSTask::Id;
|
||||||
|
|
||||||
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
friend auto operator<<(std::ostream& os, const DDSSession& session) -> std::ostream&;
|
||||||
|
@@ -9,18 +9,14 @@
|
|||||||
#include "DDSTopology.h"
|
#include "DDSTopology.h"
|
||||||
|
|
||||||
#include <boost/range/iterator_range.hpp>
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
#include <dds/dds.h>
|
||||||
#include <fairmq/sdk/DDSEnvironment.h>
|
|
||||||
#include <fairmq/Tools.h>
|
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
#include <DDS/Topology.h>
|
#include <fairmq/sdk/DDSEnvironment.h>
|
||||||
|
#include <memory>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
@@ -68,22 +64,23 @@ auto DDSTopology::GetNumRequiredAgents() const -> int
|
|||||||
return fImpl->fTopo.getRequiredNofAgents();
|
return fImpl->fTopo.getRequiredNofAgents();
|
||||||
}
|
}
|
||||||
|
|
||||||
auto DDSTopology::GetTasks() const -> std::vector<DDSTask>
|
auto DDSTopology::GetTasks(const std::string& path /* = "" */) const -> std::vector<DDSTask>
|
||||||
{
|
{
|
||||||
std::vector<DDSTask> list;
|
std::vector<DDSTask> list;
|
||||||
list.reserve(GetNumRequiredAgents());
|
|
||||||
|
|
||||||
auto itPair = fImpl->fTopo.getRuntimeTaskIterator(
|
dds::topology_api::STopoRuntimeTask::FilterIteratorPair_t itPair;
|
||||||
[](const dds::topology_api::STopoRuntimeTask::FilterIterator_t::value_type&) -> bool {
|
if (path == "") {
|
||||||
return true;
|
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);
|
auto tasks = boost::make_iterator_range(itPair.first, itPair.second);
|
||||||
|
|
||||||
for (const auto& task : tasks) {
|
for (const auto& task : tasks) {
|
||||||
LOG(debug) << "Found task with id: " << task.first << ", "
|
// LOG(debug) << "Found task with id: " << task.first << ", "
|
||||||
<< "Path: " << task.second.m_taskPath << ", "
|
// << "Path: " << task.second.m_taskPath << ", "
|
||||||
<< "Collection id: " << task.second.m_taskCollectionId << ", "
|
// << "Collection id: " << task.second.m_taskCollectionId << ", "
|
||||||
<< "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
// << "Name: " << task.second.m_task->getName() << "_" << task.second.m_taskIndex;
|
||||||
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
list.emplace_back(task.first, task.second.m_taskCollectionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,10 +91,7 @@ auto DDSTopology::GetCollections() const -> std::vector<DDSCollection>
|
|||||||
{
|
{
|
||||||
std::vector<DDSCollection> list;
|
std::vector<DDSCollection> list;
|
||||||
|
|
||||||
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(
|
auto itPair = fImpl->fTopo.getRuntimeCollectionIterator(nullptr); // passing nullptr will get all collections
|
||||||
[](const dds::topology_api::STopoRuntimeCollection::FilterIterator_t::value_type&) -> bool {
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
auto collections = boost::make_iterator_range(itPair.first, itPair.second);
|
||||||
|
|
||||||
for (const auto& c : collections) {
|
for (const auto& c : collections) {
|
||||||
|
@@ -53,8 +53,8 @@ class DDSTopology
|
|||||||
/// @brief Get number of required agents for this topology
|
/// @brief Get number of required agents for this topology
|
||||||
auto GetNumRequiredAgents() const -> int;
|
auto GetNumRequiredAgents() const -> int;
|
||||||
|
|
||||||
/// @brief Get list of tasks in this topology
|
/// @brief Get list of tasks in this topology, optionally matching provided path
|
||||||
auto GetTasks() const -> std::vector<DDSTask>;
|
auto GetTasks(const std::string& = "") const -> std::vector<DDSTask>;
|
||||||
|
|
||||||
/// @brief Get list of tasks in this topology
|
/// @brief Get list of tasks in this topology
|
||||||
auto GetCollections() const -> std::vector<DDSCollection>;
|
auto GetCollections() const -> std::vector<DDSCollection>;
|
||||||
|
@@ -27,6 +27,10 @@ std::string ErrorCategory::message(int ev) const
|
|||||||
return "async operation canceled";
|
return "async operation canceled";
|
||||||
case ErrorCode::DeviceChangeStateFailed:
|
case ErrorCode::DeviceChangeStateFailed:
|
||||||
return "failed to change state of a fairmq device";
|
return "failed to change state of a fairmq device";
|
||||||
|
case ErrorCode::DeviceGetPropertiesFailed:
|
||||||
|
return "failed to get fairmq device properties";
|
||||||
|
case ErrorCode::DeviceSetPropertiesFailed:
|
||||||
|
return "failed to set fairmq device properties";
|
||||||
default:
|
default:
|
||||||
return "(unrecognized error)";
|
return "(unrecognized error)";
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,9 @@ enum class ErrorCode
|
|||||||
OperationInProgress = 10,
|
OperationInProgress = 10,
|
||||||
OperationTimeout,
|
OperationTimeout,
|
||||||
OperationCanceled,
|
OperationCanceled,
|
||||||
DeviceChangeStateFailed
|
DeviceChangeStateFailed,
|
||||||
|
DeviceGetPropertiesFailed,
|
||||||
|
DeviceSetPropertiesFailed
|
||||||
};
|
};
|
||||||
|
|
||||||
std::error_code MakeErrorCode(ErrorCode);
|
std::error_code MakeErrorCode(ErrorCode);
|
||||||
|
@@ -8,8 +8,7 @@
|
|||||||
|
|
||||||
#include "Topology.h"
|
#include "Topology.h"
|
||||||
|
|
||||||
#include <DDS/Tools.h>
|
#include <dds/dds.h>
|
||||||
#include <DDS/Topology.h>
|
|
||||||
|
|
||||||
namespace fair {
|
namespace fair {
|
||||||
namespace mq {
|
namespace mq {
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,11 @@ target_link_libraries(${target}
|
|||||||
PRIVATE
|
PRIVATE
|
||||||
${_flatbuffers}
|
${_flatbuffers}
|
||||||
)
|
)
|
||||||
|
set_target_properties(${target} PROPERTIES
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||||
|
OUTPUT_NAME FairMQ${target}
|
||||||
|
)
|
||||||
|
|
||||||
target_include_directories(${target}
|
target_include_directories(${target}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
@@ -52,21 +52,21 @@ array<string, 17> typeNames =
|
|||||||
"CheckState",
|
"CheckState",
|
||||||
"ChangeState",
|
"ChangeState",
|
||||||
"DumpConfig",
|
"DumpConfig",
|
||||||
"SubscribeToHeartbeats",
|
|
||||||
"UnsubscribeFromHeartbeats",
|
|
||||||
"SubscribeToStateChange",
|
"SubscribeToStateChange",
|
||||||
"UnsubscribeFromStateChange",
|
"UnsubscribeFromStateChange",
|
||||||
"StateChangeExitingReceived",
|
"StateChangeExitingReceived",
|
||||||
|
"GetProperties",
|
||||||
|
"SetProperties",
|
||||||
|
"SubscriptionHeartbeat",
|
||||||
|
|
||||||
"CurrentState",
|
"CurrentState",
|
||||||
"TransitionStatus",
|
"TransitionStatus",
|
||||||
"Config",
|
"Config",
|
||||||
"HeartbeatSubscription",
|
|
||||||
"HeartbeatUnsubscription",
|
|
||||||
"Heartbeat",
|
|
||||||
"StateChangeSubscription",
|
"StateChangeSubscription",
|
||||||
"StateChangeUnsubscription",
|
"StateChangeUnsubscription",
|
||||||
"StateChange"
|
"StateChange",
|
||||||
|
"Properties",
|
||||||
|
"PropertiesSet"
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -154,20 +154,20 @@ array<FBCmd, 17> typeToFBCmd =
|
|||||||
FBCmd::FBCmd_check_state,
|
FBCmd::FBCmd_check_state,
|
||||||
FBCmd::FBCmd_change_state,
|
FBCmd::FBCmd_change_state,
|
||||||
FBCmd::FBCmd_dump_config,
|
FBCmd::FBCmd_dump_config,
|
||||||
FBCmd::FBCmd_subscribe_to_heartbeats,
|
|
||||||
FBCmd::FBCmd_unsubscribe_from_heartbeats,
|
|
||||||
FBCmd::FBCmd_subscribe_to_state_change,
|
FBCmd::FBCmd_subscribe_to_state_change,
|
||||||
FBCmd::FBCmd_unsubscribe_from_state_change,
|
FBCmd::FBCmd_unsubscribe_from_state_change,
|
||||||
FBCmd::FBCmd_state_change_exiting_received,
|
FBCmd::FBCmd_state_change_exiting_received,
|
||||||
|
FBCmd::FBCmd_get_properties,
|
||||||
|
FBCmd::FBCmd_set_properties,
|
||||||
|
FBCmd::FBCmd_subscription_heartbeat,
|
||||||
FBCmd::FBCmd_current_state,
|
FBCmd::FBCmd_current_state,
|
||||||
FBCmd::FBCmd_transition_status,
|
FBCmd::FBCmd_transition_status,
|
||||||
FBCmd::FBCmd_config,
|
FBCmd::FBCmd_config,
|
||||||
FBCmd::FBCmd_heartbeat_subscription,
|
|
||||||
FBCmd::FBCmd_heartbeat_unsubscription,
|
|
||||||
FBCmd::FBCmd_heartbeat,
|
|
||||||
FBCmd::FBCmd_state_change_subscription,
|
FBCmd::FBCmd_state_change_subscription,
|
||||||
FBCmd::FBCmd_state_change_unsubscription,
|
FBCmd::FBCmd_state_change_unsubscription,
|
||||||
FBCmd::FBCmd_state_change
|
FBCmd::FBCmd_state_change,
|
||||||
|
FBCmd::FBCmd_properties,
|
||||||
|
FBCmd::FBCmd_properties_set
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -177,20 +177,20 @@ array<Type, 17> fbCmdToType =
|
|||||||
Type::check_state,
|
Type::check_state,
|
||||||
Type::change_state,
|
Type::change_state,
|
||||||
Type::dump_config,
|
Type::dump_config,
|
||||||
Type::subscribe_to_heartbeats,
|
|
||||||
Type::unsubscribe_from_heartbeats,
|
|
||||||
Type::subscribe_to_state_change,
|
Type::subscribe_to_state_change,
|
||||||
Type::unsubscribe_from_state_change,
|
Type::unsubscribe_from_state_change,
|
||||||
Type::state_change_exiting_received,
|
Type::state_change_exiting_received,
|
||||||
|
Type::get_properties,
|
||||||
|
Type::set_properties,
|
||||||
|
Type::subscription_heartbeat,
|
||||||
Type::current_state,
|
Type::current_state,
|
||||||
Type::transition_status,
|
Type::transition_status,
|
||||||
Type::config,
|
Type::config,
|
||||||
Type::heartbeat_subscription,
|
|
||||||
Type::heartbeat_unsubscription,
|
|
||||||
Type::heartbeat,
|
|
||||||
Type::state_change_subscription,
|
Type::state_change_subscription,
|
||||||
Type::state_change_unsubscription,
|
Type::state_change_unsubscription,
|
||||||
Type::state_change
|
Type::state_change,
|
||||||
|
Type::properties,
|
||||||
|
Type::properties_set
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -229,16 +229,11 @@ string Cmds::Serialize(const Format type) const
|
|||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::subscribe_to_heartbeats: {
|
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::unsubscribe_from_heartbeats: {
|
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case Type::subscribe_to_state_change: {
|
case Type::subscribe_to_state_change: {
|
||||||
|
auto _cmd = static_cast<SubscribeToStateChange&>(*cmd);
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
|
cmdBuilder->add_interval(_cmd.GetInterval());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::unsubscribe_from_state_change: {
|
case Type::unsubscribe_from_state_change: {
|
||||||
@@ -249,70 +244,115 @@ string Cmds::Serialize(const Format type) const
|
|||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Type::get_properties: {
|
||||||
|
auto _cmd = static_cast<GetProperties&>(*cmd);
|
||||||
|
auto query = fbb.CreateString(_cmd.GetQuery());
|
||||||
|
cmdBuilder = tools::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 = tools::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 = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
|
cmdBuilder->add_interval(_cmd.GetInterval());
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Type::current_state: {
|
case Type::current_state: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<CurrentState&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<CurrentState&>(*cmd);
|
||||||
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_current_state(GetFBState(static_cast<CurrentState&>(*cmd).GetCurrentState()));
|
cmdBuilder->add_current_state(GetFBState(_cmd.GetCurrentState()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::transition_status: {
|
case Type::transition_status: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<TransitionStatus&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<TransitionStatus&>(*cmd);
|
||||||
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_result(GetFBResult(static_cast<TransitionStatus&>(*cmd).GetResult()));
|
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||||
cmdBuilder->add_transition(GetFBTransition(static_cast<TransitionStatus&>(*cmd).GetTransition()));
|
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||||
|
cmdBuilder->add_transition(GetFBTransition(_cmd.GetTransition()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::config: {
|
case Type::config: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<Config&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<Config&>(*cmd);
|
||||||
auto config = fbb.CreateString(static_cast<Config&>(*cmd).GetConfig());
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
|
auto config = fbb.CreateString(_cmd.GetConfig());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_config_string(config);
|
cmdBuilder->add_config_string(config);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::heartbeat_subscription: {
|
|
||||||
auto deviceId = fbb.CreateString(static_cast<HeartbeatSubscription&>(*cmd).GetDeviceId());
|
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_result(GetFBResult(static_cast<HeartbeatSubscription&>(*cmd).GetResult()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::heartbeat_unsubscription: {
|
|
||||||
auto deviceId = fbb.CreateString(static_cast<HeartbeatUnsubscription&>(*cmd).GetDeviceId());
|
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
cmdBuilder->add_result(GetFBResult(static_cast<HeartbeatUnsubscription&>(*cmd).GetResult()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::heartbeat: {
|
|
||||||
auto deviceId = fbb.CreateString(static_cast<Heartbeat&>(*cmd).GetDeviceId());
|
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
|
||||||
cmdBuilder->add_device_id(deviceId);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type::state_change_subscription: {
|
case Type::state_change_subscription: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<StateChangeSubscription&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<StateChangeSubscription&>(*cmd);
|
||||||
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_result(GetFBResult(static_cast<StateChangeSubscription&>(*cmd).GetResult()));
|
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||||
|
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::state_change_unsubscription: {
|
case Type::state_change_unsubscription: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<StateChangeUnsubscription&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<StateChangeUnsubscription&>(*cmd);
|
||||||
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_result(GetFBResult(static_cast<StateChangeUnsubscription&>(*cmd).GetResult()));
|
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||||
|
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case Type::state_change: {
|
case Type::state_change: {
|
||||||
auto deviceId = fbb.CreateString(static_cast<StateChange&>(*cmd).GetDeviceId());
|
auto _cmd = static_cast<StateChange&>(*cmd);
|
||||||
|
auto deviceId = fbb.CreateString(_cmd.GetDeviceId());
|
||||||
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
cmdBuilder = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
cmdBuilder->add_device_id(deviceId);
|
cmdBuilder->add_device_id(deviceId);
|
||||||
cmdBuilder->add_task_id(static_cast<StateChange&>(*cmd).GetTaskId());
|
cmdBuilder->add_task_id(_cmd.GetTaskId());
|
||||||
cmdBuilder->add_last_state(GetFBState(static_cast<StateChange&>(*cmd).GetLastState()));
|
cmdBuilder->add_last_state(GetFBState(_cmd.GetLastState()));
|
||||||
cmdBuilder->add_current_state(GetFBState(static_cast<StateChange&>(*cmd).GetCurrentState()));
|
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 = tools::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 = tools::make_unique<FBCommandBuilder>(fbb);
|
||||||
|
cmdBuilder->add_device_id(deviceId);
|
||||||
|
cmdBuilder->add_request_id(_cmd.GetRequestId());
|
||||||
|
cmdBuilder->add_result(GetFBResult(_cmd.GetResult()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -376,14 +416,8 @@ void Cmds::Deserialize(const string& str, const Format type)
|
|||||||
case FBCmd_dump_config:
|
case FBCmd_dump_config:
|
||||||
fCmds.emplace_back(make<DumpConfig>());
|
fCmds.emplace_back(make<DumpConfig>());
|
||||||
break;
|
break;
|
||||||
case FBCmd_subscribe_to_heartbeats:
|
|
||||||
fCmds.emplace_back(make<SubscribeToHeartbeats>());
|
|
||||||
break;
|
|
||||||
case FBCmd_unsubscribe_from_heartbeats:
|
|
||||||
fCmds.emplace_back(make<UnsubscribeFromHeartbeats>());
|
|
||||||
break;
|
|
||||||
case FBCmd_subscribe_to_state_change:
|
case FBCmd_subscribe_to_state_change:
|
||||||
fCmds.emplace_back(make<SubscribeToStateChange>());
|
fCmds.emplace_back(make<SubscribeToStateChange>(cmdPtr.interval()));
|
||||||
break;
|
break;
|
||||||
case FBCmd_unsubscribe_from_state_change:
|
case FBCmd_unsubscribe_from_state_change:
|
||||||
fCmds.emplace_back(make<UnsubscribeFromStateChange>());
|
fCmds.emplace_back(make<UnsubscribeFromStateChange>());
|
||||||
@@ -391,33 +425,49 @@ void Cmds::Deserialize(const string& str, const Format type)
|
|||||||
case FBCmd_state_change_exiting_received:
|
case FBCmd_state_change_exiting_received:
|
||||||
fCmds.emplace_back(make<StateChangeExitingReceived>());
|
fCmds.emplace_back(make<StateChangeExitingReceived>());
|
||||||
break;
|
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:
|
case FBCmd_current_state:
|
||||||
fCmds.emplace_back(make<CurrentState>(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state())));
|
fCmds.emplace_back(make<CurrentState>(cmdPtr.device_id()->str(), GetMQState(cmdPtr.current_state())));
|
||||||
break;
|
break;
|
||||||
case FBCmd_transition_status:
|
case FBCmd_transition_status:
|
||||||
fCmds.emplace_back(make<TransitionStatus>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition())));
|
fCmds.emplace_back(make<TransitionStatus>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result()), GetMQTransition(cmdPtr.transition())));
|
||||||
break;
|
break;
|
||||||
case FBCmd_config:
|
case FBCmd_config:
|
||||||
fCmds.emplace_back(make<Config>(cmdPtr.device_id()->str(), cmdPtr.config_string()->str()));
|
fCmds.emplace_back(make<Config>(cmdPtr.device_id()->str(), cmdPtr.config_string()->str()));
|
||||||
break;
|
break;
|
||||||
case FBCmd_heartbeat_subscription:
|
|
||||||
fCmds.emplace_back(make<HeartbeatSubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
|
||||||
break;
|
|
||||||
case FBCmd_heartbeat_unsubscription:
|
|
||||||
fCmds.emplace_back(make<HeartbeatUnsubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
|
||||||
break;
|
|
||||||
case FBCmd_heartbeat:
|
|
||||||
fCmds.emplace_back(make<Heartbeat>(cmdPtr.device_id()->str()));
|
|
||||||
break;
|
|
||||||
case FBCmd_state_change_subscription:
|
case FBCmd_state_change_subscription:
|
||||||
fCmds.emplace_back(make<StateChangeSubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
fCmds.emplace_back(make<StateChangeSubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
||||||
break;
|
break;
|
||||||
case FBCmd_state_change_unsubscription:
|
case FBCmd_state_change_unsubscription:
|
||||||
fCmds.emplace_back(make<StateChangeUnsubscription>(cmdPtr.device_id()->str(), GetResult(cmdPtr.result())));
|
fCmds.emplace_back(make<StateChangeUnsubscription>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetResult(cmdPtr.result())));
|
||||||
break;
|
break;
|
||||||
case FBCmd_state_change:
|
case FBCmd_state_change:
|
||||||
fCmds.emplace_back(make<StateChange>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state())));
|
fCmds.emplace_back(make<StateChange>(cmdPtr.device_id()->str(), cmdPtr.task_id(), GetMQState(cmdPtr.last_state()), GetMQState(cmdPtr.current_state())));
|
||||||
break;
|
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:
|
default:
|
||||||
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()");
|
throw CommandFormatError("unrecognized command type given to fair::mq::cmd::Cmds::Deserialize()");
|
||||||
break;
|
break;
|
||||||
|
@@ -42,26 +42,27 @@ enum class Type : int
|
|||||||
check_state, // args: { }
|
check_state, // args: { }
|
||||||
change_state, // args: { transition }
|
change_state, // args: { transition }
|
||||||
dump_config, // args: { }
|
dump_config, // args: { }
|
||||||
subscribe_to_heartbeats, // args: { }
|
|
||||||
unsubscribe_from_heartbeats, // args: { }
|
|
||||||
subscribe_to_state_change, // args: { }
|
subscribe_to_state_change, // args: { }
|
||||||
unsubscribe_from_state_change, // args: { }
|
unsubscribe_from_state_change, // args: { }
|
||||||
state_change_exiting_received, // 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 }
|
current_state, // args: { device_id, current_state }
|
||||||
transition_status, // args: { device_id, Result, transition }
|
transition_status, // args: { device_id, task_id, Result, transition }
|
||||||
config, // args: { device_id, config_string }
|
config, // args: { device_id, config_string }
|
||||||
heartbeat_subscription, // args: { device_id, Result }
|
state_change_subscription, // args: { device_id, task_id, Result }
|
||||||
heartbeat_unsubscription, // args: { device_id, Result }
|
state_change_unsubscription, // args: { device_id, task_id, Result }
|
||||||
heartbeat, // args: { device_id }
|
state_change, // args: { device_id, task_id, last_state, current_state }
|
||||||
state_change_subscription, // args: { device_id, Result }
|
properties, // args: { device_id, request_id, Result, properties }
|
||||||
state_change_unsubscription, // args: { device_id, Result }
|
properties_set // args: { device_id, request_id, Result }
|
||||||
state_change // args: { device_id, task_id, last_state, current_state }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Cmd
|
struct Cmd
|
||||||
{
|
{
|
||||||
explicit Cmd(const Type type) : fType(type) {}
|
explicit Cmd(const Type type) : fType(type) {}
|
||||||
|
virtual ~Cmd() = default;
|
||||||
|
|
||||||
Type GetType() const { return fType; }
|
Type GetType() const { return fType; }
|
||||||
|
|
||||||
@@ -93,19 +94,18 @@ struct DumpConfig : Cmd
|
|||||||
explicit DumpConfig() : Cmd(Type::dump_config) {}
|
explicit DumpConfig() : Cmd(Type::dump_config) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SubscribeToHeartbeats : Cmd
|
|
||||||
{
|
|
||||||
explicit SubscribeToHeartbeats() : Cmd(Type::subscribe_to_heartbeats) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct UnsubscribeFromHeartbeats : Cmd
|
|
||||||
{
|
|
||||||
explicit UnsubscribeFromHeartbeats() : Cmd(Type::unsubscribe_from_heartbeats) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SubscribeToStateChange : Cmd
|
struct SubscribeToStateChange : Cmd
|
||||||
{
|
{
|
||||||
explicit SubscribeToStateChange() : Cmd(Type::subscribe_to_state_change) {}
|
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
|
struct UnsubscribeFromStateChange : Cmd
|
||||||
@@ -118,6 +118,56 @@ struct StateChangeExitingReceived : Cmd
|
|||||||
explicit StateChangeExitingReceived() : Cmd(Type::state_change_exiting_received) {}
|
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
|
struct CurrentState : Cmd
|
||||||
{
|
{
|
||||||
explicit CurrentState(const std::string& id, State currentState)
|
explicit CurrentState(const std::string& id, State currentState)
|
||||||
@@ -138,15 +188,18 @@ struct CurrentState : Cmd
|
|||||||
|
|
||||||
struct TransitionStatus : Cmd
|
struct TransitionStatus : Cmd
|
||||||
{
|
{
|
||||||
explicit TransitionStatus(const std::string& id, const Result result, const Transition transition)
|
explicit TransitionStatus(const std::string& deviceId, const uint64_t taskId, const Result result, const Transition transition)
|
||||||
: Cmd(Type::transition_status)
|
: Cmd(Type::transition_status)
|
||||||
, fDeviceId(id)
|
, fDeviceId(deviceId)
|
||||||
|
, fTaskId(taskId)
|
||||||
, fResult(result)
|
, fResult(result)
|
||||||
, fTransition(transition)
|
, fTransition(transition)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
std::string GetDeviceId() const { return fDeviceId; }
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
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; }
|
Result GetResult() const { return fResult; }
|
||||||
void SetResult(const Result result) { fResult = result; }
|
void SetResult(const Result result) { fResult = result; }
|
||||||
Transition GetTransition() const { return fTransition; }
|
Transition GetTransition() const { return fTransition; }
|
||||||
@@ -154,6 +207,7 @@ struct TransitionStatus : Cmd
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::string fDeviceId;
|
std::string fDeviceId;
|
||||||
|
uint64_t fTaskId;
|
||||||
Result fResult;
|
Result fResult;
|
||||||
Transition fTransition;
|
Transition fTransition;
|
||||||
};
|
};
|
||||||
@@ -176,89 +230,47 @@ struct Config : Cmd
|
|||||||
std::string fConfig;
|
std::string fConfig;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct HeartbeatSubscription : Cmd
|
|
||||||
{
|
|
||||||
explicit HeartbeatSubscription(const std::string& id, const Result result)
|
|
||||||
: Cmd(Type::heartbeat_subscription)
|
|
||||||
, fDeviceId(id)
|
|
||||||
, fResult(result)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
Result GetResult() const { return fResult; }
|
|
||||||
void SetResult(const Result result) { fResult = result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
Result fResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct HeartbeatUnsubscription : Cmd
|
|
||||||
{
|
|
||||||
explicit HeartbeatUnsubscription(const std::string& id, const Result result)
|
|
||||||
: Cmd(Type::heartbeat_unsubscription)
|
|
||||||
, fDeviceId(id)
|
|
||||||
, fResult(result)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
Result GetResult() const { return fResult; }
|
|
||||||
void SetResult(const Result result) { fResult = result; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
Result fResult;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Heartbeat : Cmd
|
|
||||||
{
|
|
||||||
explicit Heartbeat(const std::string& id)
|
|
||||||
: Cmd(Type::heartbeat)
|
|
||||||
, fDeviceId(id)
|
|
||||||
{}
|
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string fDeviceId;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct StateChangeSubscription : Cmd
|
struct StateChangeSubscription : Cmd
|
||||||
{
|
{
|
||||||
explicit StateChangeSubscription(const std::string& id, const Result result)
|
explicit StateChangeSubscription(const std::string& id, const uint64_t taskId, const Result result)
|
||||||
: Cmd(Type::state_change_subscription)
|
: Cmd(Type::state_change_subscription)
|
||||||
, fDeviceId(id)
|
, fDeviceId(id)
|
||||||
|
, fTaskId(taskId)
|
||||||
, fResult(result)
|
, fResult(result)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
std::string GetDeviceId() const { return fDeviceId; }
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
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; }
|
Result GetResult() const { return fResult; }
|
||||||
void SetResult(const Result result) { fResult = result; }
|
void SetResult(const Result result) { fResult = result; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string fDeviceId;
|
std::string fDeviceId;
|
||||||
|
uint64_t fTaskId;
|
||||||
Result fResult;
|
Result fResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct StateChangeUnsubscription : Cmd
|
struct StateChangeUnsubscription : Cmd
|
||||||
{
|
{
|
||||||
explicit StateChangeUnsubscription(const std::string& id, const Result result)
|
explicit StateChangeUnsubscription(const std::string& id, const uint64_t taskId, const Result result)
|
||||||
: Cmd(Type::state_change_unsubscription)
|
: Cmd(Type::state_change_unsubscription)
|
||||||
, fDeviceId(id)
|
, fDeviceId(id)
|
||||||
|
, fTaskId(taskId)
|
||||||
, fResult(result)
|
, fResult(result)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
std::string GetDeviceId() const { return fDeviceId; }
|
std::string GetDeviceId() const { return fDeviceId; }
|
||||||
void SetDeviceId(const std::string& deviceId) { fDeviceId = deviceId; }
|
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; }
|
Result GetResult() const { return fResult; }
|
||||||
void SetResult(const Result result) { fResult = result; }
|
void SetResult(const Result result) { fResult = result; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string fDeviceId;
|
std::string fDeviceId;
|
||||||
|
uint64_t fTaskId;
|
||||||
Result fResult;
|
Result fResult;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -288,6 +300,53 @@ struct StateChange : Cmd
|
|||||||
fair::mq::State fCurrentState;
|
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>
|
template<typename C, typename... Args>
|
||||||
std::unique_ptr<Cmd> make(Args&&... args)
|
std::unique_ptr<Cmd> make(Args&&... args)
|
||||||
{
|
{
|
||||||
@@ -307,7 +366,6 @@ struct Cmds
|
|||||||
Unpack(std::forward<std::unique_ptr<Cmd>&&>(first), std::forward<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)); }
|
void Add(std::unique_ptr<Cmd>&& cmd) { fCmds.emplace_back(std::move(cmd)); }
|
||||||
|
|
||||||
template<typename C, typename... Args>
|
template<typename C, typename... Args>
|
||||||
|
@@ -38,31 +38,38 @@ enum FBTransition:byte {
|
|||||||
ErrorFound
|
ErrorFound
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table FBProperty {
|
||||||
|
key:string;
|
||||||
|
value:string;
|
||||||
|
}
|
||||||
|
|
||||||
enum FBCmd:byte {
|
enum FBCmd:byte {
|
||||||
check_state, // args: { }
|
check_state, // args: { }
|
||||||
change_state, // args: { transition }
|
change_state, // args: { transition }
|
||||||
dump_config, // args: { }
|
dump_config, // args: { }
|
||||||
subscribe_to_heartbeats, // args: { }
|
subscribe_to_state_change, // args: { interval }
|
||||||
unsubscribe_from_heartbeats, // args: { }
|
|
||||||
subscribe_to_state_change, // args: { }
|
|
||||||
unsubscribe_from_state_change, // args: { }
|
unsubscribe_from_state_change, // args: { }
|
||||||
state_change_exiting_received, // 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 }
|
current_state, // args: { device_id, current_state }
|
||||||
transition_status, // args: { device_id, Result, transition }
|
transition_status, // args: { device_id, task_id, Result, transition }
|
||||||
config, // args: { device_id, config_string }
|
config, // args: { device_id, config_string }
|
||||||
heartbeat_subscription, // args: { device_id, Result }
|
state_change_subscription, // args: { device_id, task_id, Result }
|
||||||
heartbeat_unsubscription, // args: { device_id, Result }
|
state_change_unsubscription, // args: { device_id, task_id, Result }
|
||||||
heartbeat, // args: { device_id }
|
state_change, // args: { device_id, task_id, last_state, current_state }
|
||||||
state_change_subscription, // args: { device_id, Result }
|
properties, // args: { device_id, request_id, Result, properties }
|
||||||
state_change_unsubscription, // args: { device_id, Result }
|
properties_set // args: { device_id, request_id, Result }
|
||||||
state_change // args: { device_id, task_id, last_state, current_state }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
table FBCommand {
|
table FBCommand {
|
||||||
command_id:FBCmd;
|
command_id:FBCmd;
|
||||||
device_id:string;
|
device_id:string;
|
||||||
task_id:uint64;
|
task_id:uint64;
|
||||||
|
request_id:uint64;
|
||||||
|
interval:int64;
|
||||||
state:FBState;
|
state:FBState;
|
||||||
transition:FBTransition;
|
transition:FBTransition;
|
||||||
result:FBResult;
|
result:FBResult;
|
||||||
@@ -70,6 +77,8 @@ table FBCommand {
|
|||||||
last_state:FBState;
|
last_state:FBState;
|
||||||
current_state:FBState;
|
current_state:FBState;
|
||||||
debug:string;
|
debug:string;
|
||||||
|
properties:[FBProperty];
|
||||||
|
property_query:string;
|
||||||
}
|
}
|
||||||
|
|
||||||
table FBCommands {
|
table FBCommands {
|
||||||
|
@@ -41,15 +41,21 @@ struct RegionInfo
|
|||||||
RegionInfo(const VoidAlloc& alloc)
|
RegionInfo(const VoidAlloc& alloc)
|
||||||
: fPath("", alloc)
|
: fPath("", alloc)
|
||||||
, fFlags(0)
|
, fFlags(0)
|
||||||
|
, fUserFlags(0)
|
||||||
|
, fDestroyed(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
RegionInfo(const char* path, int flags, const VoidAlloc& alloc)
|
RegionInfo(const char* path, const int flags, const uint64_t userFlags, const VoidAlloc& alloc)
|
||||||
: fPath(path, alloc)
|
: fPath(path, alloc)
|
||||||
, fFlags(flags)
|
, fFlags(flags)
|
||||||
|
, fUserFlags(userFlags)
|
||||||
|
, fDestroyed(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Str fPath;
|
Str fPath;
|
||||||
int fFlags;
|
int fFlags;
|
||||||
|
uint64_t fUserFlags;
|
||||||
|
bool fDestroyed;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Uint64RegionInfoPairAlloc = boost::interprocess::allocator<std::pair<const uint64_t, RegionInfo>, SegmentManager>;
|
using Uint64RegionInfoPairAlloc = boost::interprocess::allocator<std::pair<const uint64_t, RegionInfo>, SegmentManager>;
|
||||||
@@ -77,8 +83,8 @@ struct MetaHeader
|
|||||||
{
|
{
|
||||||
size_t fSize;
|
size_t fSize;
|
||||||
size_t fRegionId;
|
size_t fRegionId;
|
||||||
boost::interprocess::managed_shared_memory::handle_t fHandle;
|
|
||||||
size_t fHint;
|
size_t fHint;
|
||||||
|
boost::interprocess::managed_shared_memory::handle_t fHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct RegionBlock
|
struct RegionBlock
|
||||||
|
@@ -1,281 +0,0 @@
|
|||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2014 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 "Common.h"
|
|
||||||
#include "Region.h"
|
|
||||||
|
|
||||||
#include "FairMQMessageSHM.h"
|
|
||||||
#include "FairMQUnmanagedRegionSHM.h"
|
|
||||||
#include "FairMQLogger.h"
|
|
||||||
|
|
||||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
|
||||||
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace fair::mq::shmem;
|
|
||||||
|
|
||||||
namespace bipc = ::boost::interprocess;
|
|
||||||
namespace bpt = ::boost::posix_time;
|
|
||||||
|
|
||||||
atomic<bool> FairMQMessageSHM::fInterrupted(false);
|
|
||||||
fair::mq::Transport FairMQMessageSHM::fTransportType = fair::mq::Transport::SHM;
|
|
||||||
|
|
||||||
FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQTransportFactory* factory)
|
|
||||||
: FairMQMessage{factory}
|
|
||||||
, fManager(manager)
|
|
||||||
, fMessage()
|
|
||||||
, fQueued(false)
|
|
||||||
, fMetaCreated(false)
|
|
||||||
, fRegionId(0)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fHandle(-1)
|
|
||||||
, fSize(0)
|
|
||||||
, fHint(0)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
|
||||||
if (zmq_msg_init(&fMessage) != 0) {
|
|
||||||
LOG(error) << "failed initializing message, reason: " << zmq_strerror(errno);
|
|
||||||
}
|
|
||||||
fMetaCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
FairMQMessageSHM::FairMQMessageSHM(Manager& manager, const size_t size, FairMQTransportFactory* factory)
|
|
||||||
: FairMQMessage{factory}
|
|
||||||
, fManager(manager)
|
|
||||||
, fMessage()
|
|
||||||
, fQueued(false)
|
|
||||||
, fMetaCreated(false)
|
|
||||||
, fRegionId(0)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fHandle(-1)
|
|
||||||
, fSize(0)
|
|
||||||
, fHint(0)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
|
||||||
InitializeChunk(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
FairMQMessageSHM::FairMQMessageSHM(Manager& manager, void* data, const size_t size, fairmq_free_fn* ffn, void* hint, FairMQTransportFactory* factory)
|
|
||||||
: FairMQMessage{factory}
|
|
||||||
, fManager(manager)
|
|
||||||
, fMessage()
|
|
||||||
, fQueued(false)
|
|
||||||
, fMetaCreated(false)
|
|
||||||
, fRegionId(0)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fHandle(-1)
|
|
||||||
, fSize(0)
|
|
||||||
, fHint(0)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
|
||||||
if (InitializeChunk(size)) {
|
|
||||||
memcpy(fLocalPtr, data, size);
|
|
||||||
if (ffn) {
|
|
||||||
ffn(data, hint);
|
|
||||||
} else {
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
FairMQMessageSHM::FairMQMessageSHM(Manager& manager, FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint, FairMQTransportFactory* factory)
|
|
||||||
: FairMQMessage{factory}
|
|
||||||
, fManager(manager)
|
|
||||||
, fMessage()
|
|
||||||
, fQueued(false)
|
|
||||||
, fMetaCreated(false)
|
|
||||||
, fRegionId(static_cast<FairMQUnmanagedRegionSHM*>(region.get())->fRegionId)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fHandle(-1)
|
|
||||||
, fSize(size)
|
|
||||||
, fHint(reinterpret_cast<size_t>(hint))
|
|
||||||
, fLocalPtr(static_cast<char*>(data))
|
|
||||||
{
|
|
||||||
if (reinterpret_cast<const char*>(data) >= reinterpret_cast<const char*>(region->GetData()) ||
|
|
||||||
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize()) {
|
|
||||||
fHandle = (bipc::managed_shared_memory::handle_t)(reinterpret_cast<const char*>(data) - reinterpret_cast<const char*>(region->GetData()));
|
|
||||||
|
|
||||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0) {
|
|
||||||
LOG(error) << "failed initializing meta message, reason: " << zmq_strerror(errno);
|
|
||||||
} else {
|
|
||||||
MetaHeader header;
|
|
||||||
header.fSize = size;
|
|
||||||
header.fHandle = fHandle;
|
|
||||||
header.fRegionId = fRegionId;
|
|
||||||
header.fHint = fHint;
|
|
||||||
memcpy(zmq_msg_data(&fMessage), &header, sizeof(MetaHeader));
|
|
||||||
|
|
||||||
fMetaCreated = true;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(error) << "trying to create region message with data from outside the region";
|
|
||||||
throw runtime_error("trying to create region message with data from outside the region");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FairMQMessageSHM::InitializeChunk(const size_t size)
|
|
||||||
{
|
|
||||||
while (fHandle < 0) {
|
|
||||||
try {
|
|
||||||
bipc::managed_shared_memory::size_type actualSize = size;
|
|
||||||
char* hint = 0; // unused for bipc::allocate_new
|
|
||||||
fLocalPtr = fManager.Segment().allocation_command<char>(bipc::allocate_new, size, actualSize, hint);
|
|
||||||
} catch (bipc::bad_alloc& ba) {
|
|
||||||
// LOG(warn) << "Shared memory full...";
|
|
||||||
this_thread::sleep_for(chrono::milliseconds(50));
|
|
||||||
if (fInterrupted) {
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fHandle = fManager.Segment().get_handle_from_address(fLocalPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
fSize = size;
|
|
||||||
|
|
||||||
if (zmq_msg_init_size(&fMessage, sizeof(MetaHeader)) != 0) {
|
|
||||||
LOG(error) << "failed initializing meta message, reason: " << zmq_strerror(errno);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
MetaHeader header;
|
|
||||||
header.fSize = size;
|
|
||||||
header.fHandle = fHandle;
|
|
||||||
header.fRegionId = fRegionId;
|
|
||||||
header.fHint = fHint;
|
|
||||||
memcpy(zmq_msg_data(&fMessage), &header, sizeof(MetaHeader));
|
|
||||||
|
|
||||||
fMetaCreated = true;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQMessageSHM::Rebuild()
|
|
||||||
{
|
|
||||||
CloseMessage();
|
|
||||||
|
|
||||||
fQueued = false;
|
|
||||||
|
|
||||||
if (zmq_msg_init(&fMessage) != 0) {
|
|
||||||
LOG(error) << "failed initializing message, reason: " << zmq_strerror(errno);
|
|
||||||
}
|
|
||||||
fMetaCreated = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQMessageSHM::Rebuild(const size_t size)
|
|
||||||
{
|
|
||||||
CloseMessage();
|
|
||||||
fQueued = false;
|
|
||||||
InitializeChunk(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQMessageSHM::Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
|
||||||
{
|
|
||||||
CloseMessage();
|
|
||||||
|
|
||||||
fQueued = false;
|
|
||||||
|
|
||||||
if (InitializeChunk(size)) {
|
|
||||||
memcpy(fLocalPtr, data, size);
|
|
||||||
if (ffn) {
|
|
||||||
ffn(data, hint);
|
|
||||||
} else {
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void* FairMQMessageSHM::GetData() const
|
|
||||||
{
|
|
||||||
if (!fLocalPtr) {
|
|
||||||
if (fRegionId == 0) {
|
|
||||||
if (fSize > 0) {
|
|
||||||
fLocalPtr = reinterpret_cast<char*>(fManager.Segment().get_address_from_handle(fHandle));
|
|
||||||
} else {
|
|
||||||
fLocalPtr = nullptr;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
fRegionPtr = fManager.GetRemoteRegion(fRegionId);
|
|
||||||
if (fRegionPtr) {
|
|
||||||
fLocalPtr = reinterpret_cast<char*>(fRegionPtr->fRegion.get_address()) + fHandle;
|
|
||||||
} else {
|
|
||||||
// LOG(warn) << "could not get pointer from a region message";
|
|
||||||
fLocalPtr = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return fLocalPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FairMQMessageSHM::SetUsedSize(const size_t size)
|
|
||||||
{
|
|
||||||
if (size == fSize) {
|
|
||||||
return true;
|
|
||||||
} else if (size <= fSize) {
|
|
||||||
try {
|
|
||||||
bipc::managed_shared_memory::size_type shrunkSize = size;
|
|
||||||
fLocalPtr = fManager.Segment().allocation_command<char>(bipc::shrink_in_place, fSize + 128, shrunkSize, fLocalPtr);
|
|
||||||
fSize = size;
|
|
||||||
|
|
||||||
// update meta header
|
|
||||||
MetaHeader* hdrPtr = static_cast<MetaHeader*>(zmq_msg_data(&fMessage));
|
|
||||||
hdrPtr->fSize = fSize;
|
|
||||||
return true;
|
|
||||||
} catch (bipc::interprocess_exception& e) {
|
|
||||||
LOG(info) << "could not set used size: " << e.what();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(error) << "cannot set used size higher than original.";
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQMessageSHM::Copy(const FairMQMessage& msg)
|
|
||||||
{
|
|
||||||
if (fHandle < 0) {
|
|
||||||
bipc::managed_shared_memory::handle_t otherHandle = static_cast<const FairMQMessageSHM&>(msg).fHandle;
|
|
||||||
if (otherHandle) {
|
|
||||||
if (InitializeChunk(msg.GetSize())) {
|
|
||||||
memcpy(GetData(), msg.GetData(), msg.GetSize());
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(error) << "copy fail: source message not initialized!";
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
LOG(error) << "copy fail: target message already initialized!";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FairMQMessageSHM::CloseMessage()
|
|
||||||
{
|
|
||||||
if (fHandle >= 0 && !fQueued) {
|
|
||||||
if (fRegionId == 0) {
|
|
||||||
fManager.Segment().deallocate(fManager.Segment().get_address_from_handle(fHandle));
|
|
||||||
fHandle = -1;
|
|
||||||
} else {
|
|
||||||
if (!fRegionPtr) {
|
|
||||||
fRegionPtr = fManager.GetRemoteRegion(fRegionId);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fRegionPtr) {
|
|
||||||
fRegionPtr->ReleaseBlock({fHandle, fSize, fHint});
|
|
||||||
} else {
|
|
||||||
LOG(warn) << "region ack queue for id " << fRegionId << " no longer exist. Not sending ack";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fMetaCreated) {
|
|
||||||
if (zmq_msg_close(&fMessage) != 0) {
|
|
||||||
LOG(error) << "failed closing message, reason: " << zmq_strerror(errno);
|
|
||||||
}
|
|
||||||
fMetaCreated = false;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,72 +0,0 @@
|
|||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2014 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 FAIRMQMESSAGESHM_H_
|
|
||||||
#define FAIRMQMESSAGESHM_H_
|
|
||||||
|
|
||||||
#include <fairmq/shmem/Manager.h>
|
|
||||||
|
|
||||||
#include "FairMQMessage.h"
|
|
||||||
#include "FairMQUnmanagedRegion.h"
|
|
||||||
|
|
||||||
#include <zmq.h>
|
|
||||||
|
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
|
||||||
|
|
||||||
#include <cstddef> // size_t
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
class FairMQSocketSHM;
|
|
||||||
|
|
||||||
class FairMQMessageSHM final : public FairMQMessage
|
|
||||||
{
|
|
||||||
friend class FairMQSocketSHM;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FairMQMessageSHM(fair::mq::shmem::Manager& manager, FairMQTransportFactory* factory = nullptr);
|
|
||||||
FairMQMessageSHM(fair::mq::shmem::Manager& manager, const size_t size, FairMQTransportFactory* factory = nullptr);
|
|
||||||
FairMQMessageSHM(fair::mq::shmem::Manager& manager, void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr, FairMQTransportFactory* factory = nullptr);
|
|
||||||
FairMQMessageSHM(fair::mq::shmem::Manager& manager, FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, FairMQTransportFactory* factory = nullptr);
|
|
||||||
|
|
||||||
FairMQMessageSHM(const FairMQMessageSHM&) = delete;
|
|
||||||
FairMQMessageSHM operator=(const FairMQMessageSHM&) = delete;
|
|
||||||
|
|
||||||
void Rebuild() override;
|
|
||||||
void Rebuild(const size_t size) override;
|
|
||||||
void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
|
||||||
|
|
||||||
void* GetData() const override;
|
|
||||||
size_t GetSize() const override { return fSize; }
|
|
||||||
|
|
||||||
bool SetUsedSize(const size_t size) override;
|
|
||||||
|
|
||||||
fair::mq::Transport GetType() const override { return fTransportType; }
|
|
||||||
|
|
||||||
void Copy(const FairMQMessage& msg) override;
|
|
||||||
|
|
||||||
~FairMQMessageSHM() override { CloseMessage(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
fair::mq::shmem::Manager& fManager;
|
|
||||||
zmq_msg_t fMessage;
|
|
||||||
bool fQueued;
|
|
||||||
bool fMetaCreated;
|
|
||||||
static std::atomic<bool> fInterrupted;
|
|
||||||
static fair::mq::Transport fTransportType;
|
|
||||||
size_t fRegionId;
|
|
||||||
mutable fair::mq::shmem::Region* fRegionPtr;
|
|
||||||
boost::interprocess::managed_shared_memory::handle_t fHandle;
|
|
||||||
size_t fSize;
|
|
||||||
size_t fHint;
|
|
||||||
mutable char* fLocalPtr;
|
|
||||||
|
|
||||||
bool InitializeChunk(const size_t size);
|
|
||||||
zmq_msg_t* GetMessage() { return &fMessage; }
|
|
||||||
void CloseMessage();
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FAIRMQMESSAGESHM_H_ */
|
|
@@ -1,67 +0,0 @@
|
|||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2016-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 FAIRMQTRANSPORTFACTORYSHM_H_
|
|
||||||
#define FAIRMQTRANSPORTFACTORYSHM_H_
|
|
||||||
|
|
||||||
#include <fairmq/shmem/Manager.h>
|
|
||||||
#include <fairmq/shmem/Common.h>
|
|
||||||
|
|
||||||
#include "FairMQTransportFactory.h"
|
|
||||||
#include "FairMQMessageSHM.h"
|
|
||||||
#include "FairMQSocketSHM.h"
|
|
||||||
#include "FairMQPollerSHM.h"
|
|
||||||
#include "FairMQUnmanagedRegionSHM.h"
|
|
||||||
#include <fairmq/ProgOptions.h>
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <thread>
|
|
||||||
#include <atomic>
|
|
||||||
|
|
||||||
class FairMQTransportFactorySHM final : public FairMQTransportFactory
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FairMQTransportFactorySHM(const std::string& id = "", const fair::mq::ProgOptions* config = nullptr);
|
|
||||||
FairMQTransportFactorySHM(const FairMQTransportFactorySHM&) = delete;
|
|
||||||
FairMQTransportFactorySHM operator=(const FairMQTransportFactorySHM&) = delete;
|
|
||||||
|
|
||||||
FairMQMessagePtr CreateMessage() override;
|
|
||||||
FairMQMessagePtr CreateMessage(const size_t size) override;
|
|
||||||
FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
|
||||||
FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0) override;
|
|
||||||
|
|
||||||
FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) override;
|
|
||||||
|
|
||||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const override;
|
|
||||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const override;
|
|
||||||
FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const override;
|
|
||||||
|
|
||||||
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0) const override;
|
|
||||||
|
|
||||||
fair::mq::Transport GetType() const override;
|
|
||||||
|
|
||||||
void Interrupt() override { FairMQSocketSHM::Interrupt(); }
|
|
||||||
void Resume() override { FairMQSocketSHM::Resume(); }
|
|
||||||
void Reset() override {}
|
|
||||||
|
|
||||||
~FairMQTransportFactorySHM() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void SendHeartbeats();
|
|
||||||
|
|
||||||
static fair::mq::Transport fTransportType;
|
|
||||||
std::string fDeviceId;
|
|
||||||
std::string fShmId;
|
|
||||||
void* fZMQContext;
|
|
||||||
std::unique_ptr<fair::mq::shmem::Manager> fManager;
|
|
||||||
std::thread fHeartbeatThread;
|
|
||||||
std::atomic<bool> fSendHeartbeats;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FAIRMQTRANSPORTFACTORYSHM_H_ */
|
|
@@ -1,43 +0,0 @@
|
|||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2014 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 "Common.h"
|
|
||||||
|
|
||||||
#include "FairMQUnmanagedRegionSHM.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
using namespace fair::mq::shmem;
|
|
||||||
|
|
||||||
namespace bipc = ::boost::interprocess;
|
|
||||||
|
|
||||||
FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_t size, FairMQRegionCallback callback, const std::string& path /* = "" */, int flags /* = 0 */)
|
|
||||||
: fManager(manager)
|
|
||||||
, fRegion(nullptr)
|
|
||||||
, fRegionId(0)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
RegionCounter* rc = fManager.ManagementSegment().find<RegionCounter>(bipc::unique_instance).first;
|
|
||||||
if (rc) {
|
|
||||||
LOG(debug) << "region counter found, with value of " << rc->fCount << ". incrementing.";
|
|
||||||
(rc->fCount)++;
|
|
||||||
LOG(debug) << "incremented region counter, now: " << rc->fCount;
|
|
||||||
} else {
|
|
||||||
LOG(debug) << "no region counter found, creating one and initializing with 1";
|
|
||||||
rc = fManager.ManagementSegment().construct<RegionCounter>(bipc::unique_instance)(1);
|
|
||||||
LOG(debug) << "initialized region counter with: " << rc->fCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
fRegionId = rc->fCount;
|
|
||||||
|
|
||||||
fRegion = fManager.CreateRegion(size, fRegionId, callback, path, flags);
|
|
||||||
} catch (bipc::interprocess_exception& e) {
|
|
||||||
LOG(error) << "cannot create region. Already created/not cleaned up?";
|
|
||||||
LOG(error) << e.what();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,42 +0,0 @@
|
|||||||
/********************************************************************************
|
|
||||||
* Copyright (C) 2014 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 FAIRMQUNMANAGEDREGIONSHM_H_
|
|
||||||
#define FAIRMQUNMANAGEDREGIONSHM_H_
|
|
||||||
|
|
||||||
#include <fairmq/shmem/Manager.h>
|
|
||||||
|
|
||||||
#include "FairMQUnmanagedRegion.h"
|
|
||||||
#include "FairMQLogger.h"
|
|
||||||
|
|
||||||
#include <boost/interprocess/shared_memory_object.hpp>
|
|
||||||
#include <boost/interprocess/mapped_region.hpp>
|
|
||||||
|
|
||||||
#include <cstddef> // size_t
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
class FairMQUnmanagedRegionSHM final : public FairMQUnmanagedRegion
|
|
||||||
{
|
|
||||||
friend class FairMQSocketSHM;
|
|
||||||
friend class FairMQMessageSHM;
|
|
||||||
|
|
||||||
public:
|
|
||||||
FairMQUnmanagedRegionSHM(fair::mq::shmem::Manager& manager, const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0);
|
|
||||||
|
|
||||||
void* GetData() const override { return fRegion->get_address(); }
|
|
||||||
size_t GetSize() const override { return fRegion->get_size(); }
|
|
||||||
|
|
||||||
~FairMQUnmanagedRegionSHM() override { fManager.RemoveRegion(fRegionId); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
fair::mq::shmem::Manager& fManager;
|
|
||||||
boost::interprocess::mapped_region* fRegion;
|
|
||||||
uint64_t fRegionId;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* FAIRMQUNMANAGEDREGIONSHM_H_ */
|
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user