mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 17:41:45 +00:00
Compare commits
1 Commits
v1.4.5
...
v1.2.7-pat
Author | SHA1 | Date | |
---|---|---|---|
|
e642262468 |
@@ -1,33 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Mozilla
|
||||
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: true
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: NonAssignment
|
||||
BreakConstructorInitializers: BeforeComma
|
||||
ColumnLimit: 100
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: true
|
||||
DerivePointerAlignment: true
|
||||
FixNamespaceComments: true
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: true
|
||||
IncludeBlocks: Regroup
|
||||
NamespaceIndentation: None
|
||||
PointerAlignment: Left
|
||||
SortIncludes: true
|
||||
SpacesBeforeTrailingComments: 3
|
||||
Standard: Cpp11
|
||||
UseTab: Never
|
||||
...
|
@@ -1,2 +0,0 @@
|
||||
comment:
|
||||
layout: "diff, files"
|
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,30 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Describe environment
|
||||
2. Describe compile options used
|
||||
3. Give commands you invoked
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Logs / Screenshots**
|
||||
If applicable, add logs or screenshots to help explain your problem.
|
||||
|
||||
**System information (please complete the following information):**
|
||||
- OS: [e.g. MacOS 10.13, Fedora 28, Ubuntu 14.04]
|
||||
- Compiler: [e.g. GCC 8.1, Clang 3.5]
|
||||
- Environment: [e.g. FairSoft version, alfadist revision]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
|
||||
See [github markdown cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) on how to format inline codes examples and logs.
|
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,17 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
7
.github/ISSUE_TEMPLATE/question.md
vendored
7
.github/ISSUE_TEMPLATE/question.md
vendored
@@ -1,7 +0,0 @@
|
||||
---
|
||||
name: Question / Support
|
||||
about: Any FairMQ related matter you are interested in
|
||||
|
||||
---
|
||||
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,3 @@
|
||||
build
|
||||
|
||||
.DS_Store
|
||||
|
||||
.vscode
|
||||
|
208
CMakeLists.txt
208
CMakeLists.txt
@@ -6,24 +6,19 @@
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
cmake_policy(VERSION 3.10...3.14)
|
||||
cmake_minimum_required(VERSION 3.9.4 FATAL_ERROR)
|
||||
|
||||
|
||||
# Project ######################################################################
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||
include(FairMQLib)
|
||||
|
||||
set_fairmq_cmake_policies()
|
||||
get_git_version()
|
||||
|
||||
project(FairMQ VERSION ${PROJECT_VERSION} LANGUAGES CXX)
|
||||
message(STATUS "${BWhite}${PROJECT_NAME}${CR} ${PROJECT_GIT_VERSION} from ${PROJECT_DATE}")
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(PROJECT_MIN_CXX_STANDARD 14)
|
||||
else()
|
||||
set(PROJECT_MIN_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
set_fairmq_defaults()
|
||||
|
||||
include(CTest)
|
||||
@@ -37,99 +32,45 @@ cmake_dependent_option(BUILD_TESTING "Build tests." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_NANOMSG_TRANSPORT "Build nanomsg transport." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_PMIX_PLUGIN "Build PMIx plugin." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
|
||||
option(BUILD_DOCS "Build FairMQ documentation." OFF)
|
||||
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
|
||||
################################################################################
|
||||
|
||||
|
||||
# Dependencies #################################################################
|
||||
if(FAST_BUILD)
|
||||
include(cotire)
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
|
||||
COMPONENTS program_options thread system filesystem regex date_time signals
|
||||
)
|
||||
find_package2(PUBLIC FairLogger VERSION 1.2.0 REQUIRED)
|
||||
find_package2(PRIVATE ZeroMQ VERSION 4.1.5 REQUIRED)
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE nanomsg REQUIRED)
|
||||
set(PROJECT_nanomsg_VERSION 1.1.3) # Once upstream releases 1.1.5, we should bump again and use version check
|
||||
find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED)
|
||||
find_package2(PRIVATE msgpack VERSION 3.0.0)
|
||||
set(PROJECT_msgpack_VERSION 2.1.5)
|
||||
if(NOT msgpack_FOUND)
|
||||
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
|
||||
endif()
|
||||
set(msgpack_ROOT ${PACKAGE_PREFIX_DIR})
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
find_package2(PRIVATE asiofi REQUIRED
|
||||
VERSION 0.3.1
|
||||
)
|
||||
find_package2(PRIVATE OFI REQUIRED
|
||||
ADD_REQUIREMENTS_OF asiofi
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE msgpack REQUIRED
|
||||
VERSION 3.1.0
|
||||
)
|
||||
find_package2(PRIVATE OFI VERSION 1.6.0 REQUIRED COMPONENTS fi_sockets fi_verbs)
|
||||
find_package2(PRIVATE Protobuf VERSION 3.4.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
find_package2(PRIVATE DDS REQUIRED
|
||||
VERSION 2.4
|
||||
)
|
||||
set(DDS_Boost_COMPONENTS system log log_setup)
|
||||
set(DDS_Boost_VERSION 1.67)
|
||||
endif()
|
||||
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
find_package2(PRIVATE PMIx REQUIRED
|
||||
VERSION 2.1.4
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PUBLIC FairLogger REQUIRED
|
||||
VERSION 1.2.0
|
||||
)
|
||||
|
||||
if(NOT DEFINED Boost_NO_BOOST_CMAKE AND CMAKE_VERSION VERSION_LESS 3.15)
|
||||
# Since Boost 1.70 a CMake package is shipped by default. Unfortunately, it has a number
|
||||
# of problems that are only fixed in Boost 1.71 or CMake 3.15. By default we skip the
|
||||
# BoostConfig lookup. This can be overridden on the command line via -DBoost_NO_BOOST_CMAKE=OFF
|
||||
set(Boost_NO_BOOST_CMAKE ON)
|
||||
endif()
|
||||
find_package2(PUBLIC Boost REQUIRED
|
||||
VERSION 1.64
|
||||
|
||||
COMPONENTS
|
||||
container
|
||||
program_options
|
||||
filesystem
|
||||
date_time
|
||||
regex
|
||||
|
||||
ADD_REQUIREMENTS_OF
|
||||
asiofi
|
||||
DDS
|
||||
FairLogger
|
||||
)
|
||||
find_package2(PRIVATE ZeroMQ REQUIRED
|
||||
VERSION 4.1.5
|
||||
)
|
||||
find_package2(PRIVATE DDS VERSION 2.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package2(PRIVATE GTest REQUIRED
|
||||
VERSION 1.7.0
|
||||
)
|
||||
find_package2(PRIVATE GTest VERSION 1.7.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_DOCS)
|
||||
find_package2(PRIVATE Doxygen REQUIRED
|
||||
VERSION 1.8.8
|
||||
COMPONENTS dot
|
||||
OPTIONAL_COMPONENTS mscgen dia
|
||||
)
|
||||
find_package2(PRIVATE Doxygen VERSION 1.8.8 REQUIRED COMPONENTS dot OPTIONAL_COMPONENTS mscgen dia)
|
||||
endif()
|
||||
################################################################################
|
||||
|
||||
@@ -155,7 +96,7 @@ endif()
|
||||
if(BUILD_DOCS)
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY doxygen)
|
||||
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_GIT_VERSION})
|
||||
set(DOXYGEN_PROJECT_BRIEF "C++ Message Queuing Library and Framework")
|
||||
set(DOXYGEN_PROJECT_BRIEF "C++ Message Passing Framework")
|
||||
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md)
|
||||
set(DOXYGEN_HTML_FOOTER docs/footer.html)
|
||||
doxygen_add_docs(doxygen README.md fairmq)
|
||||
@@ -174,9 +115,6 @@ endif()
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS dds_plugin)
|
||||
endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
||||
endif()
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS nanomsg_transport)
|
||||
endif()
|
||||
@@ -202,6 +140,21 @@ if(BUILD_FAIRMQ)
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
install(FILES cmake/FindDDS.cmake
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
install(FILES cmake/Findnanomsg.cmake
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
install(FILES cmake/FindOFI.cmake
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
if(BUILD_DOCS)
|
||||
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
|
||||
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
|
||||
@@ -213,42 +166,13 @@ install_cmake_package()
|
||||
|
||||
|
||||
# Summary ######################################################################
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}CXX STANDARD${CR} ${BGreen}C++${CMAKE_CXX_STANDARD}${CR} (>= C++${PROJECT_MIN_CXX_STANDARD}, change with ${BMagenta}-DCMAKE_CXX_STANDARD=17${CR})")
|
||||
if(CMAKE_CXX_FLAGS)
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}GLOBAL CXX FLAGS${CR} ${BGreen}${CMAKE_CXX_FLAGS}${CR}")
|
||||
endif()
|
||||
if(CMAKE_CONFIGURATION_TYPES)
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}BUILD TYPE CXX FLAGS${CR}")
|
||||
string(TOUPPER "${CMAKE_BUILD_TYPE}" selected_type)
|
||||
foreach(type IN LISTS CMAKE_CONFIGURATION_TYPES)
|
||||
string(TOUPPER "${type}" type_upper)
|
||||
if(type_upper STREQUAL selected_type)
|
||||
pad("${type}" 18 " " type_padded)
|
||||
message(STATUS "${BGreen}* ${type_padded}${CMAKE_CXX_FLAGS_${type_upper}}${CR}")
|
||||
else()
|
||||
pad("${type}" 18 " " type_padded)
|
||||
message(STATUS " ${BWhite}${type_padded}${CR}${CMAKE_CXX_FLAGS_${type_upper}}")
|
||||
endif()
|
||||
unset(type_padded)
|
||||
unset(type_upper)
|
||||
endforeach()
|
||||
message(STATUS " ")
|
||||
message(STATUS " (Change the build type with ${BMagenta}-DCMAKE_BUILD_TYPE=...${CR})")
|
||||
endif()
|
||||
if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}")
|
||||
foreach(dep IN LISTS PROJECT_PACKAGE_DEPENDENCIES)
|
||||
if(${dep}_VERSION)
|
||||
if(${dep} STREQUAL Boost)
|
||||
if(Boost_VERSION_MAJOR)
|
||||
set(version_str "${BGreen}${${dep}_VERSION_MAJOR}.${${dep}_VERSION_MINOR}${CR}")
|
||||
else()
|
||||
set(version_str "${BGreen}${${dep}_MAJOR_VERSION}.${${dep}_MINOR_VERSION}${CR}")
|
||||
endif()
|
||||
set(version_str "${BGreen}${${dep}_MAJOR_VERSION}.${${dep}_MINOR_VERSION}${CR}")
|
||||
else()
|
||||
set(version_str "${BGreen}${${dep}_VERSION}${CR}")
|
||||
endif()
|
||||
@@ -265,33 +189,13 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
pad("${version_str}${version_req_str}" 25 " " version_padded COLOR 1)
|
||||
endif()
|
||||
if(${dep} STREQUAL FairLogger)
|
||||
if(FairLogger_PREFIX)
|
||||
set(prefix ${FairLogger_PREFIX})
|
||||
else()
|
||||
set(prefix ${FairLogger_ROOT})
|
||||
endif()
|
||||
set(prefix ${FairLogger_ROOT})
|
||||
elseif(${dep} STREQUAL GTest)
|
||||
get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL msgpack)
|
||||
get_target_property(msgpack_include msgpackc-cxx INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${msgpack_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL asiofi)
|
||||
set(prefix ${asiofi_ROOT})
|
||||
set(prefix ${msgpack_ROOT})
|
||||
elseif(${dep} STREQUAL OFI)
|
||||
get_filename_component(prefix ${${dep}_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL nanomsg)
|
||||
get_target_property(nn_include nanomsg INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${nn_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL DDS)
|
||||
get_target_property(dds_include DDS::dds_intercom_lib INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${dds_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL Boost)
|
||||
if(TARGET Boost::headers)
|
||||
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
|
||||
else()
|
||||
get_target_property(boost_include Boost::boost INTERFACE_INCLUDE_DIRECTORIES)
|
||||
endif()
|
||||
get_filename_component(prefix ${boost_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL Doxygen)
|
||||
get_target_property(doxygen_bin Doxygen::doxygen INTERFACE_LOCATION)
|
||||
get_filename_component(prefix ${doxygen_bin} DIRECTORY)
|
||||
@@ -326,9 +230,9 @@ else()
|
||||
endif()
|
||||
message(STATUS " ${BWhite}nanomsg_transport${CR} ${nn_summary}")
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (requires C++14) (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
|
||||
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
|
||||
else()
|
||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (requires C++14) (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
@@ -337,12 +241,6 @@ else()
|
||||
set(dds_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DDS_PLUGIN=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
set(pmix_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
||||
else()
|
||||
set(pmix_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_PMIX_PLUGIN=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}pmix_plugin${CR} ${pmix_summary}")
|
||||
if(BUILD_EXAMPLES)
|
||||
set(examples_summary "${BGreen}YES${CR} (default, disable with ${BMagenta}-DBUILD_EXAMPLES=OFF${CR})")
|
||||
else()
|
||||
@@ -356,26 +254,4 @@ else()
|
||||
endif()
|
||||
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
|
||||
message(STATUS " ")
|
||||
if(RUN_STATIC_ANALYSIS)
|
||||
list(LENGTH PROJECT_STATIC_ANALYSERS size)
|
||||
unset(analyser_list)
|
||||
set(count 0)
|
||||
foreach(analyser IN LISTS PROJECT_STATIC_ANALYSERS)
|
||||
if(${analyser}_FOUND)
|
||||
set(${analyser}_status "${analyser} ${BGreen}YES${CR}")
|
||||
else()
|
||||
set(${analyser}_status "${analyser} ${BRed}NO${CR}")
|
||||
endif()
|
||||
math(EXPR count "${count} + 1")
|
||||
string(APPEND analyser_list "${${analyser}_status}")
|
||||
if(count LESS size)
|
||||
string(APPEND analyser_list "${BWhite},${CR} ")
|
||||
endif()
|
||||
endforeach()
|
||||
set(static_ana_summary "${BWhite}(${CR}${analyser_list}${BWhite})${CR} (disable with ${BMagenta}-DRUN_STATIC_ANALYSIS=OFF${CR})")
|
||||
else()
|
||||
set(static_ana_summary "${BRed}OFF${CR} (default, enable with ${BMagenta}-DRUN_STATIC_ANALYSIS=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${Cyan}RUN STATIC ANALYSIS ${static_ana_summary}")
|
||||
message(STATUS " ")
|
||||
################################################################################
|
||||
|
@@ -4,7 +4,6 @@ Eulisse, Giulio
|
||||
Karabowicz, Radoslaw
|
||||
Kretz, Matthias <kretz@kde.org>
|
||||
Krzewicki, Mikolaj
|
||||
Mrnjavac, Teo <teo.m@cern.ch>
|
||||
Neskovic, Gvozden
|
||||
Richter, Matthias
|
||||
Uhlig, Florian
|
||||
|
41
COPYRIGHT
41
COPYRIGHT
@@ -1,41 +0,0 @@
|
||||
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: FairMQ
|
||||
Upstream-Contact: Mohammad Al-Turany <m.al-turany@gsi.de>
|
||||
Source: https://github.com/FairRootGroup/FairMQ
|
||||
|
||||
Files: *
|
||||
Copyright: 2012-2018, GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
|
||||
Copyright: 2012-2018, [see AUTHORS file]
|
||||
Copyright: 2012-2018, [see CONTRIBUTORS file]
|
||||
Comment: The copyright of individual contributors is documented in the
|
||||
Git history.
|
||||
License: LGPL-3.0-only
|
||||
|
||||
Files: cmake/cotire.cmake
|
||||
Copyright: 2012-2018 Sascha Kratky
|
||||
License: COTIRE
|
||||
|
||||
License: LGPL-3.0-only
|
||||
[see LICENSE file]
|
||||
|
||||
License: COTIRE
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
40
Dart.sh
40
Dart.sh
@@ -41,15 +41,13 @@ if [ "$#" -lt "2" ]; then
|
||||
fi
|
||||
|
||||
# test if a valid ctest model is defined
|
||||
case "$1" in
|
||||
Experimental|Nightly|Continuous|Profile|alfa_ci|codecov)
|
||||
;;
|
||||
*)
|
||||
echo "-- Error -- This ctest model is not supported."
|
||||
echo "-- Error -- Possible arguments are Nightly, Experimental, Continuous or Profile."
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
if [ "$1" == "Experimental" -o "$1" == "Nightly" -o "$1" == "Continuous" -o "$1" == "Profile" -o "$1" == "alfa_ci" ]; then
|
||||
echo ""
|
||||
else
|
||||
echo "-- Error -- This ctest model is not supported."
|
||||
echo "-- Error -- Possible arguments are Nightly, Experimental, Continuous or Profile."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# test if the input file exists and execute it
|
||||
if [ -e "$2" ];then
|
||||
@@ -63,9 +61,6 @@ fi
|
||||
# set the ctest model to command line parameter
|
||||
if [ "$1" == "alfa_ci" ]; then
|
||||
export ctest_model=Experimental
|
||||
elif [ "$1" == "codecov" ]; then
|
||||
export ctest_model=Profile
|
||||
export do_codecov_upload=1
|
||||
else
|
||||
export ctest_model=$1
|
||||
fi
|
||||
@@ -88,20 +83,13 @@ else
|
||||
COMPILER=$CXX$($CXX -dumpversion)
|
||||
fi
|
||||
|
||||
case "$1" in
|
||||
alfa_ci)
|
||||
export LABEL1=alfa_ci-$COMPILER-FairMQ_$GIT_BRANCH
|
||||
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
|
||||
;;
|
||||
codecov)
|
||||
export LABEL1=codecov-$COMPILER-FairMQ_$GIT_BRANCH
|
||||
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
|
||||
;;
|
||||
*)
|
||||
export LABEL1=${LINUX_FLAVOUR}-$chip-$COMPILER-FairMQ_$GIT_BRANCH
|
||||
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
|
||||
;;
|
||||
esac
|
||||
if [ "$1" == "alfa_ci" ]; then
|
||||
export LABEL1=alfa_ci-$COMPILER-FairMQ_$GIT_BRANCH
|
||||
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
|
||||
else
|
||||
export LABEL1=${LINUX_FLAVOUR}-$chip-$COMPILER-FairMQ_$GIT_BRANCH
|
||||
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
|
||||
fi
|
||||
|
||||
# get the number of processors
|
||||
# and information about the host
|
||||
|
@@ -19,7 +19,7 @@ Set(BUILD_COMMAND "make")
|
||||
Set(CTEST_BUILD_COMMAND "${BUILD_COMMAND} -j$ENV{number_of_processors}")
|
||||
|
||||
String(TOUPPER $ENV{ctest_model} _Model)
|
||||
Set(configure_options "-DCMAKE_BUILD_TYPE=$ENV{ctest_model}")
|
||||
Set(configure_options "-DCMAKE_BUILD_TYPE=${_Model}")
|
||||
|
||||
Set(CTEST_USE_LAUNCHERS 1)
|
||||
Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LAUNCHERS}")
|
||||
@@ -27,26 +27,25 @@ Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LA
|
||||
Set(configure_options "${configure_options};-DDISABLE_COLOR=ON")
|
||||
Set(configure_options "${configure_options};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
|
||||
Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON")
|
||||
# Set(configure_options "${configure_options};-DBUILD_OFI_TRANSPORT=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=ON")
|
||||
Set(configure_options "${configure_options};-DFAST_BUILD=ON")
|
||||
Set(configure_options "${configure_options};-DCOTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES=-j$ENV{number_of_processors}")
|
||||
|
||||
Set(EXTRA_FLAGS $ENV{EXTRA_FLAGS})
|
||||
If(EXTRA_FLAGS)
|
||||
Set(configure_options "${configure_options};${EXTRA_FLAGS}")
|
||||
EndIf()
|
||||
|
||||
If($ENV{ctest_model} MATCHES Profile)
|
||||
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
|
||||
|
||||
Find_Program(GCOV_COMMAND gcov)
|
||||
If(GCOV_COMMAND)
|
||||
Message("Found GCOV: ${GCOV_COMMAND}")
|
||||
Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND})
|
||||
EndIf(GCOV_COMMAND)
|
||||
EndIf()
|
||||
|
||||
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
|
||||
Ctest_Empty_Binary_Directory(${CTEST_BINARY_DIRECTORY})
|
||||
Set(ENV{ctest_model} Nightly)
|
||||
|
||||
CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
|
||||
|
||||
EndIf()
|
||||
|
||||
Ctest_Start($ENV{ctest_model})
|
||||
@@ -58,30 +57,12 @@ Ctest_Configure(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
Ctest_Build(BUILD "${CTEST_BINARY_DIRECTORY}")
|
||||
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
# PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
PARALLEL_LEVEL 1
|
||||
PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
RETURN_VALUE _ctest_test_ret_val
|
||||
)
|
||||
If("$ENV{do_codecov_upload}")
|
||||
ForEach(i RANGE 4)
|
||||
# Gather statistics to catch time sensitive branches
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
)
|
||||
EndForEach()
|
||||
EndIf()
|
||||
|
||||
If(GCOV_COMMAND)
|
||||
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}" LABELS coverage)
|
||||
EndIf()
|
||||
|
||||
If("$ENV{do_codecov_upload}")
|
||||
Execute_Process(COMMAND curl https://codecov.io/bash -o codecov_uploader.sh
|
||||
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
|
||||
TIMEOUT 60)
|
||||
Execute_Process(COMMAND bash ./codecov_uploader.sh -X gcov
|
||||
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
|
||||
TIMEOUT 60)
|
||||
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}")
|
||||
EndIf()
|
||||
|
||||
Ctest_Submit()
|
||||
|
67
Jenkinsfile
vendored
67
Jenkinsfile
vendored
@@ -4,53 +4,24 @@ def specToLabel(Map spec) {
|
||||
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}"
|
||||
}
|
||||
|
||||
def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
def buildMatrix(List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def fairsoft = spec.fairsoft
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes["${prefix}/${label}"] = {
|
||||
nodes[label] = {
|
||||
node(label) {
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Building ...', status: 'PENDING')
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
}
|
||||
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Success', status: 'SUCCESS')
|
||||
} catch (e) {
|
||||
deleteDir()
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Error', status: 'ERROR')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -62,26 +33,22 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
pipeline{
|
||||
agent none
|
||||
stages {
|
||||
stage("Run CI Matrix") {
|
||||
stage("Run Build/Test Matrix") {
|
||||
steps{
|
||||
script {
|
||||
def build_jobs = jobMatrix('alfa-ci/build', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
parallel(buildMatrix([
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.11', arch: 'x86_64', compiler: 'AppleLLVM8.0.0', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
|
||||
]) { spec, label ->
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
|
||||
'''
|
||||
sh './Dart.sh alfa_ci Dart.cfg'
|
||||
}
|
||||
|
||||
def profile_jobs = jobMatrix('alfa-ci/codecov', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
|
||||
sh './Dart.sh codecov Dart.cfg'
|
||||
}
|
||||
}
|
||||
|
||||
parallel(build_jobs + profile_jobs)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -8,40 +8,12 @@ def buildMatrix(List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def fairsoft = spec.fairsoft
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes[label] = {
|
||||
node(label) {
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
}
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=dev" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
@@ -63,10 +35,16 @@ pipeline{
|
||||
steps{
|
||||
script {
|
||||
parallel(buildMatrix([
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.11', arch: 'x86_64', compiler: 'AppleLLVM8.0.0', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
|
||||
]) { spec, label ->
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=dev" >> Dart.cfg
|
||||
'''
|
||||
sh './Dart.sh Nightly Dart.cfg'
|
||||
sh './Dart.sh Profile Dart.cfg'
|
||||
})
|
||||
|
2
LICENSE
2
LICENSE
@@ -1,4 +1,4 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
|
@@ -1,6 +1,4 @@
|
||||
Describe your proposal.
|
||||
|
||||
Mention any issue this PR resolves or is related to.
|
||||
Replace me with your description.
|
||||
|
||||
---
|
||||
|
69
README.md
69
README.md
@@ -1,16 +1,12 @@
|
||||
<!-- {#mainpage} -->
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) [](https://scan.coverity.com/projects/fairrootgroup-fairmq) [](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&utm_medium=referral&utm_content=FairRootGroup/FairMQ&utm_campaign=Badge_Grade)
|
||||
# FairMQ
|
||||
|
||||
C++ Message Queuing Library and Framework
|
||||
C++ Message passing framework
|
||||
|
||||
| Release | Version | Docs |
|
||||
| :---: | :--- | :--- |
|
||||
| `stable` | [](https://github.com/FairRootGroup/FairMQ/releases/latest) | [API](https://fairrootgroup.github.io/FairMQ/latest), [Book](https://github.com/FairRootGroup/FairMQ/blob/master/README.md#documentation) |
|
||||
| `testing` | [](https://github.com/FairRootGroup/FairMQ/tags) | [Book](https://github.com/FairRootGroup/FairMQ/blob/dev/README.md#documentation) |
|
||||
|
||||
Find all FairMQ releases [here](https://github.com/FairRootGroup/FairMQ/releases).
|
||||
|
||||
## Introduction
|
||||
| Branch | Build Status |
|
||||
| :---: | :--- |
|
||||
| `master` |  |
|
||||
| `dev` |  |
|
||||
|
||||
FairMQ is designed to help implementing large-scale data processing workflows needed in next-generation Particle Physics experiments. FairMQ is written in C++ and aims to
|
||||
* provide **an asynchronous message passing abstraction** of different data transport technologies,
|
||||
@@ -35,13 +31,30 @@ a simulation, reconstruction and analysis framework.
|
||||
|
||||
## Dependencies
|
||||
|
||||
* PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger)
|
||||
* BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/)
|
||||
* PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/),
|
||||
[asiofi](https://github.com/FairRootGroup/asiofi), [DDS](http://dds.gsi.de), [PMIx](https://pmix.org/)
|
||||
* [**Boost**](https://www.boost.org/) (PUBLIC)
|
||||
* [**FairLogger**](https://github.com/FairRootGroup/FairLogger) (PUBLIC)
|
||||
* [CMake](https://cmake.org/) (BUILD)
|
||||
* [GTest](https://github.com/google/googletest) (BUILD, optional, `tests`)
|
||||
* [Doxygen](http://www.doxygen.org/) (BUILD, optional, `docs`)
|
||||
* [ZeroMQ](http://zeromq.org/) (PRIVATE)
|
||||
* [Msgpack](https://msgpack.org/index.html) (PRIVATE, optional, `nanomsg_transport`)
|
||||
* [nanomsg](http://nanomsg.org/) (PRIVATE, optional, `nanomsg_transport`)
|
||||
* [OFI](https://ofiwg.github.io/libfabric/) (PRIVATE, optional, `ofi_transport`)
|
||||
* [Protobuf](https://developers.google.com/protocol-buffers/) (PRIVATE, optional, `ofi_transport`)
|
||||
* [DDS](http://dds.gsi.de) (PRIVATE, optional, `dds_plugin`)
|
||||
|
||||
Supported platforms: Linux and MacOS.
|
||||
|
||||
## Releases
|
||||
|
||||
| Stable release | Date | API Docs |
|
||||
| --- | --- | --- |
|
||||
| [**1.2.3**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.3) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.3/index.html) |
|
||||
| [**1.2.1**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.1) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.1/index.html) |
|
||||
| [**1.2.0**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.0) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.0/index.html) |
|
||||
|
||||
Find all FairMQ stable and development releases [here](https://github.com/FairRootGroup/FairMQ/releases).
|
||||
|
||||
## Installation from Source
|
||||
|
||||
```bash
|
||||
@@ -51,7 +64,7 @@ cmake -DCMAKE_INSTALL_PREFIX=./fairmq_install ../fairmq
|
||||
cmake --build . --target install
|
||||
```
|
||||
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PMIX`, `ASIOFI` or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PROTOBUF`, or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -76,7 +89,7 @@ In order to succesfully compile and link against the `FairMQ::FairMQ` target, yo
|
||||
find_package(FairMQ)
|
||||
if(FairMQ_FOUND)
|
||||
find_package(FairLogger ${FairMQ_FairLogger_VERSION})
|
||||
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS})
|
||||
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
|
||||
endif()
|
||||
```
|
||||
|
||||
@@ -88,7 +101,7 @@ Optionally, you can require certain FairMQ package components and a minimum vers
|
||||
find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin)
|
||||
if(FairMQ_FOUND)
|
||||
find_package(FairLogger ${FairMQ_FairLogger_VERSION})
|
||||
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS})
|
||||
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
|
||||
endif()
|
||||
```
|
||||
|
||||
@@ -104,7 +117,6 @@ On command line:
|
||||
* `-DBUILD_NANOMSG_TRANSPORT=ON` enables building of nanomsg transport.
|
||||
* `-DBUILD_OFI_TRANSPORT=ON` enables building of the experimental OFI transport.
|
||||
* `-DBUILD_DDS_PLUGIN=ON` enables building of the DDS plugin.
|
||||
* `-DBUILD_PMIX_PLUGIN=ON` enables building of the PMIx plugin.
|
||||
* `-DBUILD_DOCS=ON` enables building of API docs.
|
||||
* You can hint non-system installations for dependent packages, see the #Installation section above
|
||||
|
||||
@@ -120,17 +132,15 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
| `${FairMQ_#COMPONENT#_FOUND}` | `TRUE` if this component was built |
|
||||
| `${FairMQ_VERSION}` | the version in format `MAJOR.MINOR.PATCH` |
|
||||
| `${FairMQ_GIT_VERSION}` | the version in the format returned by `git describe --tags --dirty --match "v*"` |
|
||||
| `${FairMQ_PREFIX}` | the actual installation prefix |
|
||||
| `${FairMQ_ROOT}` | the actual installation prefix, notice the difference to the hint variable `FAIRMQ_ROOT` |
|
||||
| `${FairMQ_BINDIR}` | the installation bin directory |
|
||||
| `${FairMQ_INCDIR}` | the installation include directory |
|
||||
| `${FairMQ_LIBDIR}` | the installation lib directory |
|
||||
| `${FairMQ_DATADIR}` | the installation data directory (`../share/fairmq`) |
|
||||
| `${FairMQ_CMAKEMODDIR}` | the installation directory of shipped CMake find modules |
|
||||
| `${FairMQ_CXX_STANDARD_REQUIRED}` | the value of `CMAKE_CXX_STANDARD_REQUIRED` at build-time |
|
||||
| `${FairMQ_CXX_STANDARD}` | the value of `CMAKE_CXX_STANDARD` at build-time |
|
||||
| `${FairMQ_CXX_EXTENSIONS}` | the values of `CMAKE_CXX_EXTENSIONS` at build-time |
|
||||
| `${FairMQ_BUILD_TYPE}` | the value of `CMAKE_BUILD_TYPE` at build-time |
|
||||
| `${FairMQ_CXX_FLAGS}` | the values of `CMAKE_CXX_FLAGS` and `CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}` at build-time |
|
||||
| `${FairMQ_CXX_STANDARD_REQUIRED}` | the value of `CMAKE_CXX_STANDARD_REQUIRED` at built-time |
|
||||
| `${FairMQ_CXX_STANDARD}` | the value of `CMAKE_CXX_STANDARD` at built-time |
|
||||
| `${FairMQ_CXX_EXTENSIONS}` | the values of `CMAKE_CXX_EXTENSIONS` at built-time |
|
||||
|
||||
## Documentation
|
||||
|
||||
@@ -159,10 +169,9 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
4. [File output](docs/Logging.md#54-file-output)
|
||||
5. [Custom sinks](docs/Logging.md#55-custom-sinks)
|
||||
6. [Examples](docs/Examples.md#6-examples)
|
||||
7. [Plugins](docs/Plugins.md#7-plugins)
|
||||
1. [Usage](docs/Plugins.md#71-usage)
|
||||
2. [Development](docs/Plugins.md#72-development)
|
||||
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
|
||||
1. [DDS](docs/Plugins.md#731-dds)
|
||||
2. [PMIx](docs/Plugins.md#732-pmix)
|
||||
|
||||
## License
|
||||
|
||||
GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE).
|
||||
|
||||
Copyright (C) 2013-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
|
||||
|
@@ -13,7 +13,7 @@ set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
|
||||
set(@PROJECT_NAME@_GIT_VERSION @PROJECT_GIT_VERSION@)
|
||||
set(@PROJECT_NAME@_GIT_DATE @PROJECT_GIT_DATE@)
|
||||
|
||||
set_and_check(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@)
|
||||
set_and_check(@PROJECT_NAME@_ROOT @PACKAGE_CMAKE_INSTALL_PREFIX@)
|
||||
set_and_check(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@)
|
||||
set_and_check(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
|
||||
set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@)
|
||||
@@ -23,10 +23,6 @@ set_and_check(@PROJECT_NAME@_CMAKEMODDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT
|
||||
set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@)
|
||||
set(@PROJECT_NAME@_CXX_STANDARD @CMAKE_CXX_STANDARD@)
|
||||
set(@PROJECT_NAME@_CXX_EXTENSIONS @CMAKE_CXX_EXTENSIONS@)
|
||||
set(@PROJECT_NAME@_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@)
|
||||
set(@PROJECT_NAME@_BUILD_TYPE @CMAKE_BUILD_TYPE@)
|
||||
set(@PROJECT_NAME@_BUILD_TYPE_UPPER @PROJECT_BUILD_TYPE_UPPER@)
|
||||
set(@PROJECT_NAME@_CXX_FLAGS @PROJECT_CXX_FLAGS@)
|
||||
|
||||
### Import cmake modules
|
||||
set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKEMODDIR} ${CMAKE_MODULE_PATH})
|
||||
|
@@ -29,6 +29,25 @@ if(NOT WIN32 AND NOT DISABLE_COLOR)
|
||||
set(BWhite "${Esc}[1;37m")
|
||||
endif()
|
||||
|
||||
# set_fairmq_cmake_policies()
|
||||
#
|
||||
# Sets CMake policies.
|
||||
macro(set_fairmq_cmake_policies)
|
||||
# Find more details to each policy with cmake --help-policy CMPXXXX
|
||||
foreach(policy
|
||||
CMP0025 # Compiler id for Apple Clang is now AppleClang.
|
||||
CMP0028 # Double colon in target name means ALIAS or IMPORTED target.
|
||||
CMP0042 # MACOSX_RPATH is enabled by default.
|
||||
CMP0048 # The ``project()`` command manages VERSION variables.
|
||||
CMP0054 # Only interpret ``if()`` arguments as variables or keywords when unquoted.
|
||||
)
|
||||
if(POLICY ${policy})
|
||||
cmake_policy(SET ${policy} NEW)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
|
||||
find_package(Git)
|
||||
# get_git_version([DEFAULT_VERSION version] [DEFAULT_DATE date] [OUTVAR_PREFIX prefix])
|
||||
#
|
||||
@@ -93,23 +112,20 @@ macro(set_fairmq_defaults)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo)
|
||||
endif()
|
||||
|
||||
|
||||
# Handle C++ standard level
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD ${PROJECT_MIN_CXX_STANDARD})
|
||||
elseif(${CMAKE_CXX_STANDARD} LESS ${PROJECT_MIN_CXX_STANDARD})
|
||||
message(FATAL_ERROR "A minimum CMAKE_CXX_STANDARD of ${PROJECT_MIN_CXX_STANDARD} is required.")
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
elseif(${CMAKE_CXX_STANDARD} LESS 11)
|
||||
message(FATAL_ERROR "A minimum CMAKE_CXX_STANDARD of 11 is required.")
|
||||
elseif(${CMAKE_CXX_STANDARD} GREATER 11)
|
||||
message(WARNING "A CMAKE_CXX_STANDARD of ${CMAKE_CXX_STANDARD} (greater than 11) is not tested. Use on your own risk.")
|
||||
endif()
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
if(NOT BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS ON CACHE BOOL "Whether to build shared libraries or static archives")
|
||||
endif()
|
||||
|
||||
# Set -fPIC as default for all library types
|
||||
if(NOT CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
# Generate compile_commands.json file (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
@@ -142,58 +158,9 @@ macro(set_fairmq_defaults)
|
||||
# Define export set, only one for now
|
||||
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
|
||||
|
||||
# Configure build types
|
||||
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "Experimental" "AdressSan" "ThreadSan")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wshadow -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS_PROFILE "-g3 -Wshadow -Wall -Wextra -fno-inline -ftest-coverage -fprofile-arcs")
|
||||
set(CMAKE_CXX_FLAGS_EXPERIMENTAL "-O2 -g -Wshadow -Wall -Wextra -DNDEBUG")
|
||||
set(CMAKE_CXX_FLAGS_ADRESSSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=address -fno-omit-frame-pointer")
|
||||
set(CMAKE_CXX_FLAGS_THREADSAN "-O2 -g -Wshadow -Wall -Wextra -fsanitize=thread")
|
||||
|
||||
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 "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)))
|
||||
# Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
|
||||
# Rationale in https://github.com/ninja-build/ninja/issues/814
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
|
||||
endif()
|
||||
|
||||
if(NOT PROJECT_VERSION_TWEAK)
|
||||
set(PROJECT_VERSION_HOTFIX 0)
|
||||
else()
|
||||
set(PROJECT_VERSION_HOTFIX ${PROJECT_VERSION_TWEAK})
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED RUN_STATIC_ANALYSIS)
|
||||
set(RUN_STATIC_ANALYSIS OFF)
|
||||
endif()
|
||||
|
||||
unset(PROJECT_STATIC_ANALYSERS)
|
||||
if(RUN_STATIC_ANALYSIS)
|
||||
set(analyser "clang-tidy")
|
||||
find_program(${analyser}_FOUND "${analyser}")
|
||||
if(${analyser}_FOUND)
|
||||
set(CMAKE_CXX_CLANG_TIDY "${${analyser}_FOUND}" "-color")
|
||||
endif()
|
||||
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
|
||||
|
||||
set(analyser "iwyu")
|
||||
find_program(${analyser}_FOUND "${analyser}")
|
||||
if(${analyser}_FOUND)
|
||||
set(CMAKE_CXX_IWYU "${${analyser}_FOUND}")
|
||||
endif()
|
||||
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
|
||||
|
||||
set(analyser "cpplint")
|
||||
find_program(${analyser}_FOUND "${analyser}")
|
||||
if(${analyser}_FOUND)
|
||||
set(CMAKE_CXX_CPPLINT "${${analyser}_FOUND}")
|
||||
endif()
|
||||
list(APPEND PROJECT_STATIC_ANALYSERS "${analyser}")
|
||||
endif()
|
||||
# Override CMake defaults
|
||||
set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
|
||||
set(CMAKE_CXX_FLAGS_PROFILE "-g3 -fno-inline -ftest-coverage -fprofile-arcs -Wshadow -Wall -Wextra -Wunused-variable")
|
||||
endmacro()
|
||||
|
||||
function(join VALUES GLUE OUTPUT)
|
||||
@@ -268,11 +235,9 @@ endfunction()
|
||||
|
||||
# Configure/Install CMake package
|
||||
macro(install_cmake_package)
|
||||
list(SORT PROJECT_PACKAGE_DEPENDENCIES)
|
||||
list(SORT PROJECT_INTERFACE_PACKAGE_DEPENDENCIES)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(PACKAGE_INSTALL_DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_GIT_VERSION}
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
|
||||
)
|
||||
if(BUILD_FAIRMQ)
|
||||
install(EXPORT ${PROJECT_EXPORT_SET}
|
||||
@@ -288,8 +253,6 @@ macro(install_cmake_package)
|
||||
)
|
||||
generate_package_dependencies() # fills ${PACKAGE_DEPENDENCIES}
|
||||
generate_package_components() # fills ${PACKAGE_COMPONENTS}
|
||||
string(TOUPPER ${CMAKE_BUILD_TYPE} PROJECT_BUILD_TYPE_UPPER)
|
||||
set(PROJECT_CXX_FLAGS ${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${PROJECT_BUILD_TYPE_UPPER}})
|
||||
configure_package_config_file(
|
||||
${CMAKE_SOURCE_DIR}/cmake/${PROJECT_NAME}Config.cmake.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
@@ -303,97 +266,36 @@ macro(install_cmake_package)
|
||||
)
|
||||
endmacro()
|
||||
|
||||
#
|
||||
# find_package2(PRIVATE|PUBLIC|INTERFACE <pkgname>
|
||||
# [VERSION <version>]
|
||||
# [COMPONENTS <list of components>]
|
||||
# [ADD_REQUIREMENTS_OF <list of dep_pgkname>]
|
||||
# [any other option the native find_package supports]...)
|
||||
#
|
||||
# Wrapper around CMake's native find_package command to add some features and bookkeeping.
|
||||
#
|
||||
# The qualifier (PRIVATE|PUBLIC|INTERFACE) to the package to populate
|
||||
# the variables PROJECT_[INTERFACE]_<pkgname>_([VERSION]|[COMPONENTS]|PACKAGE_DEPENDENCIES)
|
||||
# accordingly. This bookkeeping information is used to print our dependency found summary
|
||||
# table and to generate a part of our CMake package.
|
||||
#
|
||||
# When a dependending package is listed with ADD_REQUIREMENTS_OF the variables
|
||||
# <dep_pkgname>_<pkgname>_VERSION|COMPONENTS are looked up to and added to the native
|
||||
# VERSION (selected highest version) and COMPONENTS (deduplicated) args.
|
||||
#
|
||||
# COMPONENTS and VERSION args are then just passed to the native find_package.
|
||||
#
|
||||
macro(find_package2 qualifier pkgname)
|
||||
cmake_parse_arguments(ARGS "" "VERSION" "COMPONENTS;ADD_REQUIREMENTS_OF" ${ARGN})
|
||||
cmake_parse_arguments(ARGS "" "VERSION" "COMPONENTS" ${ARGN})
|
||||
|
||||
string(TOUPPER ${pkgname} pkgname_upper)
|
||||
set(__old_cpp__ ${CMAKE_PREFIX_PATH})
|
||||
set(old_CPP ${CMAKE_PREFIX_PATH})
|
||||
set(CMAKE_PREFIX_PATH ${${pkgname_upper}_ROOT} $ENV{${pkgname_upper}_ROOT} ${CMAKE_PREFIX_PATH})
|
||||
|
||||
# build lists of required versions and components
|
||||
unset(__required_versions__)
|
||||
unset(__components__)
|
||||
if(ARGS_VERSION)
|
||||
list(APPEND __required_versions__ ${ARGS_VERSION})
|
||||
endif()
|
||||
if(ARGS_COMPONENTS)
|
||||
list(APPEND __components__ ${ARGS_COMPONENTS})
|
||||
endif()
|
||||
if(ARGS_ADD_REQUIREMENTS_OF)
|
||||
foreach(dep_pkgname IN LISTS ARGS_ADD_REQUIREMENTS_OF)
|
||||
if(${dep_pkgname}_${pkgname}_VERSION)
|
||||
list(APPEND __required_versions__ ${${dep_pkgname}_${pkgname}_VERSION})
|
||||
endif()
|
||||
if(${dep_pkgname}_${pkgname}_COMPONENTS)
|
||||
list(APPEND __components__ ${${dep_pkgname}_${pkgname}_COMPONENTS})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# select highest required version
|
||||
unset(__version__)
|
||||
if(__required_versions__)
|
||||
list(GET __required_versions__ 0 __version__)
|
||||
foreach(v IN LISTS __required_versions__)
|
||||
if(${v} VERSION_GREATER ${__version__})
|
||||
set(__version__ ${v})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
# deduplicate required component list
|
||||
if(__components__)
|
||||
list(REMOVE_DUPLICATES __components__)
|
||||
endif()
|
||||
|
||||
# call native find_package
|
||||
if(__components__)
|
||||
find_package(${pkgname} ${__version__} QUIET COMPONENTS ${__components__} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
find_package(${pkgname} ${ARGS_VERSION} QUIET COMPONENTS ${ARGS_COMPONENTS} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
else()
|
||||
find_package(${pkgname} ${__version__} QUIET ${ARGS_UNPARSED_ARGUMENTS})
|
||||
find_package(${pkgname} ${ARGS_VERSION} QUIET ${ARGS_UNPARSED_ARGUMENTS})
|
||||
endif()
|
||||
set(CMAKE_PREFIX_PATH ${old_CPP})
|
||||
unset(old_CPP)
|
||||
|
||||
if(${pkgname}_FOUND)
|
||||
if(${qualifier} STREQUAL PRIVATE)
|
||||
set(PROJECT_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
elseif(${qualifier} STREQUAL PUBLIC)
|
||||
set(PROJECT_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
elseif(${qualifier} STREQUAL INTERFACE)
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(__version__)
|
||||
unset(__components__)
|
||||
unset(__required_versions__)
|
||||
set(CMAKE_PREFIX_PATH ${__old_cpp__})
|
||||
unset(__old_cpp__)
|
||||
endmacro()
|
||||
|
88
cmake/FindDDS.cmake
Normal file
88
cmake/FindDDS.cmake
Normal file
@@ -0,0 +1,88 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
find_path(DDS_INCLUDE_DIR
|
||||
NAMES dds_intercom.h
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_path(DDS_LIBRARY_DIR
|
||||
NAMES libdds_intercom_lib.dylib libdds_intercom_lib.so
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_library(DDS_INTERCOM_LIBRARY_SHARED
|
||||
NAMES libdds_intercom_lib.dylib libdds_intercom_lib.so
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "Path to libdds_intercom_lib.dylib libdds_intercom_lib.so."
|
||||
)
|
||||
|
||||
find_library(DDS_PROTOCOL_LIBRARY_SHARED
|
||||
NAMES libdds_protocol_lib.dylib libdds_protocol_lib.so
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "Path to libdds_protocol_lib.dylib libdds_protocol_lib.so."
|
||||
)
|
||||
|
||||
find_library(DDS_USER_DEFAULTS_LIBRARY_SHARED
|
||||
NAMES libdds-user-defaults.dylib libdds-user-defaults.so
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "Path to libdds-user-defaults.dylib libdds-user-defaults.so."
|
||||
)
|
||||
|
||||
find_file(DDS_VERSION_FILE
|
||||
NAMES version
|
||||
HINTS ${DDS_ROOT} $ENV{DDS_ROOT}
|
||||
PATH_SUFFIXES etc
|
||||
)
|
||||
|
||||
if(DDS_VERSION_FILE AND NOT DDS_VERSION)
|
||||
file(READ ${DDS_VERSION_FILE} DDS_VERSION)
|
||||
string(STRIP "${DDS_VERSION}" DDS_VERSION)
|
||||
set(DDS_VERSION ${DDS_VERSION} CACHE string "DDS version.")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(DDS
|
||||
REQUIRED_VARS
|
||||
DDS_INCLUDE_DIR
|
||||
DDS_LIBRARY_DIR
|
||||
DDS_INTERCOM_LIBRARY_SHARED
|
||||
DDS_PROTOCOL_LIBRARY_SHARED
|
||||
DDS_USER_DEFAULTS_LIBRARY_SHARED
|
||||
|
||||
VERSION_VAR DDS_VERSION
|
||||
)
|
||||
|
||||
if(NOT TARGET DDS::dds_intercom_lib AND DDS_FOUND)
|
||||
add_library(DDS::dds_intercom_lib SHARED IMPORTED)
|
||||
set_target_properties(DDS::dds_intercom_lib PROPERTIES
|
||||
IMPORTED_LOCATION ${DDS_INTERCOM_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET DDS::dds_protocol_lib AND DDS_FOUND)
|
||||
add_library(DDS::dds_protocol_lib SHARED IMPORTED)
|
||||
set_target_properties(DDS::dds_protocol_lib PROPERTIES
|
||||
IMPORTED_LOCATION ${DDS_PROTOCOL_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET DDS::dds-user-defaults AND DDS_FOUND)
|
||||
add_library(DDS::dds-user-defaults SHARED IMPORTED)
|
||||
set_target_properties(DDS::dds-user-defaults PROPERTIES
|
||||
IMPORTED_LOCATION ${DDS_USER_DEFAULTS_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${DDS_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
67
cmake/FindFlatBuffers.cmake
Normal file
67
cmake/FindFlatBuffers.cmake
Normal file
@@ -0,0 +1,67 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
find_path(FLATBUFFERS_INCLUDE_DIR
|
||||
NAMES flatbuffers/flatbuffers.h
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_path(FLATBUFFERS_LIBRARY_DIR
|
||||
NAMES libflatbuffers.a
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_library(FLATBUFFERS_STATIC_LIBRARY
|
||||
NAMES libflatbuffers.a
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_path(FLATBUFFERS_BINARY_DIR
|
||||
NAMES flatc
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
find_program(FLATBUFFERS_BINARY_FLATC
|
||||
NAMES flatc
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FlatBuffers
|
||||
REQUIRED_VARS
|
||||
FLATBUFFERS_INCLUDE_DIR
|
||||
FLATBUFFERS_LIBRARY_DIR
|
||||
FLATBUFFERS_BINARY_DIR
|
||||
)
|
||||
|
||||
# idempotently import targets
|
||||
if(NOT TARGET FlatBuffers)
|
||||
if(FLATBUFFERS_FOUND)
|
||||
# import target
|
||||
add_library(FlatBuffers STATIC IMPORTED)
|
||||
set_target_properties(FlatBuffers PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${FLATBUFFERS_INCLUDE_DIR}
|
||||
IMPORTED_LOCATION ${FLATBUFFERS_STATIC_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET FlatBuffers::flatc)
|
||||
if(FLATBUFFERS_FOUND)
|
||||
# import target
|
||||
add_executable(FlatBuffers::flatc IMPORTED)
|
||||
set_target_properties(FlatBuffers::flatc PROPERTIES
|
||||
IMPORTED_LOCATION ${FLATBUFFERS_BINARY_FLATC}
|
||||
)
|
||||
endif()
|
||||
endif()
|
89
cmake/FindOFI.cmake
Normal file
89
cmake/FindOFI.cmake
Normal file
@@ -0,0 +1,89 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
# According to the docs the modification of the PKG_CONFIG_PATH environment should
|
||||
# not be necessary, but it does not work otherwise.
|
||||
if(OFI_ROOT)
|
||||
list(APPEND CMAKE_PREFIX_PATH "${OFI_ROOT}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "${OFI_ROOT}/lib/pkgconfig:" $ENV{PKG_CONFIG_PATH})
|
||||
endif()
|
||||
|
||||
if(ENV{OFI_ROOT})
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{OFI_ROOT}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{OFI_ROOT}/lib/pkgconfig:" $ENV{PKG_CONFIG_PATH})
|
||||
endif()
|
||||
|
||||
# This should be the default as of CMake 3.1, but it is not set. BUG? Also, it does not work
|
||||
set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH 1)
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
# Find include dir and dependencies from pkgconfig
|
||||
pkg_check_modules(_OFI libfabric QUIET)
|
||||
|
||||
# Retrieve version from pkgconfig
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} libfabric --modversion
|
||||
OUTPUT_VARIABLE OFI_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# The IMPORTED_TARGET option of the pkg_check_modules() function is useless,
|
||||
# so let's build it ourselves
|
||||
find_library(OFI_LIBFABRIC
|
||||
NAMES libfabric.so libfabric.dylib
|
||||
HINTS ${OFI_ROOT} $ENV{OFI_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
# Just take the include dirs found by the PkgConfig module
|
||||
set(OFI_INCLUDE_DIRS ${_OFI_INCLUDE_DIRS})
|
||||
|
||||
# Find fi_info command to be able to check required features of the OFI installation
|
||||
find_program(OFI_INFO_EXECUTABLE
|
||||
NAMES fi_info
|
||||
HINTS ${OFI_ROOT} $ENV{OFI_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
# Detect ofi providers, they can be required via the COMPONENTS argument of find_package
|
||||
if(OFI_INFO_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${OFI_INFO_EXECUTABLE} -l
|
||||
OUTPUT_VARIABLE output
|
||||
)
|
||||
string(REPLACE "\n" ";" lines ${output})
|
||||
foreach(line IN LISTS lines)
|
||||
string(REGEX
|
||||
MATCH "^([a-zA-Z0-9_]+):"
|
||||
found "${line}"
|
||||
)
|
||||
if(found)
|
||||
string(TOLOWER "${CMAKE_MATCH_1}" provider)
|
||||
set(OFI_fi_${provider}_FOUND TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Check search result, check version constraints and print status
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(OFI
|
||||
REQUIRED_VARS OFI_LIBFABRIC OFI_INCLUDE_DIRS OFI_INFO_EXECUTABLE
|
||||
VERSION_VAR OFI_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET OFI::libfabric AND OFI_FOUND)
|
||||
# Define an imported target
|
||||
add_library(OFI::libfabric SHARED IMPORTED GLOBAL)
|
||||
set_target_properties(OFI::libfabric PROPERTIES
|
||||
IMPORTED_LOCATION ${OFI_LIBFABRIC}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${OFI_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
@@ -1,67 +0,0 @@
|
||||
################################################################################
|
||||
# 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" #
|
||||
################################################################################
|
||||
|
||||
find_path(PMIx_INCLUDE_DIR
|
||||
NAMES pmix.h
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_path(PMIx_LIBRARY_DIR
|
||||
NAMES libpmix.dylib libpmix.so
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES lib lib64
|
||||
)
|
||||
|
||||
find_library(PMIx_LIBRARY_SHARED
|
||||
NAMES libpmix.dylib libpmix.so
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES lib lib64
|
||||
)
|
||||
|
||||
find_file(PMIx_VERSION_FILE
|
||||
NAMES pmix_version.h
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
file(READ "${PMIx_VERSION_FILE}" __version_raw)
|
||||
string(REGEX MATCH "#define PMIX_VERSION_MAJOR ([0-9]?)L?"
|
||||
__version_major_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define PMIX_VERSION_MINOR ([0-9]?)L?"
|
||||
__version_minor_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define PMIX_VERSION_RELEASE ([0-9]?)L?"
|
||||
__version_patch_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_PATCH "${CMAKE_MATCH_1}")
|
||||
|
||||
set(PMIx_VERSION "${PMIx_VERSION_MAJOR}.${PMIx_VERSION_MINOR}.${PMIx_VERSION_PATCH}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PMIx
|
||||
REQUIRED_VARS
|
||||
PMIx_INCLUDE_DIR
|
||||
PMIx_LIBRARY_DIR
|
||||
PMIx_LIBRARY_SHARED
|
||||
|
||||
VERSION_VAR PMIx_VERSION
|
||||
)
|
||||
|
||||
if(NOT TARGET PMIx::libpmix AND PMIx_FOUND)
|
||||
add_library(PMIx::libpmix SHARED IMPORTED)
|
||||
set_target_properties(PMIx::libpmix PROPERTIES
|
||||
IMPORTED_LOCATION ${PMIx_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${PMIx_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
@@ -89,7 +89,7 @@ endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ZeroMQ
|
||||
REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR
|
||||
REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR ZeroMQ_LIBRARY_STATIC
|
||||
VERSION_VAR ZeroMQ_VERSION
|
||||
)
|
||||
|
||||
|
34
cmake/Findnanomsg.cmake
Normal file
34
cmake/Findnanomsg.cmake
Normal file
@@ -0,0 +1,34 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
find_path(nanomsg_INCLUDE_DIR
|
||||
NAMES nanomsg/nn.h
|
||||
HINTS ${NANOMSG_ROOT} $ENV{NANOMSG_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
DOC "Path to nanomsg include header files."
|
||||
)
|
||||
|
||||
find_library(nanomsg_LIBRARY_SHARED
|
||||
NAMES libnanomsg.dylib libnanomsg.so
|
||||
HINTS ${NANOMSG_ROOT} $ENV{NANOMSG_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
DOC "Path to libnanomsg.dylib libnanomsg.so."
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(nanomsg
|
||||
REQUIRED_VARS nanomsg_LIBRARY_SHARED nanomsg_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(NOT TARGET nanomsg AND nanomsg_FOUND)
|
||||
add_library(nanomsg SHARED IMPORTED)
|
||||
set_target_properties(nanomsg PROPERTIES
|
||||
IMPORTED_LOCATION ${nanomsg_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${nanomsg_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
@@ -47,13 +47,11 @@
|
||||
#
|
||||
#
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
function(add_testsuite suitename)
|
||||
cmake_parse_arguments(testsuite
|
||||
""
|
||||
"TIMEOUT;RUN_SERIAL"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -71,27 +69,14 @@ function(add_testsuite suitename)
|
||||
if(testsuite_INCLUDES)
|
||||
target_include_directories(${target} PUBLIC ${testsuite_INCLUDES})
|
||||
endif()
|
||||
if(testsuite_DEFINITIONS)
|
||||
target_compile_definitions("${target}" PUBLIC ${testsuite_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
# add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
|
||||
add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
|
||||
if(testsuite_TIMEOUT)
|
||||
# set_tests_properties("${suitename}" PROPERTIES TIMEOUT ${testsuite_TIMEOUT})
|
||||
else()
|
||||
set(testsuite_TIMEOUT 10)
|
||||
set_tests_properties("${suitename}" PROPERTIES TIMEOUT ${testsuite_TIMEOUT})
|
||||
endif()
|
||||
if(testsuite_RUN_SERIAL)
|
||||
# set_tests_properties("${suitename}" PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL})
|
||||
else()
|
||||
set(testsuite_RUN_SERIAL OFF)
|
||||
set_tests_properties("${suitename}" PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL})
|
||||
endif()
|
||||
gtest_discover_tests(${target}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
TEST_PREFIX ${suitename}.
|
||||
PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL}
|
||||
TIMEOUT ${testsuite_TIMEOUT}
|
||||
)
|
||||
|
||||
list(APPEND ALL_TEST_TARGETS ${target})
|
||||
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
|
||||
@@ -101,7 +86,7 @@ function(add_testhelper helpername)
|
||||
cmake_parse_arguments(testhelper
|
||||
""
|
||||
""
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -117,9 +102,6 @@ function(add_testhelper helpername)
|
||||
if(testhelper_INCLUDES)
|
||||
target_include_directories(${target} PUBLIC ${testhelper_INCLUDES})
|
||||
endif()
|
||||
if(testhelper_DEFINITIONS)
|
||||
target_compile_definitions(${target} PUBLIC ${testhelper_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
list(APPEND ALL_TEST_TARGETS ${target})
|
||||
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
|
||||
@@ -129,7 +111,7 @@ function(add_testlib libname)
|
||||
cmake_parse_arguments(testlib
|
||||
"HIDDEN"
|
||||
"VERSION"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -151,9 +133,6 @@ function(add_testlib libname)
|
||||
if(testlib_VERSION)
|
||||
set_target_properties(${target} PROPERTIES VERSION ${testlib_VERSION})
|
||||
endif()
|
||||
if(testlib_DEFINITIONS)
|
||||
target_compile_definitions(${target} PUBLIC ${testlib_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
list(APPEND ALL_TEST_TARGETS ${target})
|
||||
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
|
||||
|
4190
cmake/cotire.cmake
4190
cmake/cotire.cmake
File diff suppressed because it is too large
Load Diff
@@ -24,22 +24,21 @@ FairMQ devices communicate via the communication patterns offered by ZeroMQ (or
|
||||
|
||||
Each FairMQ device has an internal state machine:
|
||||
|
||||

|
||||

|
||||
|
||||
The state machine can be querried and controlled via `GetCurrentStateName()` and `ChangeState("<state name>")` methods. Only legal state transitions are allowed (see image above). Illegal transitions will fail with an error.
|
||||
|
||||
If the device is running in interactive mode (default), states can be changed via keyboard input:
|
||||
|
||||
- `'h'` - help
|
||||
- `'p'` - pause
|
||||
- `'r'` - run
|
||||
- `'s'` - stop
|
||||
- `'t'` - reset task
|
||||
- `'d'` - reset device
|
||||
- `'q'` - end
|
||||
- `'j'` - init task
|
||||
- `'i'` - initialize
|
||||
- `'b'` - bind
|
||||
- `'x'` - connect
|
||||
- `'i'` - init device
|
||||
|
||||
Without the interactive mode, for example for a run in background, two other control mechanisms are available:
|
||||
|
||||
|
@@ -1,93 +0,0 @@
|
||||
← [Back](../README.md)
|
||||
|
||||
# 7. Plugins
|
||||
|
||||
FairMQ devices can be integrated with external configuration and control systems through its plugin system. FairMQ plugins are special dynamic libraries that can be loaded at runtime. Plugins have access to the Plugin API which includes the capability to control/monitor the device [state machine](Device.md#13-state-machine) and change/monitor configuration properties.
|
||||
|
||||
A simple plugin may add the feature to read configuration from a certain desired file format once at the start of a device. A more complex plugin may create a long-running thread that integrates a network client to an external API of a central experiment control system.
|
||||
|
||||
Because plugins are loaded dynamically, they can be developed in separate repositories/projects and also have their own set of runtime dependency that are not needed to be known at compile-time of the FairMQ device.
|
||||
|
||||
## 7.1 Usage
|
||||
|
||||
To load a plugin pass the `-P <name>[,<name>]` (or long `--plugin`) command line option. Multiple plugins can be loaded at the same time. The load order is as specified at the command line. This determines the order in which the plugins are instantiated (ctor call order) and in which order they are notified, should they subscribe to any notifications.
|
||||
|
||||
When passing `-h/--help` on the command line one can find more detailed information:
|
||||
|
||||
```
|
||||
Plugin Manager:
|
||||
-S [ --plugin-search-path ] arg List of plugin search paths.
|
||||
* Override default search path, e.g.
|
||||
-S /home/user/lib /lib
|
||||
* Append(>) or prepend(<) to default
|
||||
search path, e.g.
|
||||
-S >/lib </home/user/lib
|
||||
* If you mix the overriding and
|
||||
appending/prepending syntaxes, the
|
||||
overriding paths act as default search
|
||||
path, e.g.
|
||||
-S /usr/lib >/lib </home/user/lib
|
||||
/usr/local/lib results in
|
||||
/home/user/lib,/usr/local/lib,/usr/lib/
|
||||
,/lib
|
||||
If nothing is found, the default
|
||||
dynamic library lookup is performed,
|
||||
see man ld.so(8) for details.
|
||||
-P [ --plugin ] arg List of plugin names to load in
|
||||
order,e.g. if the file is called
|
||||
'libFairMQPlugin_example.so', just list
|
||||
'example' or 'd:example' here.To load a
|
||||
prelinked plugin, list 'p:example'
|
||||
here.
|
||||
```
|
||||
|
||||
## 7.2 Development
|
||||
|
||||
To develop a custom FairMQ plugin, one simply needs to inherit from the `fair::mq::Plugin` base class (`#include <fairmq/Plugin.h>`) and call the `REGISTER_FAIRMQ_PLUGIN` macro. It is possible to introduce new command line option together with a plugin.
|
||||
|
||||
The Plugin API includes:
|
||||
* `Take/Steal/ReleaseDeviceControl()`/`GetCurrent/ChangeDeviceState()`/`SubscribeTo/UnsubscribeFromDeviceStateChange()` APIs enable controlling the device state machine. Only one plugin is authorized to control at the same time. Which one is determined by which plugin calls `TakeDeviceControl()` first.
|
||||
* `Set/GetProperty()`/`GetPropertyKeys()`/`SubscribeTo/UnsubscribeFromPropertyChange()` APIs enable configuration of device properties.
|
||||
See [`<fairmq/Plugin.h>`](/fairmq/Plugin.h) for the full API.
|
||||
|
||||
A more complete example which may serve as a start including example CMake code can be found here: [FairRootGroup/FairMQPlugin_example](https://github.com/FairRootGroup/FairMQPlugin_example).
|
||||
|
||||
## 7.3 Provided Plugins
|
||||
|
||||
### 7.3.1 DDS
|
||||
|
||||
When launching a FairMQ topology via [DDS](http://dds.gsi.de/) the DDS plugin enables FairMQ devices to interact with DDS' custom command and property subsystems - enable the plugin by passing `-P dds` on the command line.
|
||||
|
||||
Via the property subsystem a FairMQ topology may exchange channel connection data (essentially to do service discovery) needed to connect/bind all FairMQ channels appropriately. DDS is highly optimized for this use case. See [examples/dds](examples/dds/README.md) for more details.
|
||||
|
||||
Via the custom command subsystem a FairMQ device can receive a number of commands. FairMQ provides a convenient command line tool `fairmq-dds-command-ui` that allows interactive or scripted control of a running FairMQ topology managed via DDS. If one develops directly against the custom command DDS API, the following table lists all the commands the DDS plugin currently understands:
|
||||
|
||||
| Custom Command | Response | Error | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| `check-state` | `<ID>: <STATE> (pid: <PID>)` | n/a | Query current device state, see state machine for possible states |
|
||||
| `dump-config` | `(<ID>: <PKEY> -> <PVALUE>\n)+` | n/a | Query current device config (list property key/value pairs) |
|
||||
| `INIT DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `BIND` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `CONNECT` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `INIT TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RUN` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `STOP` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RESET TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `RESET DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `END` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
|
||||
| `subscribe-to-heartbeats` | `heartbeat-subscription: <ID>,OK` | n/a | Subscribe to heartbeats |
|
||||
| on heartbeat subscription | `heartbeat: <ID>,<PID>` | n/a | Heartbeat every 100ms |
|
||||
| `unsubscribe-from-heartbeats` | `heartbeat-unsubscription: <ID>,OK` | n/a | Unsubscribe from heartbeats |
|
||||
| `subscribe-to-state-changes` | `state-changes-subscription: <ID>,OK` | n/a | Subscribe to state changes |
|
||||
| on state changes subscription | `state-change: <ID>,<STATE>` | n/a | State change notification |
|
||||
| `unsubscribe-from-state-changes` | `state-changes-unsubscription: <ID>,OK` | n/a | Unsubscribe from state changes |
|
||||
|
||||
If unknown commands are received the plugin will print a warning.
|
||||
|
||||
### 7.3.2 PMIx
|
||||
|
||||
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
|
||||
|
||||
TODO example usage
|
||||
|
||||
← [Back](../README.md)
|
BIN
docs/images/device_states.png
Normal file
BIN
docs/images/device_states.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 104 KiB |
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 170 KiB |
@@ -31,16 +31,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-1.sh.in ${CMAKE_CUR
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh)
|
||||
|
||||
add_test(NAME Example.1-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
|
||||
set_tests_properties(Example.1-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
|
||||
set_tests_properties(Example-1-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.1-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
|
||||
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.1-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
|
||||
set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
|
||||
set_tests_properties(Example-1-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -1,10 +1,16 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sampler.cpp
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <thread> // this_thread::sleep_for
|
||||
#include <chrono>
|
||||
@@ -58,6 +64,8 @@ bool Sampler::ConditionalRun()
|
||||
return false;
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -4,7 +4,6 @@ export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
SAMPLER="fairmq-ex-1-1-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --rate 1"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
|
@@ -8,17 +8,13 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID;' TERM
|
||||
|
||||
SAMPLER="fairmq-ex-1-1-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --rate 1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --control static --color false"
|
||||
SAMPLER+=" --max-iterations 1"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
|
||||
@@ -29,7 +25,6 @@ SINK="fairmq-ex-1-1-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --control static --color false"
|
||||
SINK+=" --max-iterations 1"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://localhost:5555,rateLogging=0"
|
||||
|
@@ -39,16 +39,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-1-n-1.json ${CMAKE_CURRENT_BINARY_
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh)
|
||||
|
||||
add_test(NAME Example.1-n-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
|
||||
set_tests_properties(Example.1-n-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-n-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
|
||||
set_tests_properties(Example-1-n-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.1-n-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-n-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-n-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
|
||||
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.1-n-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
|
||||
set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example-1-n-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
|
||||
set_tests_properties(Example-1-n-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -9,7 +9,6 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
fi
|
||||
|
||||
ex2config="@CMAKE_CURRENT_BINARY_DIR@/ex-1-n-1.json"
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $PROCESSOR1_PID; kill -TERM $PROCESSOR2_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $PROCESSOR1_PID; wait $PROCESSOR2_PID;' TERM
|
||||
@@ -18,7 +17,6 @@ SAMPLER="fairmq-ex-1-n-1-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --control static --color false"
|
||||
SAMPLER+=" --max-iterations 2"
|
||||
SAMPLER+=" --mq-config $ex2config"
|
||||
@@ -29,7 +27,6 @@ PROCESSOR1="fairmq-ex-1-n-1-processor"
|
||||
PROCESSOR1+=" --id processor1"
|
||||
PROCESSOR1+=" --transport $transport"
|
||||
PROCESSOR1+=" --verbosity veryhigh"
|
||||
PROCESSOR1+=" --session $SESSION"
|
||||
PROCESSOR1+=" --control static --color false"
|
||||
PROCESSOR1+=" --mq-config $ex2config"
|
||||
PROCESSOR1+=" --config-key processor"
|
||||
@@ -40,7 +37,6 @@ PROCESSOR2="fairmq-ex-1-n-1-processor"
|
||||
PROCESSOR2+=" --id processor2"
|
||||
PROCESSOR2+=" --transport $transport"
|
||||
PROCESSOR2+=" --verbosity veryhigh"
|
||||
PROCESSOR2+=" --session $SESSION"
|
||||
PROCESSOR2+=" --control static --color false"
|
||||
PROCESSOR2+=" --mq-config $ex2config"
|
||||
PROCESSOR2+=" --config-key processor"
|
||||
@@ -51,7 +47,6 @@ SINK="fairmq-ex-1-n-1-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --control static --color false"
|
||||
SINK+=" --max-iterations 2"
|
||||
SINK+=" --mq-config $ex2config"
|
||||
|
@@ -8,7 +8,6 @@
|
||||
|
||||
add_subdirectory(1-1)
|
||||
add_subdirectory(1-n-1)
|
||||
add_subdirectory(builtin-devices)
|
||||
add_subdirectory(copypush)
|
||||
add_subdirectory(dds)
|
||||
add_subdirectory(multipart)
|
||||
@@ -16,6 +15,5 @@ add_subdirectory(multiple-channels)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_subdirectory(multiple-transports)
|
||||
endif()
|
||||
add_subdirectory(readout)
|
||||
add_subdirectory(region)
|
||||
add_subdirectory(req-rep)
|
||||
|
@@ -1,50 +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" #
|
||||
################################################################################
|
||||
|
||||
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh)
|
||||
|
||||
# test
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh)
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq)
|
||||
set_tests_properties(Example.BuiltinDevices.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg)
|
||||
set_tests_properties(Example.BuiltinDevices.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem)
|
||||
set_tests_properties(Example.BuiltinDevices.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
# install
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-builtin-devices.sh
|
||||
)
|
@@ -1,4 +0,0 @@
|
||||
Built-in devices
|
||||
==========================
|
||||
|
||||
This example demonstrates use of generic devices that are provided with FairMQ - BenchmarkSampler, Merger, Multiplier, Proxy, Sink, Splitter. They are all connected in one topology and transfer some dummy buffers generated by the BenchmarkSampler.
|
@@ -1,93 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
transport="zeromq"
|
||||
multipart="false"
|
||||
numParts="1"
|
||||
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
if [[ $2 =~ ^[a-z]+$ ]]; then
|
||||
multipart=$2
|
||||
fi
|
||||
|
||||
if [[ $3 =~ ^[0-9]+$ ]]; then
|
||||
numParts=$3
|
||||
fi
|
||||
|
||||
SAMPLER="fairmq-bsampler"
|
||||
SAMPLER+=" --id bsampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --control interactive"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size 100000"
|
||||
SAMPLER+=" --multipart $multipart"
|
||||
SAMPLER+=" --num-parts $numParts"
|
||||
SAMPLER+=" --msg-rate 100"
|
||||
SAMPLER+=" --max-iterations 0"
|
||||
SAMPLER+=" --out-channel data1"
|
||||
SAMPLER+=" --channel-config name=data1,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
xterm -geometry 90x20+0+175 -hold -e @FAIRMQ_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SPLITTER="fairmq-splitter"
|
||||
SPLITTER+=" --id splitter"
|
||||
SPLITTER+=" --transport $transport"
|
||||
SPLITTER+=" --multipart $multipart"
|
||||
SPLITTER+=" --in-channel data1"
|
||||
SPLITTER+=" --out-channel data2"
|
||||
SPLITTER+=" --channel-config name=data1,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
SPLITTER+=" name=data2,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556,address=tcp://localhost:5557"
|
||||
xterm -geometry 90x20+0+475 -hold -e @FAIRMQ_BIN_DIR@/$SPLITTER &
|
||||
|
||||
PROXY1="fairmq-proxy"
|
||||
PROXY1+=" --id proxy1"
|
||||
PROXY1+=" --transport $transport"
|
||||
PROXY1+=" --multipart $multipart"
|
||||
PROXY1+=" --in-channel data2"
|
||||
PROXY1+=" --out-channel data3"
|
||||
PROXY1+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556"
|
||||
PROXY1+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558"
|
||||
xterm -geometry 90x20+550+175 -hold -e @FAIRMQ_BIN_DIR@/$PROXY1 &
|
||||
|
||||
PROXY2="fairmq-proxy"
|
||||
PROXY2+=" --id proxy2"
|
||||
PROXY2+=" --transport $transport"
|
||||
PROXY2+=" --multipart $multipart"
|
||||
PROXY2+=" --in-channel data2"
|
||||
PROXY2+=" --out-channel data3"
|
||||
PROXY2+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5557"
|
||||
PROXY2+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5559"
|
||||
xterm -geometry 90x20+550+475 -hold -e @FAIRMQ_BIN_DIR@/$PROXY2 &
|
||||
|
||||
MERGER="fairmq-merger"
|
||||
MERGER+=" --id merger"
|
||||
MERGER+=" --transport $transport"
|
||||
MERGER+=" --multipart $multipart"
|
||||
MERGER+=" --in-channel data3"
|
||||
MERGER+=" --out-channel data4"
|
||||
MERGER+=" --channel-config name=data3,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558,address=tcp://localhost:5559"
|
||||
MERGER+=" name=data4,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
xterm -geometry 90x20+1100+50 -hold -e @FAIRMQ_BIN_DIR@/$MERGER &
|
||||
|
||||
MULTIPLIER="fairmq-multiplier"
|
||||
MULTIPLIER+=" --id multiplier"
|
||||
MULTIPLIER+=" --transport $transport"
|
||||
MULTIPLIER+=" --multipart $multipart"
|
||||
MULTIPLIER+=" --in-channel data4"
|
||||
MULTIPLIER+=" --out-channel data5"
|
||||
MULTIPLIER+=" --channel-config name=data4,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
MULTIPLIER+=" name=data5,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561,address=tcp://localhost:5561"
|
||||
xterm -geometry 90x20+1100+350 -hold -e @FAIRMQ_BIN_DIR@/$MULTIPLIER &
|
||||
|
||||
SINK="fairmq-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --multipart $multipart"
|
||||
SINK+=" --max-iterations 0"
|
||||
SINK+=" --in-channel data5"
|
||||
SINK+=" --channel-config name=data5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561"
|
||||
xterm -geometry 90x20+1100+650 -hold -e @FAIRMQ_BIN_DIR@/$SINK &
|
@@ -1,148 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
transport="zeromq"
|
||||
multipart="false"
|
||||
numParts="1"
|
||||
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
if [[ $2 =~ ^[a-z]+$ ]]; then
|
||||
multipart=$2
|
||||
fi
|
||||
|
||||
if [[ $3 =~ ^[0-9]+$ ]]; then
|
||||
numParts=$3
|
||||
fi
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SPLITTER_PID; kill -TERM $PROXY1_PID; kill -TERM $PROXY2_PID; kill -TERM $MERGER_PID; kill -TERM $MULTIPLIER_PID; kill -TERM $SINK_PID;' TERM
|
||||
|
||||
SAMPLER="fairmq-bsampler"
|
||||
SAMPLER+=" --id bsampler1"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --color false"
|
||||
SAMPLER+=" --control static"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size 100000"
|
||||
SAMPLER+=" --multipart $multipart"
|
||||
SAMPLER+=" --num-parts $numParts"
|
||||
SAMPLER+=" --msg-rate 1"
|
||||
SAMPLER+=" --max-iterations 0"
|
||||
SAMPLER+=" --out-channel data1"
|
||||
SAMPLER+=" --channel-config name=data1,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
@FAIRMQ_BIN_DIR@/$SAMPLER &
|
||||
SAMPLER_PID=$!
|
||||
|
||||
SPLITTER="fairmq-splitter"
|
||||
SPLITTER+=" --id splitter"
|
||||
SPLITTER+=" --session $SESSION"
|
||||
SPLITTER+=" --transport $transport"
|
||||
SPLITTER+=" --color false"
|
||||
SPLITTER+=" --control static"
|
||||
SPLITTER+=" --verbosity veryhigh"
|
||||
SPLITTER+=" --multipart $multipart"
|
||||
SPLITTER+=" --in-channel data1"
|
||||
SPLITTER+=" --out-channel data2"
|
||||
SPLITTER+=" --channel-config name=data1,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
SPLITTER+=" name=data2,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556,address=tcp://localhost:5557"
|
||||
@FAIRMQ_BIN_DIR@/$SPLITTER &
|
||||
SPLITTER_PID=$!
|
||||
|
||||
PROXY1="fairmq-proxy"
|
||||
PROXY1+=" --id proxy1"
|
||||
PROXY1+=" --session $SESSION"
|
||||
PROXY1+=" --transport $transport"
|
||||
PROXY1+=" --color false"
|
||||
PROXY1+=" --control static"
|
||||
PROXY1+=" --verbosity veryhigh"
|
||||
PROXY1+=" --multipart $multipart"
|
||||
PROXY1+=" --in-channel data2"
|
||||
PROXY1+=" --out-channel data3"
|
||||
PROXY1+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556"
|
||||
PROXY1+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558"
|
||||
@FAIRMQ_BIN_DIR@/$PROXY1 &
|
||||
PROXY1_PID=$!
|
||||
|
||||
PROXY2="fairmq-proxy"
|
||||
PROXY2+=" --id proxy2"
|
||||
PROXY2+=" --session $SESSION"
|
||||
PROXY2+=" --transport $transport"
|
||||
PROXY2+=" --color false"
|
||||
PROXY2+=" --control static"
|
||||
PROXY2+=" --verbosity veryhigh"
|
||||
PROXY2+=" --multipart $multipart"
|
||||
PROXY2+=" --in-channel data2"
|
||||
PROXY2+=" --out-channel data3"
|
||||
PROXY2+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5557"
|
||||
PROXY2+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5559"
|
||||
@FAIRMQ_BIN_DIR@/$PROXY2 &
|
||||
PROXY2_PID=$!
|
||||
|
||||
MERGER="fairmq-merger"
|
||||
MERGER+=" --id merger"
|
||||
MERGER+=" --session $SESSION"
|
||||
MERGER+=" --transport $transport"
|
||||
MERGER+=" --color false"
|
||||
MERGER+=" --control static"
|
||||
MERGER+=" --verbosity veryhigh"
|
||||
MERGER+=" --multipart $multipart"
|
||||
MERGER+=" --in-channel data3"
|
||||
MERGER+=" --out-channel data4"
|
||||
MERGER+=" --channel-config name=data3,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558,address=tcp://localhost:5559"
|
||||
MERGER+=" name=data4,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
@FAIRMQ_BIN_DIR@/$MERGER &
|
||||
MERGER_PID=$!
|
||||
|
||||
MULTIPLIER="fairmq-multiplier"
|
||||
MULTIPLIER+=" --id multiplier"
|
||||
MULTIPLIER+=" --session $SESSION"
|
||||
MULTIPLIER+=" --transport $transport"
|
||||
MULTIPLIER+=" --color false"
|
||||
MULTIPLIER+=" --control static"
|
||||
MULTIPLIER+=" --verbosity veryhigh"
|
||||
MULTIPLIER+=" --multipart $multipart"
|
||||
MULTIPLIER+=" --in-channel data4"
|
||||
MULTIPLIER+=" --out-channel data5"
|
||||
MULTIPLIER+=" --channel-config name=data4,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
MULTIPLIER+=" name=data5,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561,address=tcp://localhost:5561"
|
||||
@FAIRMQ_BIN_DIR@/$MULTIPLIER &
|
||||
MULTIPLIER_PID=$!
|
||||
|
||||
SINK="fairmq-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --color false"
|
||||
SINK+=" --control static"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --multipart $multipart"
|
||||
SINK+=" --max-iterations 2"
|
||||
SINK+=" --in-channel data5"
|
||||
SINK+=" --channel-config name=data5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561"
|
||||
@FAIRMQ_BIN_DIR@/$SINK &
|
||||
SINK_PID=$!
|
||||
|
||||
wait $SINK_PID
|
||||
|
||||
kill -SIGINT $SAMPLER_PID
|
||||
kill -SIGINT $SPLITTER_PID
|
||||
kill -SIGINT $PROXY1_PID
|
||||
kill -SIGINT $PROXY2_PID
|
||||
kill -SIGINT $MERGER_PID
|
||||
kill -SIGINT $MULTIPLIER_PID
|
||||
|
||||
wait $SAMPLER_PID
|
||||
wait $SPLITTER_PID
|
||||
wait $PROXY1_PID
|
||||
wait $PROXY2_PID
|
||||
wait $MERGER_PID
|
||||
wait $MULTIPLIER_PID
|
@@ -32,16 +32,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-copypush.sh.in ${CMAK
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh)
|
||||
|
||||
add_test(NAME Example.CopyPush.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
|
||||
set_tests_properties(Example.CopyPush.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example-CopyPush-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
|
||||
set_tests_properties(Example-CopyPush-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.CopyPush.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
|
||||
set_tests_properties(Example.CopyPush.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example-CopyPush-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
|
||||
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.CopyPush.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
|
||||
set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example-CopyPush-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
|
||||
set_tests_properties(Example-CopyPush-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -8,8 +8,6 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK1_PID; kill -TERM $SINK2_PID; wait $SAMPLER_PID; wait $SINK1_PID; wait $SINK2_PID;' TERM
|
||||
|
||||
@@ -17,7 +15,6 @@ SAMPLER="fairmq-ex-copypush-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --control static --color false"
|
||||
SAMPLER+=" --max-iterations 1"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,rateLogging=0,address=tcp://*:5555,address=tcp://*:5556"
|
||||
@@ -28,7 +25,6 @@ SINK1="fairmq-ex-copypush-sink"
|
||||
SINK1+=" --id sink1"
|
||||
SINK1+=" --transport $transport"
|
||||
SINK1+=" --verbosity veryhigh"
|
||||
SINK1+=" --session $SESSION"
|
||||
SINK1+=" --control static --color false"
|
||||
SINK1+=" --max-iterations 1"
|
||||
SINK1+=" --channel-config name=data,type=pull,method=connect,rateLogging=0,address=tcp://localhost:5555"
|
||||
@@ -39,7 +35,6 @@ SINK2="fairmq-ex-copypush-sink"
|
||||
SINK2+=" --id sink2"
|
||||
SINK2+=" --transport $transport"
|
||||
SINK2+=" --verbosity veryhigh"
|
||||
SINK2+=" --session $SESSION"
|
||||
SINK2+=" --control static --color false"
|
||||
SINK2+=" --max-iterations 1"
|
||||
SINK2+=" --channel-config name=data,type=pull,method=connect,rateLogging=0,address=tcp://localhost:5556"
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* 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, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
|
@@ -1,17 +1,23 @@
|
||||
DDS Example
|
||||
===========
|
||||
|
||||
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 the one in Example 1-n-1, but now it can be easily distributed on different computing nodes without the need for manual addresses reconfiguration of the devices.
|
||||
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 socket reconfiguration of the devices.
|
||||
|
||||
To make use of DDS functionality the example executables need to find the DDS plugin libraries that are compiled with FairRoot when FairRoot find DDS installed. Custom DDS location can be given to CMake as follows:
|
||||
|
||||
```bash
|
||||
cmake -DDDS_ROOT="/path/to/dds/install/dir/" ..
|
||||
```
|
||||
|
||||
The description below outlines the minimal steps needed to run the example with DDS. For general DDS help please refer to DDS documentation on [DDS Website](http://dds.gsi.de/).
|
||||
|
||||
##### 1. The device handles the channel addresses and ports configuration via DDS Plugin.
|
||||
##### 1. The device handles the socket addresses and ports configuration via DDS Plugin.
|
||||
|
||||
It is sufficient to provide the `-S "<@FAIRMQ_INSTALL_DIR@/lib" -P dds` (`<` prepends the following path to the default plugin search paths; put in the path which points to the library dir of your FairRoot installation) command line arguments to let the devices be configured dynamically. No code changes in the device are necessary. See the XML topology file for example of using the command line arguments.
|
||||
It is sufficient to provide the `-S "<@FAIRROOT_INSTALL_DIR@/lib" -P dds` (`<` prepends the following path to the default plugin search paths; put in the path which points to the library dir of your FairRoot installation) command line arguments to let the devices be configured dynamically. No code changes in the device are necessary. See the XML topology file for example of using the command line arguments.
|
||||
|
||||
##### 2a. Write DDS hosts file that contains a list of worker nodes to run the topology on (When deploying using the SSH plug-in).
|
||||
|
||||
We run this example on the local machine for simplicity. The file below defines 3 workers - sampler, processor and sink - with a total of 12 DDS agents (thus able to accept 12 tasks). The parameters for each worker node are:
|
||||
We run this example on the local machine for simplicity. The file below defines three workers, sampler, processor and sink, with a total of 12 DDS agents (thus able to accept 12 tasks). The parameters for each worker node are:
|
||||
- user-chosen worker ID (must be unique)
|
||||
- a host name with or without a login, in a form: login@host.fqdn (password-less SSH access to these hosts must be possible)
|
||||
- additional SSH params (can be empty)
|
||||
@@ -34,31 +40,27 @@ If you want to deploy on a single host DDS 1.6+ provides a localhost rms plug-in
|
||||
|
||||
##### 3. Write DDS topology file that describes which tasks (processes) to run and their topology and configuration.
|
||||
|
||||
Take a look at `ex-dds-topology.xml`. It consists of a definition part (properties, tasks, collections and more) and execution part (main). In our example Sampler, Processor and Sink tasks are defined, containing their executables and exchanged properties. The `<main>` of the topology uses the defined tasks. Besides one Sampler and one Sink task, a group containing Processor task is defined. The group has a multiplicity of 10, meaninig 10 Processors will be executed. Each of the Processors will receive the properties with Sampler and Sink addresses.
|
||||
Take a look at `ex-dds-topology.xml`. It consists of a definition part (properties, tasks, collections and more) and execution part (main). In our example Sampler, Processor and Sink tasks are defines, containing their executables and exchanged properties. The `<main>` of the topology uses the defined tasks. Besides one Sampler and one Sink task, a group containing Processor task is defined. The group has a multiplicity of 10, meaninig 10 Processors will be executed. Each of the Processors will receive the properties with Sampler and Sink addresses.
|
||||
|
||||
The configuration of the channel connection addresses is done by the DDS plugin via the channel names. The task property names must correspond to the channel names (data1, data2), with binding channels writing the properties and connecting channel reading the properties.
|
||||
The configuration of the channel connection addresses is done by the DDS plugin via the channel names. The task property names must correspond to the channel names (data1, data2), with binding channels writing the properties and connecting channel reading the properties (see the example XML and JSON files).
|
||||
|
||||
**If you chose step 2b earlier**, then modify the provided `ex-dds-topology.xml` in the top that the following lines read as following:
|
||||
If `eth0` network interface (default for binding) is not available on your system, specify another one in the topology file for each task. For example: `--network-interface lo0`.
|
||||
|
||||
If you chose step 2b earlier, then modify the provided `ex-dds-topology.xml` in the top that the following lines read as following:
|
||||
```xml
|
||||
<declrequirement name="SamplerWorker" type="wnname" value=".*"/>
|
||||
<declrequirement name="ProcessorWorker" type="wnname" value=".*"/>
|
||||
<declrequirement name="SinkWorker" type="wnname" value=".*"/>
|
||||
<declrequirement id="SamplerWorker" type="wnname" value=".*"/>
|
||||
<declrequirement id="ProcessorWorker" type="wnname" value=".*"/>
|
||||
<declrequirement id="SinkWorker" type="wnname" value=".*"/>
|
||||
```
|
||||
|
||||
Note that the attributes `value` contain a different value.
|
||||
|
||||
##### 4. Start DDS session.
|
||||
##### 4. Start DDS server.
|
||||
|
||||
First you need to initialize DDS environment:
|
||||
The DDS server is started with:
|
||||
|
||||
```bash
|
||||
source DDS_env.sh # this script is located in the DDS installation directory
|
||||
```
|
||||
|
||||
The DDS session is started with:
|
||||
|
||||
```bash
|
||||
dds-session start
|
||||
dds-server start -s
|
||||
```
|
||||
|
||||
##### 5. Submit DDS Agents (configured in the hosts file).
|
||||
@@ -69,7 +71,7 @@ dds-submit --rms ssh --config ex-dds-hosts.cfg
|
||||
```
|
||||
The `--rms` option defines a destination resource management system. The `--config` specifies an SSH plug-in resource definition file.
|
||||
|
||||
**If you chose step 2b earlier**, run the following command instead:
|
||||
If you chose step 2b earlier, run the following command instead:
|
||||
|
||||
```bash
|
||||
dds-submit --rms localhost -n 12
|
||||
@@ -83,40 +85,23 @@ dds-topology --activate ex-dds-topology.xml
|
||||
|
||||
##### 7. Run
|
||||
|
||||
After activation, agents will execute the defined tasks on the worker nodes. Output of the tasks will be stored in the directory that was specified in the hosts file (or in the system temporary directory when using the localhost plugin).
|
||||
After activation, agents will execute the defined tasks on the worker nodes. Output of the tasks will be stored in the directory that was specified in the hosts file.
|
||||
|
||||
##### 8. (optional) Use example command UI to check state of the devices
|
||||
|
||||
A simple utility (fairmq-dds-command-ui) is included with FairMQ to send commands to devices and receive replies from them. The utility uses the DDS intercom library to query state/config of devices and allows changing their state. To let the device listen to the commands from the utility, start the device with `-S "<@FAIRMQ_INSTALL_DIR@/lib" -P dds` cmd option (see example XML topology).
|
||||
A simple utility (fairmq-dds-command-ui) is included with FairRoot to send commands to devices and receive replies from them. The utility uses the DDS intercom library to send "check-state" string to all devices, to which they reply with their ID and state they are in. The utility also allows requesting state changes from devices. To let the device listen to the commands from the utility, start the device with `-S "<@FAIRROOT_INSTALL_DIR@/lib" -P dds` cmd option (see example XML topology).
|
||||
|
||||
To see it in action, start the fairmq-dds-command-ui while the topology is running. Run the utility with `-h` to see everything that it can do.
|
||||
To see it in action, start the fairmq-dds-command-ui while the topology is running.
|
||||
|
||||
The utility requires a session parameter to connect to appropriate DDS session. The session value is given when starting dds-session.
|
||||
|
||||
By default the command UI sends commands to all tasks. This can be further refined by giving a specific topology path via `-p` argument.
|
||||
Given our topology file, here are some examples of valid paths:
|
||||
```bash
|
||||
# get state of all devices
|
||||
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c
|
||||
# get state of sampler
|
||||
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/Sampler
|
||||
# get state of sink
|
||||
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/Sink
|
||||
# get state all processors
|
||||
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/ProcessorGroup/Processor
|
||||
# get state of a specific processor
|
||||
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/ProcessorGroup/Processor_9
|
||||
```
|
||||
|
||||
##### 9. Stop DDS session/topology.
|
||||
##### 9. Stop DDS server/topology.
|
||||
|
||||
The execution of tasks can be stopped with:
|
||||
```bash
|
||||
dds-topology --stop
|
||||
```
|
||||
Or by stopping the DDS session:
|
||||
Or by stopping the DDS server:
|
||||
```bash
|
||||
dds-session stop
|
||||
dds-server stop
|
||||
```
|
||||
|
||||
For general DDS documentation please refer to [DDS Website](http://dds.gsi.de/).
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* 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, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* 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, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -2,6 +2,6 @@
|
||||
# source setup.sh
|
||||
@bash_end@
|
||||
|
||||
sampler, username@localhost, , /path/to/dds-work/, 1
|
||||
processor, username@localhost, , /path/to/dds-work/, 10
|
||||
sink, username@localhost, , /path/to/dds-work/, 1
|
||||
sampler, username@localhost, , /path/to/dds-work-dir/, 1
|
||||
processor, username@localhost, , /path/to/dds-work-dir/, 10
|
||||
sink, username@localhost, , /path/to/dds-work-dir/, 1
|
||||
|
@@ -1,47 +1,47 @@
|
||||
<topology name="ExampleDDS">
|
||||
<topology id="ExampleDDS">
|
||||
|
||||
<property name="data1" />
|
||||
<property name="data2" />
|
||||
<property id="data1" />
|
||||
<property id="data2" />
|
||||
|
||||
<declrequirement name="SamplerWorker" type="wnname" value="sampler"/>
|
||||
<declrequirement name="ProcessorWorker" type="wnname" value="processor"/>
|
||||
<declrequirement name="SinkWorker" type="wnname" value="sink"/>
|
||||
<declrequirement id="SamplerWorker" type="wnname" value="sampler"/>
|
||||
<declrequirement id="ProcessorWorker" type="wnname" value="processor"/>
|
||||
<declrequirement id="SinkWorker" type="wnname" value="sink"/>
|
||||
|
||||
<decltask name="Sampler">
|
||||
<decltask id="Sampler">
|
||||
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-sampler --id sampler --color false --channel-config name=data1,type=push,method=bind -S "<@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
|
||||
<requirements>
|
||||
<name>SamplerWorker</name>
|
||||
<id>SamplerWorker</id>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data1</name>
|
||||
<id access="write">data1</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Processor">
|
||||
<decltask id="Processor">
|
||||
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-processor --id processor_%taskIndex% --config-key processor --color false --channel-config name=data1,type=pull,method=connect name=data2,type=push,method=connect -S "<@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
|
||||
<requirements>
|
||||
<name>ProcessorWorker</name>
|
||||
<id>ProcessorWorker</id>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="read">data1</name>
|
||||
<name access="read">data2</name>
|
||||
<id access="read">data1</id>
|
||||
<id access="read">data2</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<decltask name="Sink">
|
||||
<decltask id="Sink">
|
||||
<exe reachable="true">@EX_BIN_DIR@/fairmq-ex-dds-sink --id sink --color false --channel-config name=data2,type=pull,method=bind -S "<@DDS_PLUGIN_LIB_DIR@/" -P dds</exe>
|
||||
<requirements>
|
||||
<name>SinkWorker</name>
|
||||
<id>SinkWorker</id>
|
||||
</requirements>
|
||||
<properties>
|
||||
<name access="write">data2</name>
|
||||
<id access="write">data2</id>
|
||||
</properties>
|
||||
</decltask>
|
||||
|
||||
<main name="main">
|
||||
<main id="main">
|
||||
<task>Sampler</task>
|
||||
<task>Sink</task>
|
||||
<group name="ProcessorGroup" n="10">
|
||||
<group id="ProcessorGroup" n="10">
|
||||
<task>Processor</task>
|
||||
</group>
|
||||
</main>
|
||||
|
@@ -31,21 +31,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMA
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh)
|
||||
|
||||
add_test(NAME Example.Multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
add_test(NAME Example-Multipart-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example-Multipart-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.Multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
add_test(NAME Example-Multipart-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.Multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_test(NAME Example.Multipart.ofi COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh ofi)
|
||||
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 5 parts")
|
||||
endif()
|
||||
add_test(NAME Example-Multipart-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example-Multipart-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -53,13 +53,6 @@ bool Sampler::ConditionalRun()
|
||||
parts.AddPart(NewSimpleMessage(header));
|
||||
parts.AddPart(NewMessage(1000));
|
||||
|
||||
// create more data parts, testing the FairMQParts in-place constructor
|
||||
FairMQParts auxData{ NewMessage(500), NewMessage(600), NewMessage(700) };
|
||||
assert(auxData.Size() == 3);
|
||||
parts.AddPart(std::move(auxData));
|
||||
assert(auxData.Size() == 0);
|
||||
assert(parts.Size() == 5);
|
||||
|
||||
LOG(info) << "Sending body of size: " << parts.At(1)->GetSize();
|
||||
|
||||
Send(parts, "data");
|
||||
@@ -81,4 +74,4 @@ Sampler::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace example_multipart
|
||||
} // namespace example_multipart
|
@@ -8,8 +8,6 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID;' TERM
|
||||
|
||||
@@ -17,10 +15,9 @@ SAMPLER="fairmq-ex-multipart-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --max-iterations 1"
|
||||
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=push,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
|
||||
SAMPLER_PID=$!
|
||||
|
||||
@@ -28,9 +25,8 @@ SINK="fairmq-ex-multipart-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --control static --color false"
|
||||
SINK+=" --channel-config name=data,type=pair,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
SINK+=" --channel-config name=data,type=pull,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
|
||||
SINK_PID=$!
|
||||
|
||||
|
@@ -36,12 +36,12 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-channels.sh.
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh)
|
||||
|
||||
add_test(NAME Example.MultipleChannels.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
|
||||
set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example-Multiple-Channels-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
|
||||
set_tests_properties(Example-Multiple-Channels-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.MultipleChannels.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
|
||||
set_tests_properties(Example.MultipleChannels.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example-Multiple-Channels-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
|
||||
set_tests_properties(Example-Multiple-Channels-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
endif()
|
||||
|
||||
# install
|
||||
|
@@ -41,7 +41,7 @@ void Sampler::Run()
|
||||
{
|
||||
FairMQPollerPtr poller(NewPoller("data", "broadcast"));
|
||||
|
||||
while (!NewStatePending())
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
poller->Poll(100);
|
||||
|
||||
|
@@ -35,8 +35,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.s
|
||||
# test
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
add_test(NAME Example.MultipleTransports COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
set_tests_properties(Example.MultipleTransports PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example-Multiple-Transports COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
set_tests_properties(Example-Multiple-Transports PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -60,7 +60,7 @@ void Sampler1::ListenForAcks()
|
||||
{
|
||||
uint64_t numAcks = 0;
|
||||
|
||||
while (!NewStatePending())
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
FairMQMessagePtr ack(NewMessageFor("ack", 0));
|
||||
if (Receive(ack, "ack") < 0)
|
||||
|
@@ -1,46 +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 FAIRMQEXAMPLEREGIONBUILDER_H
|
||||
#define FAIRMQEXAMPLEREGIONBUILDER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace example_readout
|
||||
{
|
||||
|
||||
class Builder : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Builder()
|
||||
: fOutputChannelName()
|
||||
{}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
fOutputChannelName = fConfig->GetValue<std::string>("output-name");
|
||||
OnData("rb", &Builder::HandleData);
|
||||
}
|
||||
|
||||
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
|
||||
{
|
||||
if (Send(msg, fOutputChannelName) < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string fOutputChannelName;
|
||||
};
|
||||
|
||||
} // namespace example_readout
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONBUILDER_H */
|
@@ -1,59 +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" #
|
||||
################################################################################
|
||||
|
||||
add_executable(fairmq-ex-readout-readout runReadout.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-readout PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-readout-builder runBuilder.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-builder PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-readout-processor runProcessor.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-processor PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-readout-sender runSender.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-sender PRIVATE FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-readout-receiver runReceiver.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-receiver PRIVATE FairMQ)
|
||||
|
||||
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh)
|
||||
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-readout-readout
|
||||
fairmq-ex-readout-builder
|
||||
fairmq-ex-readout-processor
|
||||
fairmq-ex-readout-sender
|
||||
fairmq-ex-readout-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(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout.sh
|
||||
)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout-processing.sh
|
||||
)
|
@@ -1,37 +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 FAIRMQEXAMPLEREGIONPROCESSOR_H
|
||||
#define FAIRMQEXAMPLEREGIONPROCESSOR_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_readout
|
||||
{
|
||||
|
||||
class Processor : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Processor() {
|
||||
OnData("bp", &Processor::HandleData);
|
||||
}
|
||||
|
||||
protected:
|
||||
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
|
||||
{
|
||||
FairMQMessagePtr msg2(NewMessageFor("ps", 0, msg->GetSize()));
|
||||
if (Send(msg2, "ps") < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace example_readout
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONPROCESSOR_H */
|
@@ -1,27 +0,0 @@
|
||||
# Readout example
|
||||
|
||||
This examples shows two possible topologies (out of many) for a node connected to a detector readout (followed by a processing node).
|
||||
|
||||
## Setup without new data generation
|
||||
|
||||
```
|
||||
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
|
||||
| Readout --> Builder --> Sender | --> | Receiver |
|
||||
| [# shared memory segment (unused in this topology) ##################] | ofi | |
|
||||
| [# shmem unmanaged region (readout writes here, others read) ########] | | |
|
||||
|------------------------------------------------------------------------| |-------------------|
|
||||
```
|
||||
|
||||
The devices one the Readout Node communicate via shared memory transport. Readout device writes into shared memory unmanaged region. The data is then forwarded through Builder to Sender process, which sends it out via OFI transport.
|
||||
|
||||
## Setup with generating new data on the Readout node
|
||||
|
||||
```
|
||||
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
|
||||
| Readout --> Builder --> Processor --> Sender | --> | Receiver |
|
||||
| [# shared memory segment (used between Proccessor and Sender) #######] | ofi | |
|
||||
| [# shmem unmanaged region (readout writes here, builder & proc read) ] | | |
|
||||
|------------------------------------------------------------------------| |-------------------|
|
||||
```
|
||||
|
||||
In this topology one more device is added - Processor. It examines the arriving data and creates new data in shared memory. This data is not part of the unmanaged region, but lives in the general shared memory segment (unused in the previous setup). This new data is then forwarded to Sender and the Readout device is notified that the corresponding data piece in the unmanaged region is no longer used.
|
@@ -1,91 +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 FAIRMQEXAMPLEREADOUTREADOUT_H
|
||||
#define FAIRMQEXAMPLEREADOUTREADOUT_H
|
||||
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_readout
|
||||
{
|
||||
|
||||
class Readout : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Readout()
|
||||
: fMsgSize(10000)
|
||||
, fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
, fRegion(nullptr)
|
||||
, fNumUnackedMsgs(0)
|
||||
{}
|
||||
|
||||
protected:
|
||||
void InitTask() override
|
||||
{
|
||||
fMsgSize = fConfig->GetValue<int>("msg-size");
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("rb",
|
||||
0,
|
||||
10000000,
|
||||
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
|
||||
--fNumUnackedMsgs;
|
||||
if (fMaxIterations > 0) {
|
||||
LOG(debug) << "Received ack";
|
||||
}
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
bool ConditionalRun() override
|
||||
{
|
||||
FairMQMessagePtr msg(NewMessageFor("rb", // channel
|
||||
0, // sub-channel
|
||||
fRegion, // region
|
||||
fRegion->GetData(), // ptr within region
|
||||
fMsgSize, // offset from ptr
|
||||
nullptr // hint
|
||||
));
|
||||
|
||||
if (Send(msg, "rb", 0) > 0) {
|
||||
++fNumUnackedMsgs;
|
||||
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
void ResetTask() override
|
||||
{
|
||||
// if not all messages acknowledged, wait for a bit. But only once, since receiver could be already dead.
|
||||
if (fNumUnackedMsgs != 0) {
|
||||
LOG(debug) << "waiting for all acknowledgements... (" << fNumUnackedMsgs << ")";
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
|
||||
}
|
||||
fRegion.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
int fMsgSize;
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
FairMQUnmanagedRegionPtr fRegion;
|
||||
std::atomic<uint64_t> fNumUnackedMsgs;
|
||||
};
|
||||
|
||||
} // namespace example_readout
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREADOUTREADOUT_H */
|
@@ -1,54 +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 FAIRMQEXAMPLEREGIONRECEIVER_H
|
||||
#define FAIRMQEXAMPLEREGIONRECEIVER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_readout
|
||||
{
|
||||
|
||||
class Receiver : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Receiver()
|
||||
: fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
{}
|
||||
|
||||
protected:
|
||||
void InitTask() override
|
||||
{
|
||||
// Get the fMaxIterations value from the command line options (via fConfig)
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
}
|
||||
|
||||
void Run() override
|
||||
{
|
||||
FairMQChannel& dataInChannel = fChannels.at("sr").at(0);
|
||||
|
||||
while (!NewStatePending()) {
|
||||
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
|
||||
dataInChannel.Receive(msg);
|
||||
// void* ptr = msg->GetData();
|
||||
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
};
|
||||
|
||||
} // namespace example_readout
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONRECEIVER_H */
|
@@ -1,46 +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 FAIRMQEXAMPLEREGIONSENDER_H
|
||||
#define FAIRMQEXAMPLEREGIONSENDER_H
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace example_readout
|
||||
{
|
||||
|
||||
class Sender : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sender()
|
||||
: fInputChannelName()
|
||||
{}
|
||||
|
||||
void Init() override
|
||||
{
|
||||
fInputChannelName = fConfig->GetValue<std::string>("input-name");
|
||||
OnData(fInputChannelName, &Sender::HandleData);
|
||||
}
|
||||
|
||||
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
|
||||
{
|
||||
if (Send(msg, "sr") < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string fInputChannelName;
|
||||
};
|
||||
|
||||
} // namespace example_readout
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONSENDER_H */
|
@@ -1,40 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
msgSize="1000000"
|
||||
|
||||
if [[ $1 =~ ^[0-9]+$ ]]; then
|
||||
msgSize=$1
|
||||
fi
|
||||
|
||||
READOUT="fairmq-ex-readout-readout"
|
||||
READOUT+=" --id readout1"
|
||||
READOUT+=" --msg-size $msgSize"
|
||||
READOUT+=" --channel-config name=rb,type=pair,method=bind,address=tcp://localhost:7777,transport=shmem"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$READOUT &
|
||||
|
||||
BUILDER="fairmq-ex-readout-builder"
|
||||
BUILDER+=" --id builder1"
|
||||
BUILDER+=" --output-name bp"
|
||||
BUILDER+=" --channel-config name=rb,type=pair,method=connect,address=tcp://localhost:7777,transport=shmem"
|
||||
BUILDER+=" name=bp,type=pair,method=connect,address=tcp://localhost:7778,transport=shmem"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$BUILDER &
|
||||
|
||||
PROCESSOR="fairmq-ex-readout-processor"
|
||||
PROCESSOR+=" --id processor1"
|
||||
PROCESSOR+=" --channel-config name=bp,type=pair,method=bind,address=tcp://localhost:7778,transport=shmem"
|
||||
PROCESSOR+=" name=ps,type=pair,method=connect,address=tcp://localhost:7779,transport=shmem"
|
||||
xterm -geometry 80x23+750+500 -hold -e @EX_BIN_DIR@/$PROCESSOR &
|
||||
|
||||
SENDER="fairmq-ex-readout-sender"
|
||||
SENDER+=" --id sender1"
|
||||
SENDER+=" --input-name ps"
|
||||
SENDER+=" --channel-config name=ps,type=pair,method=bind,address=tcp://localhost:7779,transport=shmem"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=ofi"
|
||||
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
|
||||
|
||||
RECEIVER="fairmq-ex-readout-receiver"
|
||||
RECEIVER+=" --id receiver1"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=ofi"
|
||||
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &
|
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
msgSize="1000000"
|
||||
|
||||
if [[ $1 =~ ^[0-9]+$ ]]; then
|
||||
msgSize=$1
|
||||
fi
|
||||
|
||||
READOUT="fairmq-ex-readout-readout"
|
||||
READOUT+=" --id readout1"
|
||||
READOUT+=" --msg-size $msgSize"
|
||||
READOUT+=" --channel-config name=rb,type=pair,method=bind,address=tcp://localhost:7777,transport=shmem"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$READOUT &
|
||||
|
||||
BUILDER="fairmq-ex-readout-builder"
|
||||
BUILDER+=" --id builder1"
|
||||
BUILDER+=" --output-name bs"
|
||||
BUILDER+=" --channel-config name=rb,type=pair,method=connect,address=tcp://localhost:7777,transport=shmem"
|
||||
BUILDER+=" name=bs,type=pair,method=connect,address=tcp://localhost:7778,transport=shmem"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$BUILDER &
|
||||
|
||||
SENDER="fairmq-ex-readout-sender"
|
||||
SENDER+=" --id sender1"
|
||||
SENDER+=" --input-name bs"
|
||||
SENDER+=" --channel-config name=bs,type=pair,method=bind,address=tcp://localhost:7778,transport=shmem"
|
||||
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=ofi"
|
||||
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
|
||||
|
||||
RECEIVER="fairmq-ex-readout-receiver"
|
||||
RECEIVER+=" --id receiver1"
|
||||
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=ofi"
|
||||
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &
|
@@ -1,23 +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 "runFairMQDevice.h"
|
||||
#include "Receiver.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new example_readout::Receiver();
|
||||
}
|
@@ -18,6 +18,7 @@ target_link_libraries(ExampleRegionLib PUBLIC FairMQ)
|
||||
add_executable(fairmq-ex-region-sampler runSampler.cxx)
|
||||
target_link_libraries(fairmq-ex-region-sampler PRIVATE ExampleRegionLib)
|
||||
|
||||
|
||||
add_executable(fairmq-ex-region-sink runSink.cxx)
|
||||
target_link_libraries(fairmq-ex-region-sink PRIVATE ExampleRegionLib)
|
||||
|
||||
@@ -31,16 +32,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh)
|
||||
|
||||
add_test(NAME Example.Region.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
|
||||
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example-Region-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
|
||||
set_tests_properties(Example-Region-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.Region.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
|
||||
set_tests_properties(Example.Region.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example-Region-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
|
||||
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.Region.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
|
||||
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example-Region-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
|
||||
set_tests_properties(Example-Region-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -35,7 +35,7 @@ void Sink::Run()
|
||||
{
|
||||
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
|
||||
|
||||
while (!NewStatePending())
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
|
||||
dataInChannel.Receive(msg);
|
||||
|
@@ -14,12 +14,12 @@ SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --rate 10"
|
||||
SAMPLER+=" --transport shmem"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777,sndKernelSize=212992"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SINK="fairmq-ex-region-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --transport shmem"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777,rcvKernelSize=212992"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -32,16 +32,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-req-rep.sh.in ${CMAKE
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh)
|
||||
|
||||
add_test(NAME Example.ReqRep.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
|
||||
set_tests_properties(Example.ReqRep.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example-ReqRep-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
|
||||
set_tests_properties(Example-ReqRep-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.ReqRep.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
|
||||
set_tests_properties(Example.ReqRep.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example-ReqRep-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
|
||||
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.ReqRep.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
|
||||
set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example-ReqRep-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
|
||||
set_tests_properties(Example-ReqRep-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -8,8 +8,6 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $CLIENT_PID; kill -TERM $SERVER_PID; wait $CLIENT_PID; wait $SERVER_PID;' TERM
|
||||
|
||||
@@ -17,7 +15,6 @@ CLIENT="fairmq-ex-req-rep-client"
|
||||
CLIENT+=" --id client"
|
||||
CLIENT+=" --transport $transport"
|
||||
CLIENT+=" --verbosity veryhigh"
|
||||
CLIENT+=" --session $SESSION"
|
||||
CLIENT+=" --control static --color false"
|
||||
CLIENT+=" --max-iterations 1"
|
||||
CLIENT+=" --channel-config name=data,type=req,method=connect,rateLogging=0,address=tcp://127.0.0.1:5005"
|
||||
@@ -28,7 +25,6 @@ SERVER="fairmq-ex-req-rep-server"
|
||||
SERVER+=" --id server"
|
||||
SERVER+=" --transport $transport"
|
||||
SERVER+=" --verbosity veryhigh"
|
||||
SERVER+=" --session $SESSION"
|
||||
SERVER+=" --control static --color false"
|
||||
SERVER+=" --max-iterations 1"
|
||||
SERVER+=" --channel-config name=data,type=rep,method=bind,rateLogging=0,address=tcp://127.0.0.1:5005"
|
||||
|
54
fairmq/.clang-format
Normal file
54
fairmq/.clang-format
Normal file
@@ -0,0 +1,54 @@
|
||||
---
|
||||
Language: Cpp
|
||||
#AccessModifierOffset: -4
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlignTrailingComments: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortIfStatementsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
|
||||
# It is broken on windows. Breaks all #include "header.h"
|
||||
#AlwaysBreakBeforeMultilineStrings: true
|
||||
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
BinPackParameters: false
|
||||
ColumnLimit: 160
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
DerivePointerBinding: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
IndentCaseLabels: true
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: false
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerBindsToType: true
|
||||
SpacesBeforeTrailingComments: 1
|
||||
Cpp11BracedListStyle: false
|
||||
Standard: Cpp11
|
||||
IndentWidth: 4
|
||||
TabWidth: 4
|
||||
UseTab: Never
|
||||
BreakBeforeBraces: Allman
|
||||
IndentFunctionDeclarationAfterType: true
|
||||
SpacesInParentheses: false
|
||||
SpacesInAngles: false
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
ContinuationIndentWidth: 4
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
SpaceBeforeParens: ControlStatements
|
||||
...
|
@@ -12,8 +12,25 @@
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
add_subdirectory(plugins/DDS)
|
||||
endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
add_subdirectory(plugins/PMIx)
|
||||
|
||||
|
||||
############################
|
||||
# preprocessor definitions #
|
||||
############################
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_definitions(-DBUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_definitions(-DBUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
|
||||
|
||||
##################
|
||||
# subdirectories #
|
||||
##################
|
||||
# add_subdirectory(shmem/prototype)
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_subdirectory(ofi)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -21,145 +38,145 @@ endif()
|
||||
# libFairMQ header files #
|
||||
##########################
|
||||
set(FAIRMQ_PUBLIC_HEADER_FILES
|
||||
DeviceRunner.h
|
||||
EventManager.h
|
||||
FairMQChannel.h
|
||||
FairMQDevice.h
|
||||
FairMQLogger.h
|
||||
FairMQMessage.h
|
||||
FairMQParts.h
|
||||
FairMQPoller.h
|
||||
FairMQUnmanagedRegion.h
|
||||
FairMQSocket.h
|
||||
StateMachine.h
|
||||
FairMQTransportFactory.h
|
||||
MemoryResources.h
|
||||
MemoryResourceTools.h
|
||||
Tools.h
|
||||
Transports.h
|
||||
options/FairMQProgOptions.h
|
||||
options/FairProgOptions.h
|
||||
Plugin.h
|
||||
PluginManager.h
|
||||
PluginServices.h
|
||||
runFairMQDevice.h
|
||||
tools/CppSTL.h
|
||||
tools/Network.h
|
||||
tools/Process.h
|
||||
tools/RateLimit.h
|
||||
tools/Strings.h
|
||||
tools/Unique.h
|
||||
tools/Version.h
|
||||
DeviceRunner.h
|
||||
EventManager.h
|
||||
FairMQChannel.h
|
||||
FairMQDevice.h
|
||||
FairMQLogger.h
|
||||
FairMQMessage.h
|
||||
FairMQParts.h
|
||||
FairMQPoller.h
|
||||
FairMQUnmanagedRegion.h
|
||||
FairMQSocket.h
|
||||
FairMQStateMachine.h
|
||||
FairMQTransportFactory.h
|
||||
Tools.h
|
||||
Transports.h
|
||||
options/FairMQProgOptions.h
|
||||
options/FairProgOptions.h
|
||||
Plugin.h
|
||||
PluginManager.h
|
||||
PluginServices.h
|
||||
runFairMQDevice.h
|
||||
tools/CppSTL.h
|
||||
tools/Network.h
|
||||
tools/Process.h
|
||||
tools/Strings.h
|
||||
tools/Unique.h
|
||||
tools/Version.h
|
||||
)
|
||||
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES
|
||||
devices/FairMQBenchmarkSampler.h
|
||||
devices/FairMQMerger.h
|
||||
devices/FairMQMultiplier.h
|
||||
devices/FairMQProxy.h
|
||||
devices/FairMQSink.h
|
||||
devices/FairMQSplitter.h
|
||||
options/FairMQParser.h
|
||||
options/FairMQSuboptParser.h
|
||||
options/FairProgOptionsHelper.h
|
||||
plugins/Builtin.h
|
||||
plugins/Control.h
|
||||
shmem/FairMQMessageSHM.h
|
||||
shmem/FairMQPollerSHM.h
|
||||
shmem/FairMQUnmanagedRegionSHM.h
|
||||
shmem/FairMQSocketSHM.h
|
||||
shmem/FairMQTransportFactorySHM.h
|
||||
shmem/Common.h
|
||||
shmem/Manager.h
|
||||
shmem/Region.h
|
||||
zeromq/FairMQMessageZMQ.h
|
||||
zeromq/FairMQPollerZMQ.h
|
||||
zeromq/FairMQUnmanagedRegionZMQ.h
|
||||
zeromq/FairMQSocketZMQ.h
|
||||
zeromq/FairMQTransportFactoryZMQ.h
|
||||
devices/FairMQBenchmarkSampler.h
|
||||
devices/FairMQMerger.h
|
||||
devices/FairMQMultiplier.h
|
||||
devices/FairMQProxy.h
|
||||
devices/FairMQSink.h
|
||||
devices/FairMQSplitter.h
|
||||
options/FairMQParser.h
|
||||
options/FairMQSuboptParser.h
|
||||
options/FairProgOptionsHelper.h
|
||||
plugins/Builtin.h
|
||||
plugins/Control.h
|
||||
StateMachine.h
|
||||
shmem/FairMQMessageSHM.h
|
||||
shmem/FairMQPollerSHM.h
|
||||
shmem/FairMQUnmanagedRegionSHM.h
|
||||
shmem/FairMQSocketSHM.h
|
||||
shmem/FairMQTransportFactorySHM.h
|
||||
shmem/Common.h
|
||||
shmem/Manager.h
|
||||
shmem/Monitor.h
|
||||
shmem/Region.h
|
||||
zeromq/FairMQMessageZMQ.h
|
||||
zeromq/FairMQPollerZMQ.h
|
||||
zeromq/FairMQUnmanagedRegionZMQ.h
|
||||
zeromq/FairMQSocketZMQ.h
|
||||
zeromq/FairMQTransportFactoryZMQ.h
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
|
||||
nanomsg/FairMQMessageNN.h
|
||||
nanomsg/FairMQPollerNN.h
|
||||
nanomsg/FairMQUnmanagedRegionNN.h
|
||||
nanomsg/FairMQSocketNN.h
|
||||
nanomsg/FairMQTransportFactoryNN.h
|
||||
)
|
||||
nanomsg/FairMQMessageNN.h
|
||||
nanomsg/FairMQPollerNN.h
|
||||
nanomsg/FairMQUnmanagedRegionNN.h
|
||||
nanomsg/FairMQSocketNN.h
|
||||
nanomsg/FairMQTransportFactoryNN.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
|
||||
ofi/Context.h
|
||||
ofi/Message.h
|
||||
ofi/Poller.h
|
||||
ofi/Socket.h
|
||||
ofi/TransportFactory.h
|
||||
)
|
||||
ofi/Context.h
|
||||
ofi/Message.h
|
||||
ofi/Poller.h
|
||||
ofi/Socket.h
|
||||
ofi/TransportFactory.h
|
||||
)
|
||||
endif()
|
||||
|
||||
##########################
|
||||
# libFairMQ source files #
|
||||
##########################
|
||||
set(FAIRMQ_SOURCE_FILES
|
||||
DeviceRunner.cxx
|
||||
FairMQChannel.cxx
|
||||
FairMQDevice.cxx
|
||||
FairMQLogger.cxx
|
||||
FairMQMessage.cxx
|
||||
FairMQPoller.cxx
|
||||
FairMQSocket.cxx
|
||||
StateMachine.cxx
|
||||
FairMQTransportFactory.cxx
|
||||
devices/FairMQBenchmarkSampler.cxx
|
||||
devices/FairMQMerger.cxx
|
||||
devices/FairMQMultiplier.cxx
|
||||
devices/FairMQProxy.cxx
|
||||
devices/FairMQSplitter.cxx
|
||||
options/FairMQParser.cxx
|
||||
options/FairMQProgOptions.cxx
|
||||
options/FairMQSuboptParser.cxx
|
||||
Plugin.cxx
|
||||
PluginManager.cxx
|
||||
PluginServices.cxx
|
||||
plugins/Control.cxx
|
||||
shmem/FairMQMessageSHM.cxx
|
||||
shmem/FairMQPollerSHM.cxx
|
||||
shmem/FairMQUnmanagedRegionSHM.cxx
|
||||
shmem/FairMQSocketSHM.cxx
|
||||
shmem/FairMQTransportFactorySHM.cxx
|
||||
shmem/Manager.cxx
|
||||
shmem/Region.cxx
|
||||
tools/Network.cxx
|
||||
tools/Process.cxx
|
||||
tools/Unique.cxx
|
||||
zeromq/FairMQMessageZMQ.cxx
|
||||
zeromq/FairMQPollerZMQ.cxx
|
||||
zeromq/FairMQUnmanagedRegionZMQ.cxx
|
||||
zeromq/FairMQSocketZMQ.cxx
|
||||
zeromq/FairMQTransportFactoryZMQ.cxx
|
||||
MemoryResources.cxx
|
||||
DeviceRunner.cxx
|
||||
FairMQChannel.cxx
|
||||
FairMQDevice.cxx
|
||||
FairMQLogger.cxx
|
||||
FairMQMessage.cxx
|
||||
FairMQPoller.cxx
|
||||
FairMQSocket.cxx
|
||||
FairMQStateMachine.cxx
|
||||
FairMQTransportFactory.cxx
|
||||
devices/FairMQBenchmarkSampler.cxx
|
||||
devices/FairMQMerger.cxx
|
||||
devices/FairMQMultiplier.cxx
|
||||
devices/FairMQProxy.cxx
|
||||
devices/FairMQSplitter.cxx
|
||||
options/FairMQParser.cxx
|
||||
options/FairMQProgOptions.cxx
|
||||
options/FairMQSuboptParser.cxx
|
||||
Plugin.cxx
|
||||
PluginManager.cxx
|
||||
PluginServices.cxx
|
||||
plugins/Control.cxx
|
||||
StateMachine.cxx
|
||||
shmem/FairMQMessageSHM.cxx
|
||||
shmem/FairMQPollerSHM.cxx
|
||||
shmem/FairMQUnmanagedRegionSHM.cxx
|
||||
shmem/FairMQSocketSHM.cxx
|
||||
shmem/FairMQTransportFactorySHM.cxx
|
||||
shmem/Manager.cxx
|
||||
shmem/Monitor.cxx
|
||||
shmem/Region.cxx
|
||||
tools/Network.cxx
|
||||
tools/Process.cxx
|
||||
tools/Unique.cxx
|
||||
zeromq/FairMQMessageZMQ.cxx
|
||||
zeromq/FairMQPollerZMQ.cxx
|
||||
zeromq/FairMQUnmanagedRegionZMQ.cxx
|
||||
zeromq/FairMQSocketZMQ.cxx
|
||||
zeromq/FairMQTransportFactoryZMQ.cxx
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
nanomsg/FairMQMessageNN.cxx
|
||||
nanomsg/FairMQPollerNN.cxx
|
||||
nanomsg/FairMQUnmanagedRegionNN.cxx
|
||||
nanomsg/FairMQSocketNN.cxx
|
||||
nanomsg/FairMQTransportFactoryNN.cxx
|
||||
)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
nanomsg/FairMQMessageNN.cxx
|
||||
nanomsg/FairMQPollerNN.cxx
|
||||
nanomsg/FairMQUnmanagedRegionNN.cxx
|
||||
nanomsg/FairMQSocketNN.cxx
|
||||
nanomsg/FairMQTransportFactoryNN.cxx
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
ofi/Context.cxx
|
||||
ofi/Message.cxx
|
||||
ofi/Poller.cxx
|
||||
ofi/Socket.cxx
|
||||
ofi/TransportFactory.cxx
|
||||
)
|
||||
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
|
||||
ofi/Context.cxx
|
||||
ofi/Message.cxx
|
||||
ofi/Poller.cxx
|
||||
ofi/Socket.cxx
|
||||
ofi/TransportFactory.cxx
|
||||
)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -174,106 +191,62 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/options/startConfigExample.sh.in ${CM
|
||||
#################################
|
||||
# define libFairMQ build target #
|
||||
#################################
|
||||
if(FAST_BUILD)
|
||||
set(_target FairMQ_)
|
||||
else()
|
||||
set(_target FairMQ)
|
||||
endif()
|
||||
add_library(${_target}
|
||||
add_library(FairMQ SHARED
|
||||
${FAIRMQ_SOURCE_FILES}
|
||||
${FAIRMQ_PUBLIC_HEADER_FILES} # for IDE integration
|
||||
${FAIRMQ_PRIVATE_HEADER_FILES} # for IDE integration
|
||||
)
|
||||
set_target_properties(${_target} PROPERTIES LABELS coverage)
|
||||
if(FAST_BUILD)
|
||||
set_target_properties(${_target} PROPERTIES OUTPUT_NAME FairMQ)
|
||||
endif()
|
||||
|
||||
|
||||
############################
|
||||
# preprocessor definitions #
|
||||
############################
|
||||
target_compile_definitions(${_target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
|
||||
|
||||
#######################
|
||||
# include directories #
|
||||
#######################
|
||||
target_include_directories(${_target}
|
||||
PUBLIC # consumers inherit public include directories
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include/fairmq>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
target_include_directories(FairMQ
|
||||
PUBLIC # consumers inherit public include directories
|
||||
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
|
||||
$<INSTALL_INTERFACE:include/fairmq>
|
||||
$<INSTALL_INTERFACE:include>
|
||||
)
|
||||
|
||||
##################
|
||||
# link libraries #
|
||||
##################
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(OFI_DEPS
|
||||
asiofi::asiofi
|
||||
Boost::container
|
||||
)
|
||||
endif()
|
||||
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
|
||||
if(optional_deps)
|
||||
list(REMOVE_DUPLICATES optional_deps)
|
||||
set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>)
|
||||
endif()
|
||||
target_link_libraries(FairMQ
|
||||
INTERFACE # only consumers link against interface dependencies
|
||||
|
||||
target_link_libraries(${_target}
|
||||
INTERFACE # only consumers link against interface dependencies
|
||||
Boost::container
|
||||
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
|
||||
dl
|
||||
Boost::boost
|
||||
Boost::program_options
|
||||
Boost::thread
|
||||
Boost::system
|
||||
Boost::filesystem
|
||||
Boost::regex
|
||||
Boost::date_time
|
||||
Boost::signals
|
||||
FairLogger::FairLogger
|
||||
|
||||
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
|
||||
Threads::Threads
|
||||
dl
|
||||
$<$<PLATFORM_ID:Linux>:rt>
|
||||
Boost::boost
|
||||
Boost::program_options
|
||||
Boost::filesystem
|
||||
Boost::regex
|
||||
FairLogger::FairLogger
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
${NANOMSG_DEPS}
|
||||
${OFI_DEPS}
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
${NANOMSG_DEPS}
|
||||
${OFI_DEPS}
|
||||
)
|
||||
set_target_properties(${_target} PROPERTIES
|
||||
VERSION ${PROJECT_GIT_VERSION}
|
||||
set_target_properties(FairMQ PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
|
||||
)
|
||||
|
||||
|
||||
##############
|
||||
# fast build #
|
||||
##############
|
||||
if(FAST_BUILD)
|
||||
set_target_properties(${_target} PROPERTIES
|
||||
COTIRE_UNITY_TARGET_NAME "FairMQ"
|
||||
# COTIRE_ENABLE_PRECOMPILED_HEADER FALSE
|
||||
EXCLUDE_FROM_ALL TRUE
|
||||
)
|
||||
cotire(${_target})
|
||||
set_target_properties(FairMQ PROPERTIES EXCLUDE_FROM_ALL FALSE)
|
||||
set_target_properties(FairMQ PROPERTIES LABELS coverage)
|
||||
endif()
|
||||
|
||||
|
||||
###############
|
||||
# executables #
|
||||
###############
|
||||
|
||||
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
|
||||
target_link_libraries(fairmq-bsampler FairMQ)
|
||||
|
||||
@@ -295,48 +268,37 @@ target_link_libraries(fairmq-splitter FairMQ)
|
||||
add_executable(runConfigExample options/runConfigEx.cxx)
|
||||
target_link_libraries(runConfigExample FairMQ)
|
||||
|
||||
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
|
||||
target_link_libraries(fairmq-shmmonitor PUBLIC
|
||||
Threads::Threads
|
||||
$<$<PLATFORM_ID:Linux>:rt>
|
||||
Boost::boost
|
||||
Boost::date_time
|
||||
Boost::program_options
|
||||
)
|
||||
target_include_directories(fairmq-shmmonitor PUBLIC
|
||||
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
|
||||
)
|
||||
add_executable(fairmq-shmmonitor shmem/runMonitor.cxx)
|
||||
target_link_libraries(fairmq-shmmonitor FairMQ)
|
||||
|
||||
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
|
||||
target_link_libraries(fairmq-uuid-gen FairMQ)
|
||||
|
||||
|
||||
###########
|
||||
# install #
|
||||
###########
|
||||
install(
|
||||
TARGETS
|
||||
FairMQ
|
||||
fairmq-bsampler
|
||||
fairmq-merger
|
||||
fairmq-multiplier
|
||||
fairmq-proxy
|
||||
fairmq-sink
|
||||
fairmq-splitter
|
||||
fairmq-shmmonitor
|
||||
fairmq-uuid-gen
|
||||
TARGETS # FairMQFull, tests are not installed
|
||||
FairMQ
|
||||
fairmq-bsampler
|
||||
fairmq-merger
|
||||
fairmq-multiplier
|
||||
fairmq-proxy
|
||||
fairmq-sink
|
||||
fairmq-splitter
|
||||
fairmq-shmmonitor
|
||||
fairmq-uuid-gen
|
||||
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# preserve relative path and prepend fairmq
|
||||
foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES})
|
||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
|
||||
install(FILES ${HEADER}
|
||||
DESTINATION ${_destination}
|
||||
)
|
||||
get_filename_component(_path ${HEADER} DIRECTORY)
|
||||
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
|
||||
install(FILES ${HEADER}
|
||||
DESTINATION ${_destination}
|
||||
)
|
||||
endforeach()
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -7,21 +7,17 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "DeviceRunner.h"
|
||||
|
||||
#include <exception>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/Version.h>
|
||||
#include <exception>
|
||||
|
||||
using namespace fair::mq;
|
||||
|
||||
DeviceRunner::DeviceRunner(int argc, char* const argv[], bool printLogo)
|
||||
: fRawCmdLineArgs(tools::ToStrVector(argc, argv, false))
|
||||
, fConfig()
|
||||
, fDevice(nullptr)
|
||||
, fPluginManager(fRawCmdLineArgs)
|
||||
, fPrintLogo(printLogo)
|
||||
, fEvents()
|
||||
{}
|
||||
DeviceRunner::DeviceRunner(int argc, char* const argv[])
|
||||
: fRawCmdLineArgs{tools::ToStrVector(argc, argv, false)}
|
||||
, fPluginManager{PluginManager::MakeFromCommandLineOptions(fRawCmdLineArgs)}
|
||||
, fDevice{nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
auto DeviceRunner::Run() -> int
|
||||
{
|
||||
@@ -30,40 +26,32 @@ auto DeviceRunner::Run() -> int
|
||||
////////////////////////
|
||||
|
||||
// Load builtin plugins last
|
||||
fPluginManager.LoadPlugin("s:control");
|
||||
fPluginManager->LoadPlugin("s:control");
|
||||
|
||||
////// CALL HOOK ///////
|
||||
fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this);
|
||||
////////////////////////
|
||||
|
||||
fPluginManager.ForEachPluginProgOptions(
|
||||
[&](boost::program_options::options_description options) {
|
||||
fConfig.AddToCmdLineOptions(options);
|
||||
});
|
||||
fConfig.AddToCmdLineOptions(fPluginManager.ProgramOptions());
|
||||
fPluginManager->ForEachPluginProgOptions([&](boost::program_options::options_description options){
|
||||
fConfig.AddToCmdLineOptions(options);
|
||||
});
|
||||
fConfig.AddToCmdLineOptions(fPluginManager->ProgramOptions());
|
||||
|
||||
////// CALL HOOK ///////
|
||||
fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this);
|
||||
////////////////////////
|
||||
|
||||
if (fConfig.ParseAll(fRawCmdLineArgs, true)) {
|
||||
if (fConfig.ParseAll(fRawCmdLineArgs, true))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (fPrintLogo) {
|
||||
LOG(info) << std::endl
|
||||
<< " ______ _ _______ _________ " << std::endl
|
||||
<< " / ____/___ _(_)_______ |/ /_ __ \\ version " << FAIRMQ_GIT_VERSION << std::endl
|
||||
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE << std::endl
|
||||
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << std::endl
|
||||
<< " /_/ \\__,_/_/_/ /_/ /_/ \\___\\_\\ " << FAIRMQ_LICENSE << " © " << FAIRMQ_COPYRIGHT << std::endl;
|
||||
}
|
||||
|
||||
////// CALL HOOK ///////
|
||||
fEvents.Emit<hooks::InstantiateDevice>(*this);
|
||||
////////////////////////
|
||||
|
||||
if (!fDevice) {
|
||||
if (!fDevice)
|
||||
{
|
||||
LOG(error) << "getDevice(): no valid device provided. Exiting.";
|
||||
return 1;
|
||||
}
|
||||
@@ -72,16 +60,19 @@ auto DeviceRunner::Run() -> int
|
||||
|
||||
// Handle --print-channels
|
||||
fDevice->RegisterChannelEndpoints();
|
||||
if (fConfig.Count("print-channels")) {
|
||||
if (fConfig.Count("print-channels"))
|
||||
{
|
||||
fDevice->PrintRegisteredChannels();
|
||||
fDevice->ChangeState(fair::mq::Transition::End);
|
||||
fDevice->ChangeState(FairMQDevice::END);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle --version
|
||||
if (fConfig.Count("version")) {
|
||||
if (fConfig.Count("version"))
|
||||
{
|
||||
std::cout << "User device version: " << fDevice->GetVersion() << std::endl;
|
||||
fDevice->ChangeState(fair::mq::Transition::End);
|
||||
std::cout << "FAIRMQ_INTERFACE_VERSION: " << FAIRMQ_INTERFACE_VERSION << std::endl;
|
||||
fDevice->ChangeState(FairMQDevice::END);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -91,29 +82,31 @@ auto DeviceRunner::Run() -> int
|
||||
fDevice->SetConfig(fConfig);
|
||||
|
||||
// Initialize plugin services
|
||||
fPluginManager.EmplacePluginServices(fConfig, *fDevice);
|
||||
fPluginManager->EmplacePluginServices(&fConfig, fDevice);
|
||||
|
||||
// Instantiate and run plugins
|
||||
fPluginManager.InstantiatePlugins();
|
||||
|
||||
// Run the device
|
||||
fDevice->RunStateMachine();
|
||||
fPluginManager->InstantiatePlugins();
|
||||
|
||||
// Wait for control plugin to release device control
|
||||
fPluginManager.WaitForPluginsToReleaseDeviceControl();
|
||||
fPluginManager->WaitForPluginsToReleaseDeviceControl();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
auto DeviceRunner::RunWithExceptionHandlers() -> int
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
return Run();
|
||||
} catch (std::exception& e) {
|
||||
LOG(error) << "Uncaught exception reached the top of DeviceRunner: " << e.what();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG(error) << "Unhandled exception reached the top of main: " << e.what() << ", application will now exit";
|
||||
return 1;
|
||||
} catch (...) {
|
||||
LOG(error) << "Uncaught exception reached the top of DeviceRunner.";
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(error) << "Non-exception instance being thrown. Please make sure you use std::runtime_exception() instead. Application will now exit.";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -20,8 +20,10 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
|
||||
/**
|
||||
* @class DeviceRunner DeviceRunner.h <fairmq/DeviceRunner.h>
|
||||
@@ -29,8 +31,7 @@ namespace mq {
|
||||
*
|
||||
* Runs a single FairMQ device with config and plugin support.
|
||||
*
|
||||
* For customization user hooks are executed at various steps during device launch/shutdown in the
|
||||
* following sequence:
|
||||
* For customization user hooks are executed at various steps during device launch/shutdown in the following sequence:
|
||||
*
|
||||
* LoadPlugins
|
||||
* |
|
||||
@@ -43,41 +44,34 @@ namespace mq {
|
||||
* v
|
||||
* InstatiateDevice
|
||||
*
|
||||
* Each hook has access to all members of the DeviceRunner and really only differs by the point in
|
||||
* time it is called.
|
||||
* Each hook has access to all members of the DeviceRunner and really only differs by the point in time it is called.
|
||||
*
|
||||
* For an example usage of this class see the fairmq/runFairMQDevice.h header.
|
||||
*/
|
||||
class DeviceRunner
|
||||
{
|
||||
public:
|
||||
DeviceRunner(int argc, char* const argv[], bool printLogo = true);
|
||||
DeviceRunner(int argc, char* const argv[]);
|
||||
|
||||
auto Run() -> int;
|
||||
auto RunWithExceptionHandlers() -> int;
|
||||
|
||||
template<typename H>
|
||||
auto AddHook(std::function<void(DeviceRunner&)> hook) -> void
|
||||
{
|
||||
fEvents.Subscribe<H>("runner", hook);
|
||||
}
|
||||
auto AddHook(std::function<void(DeviceRunner&)> hook) -> void { fEvents.Subscribe<H>("runner", hook); }
|
||||
template<typename H>
|
||||
auto RemoveHook() -> void
|
||||
{
|
||||
fEvents.Unsubscribe<H>("runner");
|
||||
}
|
||||
auto RemoveHook() -> void { fEvents.Unsubscribe<H>("runner"); }
|
||||
|
||||
std::vector<std::string> fRawCmdLineArgs;
|
||||
std::shared_ptr<PluginManager> fPluginManager;
|
||||
FairMQProgOptions fConfig;
|
||||
std::unique_ptr<FairMQDevice> fDevice;
|
||||
PluginManager fPluginManager;
|
||||
const bool fPrintLogo;
|
||||
std::shared_ptr<FairMQDevice> fDevice;
|
||||
|
||||
private:
|
||||
EventManager fEvents;
|
||||
};
|
||||
|
||||
namespace hooks {
|
||||
namespace hooks
|
||||
{
|
||||
struct LoadPlugins : Event<DeviceRunner&> {};
|
||||
struct SetCustomCmdLineOptions : Event<DeviceRunner&> {};
|
||||
struct ModifyRawCmdLineArgs : Event<DeviceRunner&> {};
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -10,12 +10,10 @@
|
||||
#define FAIRMQCHANNEL_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory> // unique_ptr, shared_ptr
|
||||
#include <memory> // unique_ptr
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility> // std::move
|
||||
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <FairMQSocket.h>
|
||||
@@ -44,14 +42,6 @@ class FairMQChannel
|
||||
/// @param factory TransportFactory
|
||||
FairMQChannel(const std::string& name, const std::string& type, std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
/// Constructor
|
||||
/// @param name Channel name
|
||||
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
/// @param method Socket method (bind/connect)
|
||||
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
|
||||
/// @param factory TransportFactory
|
||||
FairMQChannel(const std::string& name, const std::string& type, const std::string& method, const std::string& address, std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
/// Copy Constructor
|
||||
FairMQChannel(const FairMQChannel&);
|
||||
|
||||
@@ -59,20 +49,18 @@ class FairMQChannel
|
||||
FairMQChannel& operator=(const FairMQChannel&);
|
||||
|
||||
/// Default destructor
|
||||
virtual ~FairMQChannel() {}
|
||||
virtual ~FairMQChannel();
|
||||
|
||||
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
FairMQSocket const & GetSocket() const;
|
||||
|
||||
FairMQSocket& GetSocket() const;
|
||||
|
||||
bool Bind(const std::string& address)
|
||||
auto Bind(const std::string& address) -> bool
|
||||
{
|
||||
fMethod = "bind";
|
||||
fAddress = address;
|
||||
return fSocket->Bind(address);
|
||||
}
|
||||
|
||||
bool Connect(const std::string& address)
|
||||
auto Connect(const std::string& address) -> void
|
||||
{
|
||||
fMethod = "connect";
|
||||
fAddress = address;
|
||||
@@ -81,18 +69,15 @@ class FairMQChannel
|
||||
|
||||
/// Get channel name
|
||||
/// @return Returns full channel name (e.g. "data[0]")
|
||||
std::string GetChannelName() const { return GetName(); } // TODO: deprecate this in favor of following
|
||||
std::string GetName() const;
|
||||
std::string GetChannelName() const;
|
||||
|
||||
/// Get channel prefix
|
||||
/// @return Returns channel prefix (e.g. "data" in "data[0]")
|
||||
std::string GetChannelPrefix() const { return GetPrefix(); } // TODO: deprecate this in favor of following
|
||||
std::string GetPrefix() const;
|
||||
std::string GetChannelPrefix() const;
|
||||
|
||||
/// Get channel index
|
||||
/// @return Returns channel index (e.g. 0 in "data[0]")
|
||||
std::string GetChannelIndex() const { return GetIndex(); } // TODO: deprecate this in favor of following
|
||||
std::string GetIndex() const;
|
||||
std::string GetChannelIndex() const;
|
||||
|
||||
/// Get socket type
|
||||
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
@@ -126,26 +111,10 @@ class FairMQChannel
|
||||
/// @return Returns socket kernel transmit receive buffer size (in bytes)
|
||||
int GetRcvKernelSize() const;
|
||||
|
||||
/// Get linger duration (in milliseconds)
|
||||
/// @return Returns linger duration (in milliseconds)
|
||||
int GetLinger() const;
|
||||
|
||||
/// Get socket rate logging interval (in seconds)
|
||||
/// @return Returns socket rate logging interval (in seconds)
|
||||
int GetRateLogging() const;
|
||||
|
||||
/// Get start of the port range for automatic binding
|
||||
/// @return start of the port range
|
||||
int GetPortRangeMin() const;
|
||||
|
||||
/// Get end of the port range for automatic binding
|
||||
/// @return end of the port range
|
||||
int GetPortRangeMax() const;
|
||||
|
||||
/// Set automatic binding (pick random port if bind fails)
|
||||
/// @return true/false, true if automatic binding is enabled
|
||||
bool GetAutoBind() const;
|
||||
|
||||
/// Set socket type
|
||||
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
void UpdateType(const std::string& type);
|
||||
@@ -178,30 +147,13 @@ class FairMQChannel
|
||||
/// @param rcvKernelSize Socket receive buffer size (in bytes)
|
||||
void UpdateRcvKernelSize(const int rcvKernelSize);
|
||||
|
||||
/// Set linger duration (in milliseconds)
|
||||
/// @param duration linger duration (in milliseconds)
|
||||
void UpdateLinger(const int duration);
|
||||
|
||||
/// Set socket rate logging interval (in seconds)
|
||||
/// @param rateLogging Socket rate logging interval (in seconds)
|
||||
void UpdateRateLogging(const int rateLogging);
|
||||
|
||||
/// Set start of the port range for automatic binding
|
||||
/// @param minPort start of the port range
|
||||
void UpdatePortRangeMin(const int minPort);
|
||||
|
||||
/// Set end of the port range for automatic binding
|
||||
/// @param maxPort end of the port range
|
||||
void UpdatePortRangeMax(const int maxPort);
|
||||
|
||||
/// Set automatic binding (pick random port if bind fails)
|
||||
/// @param autobind true/false, true to enable automatic binding
|
||||
void UpdateAutoBind(const bool autobind);
|
||||
|
||||
/// Set channel name
|
||||
/// @param name Arbitrary channel name
|
||||
void UpdateChannelName(const std::string& name) { UpdateName(name); } // TODO: deprecate this in favor of following
|
||||
void UpdateName(const std::string& name);
|
||||
void UpdateChannelName(const std::string& name);
|
||||
|
||||
/// Checks if the configured channel settings are valid (checks the validity parameter, without running full validation (as oposed to ValidateChannel()))
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
@@ -209,168 +161,166 @@ class FairMQChannel
|
||||
|
||||
/// Validates channel configuration
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
bool ValidateChannel() // TODO: deprecate this
|
||||
{
|
||||
return Validate();
|
||||
}
|
||||
|
||||
/// Validates channel configuration
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
bool Validate();
|
||||
|
||||
void Init();
|
||||
|
||||
bool ConnectEndpoint(const std::string& endpoint);
|
||||
|
||||
bool BindEndpoint(std::string& endpoint);
|
||||
bool ValidateChannel();
|
||||
|
||||
/// Resets the channel (requires validation to be used again).
|
||||
void ResetChannel();
|
||||
|
||||
int Send(FairMQMessagePtr& msg) const;
|
||||
int Receive(FairMQMessagePtr& msg) const;
|
||||
|
||||
/// Sends a message to the socket queue.
|
||||
/// @details Send method attempts to send a message by
|
||||
/// putting it in the output queue. If the queue is full or queueing is not possible
|
||||
/// for some other reason (e.g. no peers connected for a binding socket), the method blocks.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int Send(FairMQMessagePtr& msg, int sndTimeoutInMs = -1)
|
||||
{
|
||||
CheckSendCompatibility(msg);
|
||||
return fSocket->Send(msg, sndTimeoutInMs);
|
||||
}
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Send(FairMQMessagePtr& msg, int sndTimeoutInMs) const;
|
||||
|
||||
/// Receives a message from the socket queue.
|
||||
/// @details Receive method attempts to receive a message from the input queue.
|
||||
/// If the queue is empty the method blocks.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
CheckReceiveCompatibility(msg);
|
||||
return fSocket->Receive(msg, rcvTimeoutInMs);
|
||||
}
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs) const;
|
||||
|
||||
int SendAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, timeout);")))
|
||||
{
|
||||
CheckSendCompatibility(msg);
|
||||
return fSocket->Send(msg, 0);
|
||||
}
|
||||
int ReceiveAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, timeout);")))
|
||||
{
|
||||
CheckReceiveCompatibility(msg);
|
||||
return fSocket->Receive(msg, 0);
|
||||
}
|
||||
/// Sends a message in non-blocking mode.
|
||||
/// @details SendAsync method attempts to send a message without blocking by
|
||||
/// putting it in the queue.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been queued. If queueing failed due to
|
||||
/// full queue or no connected peers (when binding), returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int SendAsync(FairMQMessagePtr& msg) const;
|
||||
|
||||
/// Receives a message in non-blocking mode.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been received. If queue is empty, returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int ReceiveAsync(FairMQMessagePtr& msg) const;
|
||||
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
/// Send a vector of messages
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs = -1)
|
||||
{
|
||||
CheckSendCompatibility(msgVec);
|
||||
return fSocket->Send(msgVec, sndTimeoutInMs);
|
||||
}
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs) const;
|
||||
|
||||
/// Receive a vector of messages
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs = -1)
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs) const;
|
||||
|
||||
/// Sends a vector of message in non-blocking mode.
|
||||
/// @details SendAsync method attempts to send a vector of messages without blocking by
|
||||
/// putting it them the queue.
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been queued. If queueing failed due to
|
||||
/// full queue or no connected peers (when binding), returns -2. In case of errors, returns -1.
|
||||
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
/// Receives a vector of messages in non-blocking mode.
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been received. If queue is empty, returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
int64_t Send(FairMQParts& parts) const
|
||||
{
|
||||
CheckReceiveCompatibility(msgVec);
|
||||
return fSocket->Receive(msgVec, rcvTimeoutInMs);
|
||||
return Send(parts.fParts);
|
||||
}
|
||||
|
||||
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msgVec, timeout);")))
|
||||
int64_t Receive(FairMQParts& parts) const
|
||||
{
|
||||
CheckSendCompatibility(msgVec);
|
||||
return fSocket->Send(msgVec, 0);
|
||||
}
|
||||
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msgVec, timeout);")))
|
||||
{
|
||||
CheckReceiveCompatibility(msgVec);
|
||||
return fSocket->Receive(msgVec, 0);
|
||||
return Receive(parts.fParts);
|
||||
}
|
||||
|
||||
/// Send FairMQParts
|
||||
/// @param parts FairMQParts reference
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(FairMQParts& parts, int sndTimeoutInMs = -1)
|
||||
int64_t Send(FairMQParts& parts, int sndTimeoutInMs) const
|
||||
{
|
||||
return Send(parts.fParts, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Receive FairMQParts
|
||||
/// @param parts FairMQParts reference
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs = -1)
|
||||
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs) const
|
||||
{
|
||||
return Receive(parts.fParts, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t SendAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, timeout);")))
|
||||
int64_t SendAsync(FairMQParts& parts) const
|
||||
{
|
||||
return Send(parts.fParts, 0);
|
||||
return SendAsync(parts.fParts);
|
||||
}
|
||||
|
||||
int64_t ReceiveAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, timeout);")))
|
||||
int64_t ReceiveAsync(FairMQParts& parts) const
|
||||
{
|
||||
return Receive(parts.fParts, 0);
|
||||
return ReceiveAsync(parts.fParts);
|
||||
}
|
||||
|
||||
unsigned long GetBytesTx() const { return fSocket->GetBytesTx(); }
|
||||
unsigned long GetBytesRx() const { return fSocket->GetBytesRx(); }
|
||||
unsigned long GetMessagesTx() const { return fSocket->GetMessagesTx(); }
|
||||
unsigned long GetMessagesRx() const { return fSocket->GetMessagesRx(); }
|
||||
unsigned long GetBytesTx() const;
|
||||
unsigned long GetBytesRx() const;
|
||||
unsigned long GetMessagesTx() const;
|
||||
unsigned long GetMessagesRx() const;
|
||||
|
||||
auto Transport() -> FairMQTransportFactory*
|
||||
auto Transport() const -> const FairMQTransportFactory*
|
||||
{
|
||||
return fTransportFactory.get();
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessage(Args&&... args)
|
||||
FairMQMessagePtr NewMessage(Args&&... args) const
|
||||
{
|
||||
return Transport()->CreateMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
{
|
||||
return Transport()->NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
{
|
||||
return Transport()->NewStaticMessage(data);
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
|
||||
{
|
||||
return Transport()->CreateUnmanagedRegion(size, callback);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
|
||||
fair::mq::Transport fTransportType;
|
||||
std::unique_ptr<FairMQSocket> fSocket;
|
||||
|
||||
std::string fType;
|
||||
std::string fMethod;
|
||||
std::string fAddress;
|
||||
fair::mq::Transport fTransportType;
|
||||
int fSndBufSize;
|
||||
int fRcvBufSize;
|
||||
int fSndKernelSize;
|
||||
int fRcvKernelSize;
|
||||
int fLinger;
|
||||
int fRateLogging;
|
||||
int fPortRangeMin;
|
||||
int fPortRangeMax;
|
||||
bool fAutoBind;
|
||||
|
||||
std::string fName;
|
||||
std::atomic<bool> fIsValid;
|
||||
|
||||
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
|
||||
|
||||
void CheckSendCompatibility(FairMQMessagePtr& msg) const;
|
||||
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
void CheckReceiveCompatibility(FairMQMessagePtr& msg) const;
|
||||
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
// use static mutex to make the class easily copyable
|
||||
// implication: same mutex is used for all instances of the class
|
||||
// this does not hurt much, because mutex is used only during initialization with very low contention
|
||||
@@ -379,66 +329,8 @@ class FairMQChannel
|
||||
|
||||
bool fMultipart;
|
||||
bool fModified;
|
||||
bool fReset;
|
||||
|
||||
void CheckSendCompatibility(FairMQMessagePtr& msg)
|
||||
{
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr msgWrapper(NewMessage(
|
||||
msg->GetData(),
|
||||
msg->GetSize(),
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
msg = move(msgWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr msgWrapper(NewMessage(
|
||||
msg->GetData(),
|
||||
msg->GetSize(),
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
msg = move(msgWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckReceiveCompatibility(FairMQMessagePtr& msg)
|
||||
{
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr newMsg(NewMessage());
|
||||
msg = move(newMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr newMsg(NewMessage());
|
||||
msg = move(newMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory)
|
||||
{
|
||||
fTransportFactory = factory;
|
||||
fTransportType = factory->GetType();
|
||||
}
|
||||
auto SetModified(const bool modified) -> void;
|
||||
bool fReset;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQCHANNEL_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
#ifndef FAIRMQDEVICE_H_
|
||||
#define FAIRMQDEVICE_H_
|
||||
|
||||
#include <StateMachine.h>
|
||||
#include <FairMQStateMachine.h>
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
@@ -25,14 +25,11 @@
|
||||
#include <memory> // unique_ptr
|
||||
#include <algorithm> // std::sort()
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <assert.h> // static_assert
|
||||
#include <type_traits> // is_trivially_copyable
|
||||
#include <stdexcept>
|
||||
#include <queue>
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
@@ -44,58 +41,16 @@ using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChann
|
||||
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
|
||||
using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
|
||||
|
||||
class FairMQDevice
|
||||
class FairMQDevice : public FairMQStateMachine
|
||||
{
|
||||
friend class FairMQChannel;
|
||||
|
||||
public:
|
||||
// backwards-compatibility enum for old state machine interface, todo: delete this
|
||||
enum Event
|
||||
{
|
||||
INIT_DEVICE,
|
||||
internal_DEVICE_READY,
|
||||
INIT_TASK,
|
||||
internal_READY,
|
||||
RUN,
|
||||
STOP,
|
||||
RESET_TASK,
|
||||
RESET_DEVICE,
|
||||
internal_IDLE,
|
||||
END,
|
||||
ERROR_FOUND
|
||||
};
|
||||
|
||||
// backwards-compatibility enum for old state machine interface, todo: delete this
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
Error,
|
||||
IDLE,
|
||||
INITIALIZING_DEVICE,
|
||||
DEVICE_READY,
|
||||
INITIALIZING_TASK,
|
||||
READY,
|
||||
RUNNING,
|
||||
RESETTING_TASK,
|
||||
RESETTING_DEVICE,
|
||||
EXITING
|
||||
};
|
||||
|
||||
/// Default constructor
|
||||
FairMQDevice();
|
||||
/// Constructor with external FairMQProgOptions
|
||||
FairMQDevice(FairMQProgOptions& config);
|
||||
|
||||
/// Constructor that sets the version
|
||||
FairMQDevice(const fair::mq::tools::Version version);
|
||||
|
||||
/// Constructor that sets the version and external FairMQProgOptions
|
||||
FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version);
|
||||
|
||||
private:
|
||||
FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version);
|
||||
|
||||
public:
|
||||
/// Copy constructor (disabled)
|
||||
FairMQDevice(const FairMQDevice&) = delete;
|
||||
/// Assignment operator (disabled)
|
||||
@@ -103,6 +58,9 @@ class FairMQDevice
|
||||
/// Default destructor
|
||||
virtual ~FairMQDevice();
|
||||
|
||||
/// Catches interrupt signals (SIGINT, SIGTERM)
|
||||
void CatchSignals();
|
||||
|
||||
/// Outputs the socket transfer rates
|
||||
virtual void LogSocketRates();
|
||||
|
||||
@@ -111,6 +69,10 @@ class FairMQDevice
|
||||
/// @param reindex Should reindexing be done
|
||||
void SortChannel(const std::string& name, const bool reindex = true);
|
||||
|
||||
/// Prints channel configuration
|
||||
/// @param name Name of the channel
|
||||
void PrintChannel(const std::string& name);
|
||||
|
||||
template<typename Serializer, typename DataType, typename... Args>
|
||||
void Serialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
|
||||
{
|
||||
@@ -123,126 +85,164 @@ class FairMQDevice
|
||||
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
int Send(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(msg);
|
||||
}
|
||||
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(msg);
|
||||
}
|
||||
|
||||
/// Shorthand method to send `msg` on `chan` at index `i`
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int Send(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Send(FairMQMessagePtr& msg, const std::string& chan, const int i, int sndTimeoutInMs) const
|
||||
{
|
||||
return GetChannel(channel, index).Send(msg, sndTimeoutInMs);
|
||||
return fChannels.at(chan).at(i).Send(msg, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive `msg` on `chan` at index `i`
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& chan, const int i, int rcvTimeoutInMs) const
|
||||
{
|
||||
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
|
||||
return fChannels.at(chan).at(i).Receive(msg, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int SendAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
/// Shorthand method to send `msg` on `chan` at index `i` without blocking
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int SendAsync(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return GetChannel(channel, index).Send(msg, 0);
|
||||
return fChannels.at(chan).at(i).SendAsync(msg);
|
||||
}
|
||||
int ReceiveAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
|
||||
/// Shorthand method to receive `msg` on `chan` at index `i` without blocking
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int ReceiveAsync(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return GetChannel(channel, index).Receive(msg, 0);
|
||||
return fChannels.at(chan).at(i).ReceiveAsync(msg);
|
||||
}
|
||||
|
||||
int64_t Send(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(parts.fParts);
|
||||
}
|
||||
|
||||
int64_t Receive(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(parts.fParts);
|
||||
}
|
||||
|
||||
/// Shorthand method to send FairMQParts on `chan` at index `i`
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(FairMQParts& parts, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Send(FairMQParts& parts, const std::string& chan, const int i, int sndTimeoutInMs) const
|
||||
{
|
||||
return GetChannel(channel, index).Send(parts.fParts, sndTimeoutInMs);
|
||||
return fChannels.at(chan).at(i).Send(parts.fParts, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive FairMQParts on `chan` at index `i`
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(FairMQParts& parts, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Receive(FairMQParts& parts, const std::string& chan, const int i, int rcvTimeoutInMs) const
|
||||
{
|
||||
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
|
||||
return fChannels.at(chan).at(i).Receive(parts.fParts, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t SendAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
/// Shorthand method to send FairMQParts on `chan` at index `i` without blocking
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t SendAsync(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return GetChannel(channel, index).Send(parts.fParts, 0);
|
||||
return fChannels.at(chan).at(i).SendAsync(parts.fParts);
|
||||
}
|
||||
int64_t ReceiveAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
|
||||
/// Shorthand method to receive FairMQParts on `chan` at index `i` without blocking
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t ReceiveAsync(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return GetChannel(channel, index).Receive(parts.fParts, 0);
|
||||
return fChannels.at(chan).at(i).ReceiveAsync(parts.fParts);
|
||||
}
|
||||
|
||||
/// @brief Getter for default transport factory
|
||||
auto Transport() const -> FairMQTransportFactory*
|
||||
auto Transport() const -> const FairMQTransportFactory*
|
||||
{
|
||||
return fTransportFactory.get();
|
||||
}
|
||||
|
||||
// creates message with the default device transport
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessage(Args&&... args)
|
||||
FairMQMessagePtr NewMessage(Args&&... args) const
|
||||
{
|
||||
return Transport()->CreateMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// creates message with the transport of the specified channel
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
|
||||
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args) const
|
||||
{
|
||||
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
|
||||
return fChannels.at(channel).at(index).NewMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// creates a message that will not be cleaned up after transfer, with the default device transport
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
{
|
||||
return Transport()->NewStaticMessage(data);
|
||||
}
|
||||
|
||||
// creates a message that will not be cleaned up after transfer, with the transport of the specified channel
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
|
||||
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data) const
|
||||
{
|
||||
return GetChannel(channel, index).NewStaticMessage(data);
|
||||
return fChannels.at(channel).at(index).NewStaticMessage(data);
|
||||
}
|
||||
|
||||
// creates a message with a copy of the provided data, with the default device transport
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
{
|
||||
return Transport()->NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
// creates a message with a copy of the provided data, with the transport of the specified channel
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
|
||||
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data) const
|
||||
{
|
||||
return GetChannel(channel, index).NewSimpleMessage(data);
|
||||
return fChannels.at(channel).at(index).NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
// creates unamanaged region with the default device transport
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size)
|
||||
{
|
||||
return Transport()->CreateUnmanagedRegion(size, callback);
|
||||
return Transport()->CreateUnmanagedRegion(size);
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
return GetChannel(channel, index).NewUnmanagedRegion(size, callback);
|
||||
return fChannels.at(channel).at(index).Transport()->CreateUnmanagedRegion(size, callback);
|
||||
}
|
||||
|
||||
template<typename ...Ts>
|
||||
@@ -253,22 +253,22 @@ class FairMQDevice
|
||||
// if more than one channel provided, check compatibility
|
||||
if (chans.size() > 1)
|
||||
{
|
||||
fair::mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
|
||||
fair::mq::Transport type = fChannels.at(chans.at(0)).at(0).Transport()->GetType();
|
||||
|
||||
for (unsigned int i = 1; i < chans.size(); ++i)
|
||||
{
|
||||
if (type != GetChannel(chans.at(i), 0).Transport()->GetType())
|
||||
if (type != fChannels.at(chans.at(i)).at(0).Transport()->GetType())
|
||||
{
|
||||
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
|
||||
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
|
||||
ChangeState(ERROR_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
|
||||
return fChannels.at(chans.at(0)).at(0).Transport()->CreatePoller(fChannels, chans);
|
||||
}
|
||||
|
||||
FairMQPollerPtr NewPoller(const std::vector<FairMQChannel*>& channels)
|
||||
FairMQPollerPtr NewPoller(const std::vector<const FairMQChannel*>& channels)
|
||||
{
|
||||
// if more than one channel provided, check compatibility
|
||||
if (channels.size() > 1)
|
||||
@@ -280,7 +280,7 @@ class FairMQDevice
|
||||
if (type != channels.at(i)->Transport()->GetType())
|
||||
{
|
||||
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
|
||||
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
|
||||
ChangeState(ERROR_FOUND);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,16 +289,17 @@ class FairMQDevice
|
||||
}
|
||||
|
||||
/// Waits for the first initialization run to finish
|
||||
void WaitForInitialValidation() __attribute__((deprecated("This method will have no effect in future versions and will be removed. Instead subscribe for state changes and inspect configuration values."))) {}
|
||||
void WaitForInitialValidation();
|
||||
|
||||
/// Adds a transport to the device if it doesn't exist
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
|
||||
/// Sets the default transport for the device
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
void SetTransport(const std::string& transport = "zeromq");
|
||||
|
||||
/// Assigns config to the device
|
||||
void SetConfig(FairMQProgOptions& config);
|
||||
/// Get pointer to the config
|
||||
FairMQProgOptions* GetConfig() const
|
||||
const FairMQProgOptions* GetConfig() const
|
||||
{
|
||||
return fConfig;
|
||||
}
|
||||
@@ -308,7 +309,6 @@ class FairMQDevice
|
||||
/// @param rhs Left hand side value for comparison
|
||||
static bool SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs);
|
||||
|
||||
// overload to easily bind member functions
|
||||
template<typename T>
|
||||
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQMessagePtr& msg, int index))
|
||||
{
|
||||
@@ -335,7 +335,6 @@ class FairMQDevice
|
||||
}
|
||||
}
|
||||
|
||||
// overload to easily bind member functions
|
||||
template<typename T>
|
||||
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
|
||||
{
|
||||
@@ -362,22 +361,15 @@ class FairMQDevice
|
||||
}
|
||||
}
|
||||
|
||||
FairMQChannel& GetChannel(const std::string& channelName, const int index = 0)
|
||||
try {
|
||||
return fChannels.at(channelName).at(index);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
LOG(error) << "requested channel has not been configured? check channel names/configuration.";
|
||||
LOG(error) << "channel: " << channelName << ", index: " << index;
|
||||
LOG(error) << "out of range: " << oor.what();
|
||||
throw;
|
||||
}
|
||||
const FairMQChannel& GetChannel(const std::string& channelName, const int index = 0) const;
|
||||
|
||||
virtual void RegisterChannelEndpoints() {}
|
||||
|
||||
bool RegisterChannelEndpoint(const std::string& channelName, uint16_t minNumSubChannels = 1, uint16_t maxNumSubChannels = 1)
|
||||
{
|
||||
bool ok = fChannelRegistry.insert(std::make_pair(channelName, std::make_pair(minNumSubChannels, maxNumSubChannels))).second;
|
||||
if (!ok) {
|
||||
if (!ok)
|
||||
{
|
||||
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
|
||||
}
|
||||
return ok;
|
||||
@@ -385,10 +377,14 @@ class FairMQDevice
|
||||
|
||||
void PrintRegisteredChannels()
|
||||
{
|
||||
if (fChannelRegistry.size() < 1) {
|
||||
if (fChannelRegistry.size() < 1)
|
||||
{
|
||||
std::cout << "no channels registered." << std::endl;
|
||||
} else {
|
||||
for (const auto& c : fChannelRegistry) {
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& c : fChannelRegistry)
|
||||
{
|
||||
std::cout << c.first << ":" << c.second.first << ":" << c.second.second << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -399,148 +395,120 @@ class FairMQDevice
|
||||
|
||||
const fair::mq::tools::Version GetVersion() const { return fVersion; }
|
||||
|
||||
void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);}
|
||||
int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); }
|
||||
void SetNumIoThreads(int numIoThreads) { fNumIoThreads = numIoThreads; }
|
||||
int GetNumIoThreads() const { return fNumIoThreads; }
|
||||
|
||||
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetValue<std::string>("network-interface", networkInterface); }
|
||||
std::string GetNetworkInterface() const { return fConfig->GetValue<std::string>("network-interface"); }
|
||||
void SetPortRangeMin(int portRangeMin) { fPortRangeMin = portRangeMin; }
|
||||
int GetPortRangeMin() const { return fPortRangeMin; }
|
||||
|
||||
void SetDefaultTransport(const std::string& name) { fConfig->SetValue<std::string>("transport", name); }
|
||||
std::string GetDefaultTransport() const { return fConfig->GetValue<std::string>("transport"); }
|
||||
void SetPortRangeMax(int portRangeMax) { fPortRangeMax = portRangeMax; }
|
||||
int GetPortRangeMax() const { return fPortRangeMax; }
|
||||
|
||||
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fConfig->SetValue<int>("initialization-timeout", initializationTimeoutInS); }
|
||||
int GetInitializationTimeoutInS() const { return fConfig->GetValue<int>("initialization-timeout"); }
|
||||
void SetNetworkInterface(const std::string& networkInterface) { fNetworkInterface = networkInterface; }
|
||||
std::string GetNetworkInterface() const { return fNetworkInterface; }
|
||||
|
||||
/// Sets the default transport for the device
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
void SetTransport(const std::string& transport) { fConfig->SetValue<std::string>("transport", transport); }
|
||||
/// Gets the default transport name
|
||||
std::string GetTransportName() const { return fConfig->GetValue<std::string>("transport"); }
|
||||
void SetDefaultTransport(const std::string& name) { fDefaultTransportType = fair::mq::TransportTypes.at(name); }
|
||||
std::string GetDefaultTransport() const { return fair::mq::TransportNames.at(fDefaultTransportType); }
|
||||
|
||||
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; }
|
||||
int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; }
|
||||
|
||||
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
|
||||
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
|
||||
|
||||
void RunStateMachine()
|
||||
{
|
||||
fStateMachine.ProcessWork();
|
||||
};
|
||||
|
||||
/// Wait for the supplied amount of time or for interruption.
|
||||
/// If interrupted, returns false, otherwise true.
|
||||
/// @param duration wait duration
|
||||
template<class Rep, class Period>
|
||||
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
|
||||
{
|
||||
return !fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
|
||||
std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports
|
||||
|
||||
public:
|
||||
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
|
||||
std::unique_ptr<FairMQProgOptions> fInternalConfig; ///< Internal program options configuration
|
||||
FairMQProgOptions* fConfig; ///< Pointer to config (internal or external)
|
||||
|
||||
void AddChannel(const std::string& channelName, const FairMQChannel& channel)
|
||||
{
|
||||
fConfig->AddChannel(channelName, channel);
|
||||
}
|
||||
FairMQProgOptions* fConfig; ///< Program options configuration
|
||||
|
||||
protected:
|
||||
std::string fId; ///< Device ID
|
||||
|
||||
int fNumIoThreads; ///< Number of ZeroMQ I/O threads
|
||||
|
||||
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
|
||||
virtual void Init() {}
|
||||
|
||||
virtual void Bind() {}
|
||||
|
||||
virtual void Connect() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void Init();
|
||||
|
||||
/// Task initialization (can be overloaded in child classes)
|
||||
virtual void InitTask() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void InitTask();
|
||||
|
||||
/// Runs the device (to be overloaded in child classes)
|
||||
virtual void Run() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void Run();
|
||||
|
||||
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
|
||||
virtual void PreRun() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void PreRun();
|
||||
|
||||
/// Called during RUNNING state repeatedly until it returns false or device state changes
|
||||
virtual bool ConditionalRun() { return false; }
|
||||
/// Executed in a worker thread
|
||||
virtual bool ConditionalRun();
|
||||
|
||||
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
|
||||
virtual void PostRun() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void PostRun();
|
||||
|
||||
virtual void Pause() __attribute__((deprecated("PAUSE state is removed. This method is never called. To pause Run, go to READY with STOP transition and back to RUNNING with RUN to resume."))) {}
|
||||
/// Handles the PAUSE state
|
||||
/// Executed in a worker thread
|
||||
virtual void Pause();
|
||||
|
||||
/// Resets the user task (to be overloaded in child classes)
|
||||
virtual void ResetTask() {}
|
||||
/// Executed in a worker thread
|
||||
virtual void ResetTask();
|
||||
|
||||
/// Resets the device (can be overloaded in child classes)
|
||||
virtual void Reset() {}
|
||||
|
||||
public:
|
||||
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
|
||||
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::StateMachine::GetTransition(transition)); }
|
||||
|
||||
bool ChangeState(const int transition) __attribute__((deprecated("Use ChangeState(const fair::mq::Transition transition).")));
|
||||
|
||||
void WaitForEndOfState(const fair::mq::Transition transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState).")));
|
||||
void WaitForEndOfState(const std::string& transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState)."))) { WaitForState(transition); }
|
||||
|
||||
fair::mq::State WaitForNextState();
|
||||
void WaitForState(fair::mq::State state);
|
||||
void WaitForState(const std::string& state) { fair::mq::StateMachine::GetState(state); }
|
||||
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
|
||||
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
|
||||
|
||||
void SubscribeToNewTransition(const std::string& key, std::function<void(const fair::mq::Transition)> callback) { fStateMachine.SubscribeToNewTransition(key, callback); }
|
||||
void UnsubscribeFromNewTransition(const std::string& key) { fStateMachine.UnsubscribeFromNewTransition(key); }
|
||||
|
||||
bool CheckCurrentState(const int /* state */) const __attribute__((deprecated("Use NewStatePending()."))) { return !fStateMachine.NewStatePending(); }
|
||||
bool CheckCurrentState(const std::string& /* state */) const __attribute__((deprecated("Use NewStatePending()."))) { return !fStateMachine.NewStatePending(); }
|
||||
|
||||
/// Returns true is a new state has been requested, signaling the current handler to stop.
|
||||
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
|
||||
|
||||
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
|
||||
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
|
||||
|
||||
static std::string GetStateName(const fair::mq::State state) { return fair::mq::StateMachine::GetStateName(state); }
|
||||
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::StateMachine::GetTransitionName(transition); }
|
||||
|
||||
struct DeviceStateError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
/// Executed in a worker thread
|
||||
virtual void Reset();
|
||||
|
||||
private:
|
||||
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
|
||||
fair::mq::StateMachine fStateMachine;
|
||||
// condition variable to notify parent thread about end of initial validation.
|
||||
bool fInitialValidationFinished;
|
||||
std::condition_variable fInitialValidationCondition;
|
||||
std::mutex fInitialValidationMutex;
|
||||
|
||||
/// Handles the initialization
|
||||
int fPortRangeMin; ///< Minimum value for the port range (if dynamic)
|
||||
int fPortRangeMax; ///< Maximum value for the port range (if dynamic)
|
||||
|
||||
std::string fNetworkInterface; ///< Network interface to use for dynamic binding
|
||||
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
|
||||
|
||||
int fInitializationTimeoutInS; ///< Timeout for the initialization (in seconds)
|
||||
|
||||
/// Handles the initialization and the Init() method
|
||||
void InitWrapper();
|
||||
/// Initializes binding channels
|
||||
void BindWrapper();
|
||||
/// Initializes connecting channels
|
||||
void ConnectWrapper();
|
||||
/// Handles the InitTask() method
|
||||
void InitTaskWrapper();
|
||||
/// Handles the Run() method
|
||||
void RunWrapper();
|
||||
/// Handles the Pause() method
|
||||
void PauseWrapper();
|
||||
/// Handles the ResetTask() method
|
||||
void ResetTaskWrapper();
|
||||
/// Handles the Reset() method
|
||||
void ResetWrapper();
|
||||
|
||||
/// Notifies transports to cease any blocking activity
|
||||
void UnblockTransports();
|
||||
/// Unblocks blocking channel send/receive calls
|
||||
void Unblock();
|
||||
|
||||
/// Shuts down the transports and the device
|
||||
void Exit() {}
|
||||
void Exit();
|
||||
|
||||
/// Attach (bind/connect) channels in the list
|
||||
void AttachChannels(std::vector<FairMQChannel*>& chans);
|
||||
|
||||
/// Sets up and connects/binds a socket to an endpoint
|
||||
/// return a string with the actual endpoint if it happens
|
||||
/// to stray from default.
|
||||
bool ConnectEndpoint(FairMQSocket& socket, std::string& endpoint);
|
||||
bool BindEndpoint(FairMQSocket& socket, std::string& endpoint);
|
||||
/// Attaches the channel to all listed endpoints
|
||||
/// the list is comma separated; the default method (bind/connect) is used.
|
||||
/// to override default: prepend "@" to bind, "+" or ">" to connect endpoint.
|
||||
bool AttachChannel(FairMQChannel& ch);
|
||||
|
||||
void HandleSingleChannelInput();
|
||||
@@ -548,11 +516,10 @@ class FairMQDevice
|
||||
void HandleMultipleTransportInput();
|
||||
void PollForTransport(const FairMQTransportFactory* factory, const std::vector<std::string>& channelKeys);
|
||||
|
||||
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
|
||||
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i);
|
||||
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i) const;
|
||||
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i) const;
|
||||
|
||||
std::vector<FairMQChannel*> fUninitializedBindingChannels;
|
||||
std::vector<FairMQChannel*> fUninitializedConnectingChannels;
|
||||
void CreateOwnConfig();
|
||||
|
||||
bool fDataCallbacks;
|
||||
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
|
||||
@@ -563,14 +530,12 @@ class FairMQDevice
|
||||
std::mutex fMultitransportMutex;
|
||||
std::atomic<bool> fMultitransportProceed;
|
||||
|
||||
bool fExternalConfig;
|
||||
|
||||
const fair::mq::tools::Version fVersion;
|
||||
float fRate; ///< Rate limiting for ConditionalRun
|
||||
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).
|
||||
size_t fLastTime; ///< Rate limiting for ConditionalRun
|
||||
std::vector<std::string> fRawCmdLineArgs;
|
||||
|
||||
std::queue<fair::mq::State> fStates;
|
||||
std::mutex fStatesMtx;
|
||||
std::condition_variable fStatesCV;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQDEVICE_H_ */
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* 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, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -15,13 +15,10 @@
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
using fairmq_free_fn = void(void* data, void* hint);
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQMessage
|
||||
{
|
||||
public:
|
||||
FairMQMessage() = default;
|
||||
FairMQMessage(FairMQTransportFactory* factory):fTransport{factory} {}
|
||||
virtual void Rebuild() = 0;
|
||||
virtual void Rebuild(const size_t size) = 0;
|
||||
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||
@@ -32,15 +29,11 @@ class FairMQMessage
|
||||
virtual bool SetUsedSize(const size_t size) = 0;
|
||||
|
||||
virtual fair::mq::Transport GetType() const = 0;
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
//void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
virtual void Copy(const std::unique_ptr<FairMQMessage>& msg) __attribute__((deprecated("Use 'Copy(const FairMQMessage& msg)'"))) = 0;
|
||||
virtual void Copy(const FairMQMessage& msg) = 0;
|
||||
|
||||
virtual ~FairMQMessage() {};
|
||||
|
||||
private:
|
||||
FairMQTransportFactory* fTransport{nullptr};
|
||||
};
|
||||
|
||||
using FairMQMessagePtr = std::unique_ptr<FairMQMessage>;
|
||||
|
@@ -31,9 +31,6 @@ class FairMQParts
|
||||
FairMQParts(FairMQParts&& p) = default;
|
||||
/// Assignment operator
|
||||
FairMQParts& operator=(const FairMQParts&) = delete;
|
||||
/// Constructor from argument pack of std::unique_ptr<FairMQMessage> rvalues
|
||||
template <typename... Ts>
|
||||
FairMQParts(Ts&&... messages) : fParts() {AddPart(std::forward<Ts>(messages)...);}
|
||||
/// Default destructor
|
||||
~FairMQParts() {};
|
||||
|
||||
@@ -44,6 +41,14 @@ class FairMQParts
|
||||
fParts.push_back(std::unique_ptr<FairMQMessage>(msg));
|
||||
}
|
||||
|
||||
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
|
||||
/// @param msg unique pointer to FairMQMessage
|
||||
/// lvalue ref (move not required when passing argument)
|
||||
// inline void AddPart(std::unique_ptr<FairMQMessage>& msg)
|
||||
// {
|
||||
// fParts.push_back(std::move(msg));
|
||||
// }
|
||||
|
||||
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
|
||||
/// @param msg unique pointer to FairMQMessage
|
||||
/// rvalue ref (move required when passing argument)
|
||||
@@ -52,23 +57,6 @@ class FairMQParts
|
||||
fParts.push_back(std::move(msg));
|
||||
}
|
||||
|
||||
/// Add variable list of parts to the container (move)
|
||||
template <typename... Ts>
|
||||
void AddPart(std::unique_ptr<FairMQMessage>&& first, Ts&&... remaining)
|
||||
{
|
||||
AddPart(std::move(first));
|
||||
AddPart(std::forward<Ts>(remaining)...);
|
||||
}
|
||||
|
||||
/// Add content of another object by move
|
||||
void AddPart(FairMQParts&& other)
|
||||
{
|
||||
container parts = std::move(other.fParts);
|
||||
for (auto& part : parts) {
|
||||
fParts.push_back(std::move(part));
|
||||
}
|
||||
}
|
||||
|
||||
/// Get reference to part in the container at index (without bounds check)
|
||||
/// @param index container index
|
||||
FairMQMessage& operator[](const int index) { return *(fParts[index]); }
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* 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, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -18,8 +18,8 @@ class FairMQPoller
|
||||
virtual void Poll(const int timeout) = 0;
|
||||
virtual bool CheckInput(const int index) = 0;
|
||||
virtual bool CheckOutput(const int index) = 0;
|
||||
virtual bool CheckInput(const std::string& channelKey, const int index) = 0;
|
||||
virtual bool CheckOutput(const std::string& channelKey, const int index) = 0;
|
||||
virtual bool CheckInput(const std::string channelKey, const int index) = 0;
|
||||
virtual bool CheckOutput(const std::string channelKey, const int index) = 0;
|
||||
|
||||
virtual ~FairMQPoller() {};
|
||||
};
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -14,52 +14,46 @@
|
||||
#include <memory>
|
||||
|
||||
#include "FairMQMessage.h"
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQSocket
|
||||
{
|
||||
public:
|
||||
FairMQSocket() {}
|
||||
FairMQSocket(FairMQTransportFactory* fac): fTransport(fac) {}
|
||||
|
||||
virtual std::string GetId() = 0;
|
||||
|
||||
virtual bool Bind(const std::string& address) = 0;
|
||||
virtual bool Connect(const std::string& address) = 0;
|
||||
virtual void Connect(const std::string& address) = 0;
|
||||
|
||||
virtual int Send(FairMQMessagePtr& msg, int timeout = -1) = 0;
|
||||
virtual int Receive(FairMQMessagePtr& msg, int timeout = -1) = 0;
|
||||
virtual int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
|
||||
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
|
||||
virtual int Send(FairMQMessagePtr& msg, int timeout = 0) = 0;
|
||||
virtual int Receive(FairMQMessagePtr& msg, int timeout = 0) = 0;
|
||||
virtual int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = 0) = 0;
|
||||
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = 0) = 0;
|
||||
|
||||
virtual int TrySend(FairMQMessagePtr& msg) = 0;
|
||||
virtual int TryReceive(FairMQMessagePtr& msg) = 0;
|
||||
virtual int64_t TrySend(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) = 0;
|
||||
virtual int64_t TryReceive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) = 0;
|
||||
|
||||
virtual void* GetSocket() const = 0;
|
||||
virtual int GetSocket(int nothing) const = 0;
|
||||
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual void SetOption(const std::string& option, const void* value, size_t valueSize) = 0;
|
||||
virtual void GetOption(const std::string& option, void* value, size_t* valueSize) = 0;
|
||||
|
||||
virtual void SetLinger(const int value) = 0;
|
||||
virtual int GetLinger() const = 0;
|
||||
virtual void SetSndBufSize(const int value) = 0;
|
||||
virtual int GetSndBufSize() const = 0;
|
||||
virtual void SetRcvBufSize(const int value) = 0;
|
||||
virtual int GetRcvBufSize() const = 0;
|
||||
virtual void SetSndKernelSize(const int value) = 0;
|
||||
virtual int GetSndKernelSize() const = 0;
|
||||
virtual void SetRcvKernelSize(const int value) = 0;
|
||||
virtual int GetRcvKernelSize() const = 0;
|
||||
|
||||
virtual unsigned long GetBytesTx() const = 0;
|
||||
virtual unsigned long GetBytesRx() const = 0;
|
||||
virtual unsigned long GetMessagesTx() const = 0;
|
||||
virtual unsigned long GetMessagesRx() const = 0;
|
||||
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport=transport; }
|
||||
virtual bool SetSendTimeout(const int timeout, const std::string& address, const std::string& method) = 0;
|
||||
virtual int GetSendTimeout() const = 0;
|
||||
virtual bool SetReceiveTimeout(const int timeout, const std::string& address, const std::string& method) = 0;
|
||||
virtual int GetReceiveTimeout() const = 0;
|
||||
|
||||
virtual ~FairMQSocket() {};
|
||||
|
||||
private:
|
||||
FairMQTransportFactory* fTransport{nullptr};
|
||||
};
|
||||
|
||||
using FairMQSocketPtr = std::unique_ptr<FairMQSocket>;
|
||||
|
775
fairmq/FairMQStateMachine.cxx
Normal file
775
fairmq/FairMQStateMachine.cxx
Normal file
@@ -0,0 +1,775 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQStateMachine.cxx
|
||||
*
|
||||
* @since 2012-10-25
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "FairMQStateMachine.h"
|
||||
|
||||
// Increase maximum number of boost::msm states (default is 10)
|
||||
// This #define has to be before any msm header includes
|
||||
#define FUSION_MAX_VECTOR_SIZE 20
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/msm/back/state_machine.hpp>
|
||||
#include <boost/msm/back/tools.hpp>
|
||||
#include <boost/msm/back/metafunctions.hpp>
|
||||
#include <boost/msm/front/state_machine_def.hpp>
|
||||
#include <boost/msm/front/functor_row.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/signals2.hpp> // signal/slot for onStateChange callbacks
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace msmf = boost::msm::front;
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace fsm
|
||||
{
|
||||
|
||||
// defining events for the boost MSM state machine
|
||||
struct INIT_DEVICE_E { string name() const { return "INIT_DEVICE"; } };
|
||||
struct internal_DEVICE_READY_E { string name() const { return "internal_DEVICE_READY"; } };
|
||||
struct INIT_TASK_E { string name() const { return "INIT_TASK"; } };
|
||||
struct internal_READY_E { string name() const { return "internal_READY"; } };
|
||||
struct RUN_E { string name() const { return "RUN"; } };
|
||||
struct PAUSE_E { string name() const { return "PAUSE"; } };
|
||||
struct STOP_E { string name() const { return "STOP"; } };
|
||||
struct RESET_TASK_E { string name() const { return "RESET_TASK"; } };
|
||||
struct RESET_DEVICE_E { string name() const { return "RESET_DEVICE"; } };
|
||||
struct internal_IDLE_E { string name() const { return "internal_IDLE"; } };
|
||||
struct END_E { string name() const { return "END"; } };
|
||||
struct ERROR_FOUND_E { string name() const { return "ERROR_FOUND"; } };
|
||||
|
||||
// deactivate the warning for non-virtual destructor thrown in the boost library
|
||||
#if defined(__clang__)
|
||||
_Pragma("clang diagnostic push")
|
||||
_Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"")
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
_Pragma("GCC diagnostic push")
|
||||
_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"")
|
||||
#endif
|
||||
|
||||
// defining the boost MSM state machine
|
||||
struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
{
|
||||
public:
|
||||
Machine_()
|
||||
: fWork()
|
||||
, fWorkAvailableCondition()
|
||||
, fWorkDoneCondition()
|
||||
, fWorkMutex()
|
||||
, fWorkerTerminated(false)
|
||||
, fWorkActive(false)
|
||||
, fWorkAvailable(false)
|
||||
, fStateChangeSignal()
|
||||
, fStateChangeSignalsMap()
|
||||
, fTerminationRequested(false)
|
||||
, fState()
|
||||
, fWorkerThread()
|
||||
{}
|
||||
|
||||
virtual ~Machine_()
|
||||
{}
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
void on_entry(Event const&, FSM& fsm)
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine";
|
||||
fState = FairMQStateMachine::IDLE;
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::IDLE);
|
||||
|
||||
// start a worker thread to execute user states in.
|
||||
fsm.fWorkerThread = thread(&Machine_::Worker, &fsm);
|
||||
}
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
void on_exit(Event const&, FSM& /*fsm*/)
|
||||
{
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
// list of FSM states
|
||||
struct OK_FSM : public msmf::state<> {};
|
||||
struct ERROR_FSM : public msmf::terminate_state<> {};
|
||||
|
||||
struct IDLE_FSM : public msmf::state<> {};
|
||||
struct INITIALIZING_DEVICE_FSM : public msmf::state<> {};
|
||||
struct DEVICE_READY_FSM : public msmf::state<> {};
|
||||
struct INITIALIZING_TASK_FSM : public msmf::state<> {};
|
||||
struct READY_FSM : public msmf::state<> {};
|
||||
struct RUNNING_FSM : public msmf::state<> {};
|
||||
struct PAUSED_FSM : public msmf::state<> {};
|
||||
struct RESETTING_TASK_FSM : public msmf::state<> {};
|
||||
struct RESETTING_DEVICE_FSM : public msmf::state<> {};
|
||||
struct EXITING_FSM : public msmf::state<> {};
|
||||
|
||||
// initial states
|
||||
using initial_state = boost::mpl::vector<IDLE_FSM, OK_FSM>;
|
||||
|
||||
// actions
|
||||
struct IdleFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
LOG(state) << "Entering IDLE state";
|
||||
fsm.fState = FairMQStateMachine::IDLE;
|
||||
}
|
||||
};
|
||||
|
||||
struct InitDeviceFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::INITIALIZING_DEVICE;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering INITIALIZING DEVICE state";
|
||||
fsm.fWork = fsm.fInitWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct DeviceReadyFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
LOG(state) << "Entering DEVICE READY state";
|
||||
fsm.fState = FairMQStateMachine::DEVICE_READY;
|
||||
}
|
||||
};
|
||||
|
||||
struct InitTaskFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::INITIALIZING_TASK;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering INITIALIZING TASK state";
|
||||
fsm.fWork = fsm.fInitTaskWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct ReadyFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
LOG(state) << "Entering READY state";
|
||||
fsm.fState = FairMQStateMachine::READY;
|
||||
}
|
||||
};
|
||||
|
||||
struct RunFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::RUNNING;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering RUNNING state";
|
||||
fsm.fWork = fsm.fRunWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct PauseFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::PAUSED;
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering PAUSED state";
|
||||
fsm.fWork = fsm.fPauseWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct ResumeFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::RUNNING;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering RUNNING state";
|
||||
fsm.fWork = fsm.fRunWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct StopFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::READY;
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
LOG(state) << "Entering READY state";
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalStopFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::READY;
|
||||
fsm.fUnblockHandler();
|
||||
LOG(state) << "RUNNING state finished without an external event, entering READY state";
|
||||
}
|
||||
};
|
||||
|
||||
struct ResetTaskFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::RESETTING_TASK;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering RESETTING TASK state";
|
||||
fsm.fWork = fsm.fResetTaskWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct ResetDeviceFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::RESETTING_DEVICE;
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering RESETTING DEVICE state";
|
||||
fsm.fWork = fsm.fResetWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct ExitingFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
LOG(state) << "Entering EXITING state";
|
||||
fsm.fState = FairMQStateMachine::EXITING;
|
||||
fsm.fTerminationRequested = true;
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::EXITING);
|
||||
|
||||
// terminate worker thread
|
||||
{
|
||||
lock_guard<mutex> lock(fsm.fWorkMutex);
|
||||
fsm.fWorkerTerminated = true;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
|
||||
// join the worker thread (executing user states)
|
||||
if (fsm.fWorkerThread.joinable())
|
||||
{
|
||||
fsm.fWorkerThread.join();
|
||||
}
|
||||
|
||||
fsm.fExitHandler();
|
||||
}
|
||||
};
|
||||
|
||||
struct ErrorFoundFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
{
|
||||
LOG(state) << "Entering ERROR state";
|
||||
fsm.fState = FairMQStateMachine::Error;
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::Error);
|
||||
}
|
||||
};
|
||||
|
||||
// Transition table for Machine_
|
||||
struct transition_table : boost::mpl::vector<
|
||||
// Start Event Next Action Guard
|
||||
msmf::Row<IDLE_FSM, INIT_DEVICE_E, INITIALIZING_DEVICE_FSM, InitDeviceFct, msmf::none>,
|
||||
msmf::Row<IDLE_FSM, END_E, EXITING_FSM, ExitingFct, msmf::none>,
|
||||
msmf::Row<INITIALIZING_DEVICE_FSM, internal_DEVICE_READY_E, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>,
|
||||
msmf::Row<DEVICE_READY_FSM, INIT_TASK_E, INITIALIZING_TASK_FSM, InitTaskFct, msmf::none>,
|
||||
msmf::Row<DEVICE_READY_FSM, RESET_DEVICE_E, RESETTING_DEVICE_FSM, ResetDeviceFct, msmf::none>,
|
||||
msmf::Row<INITIALIZING_TASK_FSM, internal_READY_E, READY_FSM, ReadyFct, msmf::none>,
|
||||
msmf::Row<READY_FSM, RUN_E, RUNNING_FSM, RunFct, msmf::none>,
|
||||
msmf::Row<READY_FSM, RESET_TASK_E, RESETTING_TASK_FSM, ResetTaskFct, msmf::none>,
|
||||
msmf::Row<RUNNING_FSM, PAUSE_E, PAUSED_FSM, PauseFct, msmf::none>,
|
||||
msmf::Row<RUNNING_FSM, STOP_E, READY_FSM, StopFct, msmf::none>,
|
||||
msmf::Row<RUNNING_FSM, internal_READY_E, READY_FSM, InternalStopFct, msmf::none>,
|
||||
msmf::Row<PAUSED_FSM, RUN_E, RUNNING_FSM, ResumeFct, msmf::none>,
|
||||
msmf::Row<RESETTING_TASK_FSM, internal_DEVICE_READY_E, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>,
|
||||
msmf::Row<RESETTING_DEVICE_FSM, internal_IDLE_E, IDLE_FSM, IdleFct, msmf::none>,
|
||||
msmf::Row<OK_FSM, ERROR_FOUND_E, ERROR_FSM, ErrorFoundFct, msmf::none>>
|
||||
{};
|
||||
|
||||
// replaces the default no-transition response.
|
||||
template<typename FSM, typename Event>
|
||||
void no_transition(Event const& e, FSM&, int state)
|
||||
{
|
||||
using recursive_stt = typename boost::msm::back::recursive_get_transition_table<FSM>::type;
|
||||
using all_states = typename boost::msm::back::generate_state_set<recursive_stt>::type;
|
||||
|
||||
string stateName;
|
||||
|
||||
boost::mpl::for_each<all_states, boost::msm::wrap<boost::mpl::placeholders::_1>>(boost::msm::back::get_state_name<recursive_stt>(stateName, state));
|
||||
|
||||
stateName = boost::core::demangle(stateName.c_str());
|
||||
size_t pos = stateName.rfind(":");
|
||||
if (pos != string::npos)
|
||||
{
|
||||
stateName = stateName.substr(pos + 1);
|
||||
stateName = stateName.substr(0, stateName.size() - 4);
|
||||
}
|
||||
|
||||
if (stateName != "OK")
|
||||
{
|
||||
LOG(state) << "No transition from state " << stateName << " on event " << e.name();
|
||||
}
|
||||
}
|
||||
|
||||
static string GetStateName(const int state)
|
||||
{
|
||||
switch(state)
|
||||
{
|
||||
case FairMQStateMachine::OK:
|
||||
return "OK";
|
||||
case FairMQStateMachine::Error:
|
||||
return "Error";
|
||||
case FairMQStateMachine::IDLE:
|
||||
return "IDLE";
|
||||
case FairMQStateMachine::INITIALIZING_DEVICE:
|
||||
return "INITIALIZING_DEVICE";
|
||||
case FairMQStateMachine::DEVICE_READY:
|
||||
return "DEVICE_READY";
|
||||
case FairMQStateMachine::INITIALIZING_TASK:
|
||||
return "INITIALIZING_TASK";
|
||||
case FairMQStateMachine::READY:
|
||||
return "READY";
|
||||
case FairMQStateMachine::RUNNING:
|
||||
return "RUNNING";
|
||||
case FairMQStateMachine::PAUSED:
|
||||
return "PAUSED";
|
||||
case FairMQStateMachine::RESETTING_TASK:
|
||||
return "RESETTING_TASK";
|
||||
case FairMQStateMachine::RESETTING_DEVICE:
|
||||
return "RESETTING_DEVICE";
|
||||
case FairMQStateMachine::EXITING:
|
||||
return "EXITING";
|
||||
default:
|
||||
return "requested name for non-existent state...";
|
||||
}
|
||||
}
|
||||
|
||||
void CallStateChangeCallbacks(const FairMQStateMachine::State state) const
|
||||
{
|
||||
if (!fStateChangeSignal.empty())
|
||||
{
|
||||
fStateChangeSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
function<void(void)> fInitWrapperHandler;
|
||||
function<void(void)> fInitTaskWrapperHandler;
|
||||
function<void(void)> fRunWrapperHandler;
|
||||
function<void(void)> fPauseWrapperHandler;
|
||||
function<void(void)> fResetWrapperHandler;
|
||||
function<void(void)> fResetTaskWrapperHandler;
|
||||
function<void(void)> fExitHandler;
|
||||
function<void(void)> fUnblockHandler;
|
||||
|
||||
// function to execute user states in a worker thread
|
||||
function<void(void)> fWork;
|
||||
condition_variable fWorkAvailableCondition;
|
||||
condition_variable fWorkDoneCondition;
|
||||
mutex fWorkMutex;
|
||||
bool fWorkerTerminated;
|
||||
bool fWorkActive;
|
||||
bool fWorkAvailable;
|
||||
|
||||
boost::signals2::signal<void(const FairMQStateMachine::State)> fStateChangeSignal;
|
||||
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
|
||||
atomic<bool> fTerminationRequested;
|
||||
|
||||
atomic<FairMQStateMachine::State> fState;
|
||||
|
||||
private:
|
||||
void Worker()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
unique_lock<mutex> lock(fWorkMutex);
|
||||
// Wait for work to be done.
|
||||
while (!fWorkAvailable && !fWorkerTerminated)
|
||||
{
|
||||
fWorkAvailableCondition.wait(lock);
|
||||
}
|
||||
|
||||
if (fWorkerTerminated)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fWorkActive = true;
|
||||
}
|
||||
|
||||
fWork();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(fWorkMutex);
|
||||
fWorkActive = false;
|
||||
fWorkAvailable = false;
|
||||
fWorkDoneCondition.notify_one();
|
||||
}
|
||||
CallStateChangeCallbacks(fState);
|
||||
}
|
||||
}
|
||||
|
||||
// run state handlers in a separate thread
|
||||
thread fWorkerThread;
|
||||
}; // Machine_
|
||||
|
||||
using FairMQFSM = boost::msm::back::state_machine<Machine_>;
|
||||
|
||||
// reactivate the warning for non-virtual destructor
|
||||
#if defined(__clang__)
|
||||
_Pragma("clang diagnostic pop")
|
||||
#elif defined(__GNUC__) || defined(__GNUG__)
|
||||
_Pragma("GCC diagnostic pop")
|
||||
#endif
|
||||
|
||||
} // namespace fsm
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
using namespace fair::mq::fsm;
|
||||
|
||||
FairMQStateMachine::FairMQStateMachine()
|
||||
: fChangeStateMutex()
|
||||
, fFsm(new FairMQFSM)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fInitWrapperHandler = bind(&FairMQStateMachine::InitWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fInitTaskWrapperHandler = bind(&FairMQStateMachine::InitTaskWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fRunWrapperHandler = bind(&FairMQStateMachine::RunWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fPauseWrapperHandler = bind(&FairMQStateMachine::PauseWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fResetWrapperHandler = bind(&FairMQStateMachine::ResetWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fResetTaskWrapperHandler = bind(&FairMQStateMachine::ResetTaskWrapper, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fExitHandler = bind(&FairMQStateMachine::Exit, this);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fUnblockHandler = bind(&FairMQStateMachine::Unblock, this);
|
||||
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->start();
|
||||
}
|
||||
|
||||
FairMQStateMachine::~FairMQStateMachine()
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->stop();
|
||||
}
|
||||
|
||||
int FairMQStateMachine::GetInterfaceVersion() const
|
||||
{
|
||||
return FAIRMQ_INTERFACE_VERSION;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::ChangeState(int event)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_DEVICE_E());
|
||||
return true;
|
||||
}
|
||||
case internal_DEVICE_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_DEVICE_READY_E());
|
||||
return true;
|
||||
}
|
||||
case INIT_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_TASK_E());
|
||||
return true;
|
||||
}
|
||||
case internal_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_READY_E());
|
||||
return true;
|
||||
}
|
||||
case RUN:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RUN_E());
|
||||
return true;
|
||||
}
|
||||
case PAUSE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(PAUSE_E());
|
||||
return true;
|
||||
}
|
||||
case STOP:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(STOP_E());
|
||||
return true;
|
||||
}
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_DEVICE_E());
|
||||
return true;
|
||||
}
|
||||
case RESET_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_TASK_E());
|
||||
return true;
|
||||
}
|
||||
case internal_IDLE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_IDLE_E());
|
||||
return true;
|
||||
}
|
||||
case END:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(END_E());
|
||||
return true;
|
||||
}
|
||||
case ERROR_FOUND:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(ERROR_FOUND_E());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG(error) << "Requested state transition with an unsupported event: " << event << endl
|
||||
<< "Supported are: INIT_DEVICE, INIT_TASK, RUN, PAUSE, STOP, RESET_TASK, RESET_DEVICE, END, ERROR_FOUND";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::ChangeState(): " << e.what();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::ChangeState(const string& event)
|
||||
{
|
||||
return ChangeState(GetEventNumber(event));
|
||||
}
|
||||
|
||||
void FairMQStateMachine::WaitForEndOfState(int event)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
case INIT_TASK:
|
||||
case RUN:
|
||||
case RESET_TASK:
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
unique_lock<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
while (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive || static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.wait_for(lock, chrono::seconds(1));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(error) << "Requested state is either synchronous or does not exist.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::WaitForEndOfState(): " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQStateMachine::WaitForEndOfState(const string& event)
|
||||
{
|
||||
return WaitForEndOfState(GetEventNumber(event));
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::WaitForEndOfStateForMs(int event, int durationInMs)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
case INIT_TASK:
|
||||
case RUN:
|
||||
case RESET_TASK:
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
unique_lock<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
while (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive || static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.wait_for(lock, chrono::milliseconds(durationInMs));
|
||||
if (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LOG(error) << "Requested state is either synchronous or does not exist.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::WaitForEndOfStateForMs(): " << e.what();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::WaitForEndOfStateForMs(const string& event, int durationInMs)
|
||||
{
|
||||
return WaitForEndOfStateForMs(GetEventNumber(event), durationInMs);
|
||||
}
|
||||
|
||||
void FairMQStateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignal.connect(callback)});
|
||||
}
|
||||
void FairMQStateMachine::UnsubscribeFromStateChange(const string& key)
|
||||
{
|
||||
if (static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.count(key))
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.at(key).disconnect();
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQStateMachine::CallStateChangeCallbacks(const State state) const
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->CallStateChangeCallbacks(state);
|
||||
}
|
||||
|
||||
string FairMQStateMachine::GetCurrentStateName() const
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState);
|
||||
}
|
||||
int FairMQStateMachine::GetCurrentState() const
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->fState;
|
||||
}
|
||||
bool FairMQStateMachine::CheckCurrentState(int state) const
|
||||
{
|
||||
return state == static_pointer_cast<FairMQFSM>(fFsm)->fState;
|
||||
}
|
||||
bool FairMQStateMachine::CheckCurrentState(string state) const
|
||||
{
|
||||
return state == GetCurrentStateName();
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::Terminated()
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->fTerminationRequested;
|
||||
}
|
||||
|
||||
int FairMQStateMachine::GetEventNumber(const string& event)
|
||||
{
|
||||
if (event == "INIT_DEVICE") return INIT_DEVICE;
|
||||
if (event == "INIT_TASK") return INIT_TASK;
|
||||
if (event == "RUN") return RUN;
|
||||
if (event == "PAUSE") return PAUSE;
|
||||
if (event == "STOP") return STOP;
|
||||
if (event == "RESET_DEVICE") return RESET_DEVICE;
|
||||
if (event == "RESET_TASK") return RESET_TASK;
|
||||
if (event == "END") return END;
|
||||
if (event == "ERROR_FOUND") return ERROR_FOUND;
|
||||
LOG(error) << "Requested number for non-existent event... " << event << endl
|
||||
<< "Supported are: INIT_DEVICE, INIT_TASK, RUN, PAUSE, STOP, RESET_DEVICE, RESET_TASK, END, ERROR_FOUND";
|
||||
return -1;
|
||||
}
|
105
fairmq/FairMQStateMachine.h
Normal file
105
fairmq/FairMQStateMachine.h
Normal file
@@ -0,0 +1,105 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQStateMachine.h
|
||||
*
|
||||
* @since 2012-10-25
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSTATEMACHINE_H_
|
||||
#define FAIRMQSTATEMACHINE_H_
|
||||
|
||||
#define FAIRMQ_INTERFACE_VERSION 3
|
||||
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
class FairMQStateMachine
|
||||
{
|
||||
public:
|
||||
enum Event
|
||||
{
|
||||
INIT_DEVICE,
|
||||
internal_DEVICE_READY,
|
||||
INIT_TASK,
|
||||
internal_READY,
|
||||
RUN,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESET_TASK,
|
||||
RESET_DEVICE,
|
||||
internal_IDLE,
|
||||
END,
|
||||
ERROR_FOUND
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
Error,
|
||||
IDLE,
|
||||
INITIALIZING_DEVICE,
|
||||
DEVICE_READY,
|
||||
INITIALIZING_TASK,
|
||||
READY,
|
||||
RUNNING,
|
||||
PAUSED,
|
||||
RESETTING_TASK,
|
||||
RESETTING_DEVICE,
|
||||
EXITING
|
||||
};
|
||||
|
||||
FairMQStateMachine();
|
||||
virtual ~FairMQStateMachine();
|
||||
|
||||
int GetInterfaceVersion() const;
|
||||
|
||||
bool ChangeState(int event);
|
||||
bool ChangeState(const std::string& event);
|
||||
|
||||
void WaitForEndOfState(int event);
|
||||
void WaitForEndOfState(const std::string& event);
|
||||
|
||||
bool WaitForEndOfStateForMs(int event, int durationInMs);
|
||||
bool WaitForEndOfStateForMs(const std::string& event, int durationInMs);
|
||||
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback);
|
||||
void UnsubscribeFromStateChange(const std::string& key);
|
||||
|
||||
void CallStateChangeCallbacks(const State state) const;
|
||||
|
||||
std::string GetCurrentStateName() const;
|
||||
int GetCurrentState() const;
|
||||
bool CheckCurrentState(int state) const;
|
||||
bool CheckCurrentState(std::string state) const;
|
||||
bool Terminated();
|
||||
|
||||
// actions to be overwritten by derived classes
|
||||
virtual void InitWrapper() {}
|
||||
virtual void InitTaskWrapper() {}
|
||||
virtual void RunWrapper() {}
|
||||
virtual void PauseWrapper() {}
|
||||
virtual void ResetWrapper() {}
|
||||
virtual void ResetTaskWrapper() {}
|
||||
virtual void Exit() {}
|
||||
virtual void Unblock() {}
|
||||
|
||||
private:
|
||||
int GetEventNumber(const std::string& event);
|
||||
|
||||
std::mutex fChangeStateMutex;
|
||||
|
||||
std::shared_ptr<void> fFsm;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSTATEMACHINE_H_ */
|
@@ -9,12 +9,11 @@
|
||||
#ifndef FAIRMQTRANSPORTFACTORY_H_
|
||||
#define FAIRMQTRANSPORTFACTORY_H_
|
||||
|
||||
#include <FairMQLogger.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQPoller.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQPoller.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
#include <string>
|
||||
@@ -31,9 +30,6 @@ class FairMQTransportFactory
|
||||
/// Topology wide unique id
|
||||
const std::string fkId;
|
||||
|
||||
/// The polymorphic memory resource associated with the transport
|
||||
fair::mq::ChannelResource fMemoryResource{this};
|
||||
|
||||
public:
|
||||
/// ctor
|
||||
/// @param id Topology wide unique id, usually the device id.
|
||||
@@ -41,36 +37,34 @@ class FairMQTransportFactory
|
||||
|
||||
auto GetId() const -> const std::string { return fkId; };
|
||||
|
||||
/// Get a pointer to the associated polymorphic memory resource
|
||||
fair::mq::ChannelResource* GetMemoryResource() { return &fMemoryResource; }
|
||||
operator fair::mq::ChannelResource*() { return &fMemoryResource; }
|
||||
|
||||
/// @brief Create empty FairMQMessage
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage() = 0;
|
||||
virtual FairMQMessagePtr CreateMessage() const = 0;
|
||||
/// @brief Create new FairMQMessage of specified size
|
||||
/// @param size message size
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size) = 0;
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size) const = 0;
|
||||
/// @brief Create new FairMQMessage with user provided buffer and size
|
||||
/// @param data pointer to user provided buffer
|
||||
/// @param size size of the user provided buffer
|
||||
/// @param ffn callback, called when the message is transfered (and can be deleted)
|
||||
/// @param obj optional helper pointer that can be used in the callback
|
||||
/// @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) const = 0;
|
||||
|
||||
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) const = 0;
|
||||
|
||||
/// 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) const = 0;
|
||||
|
||||
/// Create a poller for a single channel (all subchannels)
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
|
||||
/// Create a poller for specific channels
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<const FairMQChannel*>& channels) const = 0;
|
||||
/// 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;
|
||||
/// Create a poller for two sockets
|
||||
virtual FairMQPollerPtr CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const = 0;
|
||||
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr) const = 0;
|
||||
|
||||
@@ -79,7 +73,6 @@ class FairMQTransportFactory
|
||||
|
||||
virtual void Interrupt() = 0;
|
||||
virtual void Resume() = 0;
|
||||
virtual void Reset() = 0;
|
||||
|
||||
virtual ~FairMQTransportFactory() {};
|
||||
|
||||
@@ -96,7 +89,7 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
{
|
||||
// todo: is_trivially_copyable not available on gcc < 5, workaround?
|
||||
// static_assert(std::is_trivially_copyable<T>::value, "The argument type for NewSimpleMessage has to be trivially copyable!");
|
||||
@@ -105,13 +98,13 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
FairMQMessagePtr NewSimpleMessage(const char(&data)[N])
|
||||
FairMQMessagePtr NewSimpleMessage(const char(&data)[N]) const
|
||||
{
|
||||
std::string* msgStr = new std::string(data);
|
||||
return CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
|
||||
}
|
||||
|
||||
FairMQMessagePtr NewSimpleMessage(const std::string& str)
|
||||
FairMQMessagePtr NewSimpleMessage(const std::string& str) const
|
||||
{
|
||||
|
||||
std::string* msgStr = new std::string(str);
|
||||
@@ -119,12 +112,12 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
{
|
||||
return CreateMessage(data, sizeof(T), FairMQNoCleanup, nullptr);
|
||||
}
|
||||
|
||||
FairMQMessagePtr NewStaticMessage(const std::string& str)
|
||||
FairMQMessagePtr NewStaticMessage(const std::string& str) const
|
||||
{
|
||||
return CreateMessage(const_cast<char*>(str.c_str()), str.length(), FairMQNoCleanup, nullptr);
|
||||
}
|
||||
|
@@ -1,66 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Tools for interfacing containers to the transport via polymorphic
|
||||
/// allocators
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#include <fairmq/FairMQTransportFactory.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
||||
using BytePmrAllocator = pmr::polymorphic_allocator<fair::mq::byte>;
|
||||
|
||||
//_________________________________________________________________________________________________
|
||||
// return the message associated with the container or throw if it is not possible
|
||||
template<typename ContainerT>
|
||||
// typename std::enable_if<
|
||||
// std::is_base_of<
|
||||
// pmr::polymorphic_allocator<typename
|
||||
// ContainerT::value_type>,
|
||||
// typename ContainerT::allocator_type>::value == true,
|
||||
// FairMQMessagePtr>::type
|
||||
FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targetResource = nullptr)
|
||||
{
|
||||
auto container = std::move(container_);
|
||||
auto alloc = container.get_allocator();
|
||||
|
||||
auto resource = dynamic_cast<FairMQMemoryResource *>(alloc.resource());
|
||||
if (!resource && !targetResource) {
|
||||
throw std::runtime_error("Neither the container or target resource specified");
|
||||
}
|
||||
size_t containerSizeBytes = container.size() * sizeof(typename ContainerT::value_type);
|
||||
if ((!targetResource && resource)
|
||||
|| (resource && targetResource && resource->is_equal(*targetResource))) {
|
||||
auto message = resource->getMessage(static_cast<void *>(
|
||||
const_cast<typename std::remove_const<typename ContainerT::value_type>::type *>(
|
||||
container.data())));
|
||||
if (message)
|
||||
{
|
||||
message->SetUsedSize(containerSizeBytes);
|
||||
return message;
|
||||
} else {
|
||||
//container is not required to allocate (like in std::string small string optimization)
|
||||
//in case we get no message we fall back to default (copy) behaviour)
|
||||
targetResource = resource;
|
||||
}
|
||||
}
|
||||
|
||||
auto message = targetResource->getTransportFactory()->CreateMessage(containerSizeBytes);
|
||||
std::memcpy(static_cast<fair::mq::byte *>(message->GetData()),
|
||||
container.data(),
|
||||
containerSizeBytes);
|
||||
return message;
|
||||
};
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
@@ -1,22 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Memory allocators and interfaces related to managing memory via the
|
||||
/// trasport layer
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#include <fairmq/FairMQTransportFactory.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
|
||||
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t /*alignment*/)
|
||||
{
|
||||
return setMessage(factory->CreateMessage(bytes));
|
||||
};
|
||||
|
@@ -1,116 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Memory allocators and interfaces related to managing memory via the
|
||||
/// trasport layer
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#ifndef FAIR_MQ_MEMORY_RESOURCES_H
|
||||
#define FAIR_MQ_MEMORY_RESOURCES_H
|
||||
|
||||
#include <fairmq/FairMQMessage.h>
|
||||
class FairMQTransportFactory;
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/pmr/memory_resource.hpp>
|
||||
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
|
||||
#include <boost/container/pmr/polymorphic_allocator.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
||||
using byte = unsigned char;
|
||||
namespace pmr = boost::container::pmr;
|
||||
|
||||
/// All FairMQ related memory resources need to inherit from this interface
|
||||
/// class for the
|
||||
/// getMessage() api.
|
||||
class FairMQMemoryResource : public pmr::memory_resource
|
||||
{
|
||||
public:
|
||||
/// return the message containing data associated with the pointer (to start
|
||||
/// of
|
||||
/// buffer), e.g. pointer returned by std::vector::data() return nullptr if
|
||||
/// returning
|
||||
/// a message does not make sense!
|
||||
virtual FairMQMessagePtr getMessage(void *p) = 0;
|
||||
virtual void *setMessage(FairMQMessagePtr) = 0;
|
||||
virtual FairMQTransportFactory *getTransportFactory() noexcept = 0;
|
||||
virtual size_t getNumberOfMessages() const noexcept = 0;
|
||||
};
|
||||
|
||||
/// This is the allocator that interfaces to FairMQ memory management. All
|
||||
/// allocations are
|
||||
/// delegated to FairMQ so standard (e.g. STL) containers can construct their
|
||||
/// stuff in
|
||||
/// memory regions appropriate for the data channel configuration.
|
||||
class ChannelResource : public FairMQMemoryResource
|
||||
{
|
||||
protected:
|
||||
FairMQTransportFactory *factory{nullptr};
|
||||
// TODO: for now a map to keep track of allocations, something else would
|
||||
// probably be
|
||||
// faster, but for now this does not need to be fast.
|
||||
boost::container::flat_map<void *, FairMQMessagePtr> messageMap;
|
||||
|
||||
public:
|
||||
ChannelResource() = delete;
|
||||
|
||||
ChannelResource(FairMQTransportFactory *_factory)
|
||||
: FairMQMemoryResource()
|
||||
, factory(_factory)
|
||||
, messageMap()
|
||||
{
|
||||
if (!_factory) {
|
||||
throw std::runtime_error("Tried to construct from a nullptr FairMQTransportFactory");
|
||||
}
|
||||
};
|
||||
|
||||
FairMQMessagePtr getMessage(void *p) override
|
||||
{
|
||||
auto mes = std::move(messageMap[p]);
|
||||
messageMap.erase(p);
|
||||
return mes;
|
||||
}
|
||||
|
||||
void *setMessage(FairMQMessagePtr message) override
|
||||
{
|
||||
void *addr = message->GetData();
|
||||
messageMap[addr] = std::move(message);
|
||||
return addr;
|
||||
}
|
||||
|
||||
FairMQTransportFactory *getTransportFactory() noexcept override { return factory; }
|
||||
|
||||
size_t getNumberOfMessages() const noexcept override { return messageMap.size(); }
|
||||
|
||||
protected:
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override;
|
||||
void do_deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/) override
|
||||
{
|
||||
messageMap.erase(p);
|
||||
};
|
||||
|
||||
bool do_is_equal(const pmr::memory_resource &other) const noexcept override
|
||||
{
|
||||
return this == &other;
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif /* FAIR_MQ_MEMORY_RESOURCES_H */
|
@@ -78,7 +78,7 @@ class Plugin
|
||||
auto TakeDeviceControl() -> void { fPluginServices->TakeDeviceControl(fkName); };
|
||||
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
|
||||
auto ReleaseDeviceControl() -> void { fPluginServices->ReleaseDeviceControl(fkName); };
|
||||
auto ChangeDeviceState(const DeviceStateTransition next) -> bool { return fPluginServices->ChangeDeviceState(fkName, next); }
|
||||
auto ChangeDeviceState(const DeviceStateTransition next) -> void { fPluginServices->ChangeDeviceState(fkName, next); }
|
||||
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
|
||||
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
|
||||
|
||||
@@ -116,9 +116,9 @@ class Plugin
|
||||
} /* namespace fair */
|
||||
|
||||
#define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \
|
||||
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::unique_ptr<fair::mq::Plugin> \
|
||||
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr<fair::mq::Plugin> \
|
||||
{ \
|
||||
return fair::mq::tools::make_unique<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
|
||||
return std::make_shared<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
|
||||
} \
|
||||
BOOST_DLL_ALIAS(Make_##NAME##_Plugin, make_##NAME##_plugin) \
|
||||
BOOST_DLL_ALIAS(PROGOPTIONS, get_##NAME##_plugin_progoptions)
|
||||
|
@@ -29,55 +29,13 @@ using boost::optional;
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
|
||||
|
||||
fair::mq::PluginManager::PluginManager()
|
||||
: fSearchPaths{}
|
||||
: fSearchPaths{{"."}}
|
||||
, fPluginFactories()
|
||||
, fPluginServices()
|
||||
, fPlugins()
|
||||
, fPluginOrder()
|
||||
, fPluginProgOptions()
|
||||
{
|
||||
}
|
||||
|
||||
fair::mq::PluginManager::PluginManager(const vector<string> args)
|
||||
: fSearchPaths{}
|
||||
, fPluginFactories()
|
||||
, fPluginServices()
|
||||
, fPlugins()
|
||||
, fPluginOrder()
|
||||
, fPluginProgOptions()
|
||||
{
|
||||
// Parse command line options
|
||||
auto options = ProgramOptions();
|
||||
auto vm = po::variables_map{};
|
||||
try
|
||||
{
|
||||
auto parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
|
||||
po::store(parsed, vm);
|
||||
po::notify(vm);
|
||||
} catch (const po::error& e)
|
||||
{
|
||||
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
|
||||
}
|
||||
|
||||
// Process plugin search paths
|
||||
auto append = vector<fs::path>{};
|
||||
auto prepend = vector<fs::path>{};
|
||||
auto searchPaths = vector<fs::path>{};
|
||||
if (vm.count("plugin-search-path"))
|
||||
{
|
||||
for (const auto& path : vm["plugin-search-path"].as<vector<string>>())
|
||||
{
|
||||
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
|
||||
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
|
||||
else { searchPaths.emplace_back(path); }
|
||||
}
|
||||
}
|
||||
|
||||
// Set supplied options
|
||||
SetSearchPaths(searchPaths);
|
||||
for(const auto& path : prepend) { PrependSearchPath(path); }
|
||||
for(const auto& path : append) { AppendSearchPath(path); }
|
||||
if (vm.count("plugin")) { LoadPlugins(vm["plugin"].as<vector<string>>()); }
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::ValidateSearchPath(const fs::path& path) -> void
|
||||
@@ -115,8 +73,7 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
|
||||
"* Append(>) or prepend(<) to default search path, e.g.\n"
|
||||
" -S >/lib </home/user/lib\n"
|
||||
"* If you mix the overriding and appending/prepending syntaxes, the overriding paths act as default search path, e.g.\n"
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
|
||||
"If nothing is found, the default dynamic library lookup is performed, see man ld.so(8) for details.")
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib")
|
||||
("plugin,P", po::value<vector<string>>(), "List of plugin names to load in order,"
|
||||
"e.g. if the file is called 'libFairMQPlugin_example.so', just list 'example' or 'd:example' here."
|
||||
"To load a prelinked plugin, list 'p:example' here.");
|
||||
@@ -124,6 +81,46 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
|
||||
return plugin_options;
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::MakeFromCommandLineOptions(const vector<string> args) -> shared_ptr<PluginManager>
|
||||
{
|
||||
// Parse command line options
|
||||
auto options = ProgramOptions();
|
||||
auto vm = po::variables_map{};
|
||||
try
|
||||
{
|
||||
auto parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
|
||||
po::store(parsed, vm);
|
||||
po::notify(vm);
|
||||
} catch (const po::error& e)
|
||||
{
|
||||
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
|
||||
}
|
||||
|
||||
// Process plugin search paths
|
||||
auto append = vector<fs::path>{};
|
||||
auto prepend = vector<fs::path>{};
|
||||
auto searchPaths = vector<fs::path>{};
|
||||
if (vm.count("plugin-search-path"))
|
||||
{
|
||||
for (const auto& path : vm["plugin-search-path"].as<vector<string>>())
|
||||
{
|
||||
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
|
||||
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
|
||||
else { searchPaths.emplace_back(path); }
|
||||
}
|
||||
}
|
||||
|
||||
// Create PluginManager with supplied options
|
||||
auto mgr = make_shared<PluginManager>();
|
||||
mgr->SetSearchPaths(searchPaths);
|
||||
for(const auto& path : prepend) { mgr->PrependSearchPath(path); }
|
||||
for(const auto& path : append) { mgr->AppendSearchPath(path); }
|
||||
if (vm.count("plugin")) { mgr->LoadPlugins(vm["plugin"].as<vector<string>>()); }
|
||||
|
||||
// Return the plugin manager and command line options, that have not been recognized.
|
||||
return mgr;
|
||||
}
|
||||
|
||||
auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
|
||||
{
|
||||
if (pluginName.substr(0,2) == "p:")
|
||||
@@ -171,42 +168,29 @@ auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> voi
|
||||
if (fPluginFactories.find(pluginName) == fPluginFactories.end())
|
||||
{
|
||||
auto success = false;
|
||||
for (const auto& searchPath : SearchPaths()) {
|
||||
try {
|
||||
LoadSymbols(pluginName,
|
||||
searchPath / ToString(LibPrefix(), pluginName),
|
||||
dll::load_mode::append_decorations | dll::load_mode::rtld_global);
|
||||
for(const auto& searchPath : SearchPaths())
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadSymbols(
|
||||
pluginName,
|
||||
searchPath / ToString(LibPrefix(), pluginName),
|
||||
dll::load_mode::append_decorations
|
||||
);
|
||||
|
||||
fPluginOrder.push_back(pluginName);
|
||||
success = true;
|
||||
break;
|
||||
} catch (boost::system::system_error& e) {
|
||||
if (string{e.what()}.find("No such file or directory") == string::npos) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
if(string{e.what()}.find("No such file or directory") == string::npos)
|
||||
{
|
||||
throw PluginLoadError(ToString("An error occurred while loading dynamic plugin ", pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!success) {
|
||||
try {
|
||||
// LoadSymbols(pluginName,
|
||||
// ToString(LibPrefix(), pluginName),
|
||||
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
|
||||
// Not sure, why the above does not work. Workaround for now:
|
||||
LoadSymbols(pluginName,
|
||||
ToString("lib",
|
||||
LibPrefix(),
|
||||
pluginName,
|
||||
boost::dll::detail::shared_library_impl::suffix().native()),
|
||||
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
if(!success) { throw PluginLoadError(ToString("The plugin ", pluginName, " could not be found in the plugin search paths.")); }
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -47,15 +47,9 @@ namespace mq
|
||||
class PluginManager
|
||||
{
|
||||
public:
|
||||
using PluginFactory = std::unique_ptr<fair::mq::Plugin>(PluginServices&);
|
||||
using PluginFactory = std::shared_ptr<fair::mq::Plugin>(PluginServices&);
|
||||
|
||||
PluginManager();
|
||||
PluginManager(const std::vector<std::string> args);
|
||||
|
||||
~PluginManager()
|
||||
{
|
||||
LOG(debug) << "Shutting down Plugin Manager";
|
||||
}
|
||||
|
||||
auto SetSearchPaths(const std::vector<boost::filesystem::path>&) -> void;
|
||||
auto AppendSearchPath(const boost::filesystem::path&) -> void;
|
||||
@@ -70,6 +64,7 @@ class PluginManager
|
||||
struct PluginInstantiationError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
static auto ProgramOptions() -> boost::program_options::options_description;
|
||||
static auto MakeFromCommandLineOptions(const std::vector<std::string>) -> std::shared_ptr<PluginManager>;
|
||||
struct ProgramOptionsParseError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
static auto LibPrefix() -> const std::string& { return fgkLibPrefix; }
|
||||
@@ -116,10 +111,10 @@ class PluginManager
|
||||
static const std::string fgkLibPrefix;
|
||||
std::vector<boost::filesystem::path> fSearchPaths;
|
||||
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
||||
std::unique_ptr<PluginServices> fPluginServices;
|
||||
std::map<std::string, std::unique_ptr<Plugin>> fPlugins;
|
||||
std::map<std::string, std::shared_ptr<Plugin>> fPlugins;
|
||||
std::vector<std::string> fPluginOrder;
|
||||
std::map<std::string, boost::program_options::options_description> fPluginProgOptions;
|
||||
std::unique_ptr<PluginServices> fPluginServices;
|
||||
}; /* class PluginManager */
|
||||
|
||||
} /* namespace mq */
|
||||
|
@@ -16,14 +16,11 @@ const std::unordered_map<std::string, PluginServices::DeviceState> PluginService
|
||||
{"ERROR", DeviceState::Error},
|
||||
{"IDLE", DeviceState::Idle},
|
||||
{"INITIALIZING DEVICE", DeviceState::InitializingDevice},
|
||||
{"INITIALIZED", DeviceState::Initialized},
|
||||
{"BINDING", DeviceState::Binding},
|
||||
{"BOUND", DeviceState::Bound},
|
||||
{"CONNECTING", DeviceState::Connecting},
|
||||
{"DEVICE READY", DeviceState::DeviceReady},
|
||||
{"INITIALIZING TASK", DeviceState::InitializingTask},
|
||||
{"READY", DeviceState::Ready},
|
||||
{"RUNNING", DeviceState::Running},
|
||||
{"PAUSED", DeviceState::Paused},
|
||||
{"RESETTING TASK", DeviceState::ResettingTask},
|
||||
{"RESETTING DEVICE", DeviceState::ResettingDevice},
|
||||
{"EXITING", DeviceState::Exiting}
|
||||
@@ -33,96 +30,83 @@ const std::unordered_map<PluginServices::DeviceState, std::string, tools::HashEn
|
||||
{DeviceState::Error, "ERROR"},
|
||||
{DeviceState::Idle, "IDLE"},
|
||||
{DeviceState::InitializingDevice, "INITIALIZING DEVICE"},
|
||||
{DeviceState::Initialized, "INITIALIZED"},
|
||||
{DeviceState::Binding, "BINDING"},
|
||||
{DeviceState::Bound, "BOUND"},
|
||||
{DeviceState::Connecting, "CONNECTING"},
|
||||
{DeviceState::DeviceReady, "DEVICE READY"},
|
||||
{DeviceState::InitializingTask, "INITIALIZING TASK"},
|
||||
{DeviceState::Ready, "READY"},
|
||||
{DeviceState::Running, "RUNNING"},
|
||||
{DeviceState::Paused, "PAUSED"},
|
||||
{DeviceState::ResettingTask, "RESETTING TASK"},
|
||||
{DeviceState::ResettingDevice, "RESETTING DEVICE"},
|
||||
{DeviceState::Exiting, "EXITING"}
|
||||
};
|
||||
const std::unordered_map<std::string, PluginServices::DeviceStateTransition> PluginServices::fkDeviceStateTransitionStrMap = {
|
||||
{"AUTO", DeviceStateTransition::Auto},
|
||||
{"INIT DEVICE", DeviceStateTransition::InitDevice},
|
||||
{"COMPLETE INIT", DeviceStateTransition::CompleteInit},
|
||||
{"BIND", DeviceStateTransition::Bind},
|
||||
{"CONNECT", DeviceStateTransition::Connect},
|
||||
{"INIT TASK", DeviceStateTransition::InitTask},
|
||||
{"RUN", DeviceStateTransition::Run},
|
||||
{"STOP", DeviceStateTransition::Stop},
|
||||
{"RESET TASK", DeviceStateTransition::ResetTask},
|
||||
{"RESET DEVICE", DeviceStateTransition::ResetDevice},
|
||||
{"END", DeviceStateTransition::End},
|
||||
{"ERROR FOUND", DeviceStateTransition::ErrorFound},
|
||||
{"INIT DEVICE", DeviceStateTransition::InitDevice},
|
||||
{"INIT TASK", DeviceStateTransition::InitTask},
|
||||
{"RUN", DeviceStateTransition::Run},
|
||||
{"PAUSE", DeviceStateTransition::Pause},
|
||||
{"RESUME", DeviceStateTransition::Resume},
|
||||
{"STOP", DeviceStateTransition::Stop},
|
||||
{"RESET TASK", DeviceStateTransition::ResetTask},
|
||||
{"RESET DEVICE", DeviceStateTransition::ResetDevice},
|
||||
{"END", DeviceStateTransition::End},
|
||||
{"ERROR FOUND", DeviceStateTransition::ErrorFound},
|
||||
};
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, std::string, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkStrDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::Auto, "Auto"},
|
||||
{DeviceStateTransition::InitDevice, "INIT DEVICE"},
|
||||
{DeviceStateTransition::CompleteInit, "COMPLETE INIT"},
|
||||
{DeviceStateTransition::Bind, "BIND"},
|
||||
{DeviceStateTransition::Connect, "CONNECT"},
|
||||
{DeviceStateTransition::InitTask, "INIT TASK"},
|
||||
{DeviceStateTransition::Run, "RUN"},
|
||||
{DeviceStateTransition::Stop, "STOP"},
|
||||
{DeviceStateTransition::ResetTask, "RESET TASK"},
|
||||
{DeviceStateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{DeviceStateTransition::End, "END"},
|
||||
{DeviceStateTransition::ErrorFound, "ERROR FOUND"},
|
||||
{DeviceStateTransition::InitDevice, "INIT DEVICE"},
|
||||
{DeviceStateTransition::InitTask, "INIT TASK"},
|
||||
{DeviceStateTransition::Run, "RUN"},
|
||||
{DeviceStateTransition::Pause, "PAUSE"},
|
||||
{DeviceStateTransition::Resume, "RESUME"},
|
||||
{DeviceStateTransition::Stop, "STOP"},
|
||||
{DeviceStateTransition::ResetTask, "RESET TASK"},
|
||||
{DeviceStateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{DeviceStateTransition::End, "END"},
|
||||
{DeviceStateTransition::ErrorFound, "ERROR FOUND"},
|
||||
};
|
||||
const std::unordered_map<fair::mq::State, PluginServices::DeviceState, fair::mq::tools::HashEnum<fair::mq::State>> PluginServices::fkDeviceStateMap = {
|
||||
{fair::mq::State::Ok, DeviceState::Ok},
|
||||
{fair::mq::State::Error, DeviceState::Error},
|
||||
{fair::mq::State::Idle, DeviceState::Idle},
|
||||
{fair::mq::State::InitializingDevice, DeviceState::InitializingDevice},
|
||||
{fair::mq::State::Initialized, DeviceState::Initialized},
|
||||
{fair::mq::State::Binding, DeviceState::Binding},
|
||||
{fair::mq::State::Bound, DeviceState::Bound},
|
||||
{fair::mq::State::Connecting, DeviceState::Connecting},
|
||||
{fair::mq::State::DeviceReady, DeviceState::DeviceReady},
|
||||
{fair::mq::State::InitializingTask, DeviceState::InitializingTask},
|
||||
{fair::mq::State::Ready, DeviceState::Ready},
|
||||
{fair::mq::State::Running, DeviceState::Running},
|
||||
{fair::mq::State::ResettingTask, DeviceState::ResettingTask},
|
||||
{fair::mq::State::ResettingDevice, DeviceState::ResettingDevice},
|
||||
{fair::mq::State::Exiting, DeviceState::Exiting}
|
||||
const std::unordered_map<FairMQDevice::State, PluginServices::DeviceState, fair::mq::tools::HashEnum<FairMQDevice::State>> PluginServices::fkDeviceStateMap = {
|
||||
{FairMQDevice::OK, DeviceState::Ok},
|
||||
{FairMQDevice::Error, DeviceState::Error},
|
||||
{FairMQDevice::IDLE, DeviceState::Idle},
|
||||
{FairMQDevice::INITIALIZING_DEVICE, DeviceState::InitializingDevice},
|
||||
{FairMQDevice::DEVICE_READY, DeviceState::DeviceReady},
|
||||
{FairMQDevice::INITIALIZING_TASK, DeviceState::InitializingTask},
|
||||
{FairMQDevice::READY, DeviceState::Ready},
|
||||
{FairMQDevice::RUNNING, DeviceState::Running},
|
||||
{FairMQDevice::PAUSED, DeviceState::Paused},
|
||||
{FairMQDevice::RESETTING_TASK, DeviceState::ResettingTask},
|
||||
{FairMQDevice::RESETTING_DEVICE, DeviceState::ResettingDevice},
|
||||
{FairMQDevice::EXITING, DeviceState::Exiting}
|
||||
};
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, fair::mq::Transition, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::Auto, fair::mq::Transition::Auto},
|
||||
{DeviceStateTransition::InitDevice, fair::mq::Transition::InitDevice},
|
||||
{DeviceStateTransition::CompleteInit, fair::mq::Transition::CompleteInit},
|
||||
{DeviceStateTransition::Bind, fair::mq::Transition::Bind},
|
||||
{DeviceStateTransition::Connect, fair::mq::Transition::Connect},
|
||||
{DeviceStateTransition::InitTask, fair::mq::Transition::InitTask},
|
||||
{DeviceStateTransition::Run, fair::mq::Transition::Run},
|
||||
{DeviceStateTransition::Stop, fair::mq::Transition::Stop},
|
||||
{DeviceStateTransition::ResetTask, fair::mq::Transition::ResetTask},
|
||||
{DeviceStateTransition::ResetDevice, fair::mq::Transition::ResetDevice},
|
||||
{DeviceStateTransition::End, fair::mq::Transition::End},
|
||||
{DeviceStateTransition::ErrorFound, fair::mq::Transition::ErrorFound}
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::InitDevice, FairMQDevice::INIT_DEVICE},
|
||||
{DeviceStateTransition::InitTask, FairMQDevice::INIT_TASK},
|
||||
{DeviceStateTransition::Run, FairMQDevice::RUN},
|
||||
{DeviceStateTransition::Pause, FairMQDevice::PAUSE},
|
||||
{DeviceStateTransition::Resume, FairMQDevice::RUN},
|
||||
{DeviceStateTransition::Stop, FairMQDevice::STOP},
|
||||
{DeviceStateTransition::ResetTask, FairMQDevice::RESET_TASK},
|
||||
{DeviceStateTransition::ResetDevice, FairMQDevice::RESET_DEVICE},
|
||||
{DeviceStateTransition::End, FairMQDevice::END},
|
||||
{DeviceStateTransition::ErrorFound, FairMQDevice::ERROR_FOUND}
|
||||
};
|
||||
|
||||
auto PluginServices::ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool
|
||||
auto PluginServices::ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> void
|
||||
{
|
||||
lock_guard<mutex> lock{fDeviceControllerMutex};
|
||||
|
||||
if (!fDeviceController) fDeviceController = controller;
|
||||
|
||||
bool result = false;
|
||||
|
||||
if (fDeviceController == controller) {
|
||||
result = fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
} else {
|
||||
if (fDeviceController == controller)
|
||||
{
|
||||
fDevice->ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
}
|
||||
else
|
||||
{
|
||||
throw DeviceControlError{tools::ToString(
|
||||
"Plugin '", controller, "' is not allowed to change device states. ",
|
||||
"Currently, plugin '", *fDeviceController, "' has taken control."
|
||||
)};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto PluginServices::TakeDeviceControl(const std::string& controller) -> void
|
||||
|
@@ -21,7 +21,6 @@
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -39,20 +38,15 @@ class PluginServices
|
||||
{
|
||||
public:
|
||||
PluginServices() = delete;
|
||||
PluginServices(FairMQProgOptions& config, FairMQDevice& device)
|
||||
: fConfig(config)
|
||||
, fDevice(device)
|
||||
PluginServices(FairMQProgOptions* config, std::shared_ptr<FairMQDevice> device)
|
||||
: fConfig{config}
|
||||
, fDevice{device}
|
||||
, fDeviceController()
|
||||
, fDeviceControllerMutex()
|
||||
, fReleaseDeviceControlCondition()
|
||||
{
|
||||
}
|
||||
|
||||
~PluginServices()
|
||||
{
|
||||
LOG(debug) << "Shutting down Plugin Services";
|
||||
}
|
||||
|
||||
PluginServices(const PluginServices&) = delete;
|
||||
PluginServices operator=(const PluginServices&) = delete;
|
||||
|
||||
@@ -63,14 +57,11 @@ class PluginServices
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
Paused,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
@@ -78,13 +69,11 @@ class PluginServices
|
||||
|
||||
enum class DeviceStateTransition : int // transition event between DeviceStates
|
||||
{
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Pause,
|
||||
Resume,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
@@ -120,7 +109,7 @@ class PluginServices
|
||||
friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
|
||||
|
||||
/// @return current device state
|
||||
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<fair::mq::State>(fDevice.GetCurrentState())); }
|
||||
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<FairMQDevice::State>(fDevice->GetCurrentState())); }
|
||||
|
||||
/// @brief Become device controller
|
||||
/// @param controller id
|
||||
@@ -156,7 +145,7 @@ class PluginServices
|
||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
|
||||
/// 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) -> void;
|
||||
|
||||
/// @brief Subscribe with a callback to device state changes
|
||||
/// @param subscriber id
|
||||
@@ -166,19 +155,19 @@ class PluginServices
|
||||
/// the state is running in.
|
||||
auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function<void(DeviceState /*newState*/)> callback) -> void
|
||||
{
|
||||
fDevice.SubscribeToStateChange(subscriber, [&,callback](fair::mq::State newState){
|
||||
fDevice->SubscribeToStateChange(subscriber, [&,callback](FairMQDevice::State newState){
|
||||
callback(fkDeviceStateMap.at(newState));
|
||||
});
|
||||
}
|
||||
|
||||
/// @brief Unsubscribe from device state changes
|
||||
/// @param subscriber id
|
||||
auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); }
|
||||
auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice->UnsubscribeFromStateChange(subscriber); }
|
||||
|
||||
// Config API
|
||||
struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
auto PropertyExists(const std::string& key) const -> bool { return fConfig.Count(key) > 0; }
|
||||
auto PropertyExists(const std::string& key) const -> bool { return fConfig->Count(key) > 0; }
|
||||
|
||||
/// @brief Set config property
|
||||
/// @param key
|
||||
@@ -191,18 +180,13 @@ class PluginServices
|
||||
auto SetProperty(const std::string& key, T val) -> void
|
||||
{
|
||||
auto currentState = GetCurrentDeviceState();
|
||||
if ( (currentState == DeviceState::InitializingDevice)
|
||||
|| (currentState == DeviceState::Initialized)
|
||||
|| (currentState == DeviceState::Binding)
|
||||
|| (currentState == DeviceState::Bound)
|
||||
|| (currentState == DeviceState::Connecting)
|
||||
|| (currentState == DeviceState::Ready)
|
||||
|| (currentState == DeviceState::Idle && key == "channel-config")) {
|
||||
fConfig.SetValue(key, val);
|
||||
} else {
|
||||
throw InvalidStateError{
|
||||
tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". ",
|
||||
"Supported state is ", DeviceState::InitializingDevice, ".")};
|
||||
if (currentState == DeviceState::InitializingDevice)
|
||||
{
|
||||
fConfig->SetValue(key, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw InvalidStateError{tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". Supported state is ", DeviceState::InitializingDevice, ".")};
|
||||
}
|
||||
}
|
||||
struct InvalidStateError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
@@ -216,7 +200,7 @@ class PluginServices
|
||||
template<typename T>
|
||||
auto GetProperty(const std::string& key) const -> T {
|
||||
if (PropertyExists(key)) {
|
||||
return fConfig.GetValue<T>(key);
|
||||
return fConfig->GetValue<T>(key);
|
||||
}
|
||||
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
|
||||
}
|
||||
@@ -228,16 +212,16 @@ class PluginServices
|
||||
/// If a type is not supported, the user can provide support by overloading the ostream operator for this type
|
||||
auto GetPropertyAsString(const std::string& key) const -> std::string {
|
||||
if (PropertyExists(key)) {
|
||||
return fConfig.GetStringValue(key);
|
||||
return fConfig->GetStringValue(key);
|
||||
}
|
||||
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
|
||||
}
|
||||
|
||||
auto GetChannelInfo() const -> std::unordered_map<std::string, int> { return fConfig.GetChannelInfo(); }
|
||||
auto GetChannelInfo() const -> std::unordered_map<std::string, int> { return fConfig->GetChannelInfo(); }
|
||||
|
||||
/// @brief Discover the list of property keys
|
||||
/// @return list of property keys
|
||||
auto GetPropertyKeys() const -> std::vector<std::string> { return fConfig.GetPropertyKeys(); }
|
||||
auto GetPropertyKeys() const -> std::vector<std::string> { return fConfig->GetPropertyKeys(); }
|
||||
|
||||
/// @brief Subscribe to property updates of type T
|
||||
/// @param subscriber
|
||||
@@ -247,13 +231,13 @@ class PluginServices
|
||||
template<typename T>
|
||||
auto SubscribeToPropertyChange(const std::string& subscriber, std::function<void(const std::string& key, T)> callback) const -> void
|
||||
{
|
||||
fConfig.Subscribe<T>(subscriber, callback);
|
||||
fConfig->Subscribe<T>(subscriber, callback);
|
||||
}
|
||||
|
||||
/// @brief Unsubscribe from property updates of type T
|
||||
/// @param subscriber
|
||||
template<typename T>
|
||||
auto UnsubscribeFromPropertyChange(const std::string& subscriber) -> void { fConfig.Unsubscribe<T>(subscriber); }
|
||||
auto UnsubscribeFromPropertyChange(const std::string& subscriber) -> void { fConfig->Unsubscribe<T>(subscriber); }
|
||||
|
||||
/// @brief Subscribe to property updates
|
||||
/// @param subscriber
|
||||
@@ -262,12 +246,12 @@ class PluginServices
|
||||
/// Subscribe to property changes with a callback to monitor property changes in an event based fashion. Will convert the property to string.
|
||||
auto SubscribeToPropertyChangeAsString(const std::string& subscriber, std::function<void(const std::string& key, std::string)> callback) const -> void
|
||||
{
|
||||
fConfig.SubscribeAsString(subscriber, callback);
|
||||
fConfig->SubscribeAsString(subscriber, callback);
|
||||
}
|
||||
|
||||
/// @brief Unsubscribe from property updates that convert to string
|
||||
/// @param subscriber
|
||||
auto UnsubscribeFromPropertyChangeAsString(const std::string& subscriber) -> void { fConfig.UnsubscribeAsString(subscriber); }
|
||||
auto UnsubscribeFromPropertyChangeAsString(const std::string& subscriber) -> void { fConfig->UnsubscribeAsString(subscriber); }
|
||||
|
||||
auto CycleLogConsoleSeverityUp() -> void { Logger::CycleConsoleSeverityUp(); }
|
||||
auto CycleLogConsoleSeverityDown() -> void { Logger::CycleConsoleSeverityDown(); }
|
||||
@@ -278,12 +262,12 @@ class PluginServices
|
||||
static const std::unordered_map<DeviceState, std::string, tools::HashEnum<DeviceState>> fkStrDeviceStateMap;
|
||||
static const std::unordered_map<std::string, DeviceStateTransition> fkDeviceStateTransitionStrMap;
|
||||
static const std::unordered_map<DeviceStateTransition, std::string, tools::HashEnum<DeviceStateTransition>> fkStrDeviceStateTransitionMap;
|
||||
static const std::unordered_map<fair::mq::State, DeviceState, tools::HashEnum<fair::mq::State>> fkDeviceStateMap;
|
||||
static const std::unordered_map<DeviceStateTransition, fair::mq::Transition, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
|
||||
static const std::unordered_map<FairMQDevice::State, DeviceState, tools::HashEnum<FairMQDevice::State>> fkDeviceStateMap;
|
||||
static const std::unordered_map<DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
|
||||
|
||||
private:
|
||||
FairMQProgOptions& fConfig;
|
||||
FairMQDevice& fDevice;
|
||||
FairMQProgOptions* fConfig; // TODO make it a shared pointer, once old AliceO2 code is cleaned up
|
||||
std::shared_ptr<FairMQDevice> fDevice;
|
||||
boost::optional<std::string> fDeviceController;
|
||||
mutable std::mutex fDeviceControllerMutex;
|
||||
std::condition_variable fReleaseDeviceControlCondition;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -7,474 +7,189 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "StateMachine.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
// Increase maximum number of boost::msm states (default is 10)
|
||||
// This #define has to be before any msm header includes
|
||||
#define FUSION_MAX_VECTOR_SIZE 20
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/msm/back/state_machine.hpp>
|
||||
#include <boost/msm/back/tools.hpp>
|
||||
#include <boost/msm/back/metafunctions.hpp>
|
||||
#include <boost/msm/front/state_machine_def.hpp>
|
||||
#include <boost/msm/front/functor_row.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/signals2.hpp> // signal/slot for onStateChange callbacks
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::msm;
|
||||
using namespace boost::msm::front;
|
||||
using namespace boost::msm::back;
|
||||
namespace bmpl = boost::mpl;
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<fair::mq::Transition> : fair::mq::tools::HashEnum<fair::mq::Transition> {};
|
||||
|
||||
template<>
|
||||
struct hash<fair::mq::State> : fair::mq::tools::HashEnum<fair::mq::State> {};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace fsm
|
||||
{
|
||||
|
||||
// list of FSM states
|
||||
struct OK_S : public state<> { static string Name() { return "OK"; } static State Type() { return State::Ok; } };
|
||||
|
||||
struct IDLE_S : public state<> { static string Name() { return "IDLE"; } static State Type() { return State::Idle; } };
|
||||
struct INITIALIZING_DEVICE_S : public state<> { static string Name() { return "INITIALIZING_DEVICE"; } static State Type() { return State::InitializingDevice; } };
|
||||
struct INITIALIZED_S : public state<> { static string Name() { return "INITIALIZED"; } static State Type() { return State::Initialized; } };
|
||||
struct BINDING_S : public state<> { static string Name() { return "BINDING"; } static State Type() { return State::Binding; } };
|
||||
struct BOUND_S : public state<> { static string Name() { return "BOUND"; } static State Type() { return State::Bound; } };
|
||||
struct CONNECTING_S : public state<> { static string Name() { return "CONNECTING"; } static State Type() { return State::Connecting; } };
|
||||
struct DEVICE_READY_S : public state<> { static string Name() { return "DEVICE_READY"; } static State Type() { return State::DeviceReady; } };
|
||||
struct INITIALIZING_TASK_S : public state<> { static string Name() { return "INITIALIZING_TASK"; } static State Type() { return State::InitializingTask; } };
|
||||
struct READY_S : public state<> { static string Name() { return "READY"; } static State Type() { return State::Ready; } };
|
||||
struct RUNNING_S : public state<> { static string Name() { return "RUNNING"; } static State Type() { return State::Running; } };
|
||||
struct RESETTING_TASK_S : public state<> { static string Name() { return "RESETTING_TASK"; } static State Type() { return State::ResettingTask; } };
|
||||
struct RESETTING_DEVICE_S : public state<> { static string Name() { return "RESETTING_DEVICE"; } static State Type() { return State::ResettingDevice; } };
|
||||
struct EXITING_S : public state<> { static string Name() { return "EXITING"; } static State Type() { return State::Exiting; } };
|
||||
|
||||
struct ERROR_S : public terminate_state<> { static string Name() { return "ERROR"; } static State Type() { return State::Error; } };
|
||||
|
||||
// list of FSM transitions (events)
|
||||
struct AUTO_E { static string Name() { return "AUTO"; } static Transition Type() { return Transition::Auto; } };
|
||||
struct INIT_DEVICE_E { static string Name() { return "INIT_DEVICE"; } static Transition Type() { return Transition::InitDevice; } };
|
||||
struct COMPLETE_INIT_E { static string Name() { return "COMPLETE_INIT"; } static Transition Type() { return Transition::CompleteInit; } };
|
||||
struct BIND_E { static string Name() { return "BIND"; } static Transition Type() { return Transition::Bind; } };
|
||||
struct CONNECT_E { static string Name() { return "CONNECT"; } static Transition Type() { return Transition::Connect; } };
|
||||
struct INIT_TASK_E { static string Name() { return "INIT_TASK"; } static Transition Type() { return Transition::InitTask; } };
|
||||
struct RUN_E { static string Name() { return "RUN"; } static Transition Type() { return Transition::Run; } };
|
||||
struct STOP_E { static string Name() { return "STOP"; } static Transition Type() { return Transition::Stop; } };
|
||||
struct RESET_TASK_E { static string Name() { return "RESET_TASK"; } static Transition Type() { return Transition::ResetTask; } };
|
||||
struct RESET_DEVICE_E { static string Name() { return "RESET_DEVICE"; } static Transition Type() { return Transition::ResetDevice; } };
|
||||
struct END_E { static string Name() { return "END"; } static Transition Type() { return Transition::End; } };
|
||||
struct ERROR_FOUND_E { static string Name() { return "ERROR_FOUND"; } static Transition Type() { return Transition::ErrorFound; } };
|
||||
|
||||
static array<string, 15> stateNames =
|
||||
{
|
||||
{
|
||||
"OK",
|
||||
"Error",
|
||||
"IDLE",
|
||||
"INITIALIZING_DEVICE",
|
||||
"INITIALIZED",
|
||||
"BINDING",
|
||||
"BOUND",
|
||||
"CONNECTING",
|
||||
"DEVICE_READY",
|
||||
"INITIALIZING_TASK",
|
||||
"READY",
|
||||
"RUNNING",
|
||||
"RESETTING_TASK",
|
||||
"RESETTING_DEVICE",
|
||||
"EXITING"
|
||||
}
|
||||
};
|
||||
|
||||
static array<string, 12> transitionNames =
|
||||
{
|
||||
{
|
||||
"AUTO",
|
||||
"INIT_DEVICE",
|
||||
"COMPLETE_INIT",
|
||||
"BIND",
|
||||
"CONNECT",
|
||||
"INIT_TASK",
|
||||
"RUN",
|
||||
"STOP",
|
||||
"RESET_TASK",
|
||||
"RESET_DEVICE",
|
||||
"END",
|
||||
"ERROR_FOUND"
|
||||
}
|
||||
};
|
||||
|
||||
static map<string, State> stateNumbers =
|
||||
{
|
||||
{ "OK", State::Ok },
|
||||
{ "Error", State::Error },
|
||||
{ "IDLE", State::Idle },
|
||||
{ "INITIALIZING_DEVICE", State::InitializingDevice },
|
||||
{ "INITIALIZED", State::Initialized },
|
||||
{ "BINDING", State::Binding },
|
||||
{ "BOUND", State::Bound },
|
||||
{ "CONNECTING", State::Connecting },
|
||||
{ "DEVICE_READY", State::DeviceReady },
|
||||
{ "INITIALIZING_TASK", State::InitializingTask },
|
||||
{ "READY", State::Ready },
|
||||
{ "RUNNING", State::Running },
|
||||
{ "RESETTING_TASK", State::ResettingTask },
|
||||
{ "RESETTING_DEVICE", State::ResettingDevice },
|
||||
{ "EXITING", State::Exiting }
|
||||
};
|
||||
|
||||
static map<string, Transition> transitionNumbers =
|
||||
{
|
||||
{ "AUTO", Transition::Auto },
|
||||
{ "INIT_DEVICE", Transition::InitDevice },
|
||||
{ "COMPLETE_INIT", Transition::CompleteInit },
|
||||
{ "BIND", Transition::Bind },
|
||||
{ "CONNECT", Transition::Connect },
|
||||
{ "INIT_TASK", Transition::InitTask },
|
||||
{ "RUN", Transition::Run },
|
||||
{ "STOP", Transition::Stop },
|
||||
{ "RESET_TASK", Transition::ResetTask },
|
||||
{ "RESET_DEVICE", Transition::ResetDevice },
|
||||
{ "END", Transition::End },
|
||||
{ "ERROR_FOUND", Transition::ErrorFound }
|
||||
};
|
||||
|
||||
// defining the boost MSM state machine
|
||||
struct Machine_ : public state_machine_def<Machine_>
|
||||
{
|
||||
public:
|
||||
Machine_()
|
||||
: fLastTransitionResult(true)
|
||||
, fNewStatePending(false)
|
||||
{}
|
||||
|
||||
virtual ~Machine_() {}
|
||||
|
||||
// initial states
|
||||
using initial_state = bmpl::vector<IDLE_S, OK_S>;
|
||||
|
||||
template<typename Transition, typename FSM>
|
||||
void on_entry(Transition const&, FSM& /* fsm */)
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine --> IDLE";
|
||||
fState = State::Idle;
|
||||
}
|
||||
|
||||
template<typename Transition, typename FSM>
|
||||
void on_exit(Transition const&, FSM& /*fsm*/)
|
||||
{
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
struct DefaultFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fNewState = ts.Type();
|
||||
fsm.fLastTransitionResult = true;
|
||||
fsm.CallNewTransitionCallbacks(e.Type());
|
||||
fsm.fNewStatePending = true;
|
||||
fsm.fNewStatePendingCV.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
struct transition_table : bmpl::vector<
|
||||
// Start Transition Next Action Guard
|
||||
Row<IDLE_S, END_E, EXITING_S, DefaultFct, none>,
|
||||
Row<IDLE_S, INIT_DEVICE_E, INITIALIZING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<INITIALIZING_DEVICE_S, COMPLETE_INIT_E, INITIALIZED_S, DefaultFct, none>,
|
||||
Row<INITIALIZED_S, BIND_E, BINDING_S, DefaultFct, none>,
|
||||
Row<INITIALIZED_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<BINDING_S, AUTO_E, BOUND_S, DefaultFct, none>,
|
||||
Row<BOUND_S, CONNECT_E, CONNECTING_S, DefaultFct, none>,
|
||||
Row<BOUND_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<CONNECTING_S, AUTO_E, DEVICE_READY_S, DefaultFct, none>,
|
||||
Row<DEVICE_READY_S, INIT_TASK_E, INITIALIZING_TASK_S, DefaultFct, none>,
|
||||
Row<DEVICE_READY_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<INITIALIZING_TASK_S, AUTO_E, READY_S, DefaultFct, none>,
|
||||
|
||||
Row<READY_S, RUN_E, RUNNING_S, DefaultFct, none>,
|
||||
Row<READY_S, RESET_TASK_E, RESETTING_TASK_S, DefaultFct, none>,
|
||||
|
||||
Row<RUNNING_S, STOP_E, READY_S, DefaultFct, none>,
|
||||
|
||||
Row<RESETTING_TASK_S, AUTO_E, DEVICE_READY_S, DefaultFct, none>,
|
||||
Row<RESETTING_DEVICE_S, AUTO_E, IDLE_S, DefaultFct, none>,
|
||||
|
||||
Row<OK_S, ERROR_FOUND_E, ERROR_S, DefaultFct, none>> {};
|
||||
|
||||
void CallStateChangeCallbacks(const State state) const
|
||||
{
|
||||
if (!fStateChangeSignal.empty()) {
|
||||
fStateChangeSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
void CallStateHandler(const State state) const
|
||||
{
|
||||
if (!fStateHandleSignal.empty()) {
|
||||
fStateHandleSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
void CallNewTransitionCallbacks(const Transition transition) const
|
||||
{
|
||||
if (!fNewTransitionSignal.empty()) {
|
||||
fNewTransitionSignal(transition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
atomic<State> fState;
|
||||
atomic<State> fNewState;
|
||||
atomic<bool> fLastTransitionResult;
|
||||
|
||||
mutex fStateMtx;
|
||||
atomic<bool> fNewStatePending;
|
||||
condition_variable fNewStatePendingCV;
|
||||
|
||||
boost::signals2::signal<void(const State)> fStateChangeSignal;
|
||||
boost::signals2::signal<void(const State)> fStateHandleSignal;
|
||||
boost::signals2::signal<void(const Transition)> fNewTransitionSignal;
|
||||
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
|
||||
unordered_map<string, boost::signals2::connection> fNewTransitionSignalsMap;
|
||||
|
||||
void ProcessWork()
|
||||
{
|
||||
bool stop = false;
|
||||
|
||||
while (!stop) {
|
||||
{
|
||||
unique_lock<mutex> lock(fStateMtx);
|
||||
|
||||
while (!fNewStatePending) {
|
||||
fNewStatePendingCV.wait_for(lock, chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
LOG(state) << fState << " ---> " << fNewState;
|
||||
fState = static_cast<State>(fNewState);
|
||||
fNewStatePending = false;
|
||||
|
||||
if (fState == State::Exiting || fState == State::Error) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
CallStateChangeCallbacks(fState);
|
||||
CallStateHandler(fState);
|
||||
}
|
||||
|
||||
if (fState == State::Error) {
|
||||
throw StateMachine::ErrorStateException("Device transitioned to error state");
|
||||
}
|
||||
}
|
||||
|
||||
// replaces the default no-transition response.
|
||||
template<typename FSM, typename Transition>
|
||||
void no_transition(Transition const& t, FSM& fsm, int state)
|
||||
{
|
||||
using RecursiveStt = typename recursive_get_transition_table<FSM>::type;
|
||||
using AllStates = typename generate_state_set<RecursiveStt>::type;
|
||||
|
||||
string stateName;
|
||||
|
||||
bmpl::for_each<AllStates, wrap<bmpl::placeholders::_1>>(get_state_name<RecursiveStt>(stateName, state));
|
||||
|
||||
stateName = boost::core::demangle(stateName.c_str());
|
||||
size_t pos = stateName.rfind(":");
|
||||
stateName = stateName.substr(pos + 1);
|
||||
size_t pos2 = stateName.rfind("_");
|
||||
stateName = stateName.substr(0, pos2);
|
||||
|
||||
if (stateName != "OK") {
|
||||
LOG(state) << "No transition from state " << stateName << " on transition " << t.Name();
|
||||
}
|
||||
fsm.fLastTransitionResult = false;
|
||||
}
|
||||
}; // Machine_
|
||||
|
||||
using FairMQFSM = state_machine<Machine_>;
|
||||
|
||||
} // namespace fsm
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
using namespace fair::mq::fsm;
|
||||
using namespace fair::mq;
|
||||
using namespace std;
|
||||
|
||||
StateMachine::StateMachine() : fFsm(new FairMQFSM) {}
|
||||
void StateMachine::Start() { static_pointer_cast<FairMQFSM>(fFsm)->start(); }
|
||||
StateMachine::~StateMachine() { static_pointer_cast<FairMQFSM>(fFsm)->stop(); }
|
||||
const std::unordered_map<std::string, StateMachine::State> StateMachine::fkStateStrMap = {
|
||||
{"OK", State::Ok},
|
||||
{"ERROR", State::Error},
|
||||
{"IDLE", State::Idle},
|
||||
{"INITIALIZING DEVICE", State::InitializingDevice},
|
||||
{"DEVICE READY", State::DeviceReady},
|
||||
{"INITIALIZING TASK", State::InitializingTask},
|
||||
{"READY", State::Ready},
|
||||
{"RUNNING", State::Running},
|
||||
{"RESETTING TASK", State::ResettingTask},
|
||||
{"RESETTING DEVICE", State::ResettingDevice},
|
||||
{"EXITING", State::Exiting}
|
||||
};
|
||||
const std::unordered_map<StateMachine::State, std::string, tools::HashEnum<StateMachine::State>> StateMachine::fkStrStateMap = {
|
||||
{State::Ok, "OK"},
|
||||
{State::Error, "ERROR"},
|
||||
{State::Idle, "IDLE"},
|
||||
{State::InitializingDevice, "INITIALIZING DEVICE"},
|
||||
{State::DeviceReady, "DEVICE READY"},
|
||||
{State::InitializingTask, "INITIALIZING TASK"},
|
||||
{State::Ready, "READY"},
|
||||
{State::Running, "RUNNING"},
|
||||
{State::ResettingTask, "RESETTING TASK"},
|
||||
{State::ResettingDevice, "RESETTING DEVICE"},
|
||||
{State::Exiting, "EXITING"}
|
||||
};
|
||||
const std::unordered_map<std::string, StateMachine::StateTransition> StateMachine::fkStateTransitionStrMap = {
|
||||
{"INIT DEVICE", StateTransition::InitDevice},
|
||||
{"INIT TASK", StateTransition::InitTask},
|
||||
{"RUN", StateTransition::Run},
|
||||
{"STOP", StateTransition::Stop},
|
||||
{"RESET TASK", StateTransition::ResetTask},
|
||||
{"RESET DEVICE", StateTransition::ResetDevice},
|
||||
{"END", StateTransition::End},
|
||||
{"ERROR FOUND", StateTransition::ErrorFound},
|
||||
{"AUTOMATIC", StateTransition::Automatic},
|
||||
};
|
||||
const std::unordered_map<StateMachine::StateTransition, std::string, tools::HashEnum<StateMachine::StateTransition>> StateMachine::fkStrStateTransitionMap = {
|
||||
{StateTransition::InitDevice, "INIT DEVICE"},
|
||||
{StateTransition::InitTask, "INIT TASK"},
|
||||
{StateTransition::Run, "RUN"},
|
||||
{StateTransition::Stop, "STOP"},
|
||||
{StateTransition::ResetTask, "RESET TASK"},
|
||||
{StateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{StateTransition::End, "END"},
|
||||
{StateTransition::ErrorFound, "ERROR FOUND"},
|
||||
{StateTransition::Automatic, "AUTOMATIC"},
|
||||
};
|
||||
|
||||
bool StateMachine::ChangeState(const Transition transition)
|
||||
try {
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
lock_guard<mutex> lock(fsm->fStateMtx);
|
||||
if (!static_cast<bool>(fsm->fNewStatePending) || transition == Transition::ErrorFound) {
|
||||
switch (transition) {
|
||||
case Transition::Auto:
|
||||
fsm->process_event(AUTO_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::InitDevice:
|
||||
fsm->process_event(INIT_DEVICE_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::CompleteInit:
|
||||
fsm->process_event(COMPLETE_INIT_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Bind:
|
||||
fsm->process_event(BIND_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Connect:
|
||||
fsm->process_event(CONNECT_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::InitTask:
|
||||
fsm->process_event(INIT_TASK_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Run:
|
||||
fsm->process_event(RUN_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Stop:
|
||||
fsm->process_event(STOP_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ResetDevice:
|
||||
fsm->process_event(RESET_DEVICE_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ResetTask:
|
||||
fsm->process_event(RESET_TASK_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::End:
|
||||
fsm->process_event(END_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ErrorFound:
|
||||
fsm->process_event(ERROR_FOUND_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
default:
|
||||
LOG(error) << "Requested unsupported state transition: " << transition << endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(state) << "Transition " << transitionNames.at(static_cast<int>(transition)) << " incoming, but another state transition is already ongoing.";
|
||||
return false;
|
||||
}
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "Exception in StateMachine::ChangeState(): " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
void StateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
||||
auto StateMachine::Run() -> void
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignal.connect(callback)});
|
||||
}
|
||||
LOG(state) << "Starting FairMQ state machine";
|
||||
|
||||
void StateMachine::UnsubscribeFromStateChange(const string& key)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fStateChangeSignalsMap.count(key)) {
|
||||
fsm->fStateChangeSignalsMap.at(key).disconnect();
|
||||
fsm->fStateChangeSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
LOG(debug) << "Entering initial " << fErrorState << " state (orthogonal error state machine)";
|
||||
LOG(state) << "Entering initial " << fState << " state";
|
||||
|
||||
void StateMachine::HandleStates(function<void(const State)> callback)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fStateHandleSignal.empty()) {
|
||||
fsm->fStateHandleSignal.connect(callback);
|
||||
} else {
|
||||
LOG(error) << "state handler is already set";
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::StopHandlingStates()
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (!fsm->fStateHandleSignal.empty()) {
|
||||
fsm->fStateHandleSignal.disconnect_all_slots();
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::SubscribeToNewTransition(const string& key, function<void(const Transition)> callback)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignal.connect(callback)});
|
||||
}
|
||||
|
||||
void StateMachine::UnsubscribeFromNewTransition(const string& key)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fNewTransitionSignalsMap.count(key)) {
|
||||
fsm->fNewTransitionSignalsMap.at(key).disconnect();
|
||||
fsm->fNewTransitionSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
State StateMachine::GetCurrentState() const { return static_pointer_cast<FairMQFSM>(fFsm)->fState; }
|
||||
string StateMachine::GetCurrentStateName() const { return GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState); }
|
||||
|
||||
bool StateMachine::NewStatePending() const { return static_cast<bool>(static_pointer_cast<FairMQFSM>(fFsm)->fNewStatePending); }
|
||||
void StateMachine::WaitForPendingState() const
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
unique_lock<mutex> lock(fsm->fStateMtx);
|
||||
fsm->fNewStatePendingCV.wait(lock, [&]{ return static_cast<bool>(fsm->fNewStatePending); });
|
||||
}
|
||||
bool StateMachine::WaitForPendingStateFor(const int durationInMs) const
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
unique_lock<mutex> lock(fsm->fStateMtx);
|
||||
return fsm->fNewStatePendingCV.wait_for(lock, std::chrono::milliseconds(durationInMs), [&]{ return static_cast<bool>(fsm->fNewStatePending); });
|
||||
}
|
||||
|
||||
void StateMachine::ProcessWork()
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
|
||||
try {
|
||||
fsm->CallStateChangeCallbacks(State::Idle);
|
||||
fsm->ProcessWork();
|
||||
} catch(ErrorStateException& ese) {
|
||||
LOG(trace) << "ErrorStateException caught in ProcessWork(), rethrowing";
|
||||
throw;
|
||||
} catch(...) {
|
||||
LOG(debug) << "Exception caught in ProcessWork(), going to Error state and rethrowing";
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
while (true)
|
||||
{
|
||||
while (fNextStates.empty())
|
||||
{
|
||||
lock_guard<mutex> lock(fsm->fStateMtx);
|
||||
fsm->fState = State::Error;
|
||||
fsm->CallStateChangeCallbacks(State::Error);
|
||||
fNewState.wait(lock);
|
||||
}
|
||||
ChangeState(Transition::ErrorFound);
|
||||
throw;
|
||||
|
||||
State lastState;
|
||||
|
||||
if (fNextStates.front() == State::Error)
|
||||
{
|
||||
// advance error FSM
|
||||
lastState = fErrorState;
|
||||
fErrorState = fNextStates.front();
|
||||
fNextStates.pop_front();
|
||||
LOG(error) << "Entering " << fErrorState << " state (orthogonal error state machine)";
|
||||
}
|
||||
else
|
||||
{
|
||||
// advance regular FSM
|
||||
lastState = fState;
|
||||
fState = fNextStates.front();
|
||||
fNextStates.pop_front();
|
||||
LOG(state) << "Entering " << fState << " state";
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
fCallbacks.Emit<StateChange, State>(fState, lastState);
|
||||
|
||||
lock.lock();
|
||||
if (fState == State::Exiting || fErrorState == State::Error) break;
|
||||
}
|
||||
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
string StateMachine::GetStateName(const State state) { return stateNames.at(static_cast<int>(state)); }
|
||||
string StateMachine::GetTransitionName(const Transition transition) { return transitionNames.at(static_cast<int>(transition)); }
|
||||
State StateMachine::GetState(const string& state) { return stateNumbers.at(state); }
|
||||
Transition StateMachine::GetTransition(const string& transition) { return transitionNumbers.at(transition); }
|
||||
auto StateMachine::ChangeState(StateTransition transition) -> void
|
||||
{
|
||||
State lastState;
|
||||
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
if (transition == StateTransition::ErrorFound)
|
||||
{
|
||||
lastState = fErrorState;
|
||||
}
|
||||
else if (fNextStates.empty())
|
||||
{
|
||||
lastState = fState;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastState = fNextStates.back();
|
||||
}
|
||||
|
||||
const State nextState{Transition(lastState, transition)};
|
||||
fNextStates.push_back(nextState);
|
||||
lock.unlock();
|
||||
|
||||
fCallbacks.Emit<StateQueued, State>(nextState, lastState);
|
||||
fNewState.notify_one();
|
||||
}
|
||||
|
||||
auto StateMachine::Transition(const State currentState, const StateTransition transition) -> State
|
||||
{
|
||||
switch (currentState) {
|
||||
case State::Idle:
|
||||
if (transition == StateTransition::InitDevice ) return State::InitializingDevice;
|
||||
if (transition == StateTransition::End ) return State::Exiting;
|
||||
break;
|
||||
case State::InitializingDevice:
|
||||
if (transition == StateTransition::Automatic ) return State::DeviceReady;
|
||||
break;
|
||||
case State::DeviceReady:
|
||||
if (transition == StateTransition::InitTask ) return State::InitializingTask;
|
||||
if (transition == StateTransition::ResetDevice) return State::ResettingDevice;
|
||||
break;
|
||||
case State::InitializingTask:
|
||||
if (transition == StateTransition::Automatic ) return State::Ready;
|
||||
break;
|
||||
case State::Ready:
|
||||
if (transition == StateTransition::Run ) return State::Running;
|
||||
if (transition == StateTransition::ResetTask ) return State::ResettingTask;
|
||||
break;
|
||||
case State::Running:
|
||||
if (transition == StateTransition::Stop ) return State::Ready;
|
||||
break;
|
||||
case State::ResettingTask:
|
||||
if (transition == StateTransition::Automatic ) return State::DeviceReady;
|
||||
break;
|
||||
case State::ResettingDevice:
|
||||
if (transition == StateTransition::Automatic ) return State::Idle;
|
||||
break;
|
||||
case State::Exiting:
|
||||
break;
|
||||
case State::Ok:
|
||||
if (transition == StateTransition::ErrorFound ) return State::Error;
|
||||
break;
|
||||
case State::Error:
|
||||
break;
|
||||
}
|
||||
throw IllegalTransition{tools::ToString("No transition ", transition, " from state ", currentState, ".")};
|
||||
}
|
||||
|
||||
StateMachine::StateMachine()
|
||||
: fState{State::Idle}
|
||||
, fErrorState{State::Ok}
|
||||
{
|
||||
}
|
||||
|
||||
auto StateMachine::Reset() -> void
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
fState = State::Idle;
|
||||
fErrorState = State::Ok;
|
||||
fNextStates.clear();
|
||||
}
|
||||
|
||||
auto StateMachine::NextStatePending() -> bool
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
return fNextStates.size() > 0;
|
||||
}
|
||||
|
@@ -1,109 +1,132 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIRMQSTATEMACHINE_H_
|
||||
#define FAIRMQSTATEMACHINE_H_
|
||||
#ifndef FAIR_MQ_STATEMACHINE_H
|
||||
#define FAIR_MQ_STATEMACHINE_H
|
||||
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/EventManager.h>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <condition_variable>
|
||||
#include <ostream>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
|
||||
enum class State : int
|
||||
{
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
};
|
||||
|
||||
enum class Transition : int
|
||||
{
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound
|
||||
};
|
||||
|
||||
/**
|
||||
* @class StateMachine StateMachine.h <fairmq/StateMachine.h>
|
||||
* @brief Implements the state machine for FairMQ devices
|
||||
*
|
||||
* See https://github.com/FairRootGroup/FairRoot/blob/dev/fairmq/docs/Device.md#13-state-machine
|
||||
*/
|
||||
class StateMachine
|
||||
{
|
||||
public:
|
||||
enum class State : int
|
||||
{
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
};
|
||||
|
||||
enum class StateTransition : int // transition event between States
|
||||
{
|
||||
InitDevice,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound,
|
||||
Automatic
|
||||
};
|
||||
|
||||
/// @brief Convert string to State
|
||||
/// @param state to convert
|
||||
/// @return State enum entry
|
||||
/// @throw std::out_of_range if a string cannot be resolved to a State
|
||||
static auto ToState(const std::string& state) -> State { return fkStateStrMap.at(state); }
|
||||
|
||||
/// @brief Convert string to StateTransition
|
||||
/// @param transition to convert
|
||||
/// @return StateTransition enum entry
|
||||
/// @throw std::out_of_range if a string cannot be resolved to a StateTransition
|
||||
static auto ToStateTransition(const std::string& transition) -> StateTransition { return fkStateTransitionStrMap.at(transition); }
|
||||
|
||||
/// @brief Convert State to string
|
||||
/// @param state to convert
|
||||
/// @return string representation of State enum entry
|
||||
static auto ToStr(State state) -> std::string { return fkStrStateMap.at(state); }
|
||||
|
||||
/// @brief Convert StateTransition to string
|
||||
/// @param transition to convert
|
||||
/// @return string representation of StateTransition enum entry
|
||||
static auto ToStr(StateTransition transition) -> std::string { return fkStrStateTransitionMap.at(transition); }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const State& state) -> std::ostream& { return os << ToStr(state); }
|
||||
friend auto operator<<(std::ostream& os, const StateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
|
||||
|
||||
StateMachine();
|
||||
virtual ~StateMachine();
|
||||
|
||||
bool ChangeState(const Transition transition);
|
||||
bool ChangeState(const std::string& transition) { return ChangeState(GetTransition(transition)); }
|
||||
struct IllegalTransition : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback);
|
||||
void UnsubscribeFromStateChange(const std::string& key);
|
||||
struct StateChange : Event<State> {};
|
||||
struct StateQueued : Event<State> {};
|
||||
auto SubscribeToStateChange(const std::string& subscriber, std::function<void(typename StateChange::KeyType newState, State lastState)> callback) -> void { fCallbacks.Subscribe<StateChange, State>(subscriber, callback); }
|
||||
auto UnsubscribeFromStateChange(const std::string& subscriber) -> void { fCallbacks.Unsubscribe<StateChange, State>(subscriber); }
|
||||
auto SubscribeToStateQueued(const std::string& subscriber, std::function<void(typename StateQueued::KeyType newState, State lastState)> callback) -> void { fCallbacks.Subscribe<StateQueued, State>(subscriber, callback); }
|
||||
auto UnsubscribeFromStateQueued(const std::string& subscriber) -> void { fCallbacks.Unsubscribe<StateQueued, State>(subscriber); }
|
||||
|
||||
void HandleStates(std::function<void(const State)> callback);
|
||||
void StopHandlingStates();
|
||||
auto GetCurrentState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fState; }
|
||||
auto GetCurrentErrorState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fErrorState; }
|
||||
auto GetLastQueuedState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fNextStates.back(); }
|
||||
|
||||
void SubscribeToNewTransition(const std::string& key, std::function<void(const Transition)> callback);
|
||||
void UnsubscribeFromNewTransition(const std::string& key);
|
||||
auto ChangeState(StateTransition transition) -> void;
|
||||
|
||||
bool NewStatePending() const;
|
||||
void WaitForPendingState() const;
|
||||
bool WaitForPendingStateFor(const int durationInMs) const;
|
||||
auto Run() -> void;
|
||||
auto Reset() -> void;
|
||||
|
||||
State GetCurrentState() const;
|
||||
std::string GetCurrentStateName() const;
|
||||
|
||||
void Start();
|
||||
|
||||
void ProcessWork();
|
||||
|
||||
static std::string GetStateName(const State);
|
||||
static std::string GetTransitionName(const Transition);
|
||||
static State GetState(const std::string& state);
|
||||
static Transition GetTransition(const std::string& transition);
|
||||
|
||||
struct ErrorStateException : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
auto NextStatePending() -> bool;
|
||||
|
||||
private:
|
||||
std::shared_ptr<void> fFsm;
|
||||
};
|
||||
State fState;
|
||||
State fErrorState;
|
||||
std::deque<State> fNextStates;
|
||||
EventManager fCallbacks;
|
||||
|
||||
inline std::ostream& operator<<(std::ostream& os, const State& state) { return os << StateMachine::GetStateName(state); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const Transition& transition) { return os << StateMachine::GetTransitionName(transition); }
|
||||
static const std::unordered_map<std::string, State> fkStateStrMap;
|
||||
static const std::unordered_map<State, std::string, tools::HashEnum<State>> fkStrStateMap;
|
||||
static const std::unordered_map<std::string, StateTransition> fkStateTransitionStrMap;
|
||||
static const std::unordered_map<StateTransition, std::string, tools::HashEnum<StateTransition>> fkStrStateTransitionMap;
|
||||
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
mutable std::mutex fMutex;
|
||||
std::condition_variable fNewState;
|
||||
|
||||
#endif /* FAIRMQSTATEMACHINE_H_ */
|
||||
static auto Transition(const State currentState, const StateTransition transition) -> State;
|
||||
}; /* class StateMachine */
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif /* FAIR_MQ_STATEMACHINE_H */
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <fairmq/tools/CppSTL.h>
|
||||
#include <fairmq/tools/Network.h>
|
||||
#include <fairmq/tools/Process.h>
|
||||
#include <fairmq/tools/RateLimit.h>
|
||||
#include <fairmq/tools/Strings.h>
|
||||
#include <fairmq/tools/Unique.h>
|
||||
#include <fairmq/tools/Version.h>
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user