mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-16 01:51:45 +00:00
Compare commits
88 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
e090967645 | ||
|
1d45095d75 | ||
|
1fdf510ae7 | ||
|
78acb954cd | ||
|
3a1b769937 | ||
|
9f325451e5 | ||
|
a78d35d90d | ||
|
cb199e7283 | ||
|
e39316c866 | ||
|
bde12f58b2 | ||
|
45354f268b | ||
|
1aab354a5d | ||
|
e1f555bc05 | ||
|
985150437a | ||
|
cf9a2944c2 | ||
|
94297f9833 | ||
|
957233cf95 | ||
|
5397cef9d1 | ||
|
f6c1f5dc0f | ||
|
c4145e9ef1 | ||
|
4123ebc9d4 | ||
|
88f897536e | ||
|
e3c55a0ff8 | ||
|
60f27b94b2 | ||
|
adfa0e2c95 | ||
|
c2bea85b90 | ||
|
2c6b2e7f04 | ||
|
6f7ffeef13 | ||
|
2eddde0e5f | ||
|
4aae1ad8d4 | ||
|
b89c309768 | ||
|
c02fbed331 | ||
|
76aeb2c7e6 | ||
|
db5f3d794c | ||
|
b814e40c87 | ||
|
5d37ab2f01 | ||
|
5303e916fb | ||
|
7d5e76dece | ||
|
2498837b8e | ||
|
6545daeda7 | ||
|
e95096eb37 | ||
|
1bb558a457 | ||
|
1c78b8ef0a | ||
|
017c5cdc3f | ||
|
d4daa9c262 | ||
|
9564b13c19 | ||
|
56cdb3812d | ||
|
2a002a2984 | ||
|
a7429ed79b | ||
|
09ef175736 | ||
|
a55db74848 | ||
|
8b3e3bbe28 | ||
|
e71c9c1121 | ||
|
fc0adba26b | ||
|
24dff2fd76 | ||
|
70ffc0d8c6 | ||
|
ff701006fd | ||
|
c8bd19b7a1 | ||
|
aee2ba7b9b | ||
|
9184d5bdae | ||
|
5e6f3a5430 | ||
|
d0fe175cab | ||
|
6f22ccf4c1 | ||
|
b2034c20cf | ||
|
ab6fd35a86 | ||
|
4a8e46c65c | ||
|
90e00730b1 | ||
|
924c8ac5f6 | ||
|
1e0159b775 | ||
|
ef3eb5f83e | ||
|
ee8afd7d2b | ||
|
a53ef79552 | ||
|
c064da91df | ||
|
f5e3212cbf | ||
|
c1d61007a1 | ||
|
93fb407af6 | ||
|
8e7e23e2d0 | ||
|
f0ec5fa2be | ||
|
aaaadf0a0b | ||
|
daec266341 | ||
|
38a149d50c | ||
|
cfebfb3407 | ||
|
e403d18cb9 | ||
|
9bab3f9f4c | ||
|
ee3a84ce7a | ||
|
f05118f4eb | ||
|
21419adb40 | ||
|
1554c1c273 |
33
.clang-format
Normal file
33
.clang-format
Normal file
@@ -0,0 +1,33 @@
|
||||
---
|
||||
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
|
||||
...
|
2
.codecov.yml
Normal file
2
.codecov.yml
Normal file
@@ -0,0 +1,2 @@
|
||||
comment:
|
||||
layout: "diff, files"
|
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
30
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
---
|
||||
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
Normal file
17
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
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
Normal file
7
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: Question / Support
|
||||
about: Any FairMQ related matter you are interested in
|
||||
|
||||
---
|
||||
|
||||
|
@@ -1,4 +1,6 @@
|
||||
Replace me with your description.
|
||||
Describe your proposal.
|
||||
|
||||
Mention any issue this PR is resolves or is related to.
|
||||
|
||||
---
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,3 +1,5 @@
|
||||
build
|
||||
|
||||
.DS_Store
|
||||
|
||||
.vscode
|
||||
|
@@ -34,10 +34,19 @@ cmake_dependent_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport." O
|
||||
cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS 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)
|
||||
endif()
|
||||
|
||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
|
||||
COMPONENTS program_options thread system filesystem regex date_time signals
|
||||
@@ -47,9 +56,9 @@ if(BUILD_FAIRMQ)
|
||||
endif()
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED)
|
||||
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
|
||||
set(msgpack_ROOT ${PACKAGE_PREFIX_DIR})
|
||||
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 msgpack VERSION 3.1.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
@@ -141,11 +150,6 @@ if(BUILD_DDS_PLUGIN)
|
||||
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}
|
||||
@@ -162,6 +166,29 @@ install_cmake_package()
|
||||
|
||||
|
||||
# Summary ######################################################################
|
||||
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}")
|
||||
@@ -189,9 +216,13 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
elseif(${dep} STREQUAL GTest)
|
||||
get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL msgpack)
|
||||
set(prefix ${msgpack_ROOT})
|
||||
get_target_property(msgpack_include msgpackc-cxx INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${msgpack_include}/.. ABSOLUTE)
|
||||
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 Doxygen)
|
||||
get_target_property(doxygen_bin Doxygen::doxygen INTERFACE_LOCATION)
|
||||
get_filename_component(prefix ${doxygen_bin} DIRECTORY)
|
||||
|
@@ -2,6 +2,7 @@ Aphecetche, Laurent
|
||||
Binet, Sebastien
|
||||
Eulisse, Giulio
|
||||
Karabowicz, Radoslaw
|
||||
Kretz, Matthias <kretz@kde.org>
|
||||
Krzewicki, Mikolaj
|
||||
Neskovic, Gvozden
|
||||
Richter, Matthias
|
||||
|
41
COPYRIGHT
Normal file
41
COPYRIGHT
Normal file
@@ -0,0 +1,41 @@
|
||||
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,13 +41,15 @@ if [ "$#" -lt "2" ]; then
|
||||
fi
|
||||
|
||||
# test if a valid ctest model is defined
|
||||
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
|
||||
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
|
||||
|
||||
# test if the input file exists and execute it
|
||||
if [ -e "$2" ];then
|
||||
@@ -61,6 +63,9 @@ 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
|
||||
@@ -83,13 +88,20 @@ else
|
||||
COMPILER=$CXX$($CXX -dumpversion)
|
||||
fi
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
# 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=${_Model}")
|
||||
Set(configure_options "-DCMAKE_BUILD_TYPE=$ENV{ctest_model}")
|
||||
|
||||
Set(CTEST_USE_LAUNCHERS 1)
|
||||
Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LAUNCHERS}")
|
||||
@@ -28,24 +28,24 @@ 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_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 Nightly OR $ENV{ctest_model} MATCHES Profile)
|
||||
|
||||
If($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()
|
||||
|
||||
Set(ENV{ctest_model} Nightly)
|
||||
|
||||
CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
|
||||
|
||||
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
|
||||
Ctest_Empty_Binary_Directory(${CTEST_BINARY_DIRECTORY})
|
||||
EndIf()
|
||||
|
||||
Ctest_Start($ENV{ctest_model})
|
||||
@@ -60,9 +60,26 @@ Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
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}")
|
||||
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)
|
||||
EndIf()
|
||||
|
||||
Ctest_Submit()
|
||||
|
40
Jenkinsfile
vendored
40
Jenkinsfile
vendored
@@ -4,24 +4,31 @@ def specToLabel(Map spec) {
|
||||
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}"
|
||||
}
|
||||
|
||||
def buildMatrix(List specs, Closure callback) {
|
||||
def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
nodes[label] = {
|
||||
nodes["${prefix}/${label}"] = {
|
||||
node(label) {
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Building ...', status: 'PENDING')
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
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
|
||||
'''
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Success', status: 'SUCCESS')
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
|
||||
} catch (e) {
|
||||
deleteDir()
|
||||
githubNotify(context: "alfa-ci/${label}", description: 'Error', status: 'ERROR')
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
|
||||
throw e
|
||||
}
|
||||
}
|
||||
@@ -33,22 +40,25 @@ def buildMatrix(List specs, Closure callback) {
|
||||
pipeline{
|
||||
agent none
|
||||
stages {
|
||||
stage("Run Build/Test Matrix") {
|
||||
stage("Run CI Matrix") {
|
||||
steps{
|
||||
script {
|
||||
parallel(buildMatrix([
|
||||
def build_jobs = jobMatrix('alfa-ci/build', [
|
||||
[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: 'gcc4.9', fairsoft: 'may18'],
|
||||
]) { spec, label ->
|
||||
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
|
||||
sh './Dart.sh codecov Dart.cfg'
|
||||
}
|
||||
}
|
||||
|
||||
parallel(build_jobs + profile_jobs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
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/>
|
||||
|
51
README.md
51
README.md
@@ -1,12 +1,16 @@
|
||||
<!-- {#mainpage} -->
|
||||
# FairMQ
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) [](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&utm_medium=referral&utm_content=FairRootGroup/FairMQ&utm_campaign=Badge_Grade)
|
||||
|
||||
C++ Message passing framework
|
||||
C++ Message Queuing Library and Framework
|
||||
|
||||
| Branch | Build Status |
|
||||
| :---: | :--- |
|
||||
| `master` |  |
|
||||
| `dev` |  |
|
||||
| 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
|
||||
|
||||
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,
|
||||
@@ -31,30 +35,13 @@ a simulation, reconstruction and analysis framework.
|
||||
|
||||
## Dependencies
|
||||
|
||||
* [**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`)
|
||||
* 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/),
|
||||
[OFI](https://ofiwg.github.io/libfabric/), [Protobuf](https://developers.google.com/protocol-buffers/), [DDS](http://dds.gsi.de)
|
||||
|
||||
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
|
||||
@@ -89,7 +76,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()
|
||||
```
|
||||
|
||||
@@ -101,7 +88,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()
|
||||
```
|
||||
|
||||
@@ -169,9 +156,3 @@ 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)
|
||||
|
||||
## License
|
||||
|
||||
GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE).
|
||||
|
||||
Copyright (C) 2013-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
|
||||
|
@@ -23,6 +23,7 @@ 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@)
|
||||
|
||||
### Import cmake modules
|
||||
set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKEMODDIR} ${CMAKE_MODULE_PATH})
|
||||
|
@@ -112,7 +112,6 @@ 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)
|
||||
@@ -124,8 +123,14 @@ macro(set_fairmq_defaults)
|
||||
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
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
if(NOT CMAKE_POSITION_INDEPENDENT_CODE)
|
||||
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||
endif()
|
||||
|
||||
# Generate compile_commands.json file (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
@@ -158,9 +163,30 @@ macro(set_fairmq_defaults)
|
||||
# Define export set, only one for now
|
||||
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
|
||||
|
||||
# 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")
|
||||
# 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()
|
||||
endmacro()
|
||||
|
||||
function(join VALUES GLUE OUTPUT)
|
||||
@@ -237,7 +263,7 @@ endfunction()
|
||||
macro(install_cmake_package)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(PACKAGE_INSTALL_DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_GIT_VERSION}
|
||||
)
|
||||
if(BUILD_FAIRMQ)
|
||||
install(EXPORT ${PROJECT_EXPORT_SET}
|
||||
@@ -280,20 +306,22 @@ macro(find_package2 qualifier pkgname)
|
||||
set(CMAKE_PREFIX_PATH ${old_CPP})
|
||||
unset(old_CPP)
|
||||
|
||||
if(${qualifier} STREQUAL PRIVATE)
|
||||
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 ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
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 ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
if(${pkgname}_FOUND)
|
||||
if(${qualifier} STREQUAL PRIVATE)
|
||||
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 ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
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 ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
@@ -89,7 +89,7 @@ endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(ZeroMQ
|
||||
REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR ZeroMQ_LIBRARY_STATIC
|
||||
REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR
|
||||
VERSION_VAR ZeroMQ_VERSION
|
||||
)
|
||||
|
||||
|
@@ -1,34 +0,0 @@
|
||||
################################################################################
|
||||
# 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()
|
@@ -51,7 +51,7 @@ function(add_testsuite suitename)
|
||||
cmake_parse_arguments(testsuite
|
||||
""
|
||||
"TIMEOUT;RUN_SERIAL"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -69,6 +69,9 @@ 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})
|
||||
if(testsuite_TIMEOUT)
|
||||
@@ -86,7 +89,7 @@ function(add_testhelper helpername)
|
||||
cmake_parse_arguments(testhelper
|
||||
""
|
||||
""
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -102,6 +105,9 @@ 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)
|
||||
@@ -111,7 +117,7 @@ function(add_testlib libname)
|
||||
cmake_parse_arguments(testlib
|
||||
"HIDDEN"
|
||||
"VERSION"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES"
|
||||
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
|
||||
${ARGN}
|
||||
)
|
||||
|
||||
@@ -133,6 +139,9 @@ 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
Normal file
4190
cmake/cotire.cmake
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,16 +1,10 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sampler.cpp
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <thread> // this_thread::sleep_for
|
||||
#include <chrono>
|
||||
@@ -64,8 +58,6 @@ bool Sampler::ConditionalRun()
|
||||
return false;
|
||||
}
|
||||
|
||||
this_thread::sleep_for(chrono::seconds(1));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@@ -4,6 +4,7 @@ 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,13 +8,17 @@ 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"
|
||||
@@ -25,6 +29,7 @@ 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"
|
||||
|
@@ -9,6 +9,7 @@ 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
|
||||
@@ -17,6 +18,7 @@ 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"
|
||||
@@ -27,6 +29,7 @@ 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"
|
||||
@@ -37,6 +40,7 @@ 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"
|
||||
@@ -47,6 +51,7 @@ 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,6 +8,8 @@ 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
|
||||
|
||||
@@ -15,6 +17,7 @@ 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"
|
||||
@@ -25,6 +28,7 @@ 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"
|
||||
@@ -35,6 +39,7 @@ 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,23 +1,17 @@
|
||||
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 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/" ..
|
||||
```
|
||||
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.
|
||||
|
||||
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 socket addresses and ports configuration via DDS Plugin.
|
||||
##### 1. The device handles the channel addresses and ports configuration via DDS Plugin.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
##### 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 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:
|
||||
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:
|
||||
- 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)
|
||||
@@ -40,23 +34,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 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.
|
||||
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.
|
||||
|
||||
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).
|
||||
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.
|
||||
|
||||
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:
|
||||
**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 id="SamplerWorker" type="wnname" value=".*"/>
|
||||
<declrequirement id="ProcessorWorker" type="wnname" value=".*"/>
|
||||
<declrequirement id="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 server.
|
||||
|
||||
First you need to initialize DDS environment:
|
||||
|
||||
```bash
|
||||
source DDS_env.sh # this script is located in the DDS installation directory
|
||||
```
|
||||
|
||||
The DDS server is started with:
|
||||
|
||||
```bash
|
||||
@@ -71,7 +69,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
|
||||
@@ -85,13 +83,30 @@ 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.
|
||||
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).
|
||||
|
||||
##### 8. (optional) Use example command UI to check state of the devices
|
||||
|
||||
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).
|
||||
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).
|
||||
|
||||
To see it in action, start the fairmq-dds-command-ui while the topology is running.
|
||||
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.
|
||||
|
||||
The utility requires a session parameter to connect to appropriate DDS session. The session value is given when starting dds-server.
|
||||
|
||||
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 server/topology.
|
||||
|
||||
|
@@ -8,6 +8,8 @@ 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
|
||||
|
||||
@@ -15,6 +17,7 @@ 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=push,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
@@ -25,6 +28,7 @@ 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=pull,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
|
||||
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
|
||||
|
@@ -8,6 +8,8 @@ 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
|
||||
|
||||
@@ -15,6 +17,7 @@ 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"
|
||||
@@ -25,6 +28,7 @@ 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"
|
||||
|
@@ -1,54 +0,0 @@
|
||||
---
|
||||
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
|
||||
...
|
@@ -28,7 +28,6 @@ endif()
|
||||
##################
|
||||
# subdirectories #
|
||||
##################
|
||||
# add_subdirectory(shmem/prototype)
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_subdirectory(ofi)
|
||||
endif()
|
||||
@@ -38,145 +37,144 @@ 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
|
||||
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
|
||||
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/RateLimit.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
|
||||
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
|
||||
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/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
|
||||
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
|
||||
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/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()
|
||||
|
||||
|
||||
@@ -191,62 +189,93 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/options/startConfigExample.sh.in ${CM
|
||||
#################################
|
||||
# define libFairMQ build target #
|
||||
#################################
|
||||
add_library(FairMQ SHARED
|
||||
if(FAST_BUILD)
|
||||
set(_target FairMQ_)
|
||||
else()
|
||||
set(_target FairMQ)
|
||||
endif()
|
||||
add_library(${_target}
|
||||
${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()
|
||||
|
||||
#######################
|
||||
# include directories #
|
||||
#######################
|
||||
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>
|
||||
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>
|
||||
)
|
||||
|
||||
##################
|
||||
# link libraries #
|
||||
##################
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>)
|
||||
endif()
|
||||
target_link_libraries(FairMQ
|
||||
INTERFACE # only consumers link against interface dependencies
|
||||
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
|
||||
if(optional_deps)
|
||||
list(REMOVE_DUPLICATES optional_deps)
|
||||
endif()
|
||||
|
||||
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
|
||||
target_link_libraries(${_target}
|
||||
INTERFACE # only consumers link against interface dependencies
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
${NANOMSG_DEPS}
|
||||
${OFI_DEPS}
|
||||
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
|
||||
Threads::Threads
|
||||
dl
|
||||
$<$<PLATFORM_ID:Linux>:rt>
|
||||
Boost::boost
|
||||
Boost::program_options
|
||||
Boost::thread
|
||||
Boost::system
|
||||
Boost::filesystem
|
||||
Boost::regex
|
||||
Boost::date_time
|
||||
Boost::signals
|
||||
FairLogger::FairLogger
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
libzmq
|
||||
${NANOMSG_DEPS}
|
||||
${OFI_DEPS}
|
||||
)
|
||||
set_target_properties(FairMQ PROPERTIES
|
||||
VERSION ${PROJECT_VERSION}
|
||||
set_target_properties(${_target} PROPERTIES
|
||||
VERSION ${PROJECT_GIT_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)
|
||||
|
||||
@@ -268,37 +297,48 @@ target_link_libraries(fairmq-splitter FairMQ)
|
||||
add_executable(runConfigExample options/runConfigEx.cxx)
|
||||
target_link_libraries(runConfigExample FairMQ)
|
||||
|
||||
add_executable(fairmq-shmmonitor shmem/runMonitor.cxx)
|
||||
target_link_libraries(fairmq-shmmonitor 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-uuid-gen run/runUuidGenerator.cxx)
|
||||
target_link_libraries(fairmq-uuid-gen FairMQ)
|
||||
|
||||
|
||||
###########
|
||||
# install #
|
||||
###########
|
||||
install(
|
||||
TARGETS # FairMQFull, tests are not installed
|
||||
FairMQ
|
||||
fairmq-bsampler
|
||||
fairmq-merger
|
||||
fairmq-multiplier
|
||||
fairmq-proxy
|
||||
fairmq-sink
|
||||
fairmq-splitter
|
||||
fairmq-shmmonitor
|
||||
fairmq-uuid-gen
|
||||
TARGETS
|
||||
FairMQ
|
||||
fairmq-bsampler
|
||||
fairmq-merger
|
||||
fairmq-multiplier
|
||||
fairmq-proxy
|
||||
fairmq-sink
|
||||
fairmq-splitter
|
||||
fairmq-shmmonitor
|
||||
fairmq-uuid-gen
|
||||
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
EXPORT ${PROJECT_EXPORT_SET}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
)
|
||||
|
||||
# preserve relative path and prepend fairmq
|
||||
foreach(HEADER ${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 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -7,17 +7,21 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "DeviceRunner.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <exception>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/Version.h>
|
||||
|
||||
using namespace fair::mq;
|
||||
|
||||
DeviceRunner::DeviceRunner(int argc, char* const argv[])
|
||||
: fRawCmdLineArgs{tools::ToStrVector(argc, argv, false)}
|
||||
, fPluginManager{PluginManager::MakeFromCommandLineOptions(fRawCmdLineArgs)}
|
||||
, fDevice{nullptr}
|
||||
{
|
||||
}
|
||||
DeviceRunner::DeviceRunner(int argc, char* const argv[], bool printLogo)
|
||||
: fRawCmdLineArgs(tools::ToStrVector(argc, argv, false))
|
||||
, fConfig()
|
||||
, fDevice(nullptr)
|
||||
, fPluginManager(fRawCmdLineArgs)
|
||||
, fPrintLogo(printLogo)
|
||||
, fEvents()
|
||||
{}
|
||||
|
||||
auto DeviceRunner::Run() -> int
|
||||
{
|
||||
@@ -26,32 +30,40 @@ 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;
|
||||
}
|
||||
@@ -60,16 +72,14 @@ auto DeviceRunner::Run() -> int
|
||||
|
||||
// Handle --print-channels
|
||||
fDevice->RegisterChannelEndpoints();
|
||||
if (fConfig.Count("print-channels"))
|
||||
{
|
||||
if (fConfig.Count("print-channels")) {
|
||||
fDevice->PrintRegisteredChannels();
|
||||
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;
|
||||
std::cout << "FAIRMQ_INTERFACE_VERSION: " << FAIRMQ_INTERFACE_VERSION << std::endl;
|
||||
fDevice->ChangeState(FairMQDevice::END);
|
||||
@@ -82,31 +92,29 @@ auto DeviceRunner::Run() -> int
|
||||
fDevice->SetConfig(fConfig);
|
||||
|
||||
// Initialize plugin services
|
||||
fPluginManager->EmplacePluginServices(&fConfig, fDevice);
|
||||
fPluginManager.EmplacePluginServices(fConfig, *fDevice);
|
||||
|
||||
// Instantiate and run plugins
|
||||
fPluginManager->InstantiatePlugins();
|
||||
fPluginManager.InstantiatePlugins();
|
||||
|
||||
// Run the device
|
||||
fDevice->RunStateMachine();
|
||||
|
||||
// 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) << "Unhandled exception reached the top of main: " << e.what() << ", application will now exit";
|
||||
} catch (std::exception& e) {
|
||||
LOG(error) << "Uncaught exception reached the top of DeviceRunner: " << e.what();
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(error) << "Non-exception instance being thrown. Please make sure you use std::runtime_exception() instead. Application will now exit.";
|
||||
} catch (...) {
|
||||
LOG(error) << "Uncaught exception reached the top of DeviceRunner.";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -20,10 +20,8 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
||||
/**
|
||||
* @class DeviceRunner DeviceRunner.h <fairmq/DeviceRunner.h>
|
||||
@@ -31,7 +29,8 @@ 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
|
||||
* |
|
||||
@@ -44,34 +43,41 @@ 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[]);
|
||||
DeviceRunner(int argc, char* const argv[], bool printLogo = true);
|
||||
|
||||
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::shared_ptr<FairMQDevice> fDevice;
|
||||
std::unique_ptr<FairMQDevice> fDevice;
|
||||
PluginManager fPluginManager;
|
||||
const bool fPrintLogo;
|
||||
|
||||
private:
|
||||
EventManager fEvents;
|
||||
};
|
||||
|
||||
namespace hooks
|
||||
{
|
||||
namespace hooks {
|
||||
struct LoadPlugins : Event<DeviceRunner&> {};
|
||||
struct SetCustomCmdLineOptions : Event<DeviceRunner&> {};
|
||||
struct ModifyRawCmdLineArgs : Event<DeviceRunner&> {};
|
||||
|
@@ -104,19 +104,22 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
|
||||
|
||||
FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
|
||||
{
|
||||
fSocket = nullptr;
|
||||
fType = chan.fType;
|
||||
fMethod = chan.fMethod;
|
||||
fAddress = chan.fAddress;
|
||||
fTransportType = chan.fTransportType;
|
||||
fSndBufSize = chan.fSndBufSize;
|
||||
fRcvBufSize = chan.fRcvBufSize;
|
||||
fSndKernelSize = chan.fSndKernelSize;
|
||||
fRcvKernelSize = chan.fRcvKernelSize;
|
||||
fRateLogging = chan.fRateLogging;
|
||||
fSocket = nullptr;
|
||||
fName = chan.fName;
|
||||
fIsValid = false;
|
||||
fTransportType = chan.fTransportType;
|
||||
fTransportFactory = nullptr;
|
||||
fMultipart = chan.fMultipart;
|
||||
fModified = chan.fModified;
|
||||
fReset = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -499,7 +502,7 @@ bool FairMQChannel::ValidateChannel()
|
||||
else
|
||||
{
|
||||
vector<string> endpoints;
|
||||
boost::algorithm::split(endpoints, fAddress, boost::algorithm::is_any_of(","));
|
||||
boost::algorithm::split(endpoints, fAddress, boost::algorithm::is_any_of(";"));
|
||||
for (const auto endpoint : endpoints)
|
||||
{
|
||||
string address;
|
||||
@@ -755,7 +758,7 @@ void FairMQChannel::CheckSendCompatibility(FairMQMessagePtr& msg) const
|
||||
// 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); },
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
@@ -772,7 +775,7 @@ void FairMQChannel::CheckSendCompatibility(vector<FairMQMessagePtr>& msgVec) con
|
||||
// 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); },
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
|
@@ -8,9 +8,6 @@
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
#include <boost/algorithm/string.hpp> // join/split
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
@@ -27,57 +24,44 @@
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <future>
|
||||
#include <algorithm> // std::max
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
FairMQDevice::FairMQDevice()
|
||||
: fTransportFactory(nullptr)
|
||||
, fTransports()
|
||||
, fChannels()
|
||||
, fConfig(nullptr)
|
||||
, fId()
|
||||
, fNumIoThreads(1)
|
||||
, fInitialValidationFinished(false)
|
||||
, fInitialValidationCondition()
|
||||
, fInitialValidationMutex()
|
||||
, fPortRangeMin(22000)
|
||||
, fPortRangeMax(32000)
|
||||
, fNetworkInterface()
|
||||
, fDefaultTransportType(fair::mq::Transport::DEFAULT)
|
||||
, fInitializationTimeoutInS(120)
|
||||
, fDataCallbacks(false)
|
||||
, fMsgInputs()
|
||||
, fMultipartInputs()
|
||||
, fMultitransportInputs()
|
||||
, fChannelRegistry()
|
||||
, fInputChannelKeys()
|
||||
, fMultitransportMutex()
|
||||
, fMultitransportProceed(false)
|
||||
, fExternalConfig(false)
|
||||
, fVersion({0, 0, 0})
|
||||
, fRate(0.)
|
||||
, fLastTime(0)
|
||||
, fRawCmdLineArgs()
|
||||
: FairMQDevice(nullptr, {0, 0, 0})
|
||||
{
|
||||
}
|
||||
|
||||
FairMQDevice::FairMQDevice(FairMQProgOptions& config)
|
||||
: FairMQDevice(&config, {0, 0, 0})
|
||||
{
|
||||
}
|
||||
|
||||
FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
|
||||
: FairMQDevice(nullptr, version)
|
||||
{
|
||||
}
|
||||
|
||||
FairMQDevice::FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version)
|
||||
: FairMQDevice(&config, version)
|
||||
{
|
||||
}
|
||||
|
||||
FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version)
|
||||
: fTransportFactory(nullptr)
|
||||
, fTransports()
|
||||
, fChannels()
|
||||
, fConfig(nullptr)
|
||||
, fInternalConfig(config ? nullptr : fair::mq::tools::make_unique<FairMQProgOptions>())
|
||||
, fConfig(config ? config : fInternalConfig.get())
|
||||
, fId()
|
||||
, fNumIoThreads(1)
|
||||
, fInitialValidationFinished(false)
|
||||
, fInitialValidationCondition()
|
||||
, fInitialValidationMutex()
|
||||
, fPortRangeMin(22000)
|
||||
, fPortRangeMax(32000)
|
||||
, fNetworkInterface()
|
||||
, fDefaultTransportType(fair::mq::Transport::DEFAULT)
|
||||
, fInitializationTimeoutInS(120)
|
||||
, fDataCallbacks(false)
|
||||
, fMsgInputs()
|
||||
, fMultipartInputs()
|
||||
@@ -86,26 +70,54 @@ FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
|
||||
, fInputChannelKeys()
|
||||
, fMultitransportMutex()
|
||||
, fMultitransportProceed(false)
|
||||
, fExternalConfig(false)
|
||||
, fVersion(version)
|
||||
, fRate(0.)
|
||||
, fLastTime(0)
|
||||
, fRawCmdLineArgs()
|
||||
, fInterrupted(false)
|
||||
, fInterruptedCV()
|
||||
, fInterruptedMtx()
|
||||
{
|
||||
}
|
||||
|
||||
void FairMQDevice::InitWrapper()
|
||||
{
|
||||
if (!fTransportFactory)
|
||||
fId = fConfig->GetValue<string>("id");
|
||||
fRate = fConfig->GetValue<float>("rate");
|
||||
fPortRangeMin = fConfig->GetValue<int>("port-range-min");
|
||||
fPortRangeMax = fConfig->GetValue<int>("port-range-max");
|
||||
|
||||
try
|
||||
{
|
||||
LOG(error) << "Transport not initialized. Did you call SetTransport()?";
|
||||
exit(EXIT_FAILURE);
|
||||
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
|
||||
}
|
||||
catch (const exception& e)
|
||||
{
|
||||
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
|
||||
}
|
||||
|
||||
for (auto& c : fConfig->GetFairMQMap())
|
||||
{
|
||||
if (fChannels.find(c.first) == fChannels.end())
|
||||
{
|
||||
LOG(debug) << "Inserting new device channel from config: " << c.first;
|
||||
fChannels.insert(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(debug) << "Updating existing device channel from config: " << c.first;
|
||||
fChannels[c.first] = c.second;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(debug) << "Requesting '" << fair::mq::TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
|
||||
fTransportFactory = AddTransport(fDefaultTransportType);
|
||||
|
||||
// Containers to store the uninitialized channels.
|
||||
vector<FairMQChannel*> uninitializedBindingChannels;
|
||||
vector<FairMQChannel*> uninitializedConnectingChannels;
|
||||
|
||||
string networkInterface = fConfig->GetValue<string>("network-interface");
|
||||
|
||||
// Fill the uninitialized channel containers
|
||||
for (auto& mi : fChannels)
|
||||
{
|
||||
@@ -126,11 +138,11 @@ void FairMQDevice::InitWrapper()
|
||||
if (vi->fAddress == "unspecified" || vi->fAddress == "")
|
||||
{
|
||||
// if the configured network interface is default, get its name from the default route
|
||||
if (fNetworkInterface == "default")
|
||||
if (networkInterface == "default")
|
||||
{
|
||||
fNetworkInterface = fair::mq::tools::getDefaultRouteNetworkInterface();
|
||||
networkInterface = fair::mq::tools::getDefaultRouteNetworkInterface();
|
||||
}
|
||||
vi->fAddress = "tcp://" + fair::mq::tools::getInterfaceIP(fNetworkInterface) + ":1";
|
||||
vi->fAddress = "tcp://" + fair::mq::tools::getInterfaceIP(networkInterface) + ":1";
|
||||
}
|
||||
// fill the uninitialized list
|
||||
uninitializedBindingChannels.push_back(&(*vi));
|
||||
@@ -175,10 +187,12 @@ void FairMQDevice::InitWrapper()
|
||||
fInitialValidationCondition.notify_one();
|
||||
}
|
||||
|
||||
int initializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
|
||||
|
||||
// go over the list of channels until all are initialized (and removed from the uninitialized list)
|
||||
int numAttempts = 1;
|
||||
auto sleepTimeInMS = 50;
|
||||
auto maxAttempts = fInitializationTimeoutInS * 1000 / sleepTimeInMS;
|
||||
auto maxAttempts = initializationTimeoutInS * 1000 / sleepTimeInMS;
|
||||
// first attempt
|
||||
AttachChannels(uninitializedConnectingChannels);
|
||||
// if not all channels could be connected, update their address values from config and retry
|
||||
@@ -201,9 +215,9 @@ void FairMQDevice::InitWrapper()
|
||||
|
||||
if (numAttempts++ > maxAttempts)
|
||||
{
|
||||
LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts";
|
||||
LOG(error) << "could not connect all channels after " << initializationTimeoutInS << " attempts";
|
||||
ChangeState(ERROR_FOUND);
|
||||
// throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts"));
|
||||
// throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", initializationTimeoutInS, " attempts"));
|
||||
}
|
||||
|
||||
AttachChannels(uninitializedConnectingChannels);
|
||||
@@ -252,19 +266,15 @@ void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
|
||||
|
||||
bool FairMQDevice::AttachChannel(FairMQChannel& ch)
|
||||
{
|
||||
if (!ch.fTransportFactory)
|
||||
if (ch.fTransportType == fair::mq::Transport::DEFAULT || ch.fTransportType == fTransportFactory->GetType())
|
||||
{
|
||||
if (ch.fTransportType == fair::mq::Transport::DEFAULT || ch.fTransportType == fTransportFactory->GetType())
|
||||
{
|
||||
LOG(debug) << ch.fName << ": using default transport";
|
||||
ch.InitTransport(fTransportFactory);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(debug) << ch.fName << ": channel transport (" << fair::mq::TransportNames.at(fDefaultTransportType) << ") overriden to " << fair::mq::TransportNames.at(ch.fTransportType);
|
||||
ch.InitTransport(AddTransport(ch.fTransportType));
|
||||
}
|
||||
ch.fTransportType = ch.fTransportFactory->GetType();
|
||||
LOG(debug) << ch.fName << ": using default transport";
|
||||
ch.InitTransport(fTransportFactory);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(debug) << ch.fName << ": channel transport (" << fair::mq::TransportNames.at(fDefaultTransportType) << ") overriden to " << fair::mq::TransportNames.at(ch.fTransportType);
|
||||
ch.InitTransport(AddTransport(ch.fTransportType));
|
||||
}
|
||||
|
||||
vector<string> endpoints;
|
||||
@@ -280,7 +290,7 @@ bool FairMQDevice::AttachChannel(FairMQChannel& ch)
|
||||
}
|
||||
catch (fair::mq::SocketError& se)
|
||||
{
|
||||
LOG(ERROR) << se.what();
|
||||
LOG(error) << se.what();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -482,9 +492,13 @@ void FairMQDevice::RunWrapper()
|
||||
LOG(info) << "DEVICE: Running...";
|
||||
|
||||
// start the rate logger thread
|
||||
thread rateLogger(&FairMQDevice::LogSocketRates, this);
|
||||
future<void> rateLogger = async(launch::async, &FairMQDevice::LogSocketRates, this);
|
||||
|
||||
// notify transports to resume transfers
|
||||
{
|
||||
lock_guard<mutex> guard(fInterruptedMtx);
|
||||
fInterrupted = false;
|
||||
}
|
||||
for (auto& t : fTransports)
|
||||
{
|
||||
t.second->Resume();
|
||||
@@ -509,20 +523,14 @@ void FairMQDevice::RunWrapper()
|
||||
}
|
||||
else
|
||||
{
|
||||
using Clock = chrono::steady_clock;
|
||||
using TimeScale = chrono::microseconds;
|
||||
const TimeScale::rep period = TimeScale::period::den / fRate;
|
||||
const auto reftime = Clock::now();
|
||||
fair::mq::tools::RateLimiter rateLimiter(fRate);
|
||||
|
||||
while (CheckCurrentState(RUNNING) && ConditionalRun())
|
||||
{
|
||||
if (fRate > 0.001) {
|
||||
auto timespan = static_cast<TimeScale::rep>(chrono::duration_cast<TimeScale>(Clock::now() - reftime).count() - fLastTime);
|
||||
if (timespan < period) {
|
||||
TimeScale sleepfor(period - timespan);
|
||||
this_thread::sleep_for(sleepfor);
|
||||
if (fRate > 0.001)
|
||||
{
|
||||
rateLimiter.maybe_sleep();
|
||||
}
|
||||
fLastTime = chrono::duration_cast<TimeScale>(Clock::now() - reftime).count();
|
||||
}
|
||||
}
|
||||
|
||||
Run();
|
||||
@@ -542,7 +550,7 @@ void FairMQDevice::RunWrapper()
|
||||
|
||||
PostRun();
|
||||
|
||||
rateLogger.join();
|
||||
rateLogger.get();
|
||||
}
|
||||
|
||||
void FairMQDevice::HandleSingleChannelInput()
|
||||
@@ -798,78 +806,10 @@ shared_ptr<FairMQTransportFactory> FairMQDevice::AddTransport(const fair::mq::Tr
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQDevice::CreateOwnConfig()
|
||||
{
|
||||
// TODO: make fConfig a shared_ptr when no old user code has FairMQProgOptions ptr*
|
||||
fConfig = new FairMQProgOptions();
|
||||
|
||||
string id{boost::uuids::to_string(boost::uuids::random_generator()())};
|
||||
LOG(warn) << "No FairMQProgOptions provided, creating one internally and setting device ID to " << id;
|
||||
|
||||
// dummy argc+argv
|
||||
char arg0[] = "undefined"; // executable name
|
||||
char arg1[] = "--id";
|
||||
char* arg2 = const_cast<char*>(id.c_str()); // device ID
|
||||
const char* argv[] = { &arg0[0], &arg1[0], arg2, nullptr };
|
||||
int argc = static_cast<int>((sizeof(argv) / sizeof(argv[0])) - 1);
|
||||
|
||||
fConfig->ParseAll(argc, &argv[0]);
|
||||
|
||||
fId = fConfig->GetValue<string>("id");
|
||||
fNetworkInterface = fConfig->GetValue<string>("network-interface");
|
||||
fNumIoThreads = fConfig->GetValue<int>("io-threads");
|
||||
fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
|
||||
fRate = fConfig->GetValue<float>("rate");
|
||||
try {
|
||||
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
|
||||
} catch(const exception& e) {
|
||||
LOG(ERROR) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQDevice::SetTransport(const string& transport)
|
||||
{
|
||||
// This method is the first to be called, if FairMQProgOptions are not used (either SetTransport() or SetConfig() make sense, not both).
|
||||
// Make sure here that at least internal config is available.
|
||||
if (!fExternalConfig && !fConfig)
|
||||
{
|
||||
CreateOwnConfig();
|
||||
}
|
||||
|
||||
if (fTransports.empty())
|
||||
{
|
||||
LOG(debug) << "Requesting '" << transport << "' as default transport for the device";
|
||||
fTransportFactory = AddTransport(fair::mq::TransportTypes.at(transport));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Transports container is not empty when setting transport. Setting default twice?";
|
||||
ChangeState(ERROR_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQDevice::SetConfig(FairMQProgOptions& config)
|
||||
{
|
||||
fExternalConfig = true;
|
||||
fInternalConfig.reset();
|
||||
fConfig = &config;
|
||||
for (auto& c : fConfig->GetFairMQMap())
|
||||
{
|
||||
if (!fChannels.insert(c).second)
|
||||
{
|
||||
LOG(warn) << "did not insert channel '" << c.first << "', it is already in the device.";
|
||||
}
|
||||
}
|
||||
fId = fConfig->GetValue<string>("id");
|
||||
fNetworkInterface = fConfig->GetValue<string>("network-interface");
|
||||
fNumIoThreads = fConfig->GetValue<int>("io-threads");
|
||||
fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
|
||||
fRate = fConfig->GetValue<float>("rate");
|
||||
try {
|
||||
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
|
||||
} catch(const exception& e) {
|
||||
LOG(ERROR) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
|
||||
}
|
||||
SetTransport(fConfig->GetValue<string>("transport"));
|
||||
}
|
||||
|
||||
void FairMQDevice::LogSocketRates()
|
||||
@@ -877,8 +817,6 @@ void FairMQDevice::LogSocketRates()
|
||||
chrono::time_point<chrono::high_resolution_clock> t0;
|
||||
chrono::time_point<chrono::high_resolution_clock> t1;
|
||||
|
||||
unsigned long long msSinceLastLog;
|
||||
|
||||
vector<FairMQSocket*> filteredSockets;
|
||||
vector<string> filteredChannelNames;
|
||||
vector<int> logIntervals;
|
||||
@@ -940,7 +878,7 @@ void FairMQDevice::LogSocketRates()
|
||||
{
|
||||
t1 = chrono::high_resolution_clock::now();
|
||||
|
||||
msSinceLastLog = chrono::duration_cast<chrono::milliseconds>(t1 - t0).count();
|
||||
unsigned long long msSinceLastLog = chrono::duration_cast<chrono::milliseconds>(t1 - t0).count();
|
||||
|
||||
i = 0;
|
||||
|
||||
@@ -977,6 +915,7 @@ void FairMQDevice::LogSocketRates()
|
||||
|
||||
t0 = t1;
|
||||
this_thread::sleep_for(chrono::milliseconds(1000));
|
||||
// WaitFor(chrono::milliseconds(1000)); TODO: enable this when nanomsg linger is fixed
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -987,6 +926,11 @@ void FairMQDevice::Unblock()
|
||||
{
|
||||
t.second->Interrupt();
|
||||
}
|
||||
{
|
||||
lock_guard<mutex> guard(fInterruptedMtx);
|
||||
fInterrupted = true;
|
||||
}
|
||||
fInterruptedCV.notify_all();
|
||||
}
|
||||
|
||||
void FairMQDevice::ResetTaskWrapper()
|
||||
@@ -1020,7 +964,7 @@ void FairMQDevice::Reset()
|
||||
for (auto& vi : mi.second)
|
||||
{
|
||||
// vi.fReset = true;
|
||||
vi.fSocket.reset();
|
||||
vi.fSocket.reset(); // destroy FairMQSocket
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1032,10 +976,6 @@ const FairMQChannel& FairMQDevice::GetChannel(const string& channelName, const i
|
||||
|
||||
void FairMQDevice::Exit()
|
||||
{
|
||||
if (!fExternalConfig && fConfig)
|
||||
{
|
||||
delete fConfig;
|
||||
}
|
||||
}
|
||||
|
||||
FairMQDevice::~FairMQDevice()
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <memory> // unique_ptr
|
||||
#include <algorithm> // std::sort()
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
@@ -48,9 +49,19 @@ class FairMQDevice : public FairMQStateMachine
|
||||
public:
|
||||
/// 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)
|
||||
@@ -294,12 +305,11 @@ class FairMQDevice : public FairMQStateMachine
|
||||
/// 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);
|
||||
const FairMQProgOptions* GetConfig() const
|
||||
/// Get pointer to the config
|
||||
FairMQProgOptions* GetConfig() const
|
||||
{
|
||||
return fConfig;
|
||||
}
|
||||
@@ -395,74 +405,87 @@ class FairMQDevice : public FairMQStateMachine
|
||||
|
||||
const fair::mq::tools::Version GetVersion() const { return fVersion; }
|
||||
|
||||
void SetNumIoThreads(int numIoThreads) { fNumIoThreads = numIoThreads; }
|
||||
int GetNumIoThreads() const { return fNumIoThreads; }
|
||||
void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);}
|
||||
int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); }
|
||||
|
||||
void SetPortRangeMin(int portRangeMin) { fPortRangeMin = portRangeMin; }
|
||||
int GetPortRangeMin() const { return fPortRangeMin; }
|
||||
void SetPortRangeMin(int portRangeMin) { fConfig->SetValue<int>("port-range-min", portRangeMin); }
|
||||
int GetPortRangeMin() const { return fConfig->GetValue<int>("port-range-min"); }
|
||||
|
||||
void SetPortRangeMax(int portRangeMax) { fPortRangeMax = portRangeMax; }
|
||||
int GetPortRangeMax() const { return fPortRangeMax; }
|
||||
void SetPortRangeMax(int portRangeMax) { fConfig->SetValue<int>("port-range-max", portRangeMax); }
|
||||
int GetPortRangeMax() const { return fConfig->GetValue<int>("port-range-max"); }
|
||||
|
||||
void SetNetworkInterface(const std::string& networkInterface) { fNetworkInterface = networkInterface; }
|
||||
std::string GetNetworkInterface() const { return fNetworkInterface; }
|
||||
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 SetDefaultTransport(const std::string& name) { fDefaultTransportType = fair::mq::TransportTypes.at(name); }
|
||||
std::string GetDefaultTransport() const { return fair::mq::TransportNames.at(fDefaultTransportType); }
|
||||
void SetDefaultTransport(const std::string& name) { fConfig->SetValue<std::string>("transport", name); }
|
||||
std::string GetDefaultTransport() const { return fConfig->GetValue<std::string>("transport"); }
|
||||
|
||||
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; }
|
||||
int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; }
|
||||
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fConfig->SetValue<int>("initialization-timeout", initializationTimeoutInS); }
|
||||
int GetInitializationTimeoutInS() const { return fConfig->GetValue<int>("initialization-timeout"); }
|
||||
|
||||
/// 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 SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
|
||||
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
|
||||
|
||||
void RunStateMachine() { 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)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(fInterruptedMtx);
|
||||
return !fInterruptedCV.wait_for(lock, duration, [&] { return fInterrupted.load(); }); // return true if no interruption happened
|
||||
}
|
||||
|
||||
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
|
||||
FairMQProgOptions* fConfig; ///< Program options configuration
|
||||
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);
|
||||
}
|
||||
|
||||
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().
|
||||
/// Executed in a worker thread
|
||||
virtual void Init();
|
||||
|
||||
/// Task initialization (can be overloaded in child classes)
|
||||
/// Executed in a worker thread
|
||||
virtual void InitTask();
|
||||
|
||||
/// Runs the device (to be overloaded in child classes)
|
||||
/// Executed in a worker thread
|
||||
virtual void Run();
|
||||
|
||||
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
|
||||
/// Executed in a worker thread
|
||||
virtual void PreRun();
|
||||
|
||||
/// Called during RUNNING state repeatedly until it returns false or device state changes
|
||||
/// Executed in a worker thread
|
||||
virtual bool ConditionalRun();
|
||||
|
||||
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
|
||||
/// Executed in a worker thread
|
||||
virtual void PostRun();
|
||||
|
||||
/// Handles the PAUSE state
|
||||
/// Executed in a worker thread
|
||||
virtual void Pause();
|
||||
|
||||
/// Resets the user task (to be overloaded in child classes)
|
||||
/// Executed in a worker thread
|
||||
virtual void ResetTask();
|
||||
|
||||
/// Resets the device (can be overloaded in child classes)
|
||||
/// Executed in a worker thread
|
||||
virtual void Reset();
|
||||
|
||||
private:
|
||||
@@ -474,11 +497,8 @@ class FairMQDevice : public FairMQStateMachine
|
||||
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();
|
||||
/// Handles the InitTask() method
|
||||
@@ -530,12 +550,13 @@ class FairMQDevice : public FairMQStateMachine
|
||||
std::mutex fMultitransportMutex;
|
||||
std::atomic<bool> fMultitransportProceed;
|
||||
|
||||
bool fExternalConfig;
|
||||
|
||||
const fair::mq::tools::Version fVersion;
|
||||
float fRate; ///< Rate limiting for ConditionalRun
|
||||
size_t fLastTime; ///< Rate limiting for ConditionalRun
|
||||
std::vector<std::string> fRawCmdLineArgs;
|
||||
|
||||
std::atomic<bool> fInterrupted;
|
||||
std::condition_variable fInterruptedCV;
|
||||
std::mutex fInterruptedMtx;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQDEVICE_H_ */
|
||||
|
@@ -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() {};
|
||||
};
|
||||
|
@@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "FairMQStateMachine.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
|
||||
@@ -29,13 +30,20 @@
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::msm::front;
|
||||
|
||||
namespace msmf = boost::msm::front;
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<FairMQStateMachine::Event> : fair::mq::tools::HashEnum<FairMQStateMachine::Event> {};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -44,35 +52,111 @@ 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"; } };
|
||||
// list of FSM states
|
||||
struct OK_FSM_STATE : public state<> { static string Name() { return "OK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::OK; } };
|
||||
struct ERROR_FSM_STATE : public terminate_state<> { static string Name() { return "ERROR"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::Error; } };
|
||||
|
||||
// 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
|
||||
struct IDLE_FSM_STATE : public state<> { static string Name() { return "IDLE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::IDLE; } };
|
||||
struct INITIALIZING_DEVICE_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_DEVICE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_DEVICE; } };
|
||||
struct DEVICE_READY_FSM_STATE : public state<> { static string Name() { return "DEVICE_READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::DEVICE_READY; } };
|
||||
struct INITIALIZING_TASK_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_TASK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_TASK; } };
|
||||
struct READY_FSM_STATE : public state<> { static string Name() { return "READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::READY; } };
|
||||
struct RUNNING_FSM_STATE : public state<> { static string Name() { return "RUNNING"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RUNNING; } };
|
||||
struct PAUSED_FSM_STATE : public state<> { static string Name() { return "PAUSED"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::PAUSED; } };
|
||||
struct RESETTING_TASK_FSM_STATE : public state<> { static string Name() { return "RESETTING_TASK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RESETTING_TASK; } };
|
||||
struct RESETTING_DEVICE_FSM_STATE : public state<> { static string Name() { return "RESETTING_DEVICE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RESETTING_DEVICE; } };
|
||||
struct EXITING_FSM_STATE : public state<> { static string Name() { return "EXITING"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::EXITING; } };
|
||||
|
||||
// list of FSM events
|
||||
struct INIT_DEVICE_FSM_EVENT { static string Name() { return "INIT_DEVICE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::INIT_DEVICE; } };
|
||||
struct internal_DEVICE_READY_FSM_EVENT { static string Name() { return "internal_DEVICE_READY"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_DEVICE_READY; } };
|
||||
struct INIT_TASK_FSM_EVENT { static string Name() { return "INIT_TASK"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::INIT_TASK; } };
|
||||
struct internal_READY_FSM_EVENT { static string Name() { return "internal_READY"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_READY; } };
|
||||
struct RUN_FSM_EVENT { static string Name() { return "RUN"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RUN; } };
|
||||
struct PAUSE_FSM_EVENT { static string Name() { return "PAUSE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::PAUSE; } };
|
||||
struct STOP_FSM_EVENT { static string Name() { return "STOP"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::STOP; } };
|
||||
struct RESET_TASK_FSM_EVENT { static string Name() { return "RESET_TASK"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RESET_TASK; } };
|
||||
struct RESET_DEVICE_FSM_EVENT { static string Name() { return "RESET_DEVICE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RESET_DEVICE; } };
|
||||
struct internal_IDLE_FSM_EVENT { static string Name() { return "internal_IDLE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_IDLE; } };
|
||||
struct END_FSM_EVENT { static string Name() { return "END"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::END; } };
|
||||
struct ERROR_FOUND_FSM_EVENT { static string Name() { return "ERROR_FOUND"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::ERROR_FOUND; } };
|
||||
|
||||
static array<string, 12> stateNames =
|
||||
{
|
||||
{
|
||||
"OK",
|
||||
"Error",
|
||||
"IDLE",
|
||||
"INITIALIZING_DEVICE",
|
||||
"DEVICE_READY",
|
||||
"INITIALIZING_TASK",
|
||||
"READY",
|
||||
"RUNNING",
|
||||
"PAUSED",
|
||||
"RESETTING_TASK",
|
||||
"RESETTING_DEVICE",
|
||||
"EXITING"
|
||||
}
|
||||
};
|
||||
|
||||
static array<string, 12> eventNames =
|
||||
{
|
||||
{
|
||||
"INIT_DEVICE",
|
||||
"internal_DEVICE_READY",
|
||||
"INIT_TASK",
|
||||
"internal_READY",
|
||||
"RUN",
|
||||
"PAUSE",
|
||||
"STOP",
|
||||
"RESET_TASK",
|
||||
"RESET_DEVICE",
|
||||
"internal_IDLE",
|
||||
"END",
|
||||
"ERROR_FOUND"
|
||||
}
|
||||
};
|
||||
|
||||
static map<string, int> stateNumbers =
|
||||
{
|
||||
{ "OK", FairMQStateMachine::State::OK },
|
||||
{ "Error", FairMQStateMachine::State::Error },
|
||||
{ "IDLE", FairMQStateMachine::State::IDLE },
|
||||
{ "INITIALIZING_DEVICE", FairMQStateMachine::State::INITIALIZING_DEVICE },
|
||||
{ "DEVICE_READY", FairMQStateMachine::State::DEVICE_READY },
|
||||
{ "INITIALIZING_TASK", FairMQStateMachine::State::INITIALIZING_TASK },
|
||||
{ "READY", FairMQStateMachine::State::READY },
|
||||
{ "RUNNING", FairMQStateMachine::State::RUNNING },
|
||||
{ "PAUSED", FairMQStateMachine::State::PAUSED },
|
||||
{ "RESETTING_TASK", FairMQStateMachine::State::RESETTING_TASK },
|
||||
{ "RESETTING_DEVICE", FairMQStateMachine::State::RESETTING_DEVICE },
|
||||
{ "EXITING", FairMQStateMachine::State::EXITING }
|
||||
};
|
||||
|
||||
static map<string, int> eventNumbers =
|
||||
{
|
||||
{ "INIT_DEVICE", FairMQStateMachine::Event::INIT_DEVICE },
|
||||
{ "internal_DEVICE_READY", FairMQStateMachine::Event::internal_DEVICE_READY },
|
||||
{ "INIT_TASK", FairMQStateMachine::Event::INIT_TASK },
|
||||
{ "internal_READY", FairMQStateMachine::Event::internal_READY },
|
||||
{ "RUN", FairMQStateMachine::Event::RUN },
|
||||
{ "PAUSE", FairMQStateMachine::Event::PAUSE },
|
||||
{ "STOP", FairMQStateMachine::Event::STOP },
|
||||
{ "RESET_TASK", FairMQStateMachine::Event::RESET_TASK },
|
||||
{ "RESET_DEVICE", FairMQStateMachine::Event::RESET_DEVICE },
|
||||
{ "internal_IDLE", FairMQStateMachine::Event::internal_IDLE },
|
||||
{ "END", FairMQStateMachine::Event::END },
|
||||
{ "ERROR_FOUND", FairMQStateMachine::Event::ERROR_FOUND }
|
||||
};
|
||||
|
||||
// defining the boost MSM state machine
|
||||
struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
struct Machine_ : public state_machine_def<Machine_>
|
||||
{
|
||||
public:
|
||||
Machine_()
|
||||
: fWork()
|
||||
: fUnblockHandler()
|
||||
, fStateHandlers()
|
||||
, fWork()
|
||||
, fWorkAvailableCondition()
|
||||
, fWorkDoneCondition()
|
||||
, fWorkMutex()
|
||||
@@ -81,23 +165,22 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
, fWorkAvailable(false)
|
||||
, fStateChangeSignal()
|
||||
, fStateChangeSignalsMap()
|
||||
, fTerminationRequested(false)
|
||||
, fState()
|
||||
, fWorkerThread()
|
||||
{}
|
||||
|
||||
virtual ~Machine_()
|
||||
{}
|
||||
|
||||
// initial states
|
||||
using initial_state = boost::mpl::vector<IDLE_FSM_STATE, OK_FSM_STATE>;
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
void on_entry(Event const&, FSM& fsm)
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine";
|
||||
fState = FairMQStateMachine::IDLE;
|
||||
LOG(state) << "Entering IDLE state";
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::IDLE);
|
||||
|
||||
// start a worker thread to execute user states in.
|
||||
fsm.fWorkerThread = thread(&Machine_::Worker, &fsm);
|
||||
}
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
@@ -106,41 +189,23 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
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
|
||||
struct AutomaticFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
LOG(state) << "Entering IDLE state";
|
||||
fsm.fState = FairMQStateMachine::IDLE;
|
||||
fsm.fState = ts.Type();
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct InitDeviceFct
|
||||
struct DefaultFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::INITIALIZING_DEVICE;
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
@@ -148,66 +213,8 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
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;
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.fWork = fsm.fStateHandlers.at(e.Type());
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
@@ -215,9 +222,9 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
struct PauseFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::PAUSED;
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
@@ -226,37 +233,18 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering PAUSED state";
|
||||
LOG(state) << "Entering " << ts.Name() << " 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&)
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::READY;
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
@@ -264,115 +252,70 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
LOG(state) << "Entering READY state";
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalStopFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = FairMQStateMachine::READY;
|
||||
fsm.fState = ts.Type();
|
||||
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();
|
||||
LOG(state) << "RUNNING state finished without an external event, entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct ExitingFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
LOG(state) << "Entering EXITING state";
|
||||
fsm.fState = FairMQStateMachine::EXITING;
|
||||
fsm.fTerminationRequested = true;
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.fState = ts.Type();
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::EXITING);
|
||||
|
||||
// terminate worker thread
|
||||
// Stop ProcessWork()
|
||||
{
|
||||
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();
|
||||
fsm.fStateHandlers.at(e.Type())();
|
||||
}
|
||||
};
|
||||
|
||||
struct ErrorFoundFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
LOG(state) << "Entering ERROR state";
|
||||
fsm.fState = FairMQStateMachine::Error;
|
||||
fsm.fState = ts.Type();
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
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>>
|
||||
// Start Event Next Action Guard
|
||||
Row<IDLE_FSM_STATE, INIT_DEVICE_FSM_EVENT, INITIALIZING_DEVICE_FSM_STATE, DefaultFct, none>,
|
||||
Row<IDLE_FSM_STATE, END_FSM_EVENT, EXITING_FSM_STATE, ExitingFct, none>,
|
||||
Row<INITIALIZING_DEVICE_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<DEVICE_READY_FSM_STATE, INIT_TASK_FSM_EVENT, INITIALIZING_TASK_FSM_STATE, DefaultFct, none>,
|
||||
Row<DEVICE_READY_FSM_STATE, RESET_DEVICE_FSM_EVENT, RESETTING_DEVICE_FSM_STATE, DefaultFct, none>,
|
||||
Row<INITIALIZING_TASK_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<READY_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
|
||||
Row<READY_FSM_STATE, RESET_TASK_FSM_EVENT, RESETTING_TASK_FSM_STATE, DefaultFct, none>,
|
||||
Row<RUNNING_FSM_STATE, PAUSE_FSM_EVENT, PAUSED_FSM_STATE, DefaultFct, none>,
|
||||
Row<RUNNING_FSM_STATE, STOP_FSM_EVENT, READY_FSM_STATE, StopFct, none>,
|
||||
Row<RUNNING_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, InternalStopFct, none>,
|
||||
Row<PAUSED_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
|
||||
Row<RESETTING_TASK_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<RESETTING_DEVICE_FSM_STATE, internal_IDLE_FSM_EVENT, IDLE_FSM_STATE, AutomaticFct, none>,
|
||||
Row<OK_FSM_STATE, ERROR_FOUND_FSM_EVENT, ERROR_FSM_STATE, ErrorFoundFct, none>>
|
||||
{};
|
||||
|
||||
// replaces the default no-transition response.
|
||||
@@ -391,45 +334,12 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
if (pos != string::npos)
|
||||
{
|
||||
stateName = stateName.substr(pos + 1);
|
||||
stateName = stateName.substr(0, stateName.size() - 4);
|
||||
stateName = stateName.substr(0, stateName.size() - 10);
|
||||
}
|
||||
|
||||
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...";
|
||||
LOG(state) << "No transition from state " << stateName << " on event " << e.Name();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,14 +351,8 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
unordered_map<FairMQStateMachine::Event, function<void(void)>> fStateHandlers;
|
||||
|
||||
// function to execute user states in a worker thread
|
||||
function<void(void)> fWork;
|
||||
@@ -461,12 +365,10 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
|
||||
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()
|
||||
void ProcessWork()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
@@ -475,7 +377,7 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
// Wait for work to be done.
|
||||
while (!fWorkAvailable && !fWorkerTerminated)
|
||||
{
|
||||
fWorkAvailableCondition.wait(lock);
|
||||
fWorkAvailableCondition.wait_for(lock, chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
if (fWorkerTerminated)
|
||||
@@ -497,20 +399,10 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
|
||||
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
|
||||
@@ -521,13 +413,13 @@ 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)->fStateHandlers.emplace(INIT_DEVICE, bind(&FairMQStateMachine::InitWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(INIT_TASK, bind(&FairMQStateMachine::InitTaskWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RUN, bind(&FairMQStateMachine::RunWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(PAUSE, bind(&FairMQStateMachine::PauseWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_TASK, bind(&FairMQStateMachine::ResetTaskWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_DEVICE, bind(&FairMQStateMachine::ResetWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(END, bind(&FairMQStateMachine::Exit, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fUnblockHandler = bind(&FairMQStateMachine::Unblock, this);
|
||||
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->start();
|
||||
@@ -552,79 +444,79 @@ bool FairMQStateMachine::ChangeState(int event)
|
||||
case INIT_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_DEVICE_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_DEVICE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_DEVICE_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_DEVICE_READY_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_DEVICE_READY_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case INIT_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_TASK_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_TASK_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_READY_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_READY_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RUN:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RUN_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RUN_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case PAUSE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(PAUSE_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(PAUSE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case STOP:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(STOP_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(STOP_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_DEVICE_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_DEVICE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RESET_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_TASK_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_TASK_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_IDLE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_IDLE_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_IDLE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case END:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(END_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(END_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case ERROR_FOUND:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(ERROR_FOUND_E());
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(ERROR_FOUND_FSM_EVENT());
|
||||
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";
|
||||
<< "Supported are: INIT_DEVICE, INIT_TASK, RUN, PAUSE, STOP, RESET_TASK, RESET_DEVICE, END, ERROR_FOUND";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -738,7 +630,11 @@ void FairMQStateMachine::CallStateChangeCallbacks(const State state) const
|
||||
|
||||
string FairMQStateMachine::GetCurrentStateName() const
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState);
|
||||
return GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState);
|
||||
}
|
||||
string FairMQStateMachine::GetStateName(const State state)
|
||||
{
|
||||
return stateNames.at(state);
|
||||
}
|
||||
int FairMQStateMachine::GetCurrentState() const
|
||||
{
|
||||
@@ -748,28 +644,28 @@ bool FairMQStateMachine::CheckCurrentState(int state) const
|
||||
{
|
||||
return state == static_pointer_cast<FairMQFSM>(fFsm)->fState;
|
||||
}
|
||||
bool FairMQStateMachine::CheckCurrentState(string state) const
|
||||
bool FairMQStateMachine::CheckCurrentState(const string& state) const
|
||||
{
|
||||
return state == GetCurrentStateName();
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::Terminated()
|
||||
void FairMQStateMachine::ProcessWork()
|
||||
try
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->fTerminationRequested;
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->ProcessWork();
|
||||
} catch(...) {
|
||||
{
|
||||
lock_guard<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive = false;
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable = false;
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.notify_one();
|
||||
}
|
||||
ChangeState(ERROR_FOUND);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
return eventNumbers.at(event);
|
||||
}
|
||||
|
@@ -79,10 +79,10 @@ class FairMQStateMachine
|
||||
void CallStateChangeCallbacks(const State state) const;
|
||||
|
||||
std::string GetCurrentStateName() const;
|
||||
static std::string GetStateName(const State);
|
||||
int GetCurrentState() const;
|
||||
bool CheckCurrentState(int state) const;
|
||||
bool CheckCurrentState(std::string state) const;
|
||||
bool Terminated();
|
||||
bool CheckCurrentState(const std::string& state) const;
|
||||
|
||||
// actions to be overwritten by derived classes
|
||||
virtual void InitWrapper() {}
|
||||
@@ -94,8 +94,10 @@ class FairMQStateMachine
|
||||
virtual void Exit() {}
|
||||
virtual void Unblock() {}
|
||||
|
||||
void ProcessWork();
|
||||
|
||||
private:
|
||||
int GetEventNumber(const std::string& event);
|
||||
static int GetEventNumber(const std::string& event);
|
||||
|
||||
std::mutex fChangeStateMutex;
|
||||
|
||||
|
@@ -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::shared_ptr<fair::mq::Plugin> \
|
||||
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::unique_ptr<fair::mq::Plugin> \
|
||||
{ \
|
||||
return std::make_shared<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
|
||||
return fair::mq::tools::make_unique<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)
|
||||
|
@@ -31,13 +31,55 @@ const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
|
||||
fair::mq::PluginManager::PluginManager()
|
||||
: fSearchPaths{{"."}}
|
||||
, fPluginFactories()
|
||||
, fPluginServices()
|
||||
, fPlugins()
|
||||
, fPluginOrder()
|
||||
, fPluginProgOptions()
|
||||
, fPluginServices()
|
||||
{
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
if (path.empty()) throw BadSearchPath{"Specified path is empty."};
|
||||
@@ -81,46 +123,6 @@ 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:")
|
||||
|
@@ -47,9 +47,15 @@ namespace mq
|
||||
class PluginManager
|
||||
{
|
||||
public:
|
||||
using PluginFactory = std::shared_ptr<fair::mq::Plugin>(PluginServices&);
|
||||
using PluginFactory = std::unique_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;
|
||||
@@ -64,7 +70,6 @@ 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; }
|
||||
@@ -111,10 +116,10 @@ class PluginManager
|
||||
static const std::string fgkLibPrefix;
|
||||
std::vector<boost::filesystem::path> fSearchPaths;
|
||||
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
|
||||
std::map<std::string, std::shared_ptr<Plugin>> fPlugins;
|
||||
std::unique_ptr<PluginServices> fPluginServices;
|
||||
std::map<std::string, std::unique_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 */
|
||||
|
@@ -98,7 +98,7 @@ auto PluginServices::ChangeDeviceState(const std::string& controller, const Devi
|
||||
|
||||
if (fDeviceController == controller)
|
||||
{
|
||||
fDevice->ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -21,6 +21,7 @@
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -38,15 +39,20 @@ class PluginServices
|
||||
{
|
||||
public:
|
||||
PluginServices() = delete;
|
||||
PluginServices(FairMQProgOptions* config, std::shared_ptr<FairMQDevice> device)
|
||||
: fConfig{config}
|
||||
, fDevice{device}
|
||||
PluginServices(FairMQProgOptions& config, 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;
|
||||
|
||||
@@ -109,7 +115,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<FairMQDevice::State>(fDevice->GetCurrentState())); }
|
||||
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<FairMQDevice::State>(fDevice.GetCurrentState())); }
|
||||
|
||||
/// @brief Become device controller
|
||||
/// @param controller id
|
||||
@@ -155,19 +161,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](FairMQDevice::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
|
||||
@@ -182,7 +188,7 @@ class PluginServices
|
||||
auto currentState = GetCurrentDeviceState();
|
||||
if (currentState == DeviceState::InitializingDevice)
|
||||
{
|
||||
fConfig->SetValue(key, val);
|
||||
fConfig.SetValue(key, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -200,7 +206,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));
|
||||
}
|
||||
@@ -212,16 +218,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
|
||||
@@ -231,13 +237,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
|
||||
@@ -246,12 +252,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(); }
|
||||
@@ -266,8 +272,8 @@ class PluginServices
|
||||
static const std::unordered_map<DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
|
||||
|
||||
private:
|
||||
FairMQProgOptions* fConfig; // TODO make it a shared pointer, once old AliceO2 code is cleaned up
|
||||
std::shared_ptr<FairMQDevice> fDevice;
|
||||
FairMQProgOptions& fConfig;
|
||||
FairMQDevice& fDevice;
|
||||
boost::optional<std::string> fDeviceController;
|
||||
mutable std::mutex fDeviceControllerMutex;
|
||||
std::condition_variable fReleaseDeviceControlCondition;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -13,6 +13,7 @@
|
||||
#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>
|
||||
|
@@ -9,11 +9,19 @@
|
||||
#ifndef FAIR_MQ_VERSION_H
|
||||
|
||||
#define FAIRMQ_VERSION "@PROJECT_VERSION@"
|
||||
#define FAIRMQ_VERSION_DEC (@PROJECT_VERSION_MAJOR@ * 10000) + (@PROJECT_VERSION_MINOR@ * 100) + @PROJECT_VERSION_PATCH@
|
||||
#define FAIRMQ_VERSION_DEC (@PROJECT_VERSION_MAJOR@ * 100000) \
|
||||
+ (@PROJECT_VERSION_MINOR@ * 1000) \
|
||||
+ (@PROJECT_VERSION_PATCH@ * 10) \
|
||||
+ @PROJECT_VERSION_HOTFIX@
|
||||
#define FAIRMQ_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
|
||||
#define FAIRMQ_VERSION_MINOR @PROJECT_VERSION_MINOR@
|
||||
#define FAIRMQ_VERSION_PATCH @PROJECT_VERSION_PATCH@
|
||||
#define FAIRMQ_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@
|
||||
#define FAIRMQ_GIT_VERSION "@PROJECT_GIT_VERSION@"
|
||||
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
||||
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
||||
#define FAIRMQ_LICENSE "LGPL-3.0"
|
||||
#define FAIRMQ_COPYRIGHT "2012-2018 GSI"
|
||||
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||
|
||||
#endif // FAIR_MQ_VERSION_H
|
||||
|
@@ -1,36 +1,29 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQBenchmarkSampler.cpp
|
||||
*
|
||||
* @since 2013-04-23
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "FairMQBenchmarkSampler.h"
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
#include "../FairMQLogger.h"
|
||||
#include "../options/FairMQProgOptions.h"
|
||||
|
||||
#include <vector>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
FairMQBenchmarkSampler::FairMQBenchmarkSampler()
|
||||
: fSameMessage(true)
|
||||
, fMsgSize(10000)
|
||||
, fMsgCounter(0)
|
||||
, fMsgRate(1)
|
||||
, fMsgRate(0)
|
||||
, fNumIterations(0)
|
||||
, fMaxIterations(0)
|
||||
, fOutChannelName()
|
||||
, fResetMsgCounter()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -42,16 +35,11 @@ void FairMQBenchmarkSampler::InitTask()
|
||||
{
|
||||
fSameMessage = fConfig->GetValue<bool>("same-msg");
|
||||
fMsgSize = fConfig->GetValue<int>("msg-size");
|
||||
fMsgRate = fConfig->GetValue<int>("msg-rate");
|
||||
fMsgRate = fConfig->GetValue<float>("msg-rate");
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
fOutChannelName = fConfig->GetValue<string>("out-channel");
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::PreRun()
|
||||
{
|
||||
fResetMsgCounter = std::thread(&FairMQBenchmarkSampler::ResetMsgCounter, this);
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::Run()
|
||||
{
|
||||
// store the channel reference to avoid traversing the map on every loop iteration
|
||||
@@ -62,6 +50,8 @@ void FairMQBenchmarkSampler::Run()
|
||||
LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations.";
|
||||
auto tStart = chrono::high_resolution_clock::now();
|
||||
|
||||
fair::mq::tools::RateLimiter rateLimiter(fMsgRate);
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
if (fSameMessage)
|
||||
@@ -98,31 +88,13 @@ void FairMQBenchmarkSampler::Run()
|
||||
}
|
||||
}
|
||||
|
||||
--fMsgCounter;
|
||||
|
||||
while (fMsgCounter == 0)
|
||||
if (fMsgRate > 0)
|
||||
{
|
||||
this_thread::sleep_for(chrono::milliseconds(1));
|
||||
rateLimiter.maybe_sleep();
|
||||
}
|
||||
}
|
||||
|
||||
auto tEnd = chrono::high_resolution_clock::now();
|
||||
|
||||
LOG(info) << "Done " << fNumIterations << " iterations in " << chrono::duration<double, milli>(tEnd - tStart).count() << "ms.";
|
||||
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::PostRun()
|
||||
{
|
||||
fResetMsgCounter.join();
|
||||
}
|
||||
|
||||
void FairMQBenchmarkSampler::ResetMsgCounter()
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
fMsgCounter = fMsgRate / 100;
|
||||
this_thread::sleep_for(chrono::milliseconds(10));
|
||||
}
|
||||
fMsgCounter = -1;
|
||||
}
|
||||
|
@@ -1,22 +1,17 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQBenchmarkSampler.h
|
||||
*
|
||||
* @since 2013-04-23
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQBENCHMARKSAMPLER_H_
|
||||
#define FAIRMQBENCHMARKSAMPLER_H_
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
@@ -30,20 +25,14 @@ class FairMQBenchmarkSampler : public FairMQDevice
|
||||
FairMQBenchmarkSampler();
|
||||
virtual ~FairMQBenchmarkSampler();
|
||||
|
||||
void PreRun() override;
|
||||
void PostRun() override;
|
||||
|
||||
void ResetMsgCounter();
|
||||
|
||||
protected:
|
||||
bool fSameMessage;
|
||||
int fMsgSize;
|
||||
int fMsgCounter;
|
||||
int fMsgRate;
|
||||
std::atomic<int> fMsgCounter;
|
||||
float fMsgRate;
|
||||
uint64_t fNumIterations;
|
||||
uint64_t fMaxIterations;
|
||||
std::string fOutChannelName;
|
||||
std::thread fResetMsgCounter;
|
||||
|
||||
virtual void InitTask() override;
|
||||
virtual void Run() override;
|
||||
|
@@ -68,10 +68,9 @@ FairMQPollerNN::FairMQPollerNN(const unordered_map<string, vector<FairMQChannel>
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
try
|
||||
{
|
||||
int offset = 0;
|
||||
// calculate offsets and the total size of the poll item set
|
||||
for (string channel : channelList)
|
||||
{
|
||||
@@ -184,7 +183,7 @@ bool FairMQPollerNN::CheckOutput(const int index)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckInput(const string channelKey, const int index)
|
||||
bool FairMQPollerNN::CheckInput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -203,7 +202,7 @@ bool FairMQPollerNN::CheckInput(const string channelKey, const int index)
|
||||
}
|
||||
}
|
||||
|
||||
bool FairMQPollerNN::CheckOutput(const string channelKey, const int index)
|
||||
bool FairMQPollerNN::CheckOutput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@@ -44,8 +44,8 @@ class FairMQPollerNN : public FairMQPoller
|
||||
virtual void Poll(const int timeout);
|
||||
virtual bool CheckInput(const int index);
|
||||
virtual bool CheckOutput(const int index);
|
||||
virtual bool CheckInput(const std::string channelKey, const int index);
|
||||
virtual bool CheckOutput(const std::string channelKey, const int index);
|
||||
virtual bool CheckInput(const std::string& channelKey, const int index);
|
||||
virtual bool CheckOutput(const std::string& channelKey, const int index);
|
||||
|
||||
virtual ~FairMQPollerNN();
|
||||
|
||||
|
@@ -197,7 +197,6 @@ int FairMQSocketNN::SendImpl(FairMQMessagePtr& msg, const int flags, const int t
|
||||
|
||||
int FairMQSocketNN::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
{
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
FairMQMessageNN* msgPtr = static_cast<FairMQMessageNN*>(msg.get());
|
||||
@@ -205,7 +204,7 @@ int FairMQSocketNN::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const in
|
||||
while (true)
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
nbytes = nn_recv(fSocket, &ptr, NN_MSG, flags);
|
||||
int nbytes = nn_recv(fSocket, &ptr, NN_MSG, flags);
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesRx += nbytes;
|
||||
@@ -279,11 +278,9 @@ int64_t FairMQSocketNN::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fla
|
||||
}
|
||||
}
|
||||
|
||||
int64_t nbytes = -1;
|
||||
|
||||
while (true)
|
||||
{
|
||||
nbytes = nn_send(fSocket, sbuf.data(), sbuf.size(), flags);
|
||||
int64_t nbytes = nn_send(fSocket, sbuf.data(), sbuf.size(), flags);
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesTx += nbytes;
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <fairmq/Tools.h>
|
||||
#include <FairMQLogger.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <zmq.h>
|
||||
|
||||
@@ -53,7 +54,7 @@ Message::Message(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint)
|
||||
Message::Message(FairMQUnmanagedRegionPtr& /*region*/, void* /*data*/, const size_t /*size*/, void* /*hint*/)
|
||||
{
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
@@ -91,7 +92,7 @@ auto Message::Rebuild(const size_t size) -> void
|
||||
fHint = nullptr;
|
||||
}
|
||||
|
||||
auto Message::Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint) -> void
|
||||
auto Message::Rebuild(void* /*data*/, const size_t size, fairmq_free_fn* ffn, void* hint) -> void
|
||||
{
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
@@ -132,12 +133,12 @@ auto Message::SetUsedSize(const size_t size) -> bool
|
||||
}
|
||||
}
|
||||
|
||||
auto Message::Copy(const fair::mq::Message& msg) -> void
|
||||
auto Message::Copy(const fair::mq::Message& /*msg*/) -> void
|
||||
{
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
|
||||
auto Message::Copy(const fair::mq::MessagePtr& msg) -> void
|
||||
auto Message::Copy(const fair::mq::MessagePtr& /*msg*/) -> void
|
||||
{
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
|
@@ -59,9 +59,8 @@ Poller::Poller(const vector<const FairMQChannel*>& channels)
|
||||
|
||||
Poller::Poller(const unordered_map<string, vector<FairMQChannel>>& channelsMap, const vector<string>& channelList)
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
try {
|
||||
int offset = 0;
|
||||
// calculate offsets and the total size of the poll item set
|
||||
for (string channel : channelList) {
|
||||
fOffsetMap[channel] = offset;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
#include "FairMQParser.h"
|
||||
#include "FairMQLogger.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <boost/property_tree/json_parser.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "FairMQSuboptParser.h"
|
||||
|
||||
#include <boost/algorithm/string.hpp> // join/split
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <boost/uuid/uuid_generators.hpp>
|
||||
#include <boost/uuid/uuid_io.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
@@ -136,16 +139,16 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
|
||||
fair::Logger::SetConsoleSeverity(severity);
|
||||
}
|
||||
|
||||
string id;
|
||||
string idForParser;
|
||||
|
||||
// check if config-key for config parser is provided
|
||||
if (fVarMap.count("config-key"))
|
||||
{
|
||||
id = fVarMap["config-key"].as<string>();
|
||||
idForParser = fVarMap["config-key"].as<string>();
|
||||
}
|
||||
else if (fVarMap.count("id"))
|
||||
{
|
||||
id = fVarMap["id"].as<string>();
|
||||
idForParser = fVarMap["id"].as<string>();
|
||||
}
|
||||
|
||||
// check if any config parser is selected
|
||||
@@ -154,12 +157,12 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
|
||||
if (fVarMap.count("mq-config"))
|
||||
{
|
||||
LOG(debug) << "mq-config: Using default JSON parser";
|
||||
UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), id));
|
||||
UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), idForParser));
|
||||
}
|
||||
else if (fVarMap.count("channel-config"))
|
||||
{
|
||||
LOG(debug) << "channel-config: Parsing channel configuration";
|
||||
UpdateChannelMap(parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), id));
|
||||
UpdateChannelMap(parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), idForParser));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -184,6 +187,8 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
|
||||
|
||||
void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered)
|
||||
{
|
||||
fVarMap.clear();
|
||||
|
||||
// get options from cmd line and store in variable map
|
||||
// here we use command_line_parser instead of parse_command_line, to allow unregistered and positional options
|
||||
if (allowUnregistered)
|
||||
@@ -205,8 +210,7 @@ void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bo
|
||||
|
||||
void FairMQProgOptions::ParseDefaults()
|
||||
{
|
||||
vector<string> emptyArgs;
|
||||
emptyArgs.push_back("dummy");
|
||||
vector<string> emptyArgs = {"dummy", "--id", boost::uuids::to_string(boost::uuids::random_generator()())};
|
||||
|
||||
vector<const char*> argv(emptyArgs.size());
|
||||
|
||||
@@ -413,7 +417,7 @@ int FairMQProgOptions::PrintOptions()
|
||||
|
||||
for (const auto& o : fUnregisteredOptions)
|
||||
{
|
||||
LOG(WARN) << "detected unregistered option: " << o;
|
||||
LOG(debug) << "detected unregistered option: " << o;
|
||||
}
|
||||
|
||||
stringstream ss;
|
||||
@@ -423,7 +427,7 @@ int FairMQProgOptions::PrintOptions()
|
||||
{
|
||||
ss << setfill(' ') << left
|
||||
<< setw(maxLenKey) << p.first << " = "
|
||||
<< setw(maxLenValue) << p.second.value
|
||||
<< setw(maxLenValue) << p.second.value << " "
|
||||
<< setw(maxLenType) << p.second.type
|
||||
<< setw(maxLenDefault) << p.second.defaulted
|
||||
<< "\n";
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -162,6 +162,11 @@ class FairMQProgOptions
|
||||
int PrintOptions();
|
||||
int PrintOptionsRaw();
|
||||
|
||||
void AddChannel(const std::string& channelName, const FairMQChannel& channel)
|
||||
{
|
||||
fFairMQChannelMap[channelName].push_back(channel);
|
||||
}
|
||||
|
||||
private:
|
||||
struct ChannelKey
|
||||
{
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -11,18 +11,26 @@
|
||||
#include <termios.h> // for the interactive mode
|
||||
#include <poll.h> // for the interactive mode
|
||||
#include <csignal> // catching system signals
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <atomic>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace
|
||||
{
|
||||
// ugly global state, but std::signal gives us no other choice
|
||||
std::function<void(int)> gSignalHandlerClosure;
|
||||
std::atomic<sig_atomic_t> gLastSignal(0);
|
||||
std::atomic<int> gSignalCount(0);
|
||||
|
||||
extern "C" auto signal_handler(int signal) -> void
|
||||
{
|
||||
gSignalHandlerClosure(signal);
|
||||
++gSignalCount;
|
||||
gLastSignal = signal;
|
||||
|
||||
if (gSignalCount > 1)
|
||||
{
|
||||
std::abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,15 +41,27 @@ namespace mq
|
||||
namespace plugins
|
||||
{
|
||||
|
||||
Control::Control(const string name, const Plugin::Version version, const string maintainer, const string homepage, PluginServices* pluginServices)
|
||||
Control::Control(const string& name, const Plugin::Version version, const string& maintainer, const string& homepage, PluginServices* pluginServices)
|
||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||
, fControllerThread()
|
||||
, fSignalHandlerThread()
|
||||
, fEvents()
|
||||
, fEventsMutex()
|
||||
, fControllerMutex()
|
||||
, fNewEvent()
|
||||
, fDeviceTerminationRequested{false}
|
||||
, fDeviceShutdownRequested(false)
|
||||
, fDeviceHasShutdown(false)
|
||||
, fPluginShutdownRequested(false)
|
||||
{
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState)
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lock{fEventsMutex};
|
||||
fEvents.push(newState);
|
||||
}
|
||||
fNewEvent.notify_one();
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
TakeDeviceControl();
|
||||
@@ -73,7 +93,7 @@ Control::Control(const string name, const Plugin::Version version, const string
|
||||
LOG(debug) << "catch-signals: " << GetProperty<int>("catch-signals");
|
||||
if (GetProperty<int>("catch-signals") > 0)
|
||||
{
|
||||
gSignalHandlerClosure = bind(&Control::SignalHandler, this, placeholders::_1);
|
||||
fSignalHandlerThread = thread(&Control::SignalHandler, this);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
}
|
||||
@@ -93,124 +113,140 @@ auto ControlPluginProgramOptions() -> Plugin::ProgOptions
|
||||
return pluginOptions;
|
||||
}
|
||||
|
||||
auto Control::InteractiveMode() -> void
|
||||
struct terminal_config
|
||||
{
|
||||
try
|
||||
terminal_config()
|
||||
{
|
||||
RunStartupSequence();
|
||||
|
||||
char input; // hold the user console input
|
||||
pollfd cinfd[1];
|
||||
cinfd[0].fd = fileno(stdin);
|
||||
cinfd[0].events = POLLIN;
|
||||
|
||||
struct termios t;
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag &= ~ICANON; // disable canonical input
|
||||
t.c_lflag &= ~ECHO; // do not echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
|
||||
PrintInteractiveHelp();
|
||||
|
||||
bool keepRunning = true;
|
||||
|
||||
while (keepRunning)
|
||||
{
|
||||
if (poll(cinfd, 1, 500))
|
||||
{
|
||||
if (fDeviceTerminationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cin >> input;
|
||||
|
||||
switch (input)
|
||||
{
|
||||
case 'i':
|
||||
LOG(info) << "\n\n --> [i] init device\n";
|
||||
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
||||
break;
|
||||
case 'j':
|
||||
LOG(info) << "\n\n --> [j] init task\n";
|
||||
ChangeDeviceState(DeviceStateTransition::InitTask);
|
||||
break;
|
||||
case 'p':
|
||||
LOG(info) << "\n\n --> [p] pause\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Pause);
|
||||
break;
|
||||
case 'r':
|
||||
LOG(info) << "\n\n --> [r] run\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Run);
|
||||
break;
|
||||
case 's':
|
||||
LOG(info) << "\n\n --> [s] stop\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Stop);
|
||||
break;
|
||||
case 't':
|
||||
LOG(info) << "\n\n --> [t] reset task\n";
|
||||
ChangeDeviceState(DeviceStateTransition::ResetTask);
|
||||
break;
|
||||
case 'd':
|
||||
LOG(info) << "\n\n --> [d] reset device\n";
|
||||
ChangeDeviceState(DeviceStateTransition::ResetDevice);
|
||||
break;
|
||||
case 'k':
|
||||
LOG(info) << "\n\n --> [k] increase log severity\n";
|
||||
CycleLogConsoleSeverityUp();
|
||||
break;
|
||||
case 'l':
|
||||
LOG(info) << "\n\n --> [l] decrease log severity\n";
|
||||
CycleLogConsoleSeverityDown();
|
||||
break;
|
||||
case 'n':
|
||||
LOG(info) << "\n\n --> [n] increase log verbosity\n";
|
||||
CycleLogVerbosityUp();
|
||||
break;
|
||||
case 'm':
|
||||
LOG(info) << "\n\n --> [m] decrease log verbosity\n";
|
||||
CycleLogVerbosityDown();
|
||||
break;
|
||||
case 'h':
|
||||
LOG(info) << "\n\n --> [h] help\n";
|
||||
PrintInteractiveHelp();
|
||||
break;
|
||||
// case 'x':
|
||||
// LOG(info) << "\n\n --> [x] ERROR\n";
|
||||
// ChangeDeviceState(DeviceStateTransition::ERROR_FOUND);
|
||||
// break;
|
||||
case 'q':
|
||||
LOG(info) << "\n\n --> [q] end\n";
|
||||
keepRunning = false;
|
||||
break;
|
||||
default:
|
||||
LOG(info) << "Invalid input: [" << input << "]";
|
||||
PrintInteractiveHelp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fDeviceTerminationRequested)
|
||||
{
|
||||
keepRunning = false;
|
||||
}
|
||||
}
|
||||
|
||||
~terminal_config()
|
||||
{
|
||||
termios t;
|
||||
tcgetattr(STDIN_FILENO, &t); // get the current terminal I/O structure
|
||||
t.c_lflag |= ICANON; // re-enable canonical input
|
||||
t.c_lflag |= ECHO; // echo input chars
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
}
|
||||
};
|
||||
|
||||
if (!fDeviceTerminationRequested)
|
||||
auto Control::InteractiveMode() -> void
|
||||
try
|
||||
{
|
||||
RunStartupSequence();
|
||||
|
||||
char input; // hold the user console input
|
||||
pollfd cinfd[1];
|
||||
cinfd[0].fd = fileno(stdin);
|
||||
cinfd[0].events = POLLIN;
|
||||
cinfd[0].revents = 0;
|
||||
|
||||
terminal_config tconfig;
|
||||
|
||||
PrintInteractiveHelp();
|
||||
|
||||
bool keepRunning = true;
|
||||
|
||||
while (keepRunning)
|
||||
{
|
||||
if (poll(cinfd, 1, 500))
|
||||
{
|
||||
RunShutdownSequence();
|
||||
if (fDeviceShutdownRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
cin >> input;
|
||||
|
||||
switch (input)
|
||||
{
|
||||
case 'i':
|
||||
LOG(info) << "\n\n --> [i] init device\n";
|
||||
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
||||
break;
|
||||
case 'j':
|
||||
LOG(info) << "\n\n --> [j] init task\n";
|
||||
ChangeDeviceState(DeviceStateTransition::InitTask);
|
||||
break;
|
||||
case 'p':
|
||||
LOG(info) << "\n\n --> [p] pause\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Pause);
|
||||
break;
|
||||
case 'r':
|
||||
LOG(info) << "\n\n --> [r] run\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Run);
|
||||
break;
|
||||
case 's':
|
||||
LOG(info) << "\n\n --> [s] stop\n";
|
||||
ChangeDeviceState(DeviceStateTransition::Stop);
|
||||
break;
|
||||
case 't':
|
||||
LOG(info) << "\n\n --> [t] reset task\n";
|
||||
ChangeDeviceState(DeviceStateTransition::ResetTask);
|
||||
break;
|
||||
case 'd':
|
||||
LOG(info) << "\n\n --> [d] reset device\n";
|
||||
ChangeDeviceState(DeviceStateTransition::ResetDevice);
|
||||
break;
|
||||
case 'k':
|
||||
LOG(info) << "\n\n --> [k] increase log severity\n";
|
||||
CycleLogConsoleSeverityUp();
|
||||
break;
|
||||
case 'l':
|
||||
LOG(info) << "\n\n --> [l] decrease log severity\n";
|
||||
CycleLogConsoleSeverityDown();
|
||||
break;
|
||||
case 'n':
|
||||
LOG(info) << "\n\n --> [n] increase log verbosity\n";
|
||||
CycleLogVerbosityUp();
|
||||
break;
|
||||
case 'm':
|
||||
LOG(info) << "\n\n --> [m] decrease log verbosity\n";
|
||||
CycleLogVerbosityDown();
|
||||
break;
|
||||
case 'h':
|
||||
LOG(info) << "\n\n --> [h] help\n";
|
||||
PrintInteractiveHelp();
|
||||
break;
|
||||
// case 'x':
|
||||
// LOG(info) << "\n\n --> [x] ERROR\n";
|
||||
// ChangeDeviceState(DeviceStateTransition::ERROR_FOUND);
|
||||
// break;
|
||||
case 'q':
|
||||
LOG(info) << "\n\n --> [q] end\n";
|
||||
keepRunning = false;
|
||||
break;
|
||||
default:
|
||||
LOG(info) << "Invalid input: [" << input << "]";
|
||||
PrintInteractiveHelp();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (GetCurrentDeviceState() == DeviceState::Error)
|
||||
{
|
||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||
}
|
||||
|
||||
if (fDeviceShutdownRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (PluginServices::DeviceControlError& e)
|
||||
{
|
||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||
LOG(debug) << e.what();
|
||||
}
|
||||
|
||||
RunShutdownSequence();
|
||||
}
|
||||
catch (PluginServices::DeviceControlError& e)
|
||||
{
|
||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||
LOG(debug) << e.what();
|
||||
}
|
||||
catch (DeviceErrorState&)
|
||||
{
|
||||
}
|
||||
|
||||
auto Control::PrintInteractiveHelp() -> void
|
||||
@@ -227,70 +263,88 @@ auto Control::WaitForNextState() -> DeviceState
|
||||
unique_lock<mutex> lock{fEventsMutex};
|
||||
while (fEvents.empty())
|
||||
{
|
||||
fNewEvent.wait(lock);
|
||||
fNewEvent.wait_for(lock, chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
auto result = fEvents.front();
|
||||
|
||||
if (result == DeviceState::Error)
|
||||
{
|
||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||
}
|
||||
|
||||
fEvents.pop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto Control::StaticMode() -> void
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
RunStartupSequence();
|
||||
RunStartupSequence();
|
||||
|
||||
{
|
||||
// Wait for next state, which is DeviceState::Ready,
|
||||
// or for device shutdown request (Ctrl-C)
|
||||
unique_lock<mutex> lock{fEventsMutex};
|
||||
while (fEvents.empty() && !fDeviceShutdownRequested)
|
||||
{
|
||||
// Wait for next state, which is DeviceState::Ready,
|
||||
// or for device termination request
|
||||
unique_lock<mutex> lock{fEventsMutex};
|
||||
while (fEvents.empty() && !fDeviceTerminationRequested)
|
||||
{
|
||||
fNewEvent.wait(lock);
|
||||
}
|
||||
fNewEvent.wait_for(lock, chrono::milliseconds(50));
|
||||
}
|
||||
|
||||
if (!fDeviceTerminationRequested)
|
||||
if (fEvents.front() == DeviceState::Error)
|
||||
{
|
||||
RunShutdownSequence();
|
||||
throw DeviceErrorState("Controlled device transitioned to error state.");
|
||||
}
|
||||
}
|
||||
catch (PluginServices::DeviceControlError& e)
|
||||
{
|
||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||
LOG(debug) << e.what();
|
||||
}
|
||||
|
||||
RunShutdownSequence();
|
||||
}
|
||||
catch (PluginServices::DeviceControlError& e)
|
||||
{
|
||||
// If we are here, it means another plugin has taken control. That's fine, just print the exception message and do nothing else.
|
||||
LOG(debug) << e.what();
|
||||
}
|
||||
catch (DeviceErrorState&)
|
||||
{
|
||||
}
|
||||
|
||||
auto Control::SignalHandler(int signal) -> void
|
||||
auto Control::SignalHandler() -> void
|
||||
{
|
||||
if (!fDeviceTerminationRequested)
|
||||
while (gSignalCount == 0 && !fPluginShutdownRequested)
|
||||
{
|
||||
fDeviceTerminationRequested = true;
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
StealDeviceControl();
|
||||
|
||||
LOG(info) << "Received device shutdown request (signal " << signal << ").";
|
||||
if (!fPluginShutdownRequested)
|
||||
{
|
||||
LOG(info) << "Received device shutdown request (signal " << gLastSignal << ").";
|
||||
LOG(info) << "Waiting for graceful device shutdown. Hit Ctrl-C again to abort immediately.";
|
||||
|
||||
UnsubscribeFromDeviceStateChange(); // In case, static or interactive mode have subscribed already
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState)
|
||||
// Signal and wait for controller thread, if we are controller
|
||||
fDeviceShutdownRequested = true;
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lock{fEventsMutex};
|
||||
fEvents.push(newState);
|
||||
}
|
||||
fNewEvent.notify_one();
|
||||
});
|
||||
unique_lock<mutex> lock(fControllerMutex);
|
||||
if (fControllerThread.joinable()) fControllerThread.join();
|
||||
}
|
||||
|
||||
fSignalHandlerThread = thread(&Control::RunShutdownSequence, this);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(warn) << "Received 2nd device shutdown request (signal " << signal << ").";
|
||||
LOG(warn) << "Aborting immediately !";
|
||||
abort();
|
||||
if (!fDeviceHasShutdown)
|
||||
{
|
||||
// Take over control and attempt graceful shutdown
|
||||
StealDeviceControl();
|
||||
try
|
||||
{
|
||||
RunShutdownSequence();
|
||||
}
|
||||
catch (PluginServices::DeviceControlError& e)
|
||||
{
|
||||
LOG(info) << "Graceful device shutdown failed: " << e.what() << " If hanging, hit Ctrl-C again to abort immediately.";
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(info) << "Graceful device shutdown failed. If hanging, hit Ctrl-C again to abort immediately.";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -298,7 +352,7 @@ auto Control::RunShutdownSequence() -> void
|
||||
{
|
||||
auto nextState = GetCurrentDeviceState();
|
||||
EmptyEventQueue();
|
||||
while (nextState != DeviceState::Exiting)
|
||||
while (nextState != DeviceState::Exiting && nextState != DeviceState::Error)
|
||||
{
|
||||
switch (nextState)
|
||||
{
|
||||
@@ -318,27 +372,19 @@ auto Control::RunShutdownSequence() -> void
|
||||
ChangeDeviceState(DeviceStateTransition::Resume);
|
||||
break;
|
||||
default:
|
||||
LOG(debug) << "Controller ignoring event: " << nextState;
|
||||
break;
|
||||
}
|
||||
|
||||
nextState = WaitForNextState();
|
||||
}
|
||||
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
fDeviceHasShutdown = true;
|
||||
ReleaseDeviceControl();
|
||||
}
|
||||
|
||||
auto Control::RunStartupSequence() -> void
|
||||
{
|
||||
SubscribeToDeviceStateChange([&](DeviceState newState)
|
||||
{
|
||||
{
|
||||
lock_guard<mutex> lock{fEventsMutex};
|
||||
fEvents.push(newState);
|
||||
}
|
||||
fNewEvent.notify_one();
|
||||
});
|
||||
|
||||
ChangeDeviceState(DeviceStateTransition::InitDevice);
|
||||
while (WaitForNextState() != DeviceState::DeviceReady) {}
|
||||
ChangeDeviceState(DeviceStateTransition::InitTask);
|
||||
@@ -355,8 +401,16 @@ auto Control::EmptyEventQueue() -> void
|
||||
|
||||
Control::~Control()
|
||||
{
|
||||
if (fControllerThread.joinable()) fControllerThread.join();
|
||||
// Notify threads to exit
|
||||
fPluginShutdownRequested = true;
|
||||
|
||||
{
|
||||
unique_lock<mutex> lock(fControllerMutex);
|
||||
if (fControllerThread.joinable()) fControllerThread.join();
|
||||
}
|
||||
if (fSignalHandlerThread.joinable()) fSignalHandlerThread.join();
|
||||
|
||||
UnsubscribeFromDeviceStateChange();
|
||||
}
|
||||
|
||||
} /* namespace plugins */
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#define FAIR_MQ_PLUGINS_CONTROL
|
||||
|
||||
#include <fairmq/Plugin.h>
|
||||
#include <fairmq/Version.h>
|
||||
|
||||
#include <condition_variable>
|
||||
#include <mutex>
|
||||
@@ -17,6 +18,7 @@
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -28,16 +30,16 @@ namespace plugins
|
||||
class Control : public Plugin
|
||||
{
|
||||
public:
|
||||
Control(const std::string name, const Plugin::Version version, const std::string maintainer, const std::string homepage, PluginServices* pluginServices);
|
||||
Control(const std::string& name, const Plugin::Version version, const std::string& maintainer, const std::string& homepage, PluginServices* pluginServices);
|
||||
|
||||
~Control();
|
||||
|
||||
private:
|
||||
auto InteractiveMode() -> void;
|
||||
auto PrintInteractiveHelp() -> void;
|
||||
static auto PrintInteractiveHelp() -> void;
|
||||
auto StaticMode() -> void;
|
||||
auto WaitForNextState() -> DeviceState;
|
||||
auto SignalHandler(int signal) -> void;
|
||||
auto SignalHandler() -> void;
|
||||
auto RunShutdownSequence() -> void;
|
||||
auto RunStartupSequence() -> void;
|
||||
auto EmptyEventQueue() -> void;
|
||||
@@ -46,20 +48,28 @@ class Control : public Plugin
|
||||
std::thread fSignalHandlerThread;
|
||||
std::queue<DeviceState> fEvents;
|
||||
std::mutex fEventsMutex;
|
||||
std::mutex fControllerMutex;
|
||||
std::condition_variable fNewEvent;
|
||||
std::atomic<bool> fDeviceTerminationRequested;
|
||||
std::atomic<bool> fDeviceShutdownRequested;
|
||||
std::atomic<bool> fDeviceHasShutdown;
|
||||
std::atomic<bool> fPluginShutdownRequested;
|
||||
|
||||
struct DeviceErrorState : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
}; /* class Control */
|
||||
|
||||
auto ControlPluginProgramOptions() -> Plugin::ProgOptions;
|
||||
|
||||
REGISTER_FAIRMQ_PLUGIN(
|
||||
Control, // Class name
|
||||
control, // Plugin name (string, lower case chars only)
|
||||
(Plugin::Version{1,0,1}), // Version
|
||||
"FairRootGroup <fairroot@gsi.de>", // Maintainer
|
||||
"https://github.com/FairRootGroup/FairRoot", // Homepage
|
||||
ControlPluginProgramOptions // Free function which declares custom program options for the plugin
|
||||
// signature: () -> boost::optional<boost::program_options::options_description>
|
||||
Control, // Class name
|
||||
control, // Plugin name (string, lower case chars only)
|
||||
(Plugin::Version{FAIRMQ_VERSION_MAJOR,
|
||||
FAIRMQ_VERSION_MINOR,
|
||||
FAIRMQ_VERSION_PATCH}), // Version
|
||||
"FairRootGroup <fairroot@gsi.de>", // Maintainer
|
||||
"https://github.com/FairRootGroup/FairRoot", // Homepage
|
||||
ControlPluginProgramOptions // Free function which declares custom program options for the
|
||||
// plugin signature: () ->
|
||||
// boost::optional<boost::program_options::options_description>
|
||||
)
|
||||
|
||||
} /* namespace plugins */
|
||||
|
@@ -31,7 +31,7 @@ namespace mq
|
||||
namespace plugins
|
||||
{
|
||||
|
||||
DDS::DDS(const string name, const Plugin::Version version, const string maintainer, const string homepage, PluginServices* pluginServices)
|
||||
DDS::DDS(const string& name, const Plugin::Version version, const string& maintainer, const string& homepage, PluginServices* pluginServices)
|
||||
: Plugin(name, version, maintainer, homepage, pluginServices)
|
||||
, fService()
|
||||
, fDDSCustomCmd(fService)
|
||||
@@ -110,12 +110,12 @@ auto DDS::HandleControl() -> void
|
||||
// and propagate addresses of bound channels to DDS.
|
||||
FillChannelContainers();
|
||||
|
||||
LOG(DEBUG) << "$DDS_TASK_PATH: " << getenv("DDS_TASK_PATH");
|
||||
LOG(DEBUG) << "$DDS_GROUP_NAME: " << getenv("DDS_GROUP_NAME");
|
||||
LOG(DEBUG) << "$DDS_COLLECTION_NAME: " << getenv("DDS_COLLECTION_NAME");
|
||||
LOG(DEBUG) << "$DDS_TASK_NAME: " << getenv("DDS_TASK_NAME");
|
||||
LOG(DEBUG) << "$DDS_TASK_INDEX: " << getenv("DDS_TASK_INDEX");
|
||||
LOG(DEBUG) << "$DDS_COLLECTION_INDEX: " << getenv("DDS_COLLECTION_INDEX");
|
||||
LOG(debug) << "$DDS_TASK_PATH: " << getenv("DDS_TASK_PATH");
|
||||
LOG(debug) << "$DDS_GROUP_NAME: " << getenv("DDS_GROUP_NAME");
|
||||
LOG(debug) << "$DDS_COLLECTION_NAME: " << getenv("DDS_COLLECTION_NAME");
|
||||
LOG(debug) << "$DDS_TASK_NAME: " << getenv("DDS_TASK_NAME");
|
||||
LOG(debug) << "$DDS_TASK_INDEX: " << getenv("DDS_TASK_INDEX");
|
||||
LOG(debug) << "$DDS_COLLECTION_INDEX: " << getenv("DDS_COLLECTION_INDEX");
|
||||
|
||||
// start DDS service - subscriptions will only start firing after this step
|
||||
fService.start();
|
||||
|
@@ -61,7 +61,7 @@ struct IofN
|
||||
class DDS : public Plugin
|
||||
{
|
||||
public:
|
||||
DDS(const std::string name, const Plugin::Version version, const std::string maintainer, const std::string homepage, PluginServices* pluginServices);
|
||||
DDS(const std::string& name, const Plugin::Version version, const std::string& maintainer, const std::string& homepage, PluginServices* pluginServices);
|
||||
|
||||
~DDS();
|
||||
|
||||
|
@@ -12,7 +12,6 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <exception>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
#include <atomic>
|
||||
#include <unistd.h>
|
||||
@@ -34,24 +33,27 @@ int main(int argc, char* argv[])
|
||||
{
|
||||
try {
|
||||
string sessionID;
|
||||
char commandChar;
|
||||
char command = ' ';
|
||||
string topologyPath;
|
||||
|
||||
bpo::options_description options("fairmq-dds-command-ui options");
|
||||
options.add_options()
|
||||
("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID")
|
||||
("command,c", bpo::value<char> (&commandChar)->default_value(' '), "Command character")
|
||||
("session,s", bpo::value<string> (&sessionID)->required(), "DDS Session ID")
|
||||
("command,c", bpo::value<char> (&command)->default_value(' '), "Command character")
|
||||
("path,p", bpo::value<string> (&topologyPath)->default_value(""), "DDS Topology path to send command to")
|
||||
("help,h", "Produce help message");
|
||||
|
||||
bpo::variables_map vm;
|
||||
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
|
||||
bpo::notify(vm);
|
||||
|
||||
if (vm.count("help")) {
|
||||
cout << "FairMQ DDS Command UI" << endl << options << endl;
|
||||
cout << "possible command characters: [c] check states, [o] dump config, [h] help, [p] pause, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device" << endl;
|
||||
cout << "Commands: [c] check state, [o] dump config, [h] help, [p] pause, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device" << endl;
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
bpo::notify(vm);
|
||||
|
||||
CIntercomService service;
|
||||
CCustomCmd ddsCustomCmd(service);
|
||||
|
||||
@@ -61,7 +63,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
// subscribe to receive messages from DDS
|
||||
ddsCustomCmd.subscribe([](const string& msg, const string& /*condition*/, uint64_t /*senderId*/) {
|
||||
cout << "Received: " << msg << endl;
|
||||
cout << "Received: " << endl << msg << endl;
|
||||
});
|
||||
|
||||
service.start(sessionID);
|
||||
@@ -74,8 +76,8 @@ int main(int argc, char* argv[])
|
||||
t.c_lflag &= ~ICANON; // disable canonical input
|
||||
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
|
||||
|
||||
if (commandChar != ' ') {
|
||||
cin.putback(commandChar);
|
||||
if (command != ' ') {
|
||||
cin.putback(command);
|
||||
} else {
|
||||
PrintControlsHelp();
|
||||
}
|
||||
@@ -84,39 +86,39 @@ int main(int argc, char* argv[])
|
||||
switch (c) {
|
||||
case 'c':
|
||||
cout << " > checking state of the devices" << endl;
|
||||
ddsCustomCmd.send("check-state", "");
|
||||
ddsCustomCmd.send("check-state", topologyPath);
|
||||
break;
|
||||
case 'o':
|
||||
cout << " > dumping config of the devices" << endl;
|
||||
ddsCustomCmd.send("dump-config", "");
|
||||
ddsCustomCmd.send("dump-config", topologyPath);
|
||||
break;
|
||||
case 'i':
|
||||
cout << " > init devices" << endl;
|
||||
ddsCustomCmd.send("INIT DEVICE", "");
|
||||
ddsCustomCmd.send("INIT DEVICE", topologyPath);
|
||||
break;
|
||||
case 'j':
|
||||
cout << " > init tasks" << endl;
|
||||
ddsCustomCmd.send("INIT TASK", "");
|
||||
ddsCustomCmd.send("INIT TASK", topologyPath);
|
||||
break;
|
||||
case 'p':
|
||||
cout << " > pause devices" << endl;
|
||||
ddsCustomCmd.send("PAUSE", "");
|
||||
ddsCustomCmd.send("PAUSE", topologyPath);
|
||||
break;
|
||||
case 'r':
|
||||
cout << " > run tasks" << endl;
|
||||
ddsCustomCmd.send("RUN", "");
|
||||
ddsCustomCmd.send("RUN", topologyPath);
|
||||
break;
|
||||
case 's':
|
||||
cout << " > stop devices" << endl;
|
||||
ddsCustomCmd.send("STOP", "");
|
||||
ddsCustomCmd.send("STOP", topologyPath);
|
||||
break;
|
||||
case 't':
|
||||
cout << " > reset tasks" << endl;
|
||||
ddsCustomCmd.send("RESET TASK", "");
|
||||
ddsCustomCmd.send("RESET TASK", topologyPath);
|
||||
break;
|
||||
case 'd':
|
||||
cout << " > reset devices" << endl;
|
||||
ddsCustomCmd.send("RESET DEVICE", "");
|
||||
ddsCustomCmd.send("RESET DEVICE", topologyPath);
|
||||
break;
|
||||
case 'h':
|
||||
cout << " > help" << endl;
|
||||
@@ -124,7 +126,7 @@ int main(int argc, char* argv[])
|
||||
break;
|
||||
case 'q':
|
||||
cout << " > end" << endl;
|
||||
ddsCustomCmd.send("END", "");
|
||||
ddsCustomCmd.send("END", topologyPath);
|
||||
break;
|
||||
default:
|
||||
cout << "Invalid input: [" << c << "]" << endl;
|
||||
@@ -132,8 +134,8 @@ int main(int argc, char* argv[])
|
||||
break;
|
||||
}
|
||||
|
||||
if (commandChar != ' ') {
|
||||
usleep(50000);
|
||||
if (command != ' ') {
|
||||
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
|
||||
("same-msg", bpo::value<bool>()->default_value(false), "Re-send the same message, or recreate for each iteration")
|
||||
("msg-size", bpo::value<int>()->default_value(1000000), "Message size in bytes")
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Number of run iterations (0 - infinite)")
|
||||
("msg-rate", bpo::value<int>()->default_value(0), "Msg rate limit in maximum number of messages per second");
|
||||
("msg-rate", bpo::value<float>()->default_value(0), "Msg rate limit in maximum number of messages per second");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
|
@@ -46,7 +46,7 @@ int main(int argc, char* argv[])
|
||||
// });
|
||||
|
||||
runner.AddHook<InstantiateDevice>([](DeviceRunner& r){
|
||||
r.fDevice = std::shared_ptr<FairMQDevice>{getDevice(r.fConfig)};
|
||||
r.fDevice = std::unique_ptr<FairMQDevice>{getDevice(r.fConfig)};
|
||||
});
|
||||
|
||||
return runner.Run();
|
||||
@@ -56,12 +56,12 @@ int main(int argc, char* argv[])
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG(error) << "Unhandled exception reached the top of main: " << e.what() << ", application will now exit";
|
||||
LOG(error) << "Uncaught exception reached the top of main: " << e.what();
|
||||
return 1;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
LOG(error) << "Non-exception instance being thrown. Please make sure you use std::runtime_exception() instead. Application will now exit.";
|
||||
LOG(error) << "Uncaught exception reached the top of main.";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
@@ -9,8 +9,13 @@
|
||||
#define FAIR_MQ_SHMEM_COMMON_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <string>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -73,6 +78,16 @@ struct RegionBlock
|
||||
size_t fHint;
|
||||
};
|
||||
|
||||
// find id for unique shmem name:
|
||||
// a hash of user id + session id, truncated to 8 characters (to accommodate for name size limit on some systems (MacOS)).
|
||||
inline std::string buildShmIdFromSessionIdAndUserId(const std::string& sessionId)
|
||||
{
|
||||
boost::hash<std::string> stringHash;
|
||||
std::string shmId(std::to_string(stringHash(std::string((std::to_string(geteuid()) + sessionId)))));
|
||||
shmId.resize(8, '_');
|
||||
return shmId;
|
||||
}
|
||||
|
||||
} // namespace shmem
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
@@ -19,8 +19,8 @@
|
||||
using namespace std;
|
||||
using namespace fair::mq::shmem;
|
||||
|
||||
namespace bipc = boost::interprocess;
|
||||
namespace bpt = boost::posix_time;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
namespace bpt = ::boost::posix_time;
|
||||
|
||||
atomic<bool> FairMQMessageSHM::fInterrupted(false);
|
||||
fair::mq::Transport FairMQMessageSHM::fTransportType = fair::mq::Transport::SHM;
|
||||
|
@@ -68,10 +68,9 @@ FairMQPollerSHM::FairMQPollerSHM(const unordered_map<string, vector<FairMQChanne
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
try
|
||||
{
|
||||
int offset = 0;
|
||||
// calculate offsets and the total size of the poll item set
|
||||
for (string channel : channelList)
|
||||
{
|
||||
@@ -189,7 +188,7 @@ bool FairMQPollerSHM::CheckOutput(const int index)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQPollerSHM::CheckInput(const string channelKey, const int index)
|
||||
bool FairMQPollerSHM::CheckInput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -208,7 +207,7 @@ bool FairMQPollerSHM::CheckInput(const string channelKey, const int index)
|
||||
}
|
||||
}
|
||||
|
||||
bool FairMQPollerSHM::CheckOutput(const string channelKey, const int index)
|
||||
bool FairMQPollerSHM::CheckOutput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@@ -37,8 +37,8 @@ class FairMQPollerSHM : public FairMQPoller
|
||||
void Poll(const int timeout) override;
|
||||
bool CheckInput(const int index) override;
|
||||
bool CheckOutput(const int index) override;
|
||||
bool CheckInput(const std::string channelKey, const int index) override;
|
||||
bool CheckOutput(const std::string channelKey, const int index) override;
|
||||
bool CheckInput(const std::string& channelKey, const int index) override;
|
||||
bool CheckOutput(const std::string& channelKey, const int index) override;
|
||||
|
||||
~FairMQPollerSHM() override;
|
||||
|
||||
|
@@ -121,12 +121,11 @@ int64_t FairMQSocketSHM::TryReceive(vector<unique_ptr<FairMQMessage>>& msgVec) {
|
||||
|
||||
int FairMQSocketSHM::SendImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
{
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
while (true && !fInterrupted)
|
||||
{
|
||||
nbytes = zmq_msg_send(static_cast<FairMQMessageSHM*>(msg.get())->GetMessage(), fSocket, flags);
|
||||
int nbytes = zmq_msg_send(static_cast<FairMQMessageSHM*>(msg.get())->GetMessage(), fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
return nbytes;
|
||||
@@ -177,13 +176,12 @@ int FairMQSocketSHM::SendImpl(FairMQMessagePtr& msg, const int flags, const int
|
||||
|
||||
int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
{
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
zmq_msg_t* msgPtr = static_cast<FairMQMessageSHM*>(msg.get())->GetMessage();
|
||||
while (true)
|
||||
{
|
||||
nbytes = zmq_msg_recv(msgPtr, fSocket, flags);
|
||||
int nbytes = zmq_msg_recv(msgPtr, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
++fMessagesRx;
|
||||
@@ -196,7 +194,7 @@ int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
|
||||
const auto numMsgs = nbytes / sizeof(MetaHeader);
|
||||
if (numMsgs > 1)
|
||||
{
|
||||
LOG(ERROR) << "Receiving SHM multipart with a single message receive call";
|
||||
LOG(error) << "Receiving SHM multipart with a single message receive call";
|
||||
}
|
||||
|
||||
assert (numMsgs == 1);
|
||||
@@ -246,157 +244,178 @@ int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int /*timeout*/)
|
||||
int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
{
|
||||
const unsigned int vecSize = msgVec.size();
|
||||
int64_t totalSize = 0;
|
||||
int elapsed = 0;
|
||||
|
||||
if (vecSize == 1) {
|
||||
return Send(msgVec.back(), flags);
|
||||
return SendImpl(msgVec.back(), flags, timeout);
|
||||
}
|
||||
|
||||
// put it into zmq message
|
||||
zmq_msg_t lZmqMsg;
|
||||
zmq_msg_init_size(&lZmqMsg, vecSize * sizeof(MetaHeader));
|
||||
zmq_msg_t zmqMsg;
|
||||
zmq_msg_init_size(&zmqMsg, vecSize * sizeof(MetaHeader));
|
||||
|
||||
// prepare the message with shm metas
|
||||
MetaHeader *lMetas = static_cast<MetaHeader*>(zmq_msg_data(&lZmqMsg));
|
||||
MetaHeader* metas = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg));
|
||||
|
||||
for (auto &lMsg : msgVec)
|
||||
for (auto& msg : msgVec)
|
||||
{
|
||||
zmq_msg_t *lMetaMsg = static_cast<FairMQMessageSHM*>(lMsg.get())->GetMessage();
|
||||
memcpy(lMetas++, zmq_msg_data(lMetaMsg), sizeof(MetaHeader));
|
||||
zmq_msg_t* metaMsg = static_cast<FairMQMessageSHM*>(msg.get())->GetMessage();
|
||||
memcpy(metas++, zmq_msg_data(metaMsg), sizeof(MetaHeader));
|
||||
}
|
||||
|
||||
while (!fInterrupted)
|
||||
{
|
||||
int nbytes = -1;
|
||||
nbytes = zmq_msg_send(&lZmqMsg, fSocket, flags);
|
||||
|
||||
int64_t totalSize = 0;
|
||||
int nbytes = zmq_msg_send(&zmqMsg, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
zmq_msg_close (&lZmqMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return nbytes;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
assert(nbytes == (vecSize * sizeof(MetaHeader))); // all or nothing
|
||||
|
||||
for (auto &lMsg : msgVec)
|
||||
for (auto& msg : msgVec)
|
||||
{
|
||||
FairMQMessageSHM *lShmMsg = static_cast<FairMQMessageSHM*>(lMsg.get());
|
||||
lShmMsg->fQueued = true;
|
||||
totalSize += lShmMsg->fSize;
|
||||
FairMQMessageSHM* shmMsg = static_cast<FairMQMessageSHM*>(msg.get());
|
||||
shmMsg->fQueued = true;
|
||||
totalSize += shmMsg->fSize;
|
||||
}
|
||||
|
||||
// store statistics on how many messages have been sent
|
||||
fMessagesTx++;
|
||||
fBytesTx += totalSize;
|
||||
|
||||
zmq_msg_close (&lZmqMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return totalSize;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
zmq_msg_close (&lZmqMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else if (zmq_errno() == ETERM)
|
||||
{
|
||||
zmq_msg_close (&lZmqMsg);
|
||||
LOG(INFO) << "terminating socket " << fId;
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(info) << "terminating socket " << fId;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
zmq_msg_close (&lZmqMsg);
|
||||
LOG(ERROR) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int /*timeout*/)
|
||||
int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
{
|
||||
int64_t totalSize = 0;
|
||||
int elapsed = 0;
|
||||
|
||||
zmq_msg_t zmqMsg;
|
||||
zmq_msg_init(&zmqMsg);
|
||||
|
||||
while (!fInterrupted)
|
||||
{
|
||||
zmq_msg_t lRcvMsg;
|
||||
zmq_msg_init(&lRcvMsg);
|
||||
int nbytes = zmq_msg_recv(&lRcvMsg, fSocket, flags);
|
||||
int64_t totalSize = 0;
|
||||
int nbytes = zmq_msg_recv(&zmqMsg, fSocket, flags);
|
||||
if (nbytes == 0)
|
||||
{
|
||||
zmq_msg_close (&lRcvMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return 0;
|
||||
}
|
||||
else if (nbytes > 0)
|
||||
{
|
||||
MetaHeader* lHdrVec = static_cast<MetaHeader*>(zmq_msg_data(&lRcvMsg));
|
||||
const auto lHdrVecSize = zmq_msg_size(&lRcvMsg);
|
||||
assert(lHdrVecSize > 0);
|
||||
assert(lHdrVecSize % sizeof(MetaHeader) == 0);
|
||||
MetaHeader* hdrVec = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg));
|
||||
const auto hdrVecSize = zmq_msg_size(&zmqMsg);
|
||||
assert(hdrVecSize > 0);
|
||||
assert(hdrVecSize % sizeof(MetaHeader) == 0);
|
||||
|
||||
const auto lNumMessages = lHdrVecSize / sizeof (MetaHeader);
|
||||
const auto numMessages = hdrVecSize / sizeof(MetaHeader);
|
||||
|
||||
msgVec.reserve(lNumMessages);
|
||||
msgVec.reserve(numMessages);
|
||||
|
||||
for (auto m = 0; m < lNumMessages; m++)
|
||||
for (size_t m = 0; m < numMessages; m++)
|
||||
{
|
||||
MetaHeader lMetaHeader;
|
||||
memcpy(&lMetaHeader, &lHdrVec[m], sizeof(MetaHeader));
|
||||
MetaHeader metaHeader;
|
||||
memcpy(&metaHeader, &hdrVec[m], sizeof(MetaHeader));
|
||||
|
||||
msgVec.emplace_back(fair::mq::tools::make_unique<FairMQMessageSHM>(fManager));
|
||||
|
||||
FairMQMessageSHM *lMsg = static_cast<FairMQMessageSHM*>(msgVec.back().get());
|
||||
MetaHeader *lMsgHdr = static_cast<MetaHeader*>(zmq_msg_data(lMsg->GetMessage()));
|
||||
FairMQMessageSHM* msg = static_cast<FairMQMessageSHM*>(msgVec.back().get());
|
||||
MetaHeader* msgHdr = static_cast<MetaHeader*>(zmq_msg_data(msg->GetMessage()));
|
||||
|
||||
memcpy(lMsgHdr, &lMetaHeader, sizeof(MetaHeader));
|
||||
memcpy(msgHdr, &metaHeader, sizeof(MetaHeader));
|
||||
|
||||
lMsg->fHandle = lMetaHeader.fHandle;
|
||||
lMsg->fSize = lMetaHeader.fSize;
|
||||
lMsg->fRegionId = lMetaHeader.fRegionId;
|
||||
lMsg->fHint = lMetaHeader.fHint;
|
||||
msg->fHandle = metaHeader.fHandle;
|
||||
msg->fSize = metaHeader.fSize;
|
||||
msg->fRegionId = metaHeader.fRegionId;
|
||||
msg->fHint = metaHeader.fHint;
|
||||
|
||||
totalSize += lMsg->GetSize();
|
||||
totalSize += msg->GetSize();
|
||||
}
|
||||
|
||||
// store statistics on how many messages have been received (handle all parts as a single message)
|
||||
fMessagesRx++;
|
||||
fBytesRx += totalSize;
|
||||
|
||||
zmq_msg_close (&lRcvMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return totalSize;
|
||||
}
|
||||
else if (zmq_errno() == EAGAIN)
|
||||
{
|
||||
zmq_msg_close(&lRcvMsg);
|
||||
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
{
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
{
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
zmq_msg_close (&lRcvMsg);
|
||||
zmq_msg_close(&zmqMsg);
|
||||
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << zmq_strerror(errno);
|
||||
return nbytes;
|
||||
}
|
||||
}
|
||||
|
||||
zmq_msg_close(&zmqMsg);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@@ -28,16 +28,16 @@
|
||||
using namespace std;
|
||||
using namespace fair::mq::shmem;
|
||||
|
||||
namespace bfs = boost::filesystem;
|
||||
namespace bpt = boost::posix_time;
|
||||
namespace bipc = boost::interprocess;
|
||||
namespace bfs = ::boost::filesystem;
|
||||
namespace bpt = ::boost::posix_time;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
|
||||
fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM;
|
||||
|
||||
FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const FairMQProgOptions* config)
|
||||
: FairMQTransportFactory(id)
|
||||
, fDeviceId(id)
|
||||
, fSessionName("default")
|
||||
, fShmId()
|
||||
, fContext(nullptr)
|
||||
, fHeartbeatThread()
|
||||
, fSendHeartbeats(true)
|
||||
@@ -58,25 +58,26 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const Fai
|
||||
}
|
||||
|
||||
int numIoThreads = 1;
|
||||
string sessionName = "default";
|
||||
size_t segmentSize = 2000000000;
|
||||
bool autolaunchMonitor = false;
|
||||
if (config)
|
||||
{
|
||||
numIoThreads = config->GetValue<int>("io-threads");
|
||||
fSessionName = config->GetValue<string>("session");
|
||||
sessionName = config->GetValue<string>("session");
|
||||
segmentSize = config->GetValue<size_t>("shm-segment-size");
|
||||
autolaunchMonitor = config->GetValue<bool>("shm-monitor");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(warn) << "FairMQProgOptions not available! Using defaults.";
|
||||
LOG(debug) << "FairMQProgOptions not available! Using defaults.";
|
||||
}
|
||||
|
||||
fSessionName.resize(8, '_'); // shorten the session name, to accommodate for name size limit on some systems (MacOS)
|
||||
fShmId = buildShmIdFromSessionIdAndUserId(sessionName);
|
||||
|
||||
try
|
||||
{
|
||||
fShMutex = fair::mq::tools::make_unique<bipc::named_mutex>(bipc::open_or_create, string("fmq_" + fSessionName + "_mtx").c_str());
|
||||
fShMutex = fair::mq::tools::make_unique<bipc::named_mutex>(bipc::open_or_create, string("fmq_" + fShmId + "_mtx").c_str());
|
||||
|
||||
if (zmq_ctx_set(fContext, ZMQ_IO_THREADS, numIoThreads) != 0)
|
||||
{
|
||||
@@ -89,8 +90,8 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const Fai
|
||||
LOG(error) << "failed configuring context, reason: " << zmq_strerror(errno);
|
||||
}
|
||||
|
||||
fManager = fair::mq::tools::make_unique<Manager>(fSessionName, segmentSize);
|
||||
LOG(debug) << "created/opened shared memory segment '" << "fmq_" << fSessionName << "_main" << "' of " << segmentSize << " bytes. Available are " << fManager->Segment().get_free_memory() << " bytes.";
|
||||
fManager = fair::mq::tools::make_unique<Manager>(fShmId, segmentSize);
|
||||
LOG(debug) << "created/opened shared memory segment '" << "fmq_" << fShmId << "_main" << "' of " << segmentSize << " bytes. Available are " << fManager->Segment().get_free_memory() << " bytes.";
|
||||
|
||||
{
|
||||
bipc::scoped_lock<bipc::named_mutex> lock(*fShMutex);
|
||||
@@ -145,8 +146,6 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const Fai
|
||||
|
||||
void FairMQTransportFactorySHM::StartMonitor()
|
||||
{
|
||||
int numTries = 0;
|
||||
|
||||
auto env = boost::this_process::environment();
|
||||
|
||||
vector<bfs::path> ownPath = boost::this_process::path();
|
||||
@@ -160,8 +159,8 @@ void FairMQTransportFactorySHM::StartMonitor()
|
||||
|
||||
if (!p.empty())
|
||||
{
|
||||
boost::process::spawn(p, "-x", "-s", fSessionName, "-d", "-t", "2000", env);
|
||||
|
||||
boost::process::spawn(p, "-x", "--shmid", fShmId, "-d", "-t", "2000", env);
|
||||
int numTries = 0;
|
||||
do
|
||||
{
|
||||
MonitorStatus* monitorStatus = fManager->ManagementSegment().find<MonitorStatus>(bipc::unique_instance).first;
|
||||
@@ -190,7 +189,7 @@ void FairMQTransportFactorySHM::StartMonitor()
|
||||
|
||||
void FairMQTransportFactorySHM::SendHeartbeats()
|
||||
{
|
||||
string controlQueueName("fmq_" + fSessionName + "_cq");
|
||||
string controlQueueName("fmq_" + fShmId + "_cq");
|
||||
while (fSendHeartbeats)
|
||||
{
|
||||
try
|
||||
@@ -312,7 +311,7 @@ FairMQTransportFactorySHM::~FairMQTransportFactorySHM()
|
||||
|
||||
if (lastRemoved)
|
||||
{
|
||||
boost::interprocess::named_mutex::remove(string("fmq_" + fSessionName + "_mtx").c_str());
|
||||
bipc::named_mutex::remove(string("fmq_" + fShmId + "_mtx").c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -60,7 +60,7 @@ class FairMQTransportFactorySHM : public FairMQTransportFactory
|
||||
|
||||
static fair::mq::Transport fTransportType;
|
||||
std::string fDeviceId;
|
||||
std::string fSessionName;
|
||||
std::string fShmId;
|
||||
void* fContext;
|
||||
std::thread fHeartbeatThread;
|
||||
std::atomic<bool> fSendHeartbeats;
|
||||
|
@@ -13,7 +13,7 @@
|
||||
using namespace std;
|
||||
using namespace fair::mq::shmem;
|
||||
|
||||
namespace bipc = boost::interprocess;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
|
||||
FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_t size, FairMQRegionCallback callback)
|
||||
: fManager(manager)
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#include <fairmq/shmem/Manager.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
|
||||
using namespace std;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
@@ -16,9 +19,6 @@ namespace mq
|
||||
namespace shmem
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
namespace bipc = boost::interprocess;
|
||||
|
||||
std::unordered_map<uint64_t, Region> Manager::fRegions;
|
||||
|
||||
Manager::Manager(const string& name, size_t size)
|
||||
@@ -105,7 +105,7 @@ void Manager::RemoveSegment()
|
||||
{
|
||||
if (bipc::shared_memory_object::remove(fSegmentName.c_str()))
|
||||
{
|
||||
LOG(debug) << "successfully removed " << fSegmentName << " segment after the device has stopped.";
|
||||
LOG(debug) << "successfully removed '" << fSegmentName << "' segment after the device has stopped.";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -26,8 +26,8 @@
|
||||
#include <poll.h>
|
||||
|
||||
using namespace std;
|
||||
namespace bipc = boost::interprocess;
|
||||
namespace bpt = boost::posix_time;
|
||||
namespace bipc = ::boost::interprocess;
|
||||
namespace bpt = ::boost::posix_time;
|
||||
|
||||
using CharAllocator = bipc::allocator<char, bipc::managed_shared_memory::segment_manager>;
|
||||
using String = bipc::basic_string<char, char_traits<char>, CharAllocator>;
|
||||
@@ -51,17 +51,17 @@ void signalHandler(int signal)
|
||||
gSignalStatus = signal;
|
||||
}
|
||||
|
||||
Monitor::Monitor(const string& sessionName, bool selfDestruct, bool interactive, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit)
|
||||
Monitor::Monitor(const string& shmId, bool selfDestruct, bool interactive, unsigned int timeoutInMS, bool runAsDaemon, bool cleanOnExit)
|
||||
: fSelfDestruct(selfDestruct)
|
||||
, fInteractive(interactive)
|
||||
, fSeenOnce(false)
|
||||
, fIsDaemon(runAsDaemon)
|
||||
, fCleanOnExit(cleanOnExit)
|
||||
, fTimeoutInMS(timeoutInMS)
|
||||
, fSessionName(sessionName)
|
||||
, fSegmentName("fmq_" + fSessionName + "_main")
|
||||
, fManagementSegmentName("fmq_" + fSessionName + "_mng")
|
||||
, fControlQueueName("fmq_" + fSessionName + "_cq")
|
||||
, fShmId(shmId)
|
||||
, fSegmentName("fmq_" + fShmId + "_main")
|
||||
, fManagementSegmentName("fmq_" + fShmId + "_mng")
|
||||
, fControlQueueName("fmq_" + fShmId + "_cq")
|
||||
, fTerminating(false)
|
||||
, fHeartbeatTriggered(false)
|
||||
, fLastHeartbeat(chrono::high_resolution_clock::now())
|
||||
@@ -201,7 +201,7 @@ void Monitor::Interactive()
|
||||
break;
|
||||
case 'x':
|
||||
cout << "\n[x] --> closing shared memory:" << endl;
|
||||
Cleanup(fSessionName);
|
||||
Cleanup(fShmId);
|
||||
break;
|
||||
case 'h':
|
||||
cout << "\n[h] --> help:" << endl << endl;
|
||||
@@ -245,11 +245,11 @@ void Monitor::Interactive()
|
||||
|
||||
void Monitor::CheckSegment()
|
||||
{
|
||||
static uint64_t counter = 0;
|
||||
char c = '#';
|
||||
|
||||
if (fInteractive)
|
||||
{
|
||||
static uint64_t counter = 0;
|
||||
int mod = counter++ % 5;
|
||||
switch (mod)
|
||||
{
|
||||
@@ -293,7 +293,7 @@ void Monitor::CheckSegment()
|
||||
if (fHeartbeatTriggered && duration > fTimeoutInMS)
|
||||
{
|
||||
cout << "no heartbeats since over " << fTimeoutInMS << " milliseconds, cleaning..." << endl;
|
||||
Cleanup(fSessionName);
|
||||
Cleanup(fShmId);
|
||||
fHeartbeatTriggered = false;
|
||||
if (fSelfDestruct)
|
||||
{
|
||||
@@ -340,7 +340,7 @@ void Monitor::CheckSegment()
|
||||
|
||||
if (fIsDaemon && duration > fTimeoutInMS * 2)
|
||||
{
|
||||
Cleanup(fSessionName);
|
||||
Cleanup(fShmId);
|
||||
fHeartbeatTriggered = false;
|
||||
if (fSelfDestruct)
|
||||
{
|
||||
@@ -360,9 +360,9 @@ void Monitor::CheckSegment()
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::Cleanup(const string& sessionName)
|
||||
void Monitor::Cleanup(const string& shmId)
|
||||
{
|
||||
string managementSegmentName("fmq_" + sessionName + "_mng");
|
||||
string managementSegmentName("fmq_" + shmId + "_mng");
|
||||
try
|
||||
{
|
||||
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
||||
@@ -373,8 +373,8 @@ void Monitor::Cleanup(const string& sessionName)
|
||||
unsigned int regionCount = rc->fCount;
|
||||
for (unsigned int i = 1; i <= regionCount; ++i)
|
||||
{
|
||||
RemoveObject("fmq_" + sessionName + "_rg_" + to_string(i));
|
||||
RemoveQueue(string("fmq_" + sessionName + "_rgq_" + to_string(i)));
|
||||
RemoveObject("fmq_" + shmId + "_rg_" + to_string(i));
|
||||
RemoveQueue(string("fmq_" + shmId + "_rgq_" + to_string(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -389,9 +389,8 @@ void Monitor::Cleanup(const string& sessionName)
|
||||
cout << "Did not find '" << managementSegmentName << "' shared memory segment. No regions to cleanup." << endl;
|
||||
}
|
||||
|
||||
RemoveObject("fmq_" + sessionName + "_main");
|
||||
|
||||
boost::interprocess::named_mutex::remove(string("fmq_" + sessionName + "_mtx").c_str());
|
||||
RemoveObject("fmq_" + shmId + "_main");
|
||||
RemoveMutex("fmq_" + shmId + "_mtx");
|
||||
|
||||
cout << endl;
|
||||
}
|
||||
@@ -420,6 +419,18 @@ void Monitor::RemoveQueue(const string& name)
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::RemoveMutex(const string& name)
|
||||
{
|
||||
if (bipc::named_mutex::remove(name.c_str()))
|
||||
{
|
||||
cout << "Successfully removed \"" << name << "\"." << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout << "Did not remove \"" << name << "\". Already removed?" << endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Monitor::PrintQueues()
|
||||
{
|
||||
cout << '\n';
|
||||
@@ -427,7 +438,7 @@ void Monitor::PrintQueues()
|
||||
try
|
||||
{
|
||||
bipc::managed_shared_memory segment(bipc::open_only, fSegmentName.c_str());
|
||||
StringVector* queues = segment.find<StringVector>(string("fmq_" + fSessionName + "_qs").c_str()).first;
|
||||
StringVector* queues = segment.find<StringVector>(string("fmq_" + fShmId + "_qs").c_str()).first;
|
||||
if (queues)
|
||||
{
|
||||
cout << "found " << queues->size() << " queue(s):" << endl;
|
||||
@@ -500,7 +511,7 @@ Monitor::~Monitor()
|
||||
}
|
||||
if (fCleanOnExit)
|
||||
{
|
||||
Cleanup(fSessionName);
|
||||
Cleanup(fShmId);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -39,6 +39,7 @@ class Monitor
|
||||
static void Cleanup(const std::string& sessionName);
|
||||
static void RemoveObject(const std::string&);
|
||||
static void RemoveQueue(const std::string&);
|
||||
static void RemoveMutex(const std::string&);
|
||||
|
||||
private:
|
||||
void PrintHeader();
|
||||
@@ -55,7 +56,7 @@ class Monitor
|
||||
bool fIsDaemon;
|
||||
bool fCleanOnExit;
|
||||
unsigned int fTimeoutInMS;
|
||||
std::string fSessionName;
|
||||
std::string fShmId;
|
||||
std::string fSegmentName;
|
||||
std::string fManagementSegmentName;
|
||||
std::string fControlQueueName;
|
||||
@@ -71,4 +72,4 @@ class Monitor
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
#endif /* FAIR_MQ_SHMEM_MONITOR_H_ */
|
||||
#endif /* FAIR_MQ_SHMEM_MONITOR_H_ */
|
||||
|
@@ -12,8 +12,9 @@ The shared memory monitor tool, supplied with the shared memory transport can be
|
||||
|
||||
With default arguments the monitor will run indefinitely with no output, and clean up shared memory segment if it is open and no heartbeats from devices arrive within a timeout period. It can be further customized with following parameters:
|
||||
|
||||
`--session <arg>`: customize the name of the shared memory segment via the session name (default is "default").
|
||||
`--session <arg>`: for which session to run the monitor (default is "default"). The actual ressource names will be built out of session id, user id (hashed and truncated).
|
||||
`--cleanup`: start monitor, perform cleanup of the memory and quit.
|
||||
`--shmid <arg>`: if provided, this shmem id will be used instead of the one generated from session id. Use this if you know the name of the shared memory ressource, but do not have the used session id.
|
||||
`--self-destruct`: run until the memory segment is closed (either naturally via cleanup performed by devices or in case of a crash (no heartbeats within timeout)).
|
||||
`--interactive`: run interactively, with detailed segment details and user input for various shmem operations.
|
||||
`--timeout <arg>`: specifiy the timeout for the heartbeats from shmem transports in milliseconds (default 5000).
|
||||
@@ -27,9 +28,9 @@ The Monitor class can also be used independently from the supplied executable (b
|
||||
|
||||
FairMQ Shared Memory currently uses following names to register shared memory on the system:
|
||||
|
||||
`fmq_<sessionName>_main` - main segment name, used for user data (session name can be overridden via `--session`).
|
||||
`fmq_<sessionName>_mng` - management segment name, used for storing management data.
|
||||
`fmq_<sessionName>_cq` - message queue for communicating between shm transport and shm monitor (exists independent of above segments).
|
||||
`fmq_<sessionName>_mtx` - boost::interprocess::named_mutex for management purposes (exists independent of above segments).
|
||||
`fmq_<sessionName>_rg_<index>` - names of unmanaged regions.
|
||||
`fmq_<sessionName>_rgq_<index>` - names of queues for the unmanaged regions.
|
||||
`fmq_<shmId>_main` - main segment name, used for user data (the shmId is generated out of session id and user id).
|
||||
`fmq_<shmId>_mng` - management segment name, used for storing management data.
|
||||
`fmq_<shmId>_cq` - message queue for communicating between shm transport and shm monitor (exists independent of above segments).
|
||||
`fmq_<shmId>_mtx` - boost::interprocess::named_mutex for management purposes (exists independent of above segments).
|
||||
`fmq_<shmId>_rg_<index>` - names of unmanaged regions.
|
||||
`fmq_<shmId>_rgq_<index>` - names of queues for the unmanaged regions.
|
||||
|
@@ -12,6 +12,11 @@
|
||||
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace bipc = ::boost::interprocess;
|
||||
namespace bpt = ::boost::posix_time;
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
@@ -19,11 +24,6 @@ namespace mq
|
||||
namespace shmem
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace bipc = boost::interprocess;
|
||||
namespace bpt = boost::posix_time;
|
||||
|
||||
Region::Region(Manager& manager, uint64_t id, uint64_t size, bool remote, FairMQRegionCallback callback)
|
||||
: fManager(manager)
|
||||
, fRemote(remote)
|
||||
|
@@ -1,76 +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" #
|
||||
################################################################################
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/fairmq/shmem/prototype/shm-prototype.json
|
||||
${CMAKE_BINARY_DIR}/bin/config/shm-prototype.json)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/fairmq/shmem/prototype/startShmPrototype.sh.in
|
||||
${CMAKE_BINARY_DIR}/bin/prototype/shmem/startShmPrototype.sh)
|
||||
|
||||
Set(INCLUDE_DIRECTORIES
|
||||
${CMAKE_SOURCE_DIR}/fairmq
|
||||
${CMAKE_SOURCE_DIR}/fairmq/zeromq
|
||||
${CMAKE_SOURCE_DIR}/fairmq/nanomsg
|
||||
${CMAKE_SOURCE_DIR}/fairmq/devices
|
||||
${CMAKE_SOURCE_DIR}/fairmq/tools
|
||||
${CMAKE_SOURCE_DIR}/fairmq/options
|
||||
${CMAKE_SOURCE_DIR}/fairmq/shmem/prototype
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
)
|
||||
|
||||
Set(SYSTEM_INCLUDE_DIRECTORIES
|
||||
${Boost_INCLUDE_DIR}
|
||||
${ZeroMQ_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
Include_Directories(${INCLUDE_DIRECTORIES})
|
||||
Include_Directories(SYSTEM ${SYSTEM_INCLUDE_DIRECTORIES})
|
||||
|
||||
Set(LINK_DIRECTORIES
|
||||
${Boost_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
Link_Directories(${LINK_DIRECTORIES})
|
||||
|
||||
Set(SRCS
|
||||
"FairMQShmPrototypeSampler.cxx"
|
||||
"FairMQShmPrototypeSink.cxx"
|
||||
)
|
||||
|
||||
Set(DEPENDENCIES
|
||||
${DEPENDENCIES}
|
||||
${Boost_INTERPROCESS_LIBRARY}
|
||||
FairMQ
|
||||
)
|
||||
|
||||
Set(LIBRARY_NAME FairMQShmPrototype)
|
||||
|
||||
GENERATE_LIBRARY()
|
||||
|
||||
Set(Exe_Names
|
||||
shm-prototype-sampler
|
||||
shm-prototype-sink
|
||||
)
|
||||
|
||||
Set(Exe_Source
|
||||
runShmPrototypeSampler.cxx
|
||||
runShmPrototypeSink.cxx
|
||||
)
|
||||
|
||||
list(LENGTH Exe_Names _length)
|
||||
math(EXPR _length ${_length}-1)
|
||||
|
||||
set(EXECUTABLE_OUTPUT_PATH "${EXECUTABLE_OUTPUT_PATH}/prototype/shmem")
|
||||
|
||||
ForEach(_file RANGE 0 ${_length})
|
||||
list(GET Exe_Names ${_file} _name)
|
||||
list(GET Exe_Source ${_file} _src)
|
||||
set(EXE_NAME ${_name})
|
||||
set(SRCS ${_src})
|
||||
set(DEPENDENCIES FairMQShmPrototype)
|
||||
GENERATE_EXECUTABLE()
|
||||
EndForEach(_file RANGE 0 ${_length})
|
@@ -1,227 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQShmPrototypeSampler.cpp
|
||||
*
|
||||
* @since 2016-04-08
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
|
||||
|
||||
#include "FairMQShmPrototypeSampler.h"
|
||||
#include "FairMQProgOptions.h"
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include "ShmChunk.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::interprocess;
|
||||
|
||||
FairMQShmPrototypeSampler::FairMQShmPrototypeSampler()
|
||||
: fMsgSize(10000)
|
||||
, fMsgCounter(0)
|
||||
, fMsgRate(1)
|
||||
, fBytesOut(0)
|
||||
, fMsgOut(0)
|
||||
, fBytesOutNew(0)
|
||||
, fMsgOutNew(0)
|
||||
{
|
||||
if (shared_memory_object::remove("FairMQSharedMemoryPrototype"))
|
||||
{
|
||||
LOG(info) << "Successfully removed shared memory upon device start.";
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(info) << "Did not remove shared memory upon device start.";
|
||||
}
|
||||
}
|
||||
|
||||
FairMQShmPrototypeSampler::~FairMQShmPrototypeSampler()
|
||||
{
|
||||
if (shared_memory_object::remove("FairMQSharedMemoryPrototype"))
|
||||
{
|
||||
LOG(info) << "Successfully removed shared memory after the device has stopped.";
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(info) << "Did not remove shared memory after the device stopped. Still in use?";
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSampler::Init()
|
||||
{
|
||||
fMsgSize = fConfig->GetValue<int>("msg-size");
|
||||
fMsgRate = fConfig->GetValue<int>("msg-rate");
|
||||
|
||||
SegmentManager::Instance().InitializeSegment("open_or_create", "FairMQSharedMemoryPrototype", 2000000000);
|
||||
LOG(info) << "Created/Opened shared memory segment of 2,000,000,000 bytes. Available are "
|
||||
<< SegmentManager::Instance().Segment()->get_free_memory() << " bytes.";
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSampler::Run()
|
||||
{
|
||||
// count sent messages (also used in creating ShmChunk container ID)
|
||||
static uint64_t numSentMsgs = 0;
|
||||
|
||||
LOG(info) << "Starting the benchmark with message size of " << fMsgSize;
|
||||
|
||||
// start rate logger and acknowledgement listener in separate threads
|
||||
thread rateLogger(&FairMQShmPrototypeSampler::Log, this, 1000);
|
||||
// thread resetMsgCounter(&FairMQShmPrototypeSampler::ResetMsgCounter, this);
|
||||
|
||||
// int charnum = 97;
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
void* ptr = nullptr;
|
||||
bipc::managed_shared_memory::handle_t handle;
|
||||
|
||||
while (!ptr)
|
||||
{
|
||||
try
|
||||
{
|
||||
ptr = SegmentManager::Instance().Segment()->allocate(fMsgSize);
|
||||
}
|
||||
catch (bipc::bad_alloc& ba)
|
||||
{
|
||||
this_thread::sleep_for(chrono::milliseconds(50));
|
||||
if (CheckCurrentState(RUNNING))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// // ShmChunk container ID
|
||||
// string chunkID = "c" + to_string(numSentMsgs);
|
||||
// // shared pointer ID
|
||||
// string ownerID = "o" + to_string(numSentMsgs);
|
||||
|
||||
// ShPtrOwner* owner = nullptr;
|
||||
|
||||
// try
|
||||
// {
|
||||
// owner = SegmentManager::Instance().Segment()->construct<ShPtrOwner>(ownerID.c_str())(
|
||||
// make_managed_shared_ptr(SegmentManager::Instance().Segment()->construct<ShmChunk>(chunkID.c_str())(fMsgSize),
|
||||
// *(SegmentManager::Instance().Segment())));
|
||||
// }
|
||||
// catch (bipc::bad_alloc& ba)
|
||||
// {
|
||||
// LOG(warn) << "Shared memory full...";
|
||||
// this_thread::sleep_for(chrono::milliseconds(100));
|
||||
// continue;
|
||||
// }
|
||||
|
||||
// void* ptr = owner->fPtr->GetData();
|
||||
|
||||
// write something to memory, otherwise only (incomplete) allocation will be measured
|
||||
// memset(ptr, 0, fMsgSize);
|
||||
|
||||
// static_cast<char*>(ptr)[3] = charnum++;
|
||||
// if (charnum == 123)
|
||||
// {
|
||||
// charnum = 97;
|
||||
// }
|
||||
|
||||
// LOG(debug) << "chunk handle: " << owner->fPtr->GetHandle();
|
||||
// LOG(debug) << "chunk size: " << owner->fPtr->GetSize();
|
||||
// LOG(debug) << "owner (" << ownerID << ") use count: " << owner->fPtr.use_count();
|
||||
|
||||
// char* cptr = static_cast<char*>(ptr);
|
||||
// LOG(debug) << "check: " << cptr[3];
|
||||
|
||||
// FairMQMessagePtr msg(NewSimpleMessage(ownerID));
|
||||
|
||||
if (ptr)
|
||||
{
|
||||
handle = SegmentManager::Instance().Segment()->get_handle_from_address(ptr);
|
||||
FairMQMessagePtr msg(NewMessage(sizeof(ExMetaHeader)));
|
||||
ExMetaHeader* metaPtr = new(msg->GetData()) ExMetaHeader();
|
||||
metaPtr->fSize = fMsgSize;
|
||||
metaPtr->fHandle = handle;
|
||||
|
||||
// LOG(info) << metaPtr->fSize;
|
||||
// LOG(info) << metaPtr->fHandle;
|
||||
// LOG(warn) << ptr;
|
||||
|
||||
if (Send(msg, "meta", 0) > 0)
|
||||
{
|
||||
fBytesOutNew += fMsgSize;
|
||||
++fMsgOutNew;
|
||||
++numSentMsgs;
|
||||
}
|
||||
else
|
||||
{
|
||||
SegmentManager::Instance().Segment()->deallocate(ptr);
|
||||
// SegmentManager::Instance().Segment()->destroy_ptr(owner);
|
||||
}
|
||||
}
|
||||
|
||||
// --fMsgCounter;
|
||||
// while (fMsgCounter == 0)
|
||||
// {
|
||||
// this_thread::sleep_for(chrono::milliseconds(1));
|
||||
// }
|
||||
}
|
||||
|
||||
LOG(info) << "Sent " << numSentMsgs << " messages, leaving RUNNING state.";
|
||||
|
||||
rateLogger.join();
|
||||
// resetMsgCounter.join();
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSampler::Log(const int intervalInMs)
|
||||
{
|
||||
chrono::time_point<chrono::high_resolution_clock> t0 = chrono::high_resolution_clock::now();
|
||||
chrono::time_point<chrono::high_resolution_clock> t1;
|
||||
unsigned long long msSinceLastLog;
|
||||
|
||||
double mbPerSecOut = 0;
|
||||
double msgPerSecOut = 0;
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
t1 = chrono::high_resolution_clock::now();
|
||||
|
||||
msSinceLastLog = chrono::duration_cast<chrono::milliseconds>(t1 - t0).count();
|
||||
|
||||
mbPerSecOut = (static_cast<double>(fBytesOutNew - fBytesOut) / (1024. * 1024.)) / static_cast<double>(msSinceLastLog) * 1000.;
|
||||
fBytesOut = fBytesOutNew;
|
||||
|
||||
msgPerSecOut = static_cast<double>(fMsgOutNew - fMsgOut) / static_cast<double>(msSinceLastLog) * 1000.;
|
||||
fMsgOut = fMsgOutNew;
|
||||
|
||||
LOG(debug) << fixed
|
||||
<< setprecision(0) << "out: " << msgPerSecOut << " msg ("
|
||||
<< setprecision(2) << mbPerSecOut << " MB)\t("
|
||||
<< SegmentManager::Instance().Segment()->get_free_memory() / (1024. * 1024.) << " MB free)";
|
||||
|
||||
t0 = t1;
|
||||
this_thread::sleep_for(chrono::milliseconds(intervalInMs));
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSampler::ResetMsgCounter()
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
fMsgCounter = fMsgRate / 100;
|
||||
this_thread::sleep_for(chrono::milliseconds(10));
|
||||
}
|
||||
}
|
@@ -1,45 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQShmPrototypeSampler.h
|
||||
*
|
||||
* @since 2016-04-08
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSHMPROTOTYPESAMPLER_H_
|
||||
#define FAIRMQSHMPROTOTYPESAMPLER_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
class FairMQShmPrototypeSampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
FairMQShmPrototypeSampler();
|
||||
virtual ~FairMQShmPrototypeSampler();
|
||||
|
||||
void Log(const int intervalInMs);
|
||||
void ResetMsgCounter();
|
||||
|
||||
protected:
|
||||
unsigned int fMsgSize;
|
||||
unsigned int fMsgCounter;
|
||||
unsigned int fMsgRate;
|
||||
|
||||
unsigned long long fBytesOut;
|
||||
unsigned long long fMsgOut;
|
||||
std::atomic<unsigned long long> fBytesOutNew;
|
||||
std::atomic<unsigned long long> fMsgOutNew;
|
||||
|
||||
virtual void Init();
|
||||
virtual void Run();
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSHMPROTOTYPESAMPLER_H_ */
|
@@ -1,145 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQShmPrototypeSink.cxx
|
||||
*
|
||||
* @since 2016-04-08
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
|
||||
|
||||
#include "FairMQShmPrototypeSink.h"
|
||||
#include "FairMQProgOptions.h"
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include "ShmChunk.h"
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::interprocess;
|
||||
|
||||
FairMQShmPrototypeSink::FairMQShmPrototypeSink()
|
||||
: fBytesIn(0)
|
||||
, fMsgIn(0)
|
||||
, fBytesInNew(0)
|
||||
, fMsgInNew(0)
|
||||
{
|
||||
}
|
||||
|
||||
FairMQShmPrototypeSink::~FairMQShmPrototypeSink()
|
||||
{
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSink::Init()
|
||||
{
|
||||
SegmentManager::Instance().InitializeSegment("open_or_create", "FairMQSharedMemoryPrototype", 2000000000);
|
||||
LOG(info) << "Created/Opened shared memory segment of 2,000,000,000 bytes. Available are "
|
||||
<< SegmentManager::Instance().Segment()->get_free_memory() << " bytes.";
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSink::Run()
|
||||
{
|
||||
static uint64_t numReceivedMsgs = 0;
|
||||
|
||||
thread rateLogger(&FairMQShmPrototypeSink::Log, this, 1000);
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
FairMQMessagePtr msg(NewMessage());
|
||||
|
||||
if (Receive(msg, "meta") > 0)
|
||||
{
|
||||
ExMetaHeader* hdr = static_cast<ExMetaHeader*>(msg->GetData());
|
||||
size_t size = hdr->fSize;
|
||||
bipc::managed_shared_memory::handle_t handle = hdr->fHandle;
|
||||
void* ptr = SegmentManager::Instance().Segment()->get_address_from_handle(handle);
|
||||
|
||||
// LOG(info) << size;
|
||||
// LOG(info) << handle;
|
||||
// LOG(warn) << ptr;
|
||||
|
||||
fBytesInNew += size;
|
||||
++fMsgInNew;
|
||||
SegmentManager::Instance().Segment()->deallocate(ptr);
|
||||
|
||||
// get the shared pointer ID from the received message
|
||||
// string ownerID(static_cast<char*>(msg->GetData()), msg->GetSize());
|
||||
|
||||
// find the shared pointer in shared memory with its ID
|
||||
// ShPtrOwner* owner = SegmentManager::Instance().Segment()->find<ShPtrOwner>(ownerID.c_str()).first;
|
||||
// LOG(debug) << "owner (" << ownerID << ") use count: " << owner->fPtr.use_count();
|
||||
|
||||
|
||||
// if (owner)
|
||||
// {
|
||||
// // void* ptr = owner->fPtr->GetData();
|
||||
|
||||
// // LOG(debug) << "chunk handle: " << owner->fPtr->GetHandle();
|
||||
// // LOG(debug) << "chunk size: " << owner->fPtr->GetSize();
|
||||
|
||||
// fBytesInNew += owner->fPtr->GetSize();
|
||||
// ++fMsgInNew;
|
||||
|
||||
// // char* cptr = static_cast<char*>(ptr);
|
||||
// // LOG(debug) << "check: " << cptr[3];
|
||||
|
||||
// SegmentManager::Instance().Segment()->deallocate(ptr);
|
||||
|
||||
// // SegmentManager::Instance().Segment()->destroy_ptr(owner);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// LOG(warn) << "Shared pointer is zero.";
|
||||
// }
|
||||
|
||||
|
||||
++numReceivedMsgs;
|
||||
}
|
||||
}
|
||||
|
||||
LOG(info) << "Received " << numReceivedMsgs << " messages, leaving RUNNING state.";
|
||||
|
||||
rateLogger.join();
|
||||
}
|
||||
|
||||
void FairMQShmPrototypeSink::Log(const int intervalInMs)
|
||||
{
|
||||
chrono::time_point<chrono::high_resolution_clock> t0 = chrono::high_resolution_clock::now();
|
||||
chrono::time_point<chrono::high_resolution_clock> t1;
|
||||
unsigned long long msSinceLastLog;
|
||||
|
||||
double mbPerSecIn = 0;
|
||||
double msgPerSecIn = 0;
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
{
|
||||
t1 = chrono::high_resolution_clock::now();
|
||||
|
||||
msSinceLastLog = chrono::duration_cast<chrono::milliseconds>(t1 - t0).count();
|
||||
|
||||
mbPerSecIn = (static_cast<double>(fBytesInNew - fBytesIn) / (1024. * 1024.)) / static_cast<double>(msSinceLastLog) * 1000.;
|
||||
fBytesIn = fBytesInNew;
|
||||
|
||||
msgPerSecIn = static_cast<double>(fMsgInNew - fMsgIn) / static_cast<double>(msSinceLastLog) * 1000.;
|
||||
fMsgIn = fMsgInNew;
|
||||
|
||||
LOG(debug) << fixed
|
||||
<< setprecision(0) << "in: " << msgPerSecIn << " msg ("
|
||||
<< setprecision(2) << mbPerSecIn << " MB)\t("
|
||||
<< SegmentManager::Instance().Segment()->get_free_memory() / (1024. * 1024.) << " MB free)";
|
||||
|
||||
t0 = t1;
|
||||
this_thread::sleep_for(chrono::milliseconds(intervalInMs));
|
||||
}
|
||||
}
|
@@ -1,40 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQShmPrototypeSink.h
|
||||
*
|
||||
* @since 2016-04-08
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSHMPROTOTYPESINK_H_
|
||||
#define FAIRMQSHMPROTOTYPESINK_H_
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
class FairMQShmPrototypeSink : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
FairMQShmPrototypeSink();
|
||||
virtual ~FairMQShmPrototypeSink();
|
||||
|
||||
void Log(const int intervalInMs);
|
||||
|
||||
protected:
|
||||
unsigned long long fBytesIn;
|
||||
unsigned long long fMsgIn;
|
||||
std::atomic<unsigned long long> fBytesInNew;
|
||||
std::atomic<unsigned long long> fMsgInNew;
|
||||
|
||||
virtual void Init();
|
||||
virtual void Run();
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSHMPROTOTYPESINK_H_ */
|
@@ -1,182 +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" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* ShmChunk.h
|
||||
*
|
||||
* @since 2016-04-08
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef SHMCHUNK_H_
|
||||
#define SHMCHUNK_H_
|
||||
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||
#include <boost/interprocess/smart_ptr/shared_ptr.hpp>
|
||||
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
namespace bipc = boost::interprocess;
|
||||
|
||||
class SegmentManager
|
||||
{
|
||||
public:
|
||||
static SegmentManager& Instance()
|
||||
{
|
||||
static SegmentManager man;
|
||||
return man;
|
||||
}
|
||||
|
||||
void InitializeSegment(const std::string& op, const std::string& name, const size_t size = 0)
|
||||
{
|
||||
if (!fSegment)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (op == "open_or_create")
|
||||
{
|
||||
fSegment = new bipc::managed_shared_memory(bipc::open_or_create, name.c_str(), size);
|
||||
}
|
||||
else if (op == "create_only")
|
||||
{
|
||||
fSegment = new bipc::managed_shared_memory(bipc::create_only, name.c_str(), size);
|
||||
}
|
||||
else if (op == "open_only")
|
||||
{
|
||||
int numTries = 0;
|
||||
bool success = false;
|
||||
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
fSegment = new bipc::managed_shared_memory(bipc::open_only, name.c_str());
|
||||
success = true;
|
||||
}
|
||||
catch (bipc::interprocess_exception& ie)
|
||||
{
|
||||
if (++numTries == 5)
|
||||
{
|
||||
LOG(error) << "Could not open shared memory after " << numTries << " attempts, exiting!";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(debug) << "Could not open shared memory segment on try " << numTries << ". Retrying in 1 second...";
|
||||
LOG(debug) << ie.what();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
}
|
||||
}
|
||||
while (!success);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Unknown operation when initializing shared memory segment: " << op;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
LOG(error) << "Exception during shared memory segment initialization: " << e.what() << ", application will now exit";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(info) << "Segment already initialized";
|
||||
}
|
||||
}
|
||||
|
||||
bipc::managed_shared_memory* Segment() const
|
||||
{
|
||||
if (fSegment)
|
||||
{
|
||||
return fSegment;
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(error) << "Segment not initialized";
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
SegmentManager()
|
||||
: fSegment(nullptr)
|
||||
{}
|
||||
|
||||
bipc::managed_shared_memory* fSegment;
|
||||
};
|
||||
|
||||
struct alignas(16) ExMetaHeader
|
||||
{
|
||||
uint64_t fSize;
|
||||
bipc::managed_shared_memory::handle_t fHandle;
|
||||
};
|
||||
|
||||
// class ShmChunk
|
||||
// {
|
||||
// public:
|
||||
// ShmChunk()
|
||||
// : fHandle()
|
||||
// , fSize(0)
|
||||
// {
|
||||
// }
|
||||
|
||||
// ShmChunk(const size_t size)
|
||||
// : fHandle()
|
||||
// , fSize(size)
|
||||
// {
|
||||
// void* ptr = SegmentManager::Instance().Segment()->allocate(size);
|
||||
// fHandle = SegmentManager::Instance().Segment()->get_handle_from_address(ptr);
|
||||
// }
|
||||
|
||||
// ~ShmChunk()
|
||||
// {
|
||||
// SegmentManager::Instance().Segment()->deallocate(SegmentManager::Instance().Segment()->get_address_from_handle(fHandle));
|
||||
// }
|
||||
|
||||
// bipc::managed_shared_memory::handle_t GetHandle() const
|
||||
// {
|
||||
// return fHandle;
|
||||
// }
|
||||
|
||||
// void* GetData() const
|
||||
// {
|
||||
// return SegmentManager::Instance().Segment()->get_address_from_handle(fHandle);
|
||||
// }
|
||||
|
||||
// size_t GetSize() const
|
||||
// {
|
||||
// return fSize;
|
||||
// }
|
||||
|
||||
// private:
|
||||
// bipc::managed_shared_memory::handle_t fHandle;
|
||||
// size_t fSize;
|
||||
// };
|
||||
|
||||
// typedef bipc::managed_shared_ptr<ShmChunk, bipc::managed_shared_memory>::type ShPtrType;
|
||||
|
||||
// struct ShPtrOwner
|
||||
// {
|
||||
// ShPtrOwner(const ShPtrType& other)
|
||||
// : fPtr(other)
|
||||
// {}
|
||||
|
||||
// ShPtrOwner(const ShPtrOwner& other)
|
||||
// : fPtr(other.fPtr)
|
||||
// {}
|
||||
|
||||
// ShPtrType fPtr;
|
||||
// };
|
||||
|
||||
#endif /* SHMCHUNK_H_ */
|
@@ -1,24 +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 "FairMQShmPrototypeSampler.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
|
||||
("msg-rate", bpo::value<int>()->default_value(0), "Msg rate limit in maximum number of messages per second");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQShmPrototypeSampler();
|
||||
}
|
@@ -1,21 +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 "FairMQShmPrototypeSink.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& /*options*/)
|
||||
{
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new FairMQShmPrototypeSink();
|
||||
}
|
@@ -1,34 +0,0 @@
|
||||
{
|
||||
"fairMQOptions": {
|
||||
"devices": [
|
||||
{
|
||||
"id": "sampler1",
|
||||
"channels": [
|
||||
{
|
||||
"name": "meta",
|
||||
"type": "push",
|
||||
"method": "bind",
|
||||
"address": "tcp://127.0.0.1:5555",
|
||||
"sndBufSize": 10,
|
||||
"rcvBufSize": 10,
|
||||
"rateLogging": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "sink1",
|
||||
"channels": [
|
||||
{
|
||||
"name": "meta",
|
||||
"type": "pull",
|
||||
"method": "connect",
|
||||
"address": "tcp://127.0.0.1:5555",
|
||||
"sndBufSize": 10,
|
||||
"rcvBufSize": 10,
|
||||
"rateLogging": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
@@ -1,49 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
msgSize="1000000"
|
||||
transport="zeromq"
|
||||
|
||||
if [[ $1 =~ ^[0-9]+$ ]]; then
|
||||
msgSize=$1
|
||||
fi
|
||||
|
||||
echo "Starting shared memory example with message size of $msgSize bytes."
|
||||
echo ""
|
||||
echo "Usage: startShmPrototype [message size=1000000]"
|
||||
|
||||
SAMPLER="shm-prototype-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
# SAMPLER+=" --severity TRACE"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --msg-rate 1000"
|
||||
SAMPLER+=" --mq-config @CMAKE_BINARY_DIR@/bin/config/shm-prototype.json"
|
||||
xterm -geometry 80x32+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/prototype/shmem/$SAMPLER &
|
||||
|
||||
SINK1="shm-prototype-sink"
|
||||
SINK1+=" --id sink1"
|
||||
SINK1+=" --transport $transport"
|
||||
# SINK1+=" --severity TRACE"
|
||||
SINK1+=" --mq-config @CMAKE_BINARY_DIR@/bin/config/shm-prototype.json"
|
||||
xterm -geometry 80x32+500+0 -hold -e @CMAKE_BINARY_DIR@/bin/prototype/shmem/$SINK1 &
|
||||
|
||||
# SINK2="shm-prototype-sink"
|
||||
# SINK2+=" --id sink2"
|
||||
# SINK2+=" --transport $transport"
|
||||
# # SINK2+=" --severity TRACE"
|
||||
# SINK2+=" --mq-config @CMAKE_BINARY_DIR@/bin/config/shm-prototype.json"
|
||||
# xterm -geometry 80x32+500+500 -hold -e @CMAKE_BINARY_DIR@/bin/prototype/shmem/$SINK2 &
|
||||
|
||||
# SINK3="shm-prototype-sink"
|
||||
# SINK3+=" --id sink3"
|
||||
# SINK3+=" --transport $transport"
|
||||
# # SINK3+=" --severity TRACE"
|
||||
# SINK3+=" --mq-config @CMAKE_BINARY_DIR@/bin/config/shm-prototype.json"
|
||||
# xterm -geometry 80x32+1000+0 -hold -e @CMAKE_BINARY_DIR@/bin/prototype/shmem/$SINK3 &
|
||||
|
||||
# SINK4="shm-prototype-sink"
|
||||
# SINK4+=" --id sink4"
|
||||
# SINK4+=" --transport $transport"
|
||||
# # SINK4+=" --severity TRACE"
|
||||
# SINK4+=" --mq-config @CMAKE_BINARY_DIR@/bin/config/shm-prototype.json"
|
||||
# xterm -geometry 80x32+1000+500 -hold -e @CMAKE_BINARY_DIR@/bin/prototype/shmem/$SINK4 &
|
@@ -6,6 +6,7 @@
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
#include <fairmq/shmem/Monitor.h>
|
||||
#include <fairmq/shmem/Common.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
|
||||
@@ -20,6 +21,7 @@
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::program_options;
|
||||
using namespace fair::mq::shmem;
|
||||
|
||||
static void daemonize()
|
||||
{
|
||||
@@ -68,16 +70,18 @@ int main(int argc, char** argv)
|
||||
try
|
||||
{
|
||||
string sessionName;
|
||||
string shmId;
|
||||
bool cleanup = false;
|
||||
bool selfDestruct = false;
|
||||
bool interactive = false;
|
||||
unsigned int timeoutInMS;
|
||||
unsigned int timeoutInMS = 5000;
|
||||
bool runAsDaemon = false;
|
||||
bool cleanOnExit = false;
|
||||
|
||||
options_description desc("Options");
|
||||
desc.add_options()
|
||||
("session,s", value<string>(&sessionName)->default_value("default"), "Name of the session which to monitor")
|
||||
("session,s", value<string>(&sessionName)->default_value("default"), "session id which to monitor")
|
||||
("shmid", value<string>(&shmId)->default_value(""), "Shmem Id to monitor (if not provided, it is generated out of session id and user id)")
|
||||
("cleanup,c", value<bool>(&cleanup)->implicit_value(true), "Perform cleanup and quit")
|
||||
("self-destruct,x", value<bool>(&selfDestruct)->implicit_value(true), "Quit after first closing of the memory")
|
||||
("interactive,i", value<bool>(&interactive)->implicit_value(true), "Interactive run")
|
||||
@@ -97,24 +101,27 @@ int main(int argc, char** argv)
|
||||
|
||||
notify(vm);
|
||||
|
||||
sessionName.resize(8, '_'); // shorten the session name, to accommodate for name size limit on some systems (MacOS)
|
||||
|
||||
if (runAsDaemon)
|
||||
{
|
||||
daemonize();
|
||||
}
|
||||
|
||||
if (shmId == "")
|
||||
{
|
||||
shmId = buildShmIdFromSessionIdAndUserId(sessionName);
|
||||
}
|
||||
|
||||
if (cleanup)
|
||||
{
|
||||
cout << "Cleaning up \"" << sessionName << "\"..." << endl;
|
||||
fair::mq::shmem::Monitor::Cleanup(sessionName);
|
||||
fair::mq::shmem::Monitor::RemoveQueue("fmq_" + sessionName + "_cq");
|
||||
cout << "Cleaning up \"" << shmId << "\"..." << endl;
|
||||
Monitor::Cleanup(shmId);
|
||||
Monitor::RemoveQueue("fmq_" + shmId + "_cq");
|
||||
return 0;
|
||||
}
|
||||
|
||||
cout << "Starting shared memory monitor for session: \"" << sessionName << "\"..." << endl;
|
||||
cout << "Starting shared memory monitor for session: \"" << sessionName << "\" (shmId: " << shmId << ")..." << endl;
|
||||
|
||||
fair::mq::shmem::Monitor monitor{sessionName, selfDestruct, interactive, timeoutInMS, runAsDaemon, cleanOnExit};
|
||||
Monitor monitor{shmId, selfDestruct, interactive, timeoutInMS, runAsDaemon, cleanOnExit};
|
||||
|
||||
monitor.CatchSignals();
|
||||
monitor.Run();
|
||||
|
@@ -12,6 +12,7 @@
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -30,23 +31,33 @@ namespace tools
|
||||
* @param[in] log_prefix How to prefix each captured output line with
|
||||
* @return Captured stdout output and exit code
|
||||
*/
|
||||
execute_result execute(string cmd, string prefix)
|
||||
execute_result execute(const string& cmd, const string& prefix, const string& input)
|
||||
{
|
||||
execute_result result;
|
||||
stringstream out;
|
||||
|
||||
// print full line thread-safe
|
||||
stringstream printCmd;
|
||||
printCmd << prefix << cmd << "\n";
|
||||
printCmd << prefix << " " << cmd << "\n";
|
||||
cout << printCmd.str() << flush;
|
||||
|
||||
out << prefix << cmd << endl;
|
||||
|
||||
// Execute command and capture stdout, add prefix line by line
|
||||
boost::process::ipstream stdout;
|
||||
boost::process::child c(cmd, boost::process::std_out > stdout);
|
||||
boost::process::ipstream c_stdout;
|
||||
boost::process::opstream c_stdin;
|
||||
boost::process::child c(
|
||||
cmd, boost::process::std_out > c_stdout, boost::process::std_in < c_stdin);
|
||||
|
||||
// Optionally, write to stdin of the child
|
||||
if (input != "") {
|
||||
this_thread::sleep_for(chrono::milliseconds(100));
|
||||
c_stdin << input;
|
||||
c_stdin.flush();
|
||||
}
|
||||
|
||||
string line;
|
||||
while (getline(stdout, line))
|
||||
while (getline(c_stdout, line))
|
||||
{
|
||||
// print full line thread-safe
|
||||
stringstream printLine;
|
||||
|
@@ -32,10 +32,13 @@ struct execute_result
|
||||
* and exit code.
|
||||
*
|
||||
* @param[in] cmd Command to execute
|
||||
* @param[in] log_prefix How to prefix each captured output line with
|
||||
* @param[in] prefix How to prefix each captured output line with
|
||||
* @param[in] input Data which is sent to stdin of the child process
|
||||
* @return Captured stdout output and exit code
|
||||
*/
|
||||
execute_result execute(std::string cmd, std::string prefix = "");
|
||||
execute_result execute(const std::string& cmd,
|
||||
const std::string& prefix = "",
|
||||
const std::string& input = "");
|
||||
|
||||
} /* namespace tools */
|
||||
} /* namespace mq */
|
||||
|
136
fairmq/tools/RateLimit.h
Normal file
136
fairmq/tools/RateLimit.h
Normal file
@@ -0,0 +1,136 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_TOOLS_RATELIMIT_H
|
||||
#define FAIR_MQ_TOOLS_RATELIMIT_H
|
||||
|
||||
#include <cassert>
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace tools
|
||||
{
|
||||
|
||||
/**
|
||||
* Objects of type RateLimiter can be used to limit a loop to a given rate of iterations per second.
|
||||
*
|
||||
* Example:
|
||||
* \code
|
||||
* RateLimiter limit(100); // 100 Hz
|
||||
* while (do_more_work()) {
|
||||
* work();
|
||||
* limit.maybe_sleep(); // this needs to be at the end of the loop for a
|
||||
* // correct time measurement of the first iterations
|
||||
* }
|
||||
* \endcode
|
||||
*/
|
||||
class RateLimiter
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Constructs a rate limiter.
|
||||
*
|
||||
* \param rate Work rate in Hz (calls to maybe_sleep per second). Values less than/equal
|
||||
* to 0 set the rate to 1 GHz (which is impossible to achieve, even with a
|
||||
* loop that only calls RateLimiter::maybe_sleep).
|
||||
*/
|
||||
RateLimiter(float rate) : tw_req(std::chrono::seconds(1)), start_time(clock::now())
|
||||
{
|
||||
if (rate <= 0) {
|
||||
tw_req = std::chrono::nanoseconds(1);
|
||||
} else {
|
||||
tw_req = std::chrono::duration_cast<clock::duration>(tw_req / rate);
|
||||
}
|
||||
skip_check_count = std::max(1, int(std::chrono::milliseconds(5) / tw_req));
|
||||
count = skip_check_count;
|
||||
//std::cerr << "skip_check_count: " << skip_check_count << '\n';
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function at the end of the iteration rate limited loop.
|
||||
*
|
||||
* This function might use `std::this_thread::sleep_for` to limit the iteration rate. If no sleeps
|
||||
* are necessary, the function will back off checking for the time to further allow increased
|
||||
* iteration rates (until the requested rate or 1s between rechecks is reached).
|
||||
*/
|
||||
void maybe_sleep()
|
||||
{
|
||||
using namespace std::chrono;
|
||||
if (--count == 0) {
|
||||
auto now = clock::now();
|
||||
if (tw == clock::duration::zero()) {
|
||||
tw = (now - start_time) / skip_check_count;
|
||||
} else {
|
||||
tw = (1 * tw + 3 * (now - start_time) / skip_check_count) / 4;
|
||||
}
|
||||
//std::ostringstream s; s << "tw = " << std::setw(10) << duration_cast<nanoseconds>(tw).count() << "ns, req = " << duration_cast<nanoseconds>(tw_req).count() << "ns, ";
|
||||
if (tw > tw_req * 65 / 64) {
|
||||
// the time between maybe_sleep calls is more than 1% too long
|
||||
// fix it by reducing ts towards 0 and if ts = 0 doesn't suffice, increase
|
||||
// skip_check_count
|
||||
if (ts > clock::duration::zero()) {
|
||||
ts = std::max(clock::duration::zero(),
|
||||
ts - (tw - tw_req) * skip_check_count * 1 / 2);
|
||||
//std::cerr << s.str() << "maybe_sleep: going too slow; sleep less: " << duration_cast<microseconds>(ts).count() << "µs\n";
|
||||
} else {
|
||||
skip_check_count =
|
||||
std::min(int(seconds(1) / tw_req), // recheck at least every second
|
||||
(skip_check_count * 5 + 3) / 4);
|
||||
//std::cerr << s.str() << "maybe_sleep: going too slow; work more: " << skip_check_count << "\n";
|
||||
}
|
||||
} else if (tw < tw_req * 63 / 64) {
|
||||
// the time between maybe_sleep calls is more than 1% too short
|
||||
// fix it by reducing skip_check_count towards 1 and if skip_check_count = 1
|
||||
// doesn't suffice, increase ts
|
||||
|
||||
// The minimum work count is defined such that a typical sleep time is greater
|
||||
// than 1ms.
|
||||
// The user requested 1/tw_req work iterations per second. Divided by 1000, that's
|
||||
// the count per ms.
|
||||
const int min_skip_count = std::max(1, int(milliseconds(5) / tw_req));
|
||||
if (skip_check_count > min_skip_count) {
|
||||
assert(ts == clock::duration::zero());
|
||||
skip_check_count = std::max(min_skip_count, skip_check_count * 3 / 4);
|
||||
//std::cerr << s.str() << "maybe_sleep: going too fast; work less: " << skip_check_count << "\n";
|
||||
} else {
|
||||
ts += (tw_req - tw) * (skip_check_count * 7) / 8;
|
||||
//std::cerr << s.str() << "maybe_sleep: going too fast; sleep more: " << duration_cast<microseconds>(ts).count() << "µs\n";
|
||||
}
|
||||
}
|
||||
|
||||
start_time = now;
|
||||
count = skip_check_count;
|
||||
if (ts > clock::duration::zero()) {
|
||||
std::this_thread::sleep_for(ts);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
clock::duration tw{}, //! deduced duration between maybe_sleep calls
|
||||
ts{}, //! sleep duration
|
||||
tw_req; //! requested duration between maybe_sleep calls
|
||||
clock::time_point start_time;
|
||||
int count = 1;
|
||||
int skip_check_count = 1;
|
||||
};
|
||||
|
||||
} /* namespace tools */
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif // FAIR_MQ_TOOLS_RATELIMIT_H
|
@@ -69,10 +69,9 @@ FairMQPollerZMQ::FairMQPollerZMQ(const unordered_map<string, vector<FairMQChanne
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
{
|
||||
int offset = 0;
|
||||
|
||||
try
|
||||
{
|
||||
int offset = 0;
|
||||
// calculate offsets and the total size of the poll item set
|
||||
for (string channel : channelList)
|
||||
{
|
||||
@@ -190,7 +189,7 @@ bool FairMQPollerZMQ::CheckOutput(const int index)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQPollerZMQ::CheckInput(const string channelKey, const int index)
|
||||
bool FairMQPollerZMQ::CheckInput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -209,7 +208,7 @@ bool FairMQPollerZMQ::CheckInput(const string channelKey, const int index)
|
||||
}
|
||||
}
|
||||
|
||||
bool FairMQPollerZMQ::CheckOutput(const string channelKey, const int index)
|
||||
bool FairMQPollerZMQ::CheckOutput(const string& channelKey, const int index)
|
||||
{
|
||||
try
|
||||
{
|
||||
|
@@ -45,8 +45,8 @@ class FairMQPollerZMQ : public FairMQPoller
|
||||
virtual void Poll(const int timeout);
|
||||
virtual bool CheckInput(const int index);
|
||||
virtual bool CheckOutput(const int index);
|
||||
virtual bool CheckInput(const std::string channelKey, const int index);
|
||||
virtual bool CheckOutput(const std::string channelKey, const int index);
|
||||
virtual bool CheckInput(const std::string& channelKey, const int index);
|
||||
virtual bool CheckOutput(const std::string& channelKey, const int index);
|
||||
|
||||
virtual ~FairMQPollerZMQ();
|
||||
|
||||
|
@@ -116,14 +116,13 @@ int64_t FairMQSocketZMQ::TryReceive(vector<unique_ptr<FairMQMessage>>& msgVec) {
|
||||
|
||||
int FairMQSocketZMQ::SendImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
{
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
static_cast<FairMQMessageZMQ*>(msg.get())->ApplyUsedSize();
|
||||
|
||||
while (true)
|
||||
{
|
||||
nbytes = zmq_msg_send(static_cast<FairMQMessageZMQ*>(msg.get())->GetMessage(), fSocket, flags);
|
||||
int nbytes = zmq_msg_send(static_cast<FairMQMessageZMQ*>(msg.get())->GetMessage(), fSocket, flags);
|
||||
if (nbytes >= 0)
|
||||
{
|
||||
fBytesTx += nbytes;
|
||||
@@ -212,25 +211,21 @@ int FairMQSocketZMQ::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
|
||||
int64_t FairMQSocketZMQ::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
{
|
||||
const unsigned int vecSize = msgVec.size();
|
||||
int elapsed = 0;
|
||||
|
||||
// Sending vector typicaly handles more then one part
|
||||
if (vecSize > 1)
|
||||
{
|
||||
int64_t totalSize = 0;
|
||||
int nbytes = -1;
|
||||
bool repeat = false;
|
||||
|
||||
int elapsed = 0;
|
||||
while (true)
|
||||
{
|
||||
totalSize = 0;
|
||||
repeat = false;
|
||||
int64_t totalSize = 0;
|
||||
bool repeat = false;
|
||||
|
||||
for (unsigned int i = 0; i < vecSize; ++i)
|
||||
{
|
||||
static_cast<FairMQMessageZMQ*>(msgVec[i].get())->ApplyUsedSize();
|
||||
|
||||
nbytes = zmq_msg_send(static_cast<FairMQMessageZMQ*>(msgVec[i].get())->GetMessage(),
|
||||
int nbytes = zmq_msg_send(static_cast<FairMQMessageZMQ*>(msgVec[i].get())->GetMessage(),
|
||||
fSocket,
|
||||
(i < vecSize - 1) ? ZMQ_SNDMORE|flags : flags);
|
||||
if (nbytes >= 0)
|
||||
@@ -283,7 +278,7 @@ int64_t FairMQSocketZMQ::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
|
||||
} // If there's only one part, send it as a regular message
|
||||
else if (vecSize == 1)
|
||||
{
|
||||
return Send(msgVec.back(), flags);
|
||||
return SendImpl(msgVec.back(), flags, timeout);
|
||||
}
|
||||
else // if the vector is empty, something might be wrong
|
||||
{
|
||||
@@ -294,16 +289,13 @@ int64_t FairMQSocketZMQ::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
|
||||
|
||||
int64_t FairMQSocketZMQ::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
{
|
||||
int64_t totalSize = 0;
|
||||
int64_t more = 0;
|
||||
bool repeat = false;
|
||||
int elapsed = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
totalSize = 0;
|
||||
more = 0;
|
||||
repeat = false;
|
||||
int64_t totalSize = 0;
|
||||
int64_t more = 0;
|
||||
bool repeat = false;
|
||||
|
||||
do
|
||||
{
|
||||
|
@@ -39,7 +39,7 @@ FairMQTransportFactoryZMQ::FairMQTransportFactoryZMQ(const string& id, const Fai
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(warn) << "FairMQProgOptions not available! Using defaults.";
|
||||
LOG(debug) << "FairMQProgOptions not available! Using defaults.";
|
||||
}
|
||||
|
||||
if (zmq_ctx_set(fContext, ZMQ_IO_THREADS, numIoThreads) != 0)
|
||||
|
@@ -1,5 +1,5 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
@@ -26,72 +26,84 @@ add_testhelper(runTestDevice
|
||||
helper/devices/TestReq.cxx
|
||||
helper/devices/TestSub.cxx
|
||||
helper/devices/TestTransferTimeout.cxx
|
||||
helper/devices/TestWaitFor.cxx
|
||||
helper/devices/TestExceptions.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(definitions DEFINITIONS BUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
|
||||
set(MQ_CONFIG "${CMAKE_BINARY_DIR}/test/testsuite_FairMQ.IOPatterns_config.json")
|
||||
set(RUN_TEST_DEVICE "${CMAKE_BINARY_DIR}/test/testhelper_runTestDevice")
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/protocols/config.json.in ${MQ_CONFIG})
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/protocols/runner.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/protocols/runner.cxx)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/runner.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/runner.cxx)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestEnvironment.h.in ${CMAKE_CURRENT_BINARY_DIR}/TestEnvironment.h)
|
||||
|
||||
add_testsuite(FairMQ.Protocols
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/protocols/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
protocols/_pair.cxx
|
||||
protocols/_poller.cxx
|
||||
protocols/_pub_sub.cxx
|
||||
protocols/_push_pull.cxx
|
||||
protocols/_req_rep.cxx
|
||||
protocols/_transfer_timeout.cxx
|
||||
protocols/_push_pull_multipart.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
DEPENDS testhelper_runTestDevice
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/protocols
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/protocols
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 30
|
||||
RUN_SERIAL ON
|
||||
${definitions}
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.Parts
|
||||
SOURCES
|
||||
parts/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
parts/_iterator_interface.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/parts
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/parts
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 5
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.MessageResize
|
||||
SOURCES
|
||||
message_resize/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
message_resize/_message_resize.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/message_resize
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/message_resize
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 5
|
||||
${definitions}
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.Device
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
device/TestSender.h
|
||||
device/TestReceiver.h
|
||||
device/TestVersion.h
|
||||
device/runner.cxx
|
||||
device/_multiple_devices.cxx
|
||||
device/_device_version.cxx
|
||||
device/_device_config.cxx
|
||||
device/_waitfor.cxx
|
||||
device/_exceptions.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/device
|
||||
DEPENDS testhelper_runTestDevice
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/device
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 5
|
||||
TIMEOUT 15
|
||||
RUN_SERIAL ON
|
||||
)
|
||||
|
||||
@@ -129,54 +141,81 @@ add_testlib(FairMQPlugin_test_dummy2
|
||||
|
||||
add_testsuite(FairMQ.Plugins
|
||||
SOURCES
|
||||
plugins/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
plugins/_plugin.cxx
|
||||
plugins/_plugin_manager.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
DEPENDS FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.PluginsPrelinked
|
||||
SOURCES
|
||||
plugins/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
plugins/_plugin_manager_prelink.cxx
|
||||
|
||||
LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
|
||||
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.PluginServices
|
||||
SOURCES
|
||||
plugin_services/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
plugin_services/_config.cxx
|
||||
plugin_services/_control.cxx
|
||||
plugin_services/Fixture.h
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.EventManager
|
||||
SOURCES
|
||||
event_manager/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
event_manager/_event_manager.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.StateMachine
|
||||
SOURCES
|
||||
state_machine/runner.cxx
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
state_machine/_state_machine.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.Transport
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
transport/_transfer_timeout.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
||||
add_testsuite(FairMQ.Poller
|
||||
SOURCES
|
||||
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
|
||||
poller/_poller.cxx
|
||||
|
||||
LINKS FairMQ
|
||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
TIMEOUT 10
|
||||
)
|
||||
|
122
test/device/_device_config.cxx
Normal file
122
test/device/_device_config.cxx
Normal file
@@ -0,0 +1,122 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include <FairMQDevice.h>
|
||||
#include <options/FairMQProgOptions.h>
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <sstream> // std::stringstream
|
||||
#include <thread>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
|
||||
void control(FairMQDevice& device)
|
||||
{
|
||||
device.ChangeState("INIT_DEVICE");
|
||||
device.WaitForEndOfState("INIT_DEVICE");
|
||||
device.ChangeState("INIT_TASK");
|
||||
device.WaitForEndOfState("INIT_TASK");
|
||||
|
||||
device.ChangeState("RUN");
|
||||
device.WaitForEndOfState("RUN");
|
||||
|
||||
device.ChangeState("RESET_TASK");
|
||||
device.WaitForEndOfState("RESET_TASK");
|
||||
device.ChangeState("RESET_DEVICE");
|
||||
device.WaitForEndOfState("RESET_DEVICE");
|
||||
|
||||
device.ChangeState("END");
|
||||
}
|
||||
|
||||
class DeviceConfig : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
DeviceConfig()
|
||||
{}
|
||||
|
||||
string TestDeviceSetConfig(const string& transport)
|
||||
{
|
||||
FairMQProgOptions config;
|
||||
|
||||
vector<string> emptyArgs = {"dummy", "--id", "test", "--color", "false"};
|
||||
|
||||
if (config.ParseAll(emptyArgs, true))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
config.SetValue<string>("transport", transport);
|
||||
|
||||
FairMQDevice device;
|
||||
device.SetConfig(config);
|
||||
|
||||
FairMQChannel channel;
|
||||
channel.UpdateType("pub");
|
||||
channel.UpdateMethod("connect");
|
||||
channel.UpdateAddress("tcp://localhost:5558");
|
||||
device.AddChannel("data", channel);
|
||||
|
||||
thread t(control, ref(device));
|
||||
|
||||
device.RunStateMachine();
|
||||
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
return device.GetTransportName();
|
||||
}
|
||||
|
||||
string TestDeviceSetTransport(const string& transport)
|
||||
{
|
||||
FairMQDevice device;
|
||||
device.SetTransport(transport);
|
||||
|
||||
FairMQChannel channel;
|
||||
channel.UpdateType("pub");
|
||||
channel.UpdateMethod("connect");
|
||||
channel.UpdateAddress("tcp://localhost:5558");
|
||||
device.AddChannel("data", channel);
|
||||
|
||||
std::thread t(control, std::ref(device));
|
||||
|
||||
device.RunStateMachine();
|
||||
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
return device.GetTransportName();
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(DeviceConfig, SetConfig)
|
||||
{
|
||||
string transport = "zeromq";
|
||||
string returnedTransport = TestDeviceSetConfig(transport);
|
||||
|
||||
EXPECT_EQ(transport, returnedTransport);
|
||||
}
|
||||
|
||||
TEST_F(DeviceConfig, SetTransport)
|
||||
{
|
||||
string transport = "zeromq";
|
||||
string returnedTransport = TestDeviceSetTransport(transport);
|
||||
|
||||
EXPECT_EQ(transport, returnedTransport);
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -1,12 +1,12 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "TestVersion.h"
|
||||
#include <FairMQDevice.h>
|
||||
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
@@ -19,16 +19,24 @@ namespace
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq::test;
|
||||
|
||||
class DeviceVersion : public ::testing::Test {
|
||||
class TestVersion : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
TestVersion(fair::mq::tools::Version version)
|
||||
: FairMQDevice(version)
|
||||
{}
|
||||
};
|
||||
|
||||
class DeviceVersion : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
DeviceVersion()
|
||||
{}
|
||||
|
||||
fair::mq::tools::Version TestDeviceVersion()
|
||||
{
|
||||
fair::mq::test::TestVersion versionDevice({1, 2, 3});
|
||||
TestVersion versionDevice({1, 2, 3});
|
||||
versionDevice.ChangeState("END");
|
||||
|
||||
return versionDevice.GetVersion();
|
||||
|
125
test/device/_exceptions.cxx
Normal file
125
test/device/_exceptions.cxx
Normal file
@@ -0,0 +1,125 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runner.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <boost/process.hpp>
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <iostream>
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq::test;
|
||||
using namespace fair::mq::tools;
|
||||
|
||||
void RunExceptionIn(const std::string& state, const std::string& input = "")
|
||||
{
|
||||
size_t session{fair::mq::tools::UuidHash()};
|
||||
|
||||
execute_result result{"", 100};
|
||||
thread device_thread([&]() {
|
||||
stringstream cmd;
|
||||
cmd << runTestDevice
|
||||
<< " --id exceptions_" << state << "_"
|
||||
<< " --control " << ((input == "") ? "static" : "interactive")
|
||||
<< " --session " << session
|
||||
<< " --color false";
|
||||
result = execute(cmd.str(), "[EXCEPTION IN " + state + "]", input);
|
||||
});
|
||||
|
||||
device_thread.join();
|
||||
|
||||
ASSERT_NE(std::string::npos, result.console_out.find("exception in " + state + "()"));
|
||||
|
||||
exit(result.exit_code);
|
||||
}
|
||||
|
||||
TEST(Exceptions, InInit_______static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Init"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InInitTask___static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("InitTask"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPreRun_____static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PreRun"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InRun________static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Run"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPostRun____static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PostRun"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InResetTask__static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("ResetTask"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InReset______static)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Reset"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InInit_______interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Init", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InInitTask___interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("InitTask", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPreRun_____interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PreRun", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InRun________interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Run", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPostRun____interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PostRun", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InResetTask__interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("ResetTask", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InReset______interactive)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Reset", "q"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InInit_______interactive_invalid)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Init", "_"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InInitTask___interactive_invalid)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("InitTask", "_"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPreRun_____interactive_invalid)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PreRun", "_"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InRun________interactive_invalid)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("Run", "_"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
TEST(Exceptions, InPostRun____interactive_invalid)
|
||||
{
|
||||
EXPECT_EXIT(RunExceptionIn("PostRun", "_"), ::testing::ExitedWithCode(1), "");
|
||||
}
|
||||
|
||||
} // namespace
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <future> // std::async, std::future
|
||||
|
||||
namespace
|
||||
@@ -19,6 +20,24 @@ namespace
|
||||
|
||||
using namespace std;
|
||||
|
||||
void control(FairMQDevice& device)
|
||||
{
|
||||
device.ChangeState("INIT_DEVICE");
|
||||
device.WaitForEndOfState("INIT_DEVICE");
|
||||
device.ChangeState("INIT_TASK");
|
||||
device.WaitForEndOfState("INIT_TASK");
|
||||
|
||||
device.ChangeState("RUN");
|
||||
device.WaitForEndOfState("RUN");
|
||||
|
||||
device.ChangeState("RESET_TASK");
|
||||
device.WaitForEndOfState("RESET_TASK");
|
||||
device.ChangeState("RESET_DEVICE");
|
||||
device.WaitForEndOfState("RESET_DEVICE");
|
||||
|
||||
device.ChangeState("END");
|
||||
}
|
||||
|
||||
class MultipleDevices : public ::testing::Test {
|
||||
public:
|
||||
MultipleDevices()
|
||||
@@ -32,22 +51,16 @@ class MultipleDevices : public ::testing::Test {
|
||||
|
||||
FairMQChannel channel("push", "connect", "ipc://multiple-devices-test");
|
||||
channel.UpdateRateLogging(0);
|
||||
sender.fChannels["data"].push_back(channel);
|
||||
sender.AddChannel("data", channel);
|
||||
|
||||
sender.ChangeState("INIT_DEVICE");
|
||||
sender.WaitForEndOfState("INIT_DEVICE");
|
||||
sender.ChangeState("INIT_TASK");
|
||||
sender.WaitForEndOfState("INIT_TASK");
|
||||
thread t(control, std::ref(sender));
|
||||
|
||||
sender.ChangeState("RUN");
|
||||
sender.WaitForEndOfState("RUN");
|
||||
sender.RunStateMachine();
|
||||
|
||||
sender.ChangeState("RESET_TASK");
|
||||
sender.WaitForEndOfState("RESET_TASK");
|
||||
sender.ChangeState("RESET_DEVICE");
|
||||
sender.WaitForEndOfState("RESET_DEVICE");
|
||||
|
||||
sender.ChangeState("END");
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -60,22 +73,16 @@ class MultipleDevices : public ::testing::Test {
|
||||
|
||||
FairMQChannel channel("pull", "bind", "ipc://multiple-devices-test");
|
||||
channel.UpdateRateLogging(0);
|
||||
receiver.fChannels["data"].push_back(channel);
|
||||
receiver.AddChannel("data", channel);
|
||||
|
||||
receiver.ChangeState("INIT_DEVICE");
|
||||
receiver.WaitForEndOfState("INIT_DEVICE");
|
||||
receiver.ChangeState("INIT_TASK");
|
||||
receiver.WaitForEndOfState("INIT_TASK");
|
||||
thread t(control, std::ref(receiver));
|
||||
|
||||
receiver.ChangeState("RUN");
|
||||
receiver.WaitForEndOfState("RUN");
|
||||
receiver.RunStateMachine();
|
||||
|
||||
receiver.ChangeState("RESET_TASK");
|
||||
receiver.WaitForEndOfState("RESET_TASK");
|
||||
receiver.ChangeState("RESET_DEVICE");
|
||||
receiver.WaitForEndOfState("RESET_DEVICE");
|
||||
|
||||
receiver.ChangeState("END");
|
||||
if (t.joinable())
|
||||
{
|
||||
t.join();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
74
test/device/_waitfor.cxx
Normal file
74
test/device/_waitfor.cxx
Normal file
@@ -0,0 +1,74 @@
|
||||
/********************************************************************************
|
||||
* 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" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runner.h"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <boost/process.hpp>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <iostream>
|
||||
#include <future> // std::async, std::future
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq::test;
|
||||
|
||||
void RunWaitFor()
|
||||
{
|
||||
std::mutex mtx;
|
||||
std::condition_variable cv;
|
||||
|
||||
int pid = 0;
|
||||
int exit_code = 0;
|
||||
|
||||
thread deviceThread([&]() {
|
||||
stringstream cmd;
|
||||
cmd << runTestDevice << " --id waitfor_" << " --control static " << " --severity nolog";
|
||||
|
||||
boost::process::ipstream stdout;
|
||||
boost::process::child c(cmd.str(), boost::process::std_out > stdout);
|
||||
string line;
|
||||
getline(stdout, line);
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
pid = c.id();
|
||||
}
|
||||
cv.notify_one();
|
||||
|
||||
c.wait();
|
||||
|
||||
exit_code = c.exit_code();
|
||||
});
|
||||
|
||||
{
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
cv.wait(lock, [&pid]{ return pid != 0; });
|
||||
}
|
||||
|
||||
kill(pid, SIGINT);
|
||||
|
||||
deviceThread.join();
|
||||
|
||||
exit(exit_code);
|
||||
}
|
||||
|
||||
TEST(Device, WaitFor)
|
||||
{
|
||||
EXPECT_EXIT(RunWaitFor(), ::testing::ExitedWithCode(0), "");
|
||||
}
|
||||
|
||||
} // namespace
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user