Compare commits

..

49 Commits

Author SHA1 Message Date
Dennis Klein
a7429ed79b Move and update PR template 2018-08-21 13:21:25 +02:00
Dennis Klein
09ef175736 Create issue templates 2018-08-21 13:21:25 +02:00
Dennis Klein
a55db74848 Fix variable name 2018-08-21 13:15:02 +02:00
Dennis Klein
8b3e3bbe28 Fix coverage reporting for FAST_BUILD 2018-08-09 16:15:15 +02:00
Dennis Klein
e71c9c1121 Parallelize unity build
Only needed with Makefile generator,
see https://github.com/sakra/cotire/blob/master/MANUAL.md#optimizing-the-build-process-for-multiple-processor-cores
2018-08-09 16:15:15 +02:00
Dennis Klein
fc0adba26b Support unity build 2018-08-09 16:15:15 +02:00
Dennis Klein
24dff2fd76 Enable FAST_BUILD for alfa-ci 2018-08-09 16:15:15 +02:00
Dennis Klein
70ffc0d8c6 Guard list operation for the case the list is empty 2018-08-09 16:15:15 +02:00
Dennis Klein
ff701006fd Reflect dev version in the installed artifacts 2018-08-09 16:15:15 +02:00
Dennis Klein
c8bd19b7a1 Add experimental FAST_BUILD option
Significantly reduces compile time for the FairMQ target with
precompiled headers and unity build. For maximum improvement, use
a multi-core-aware build tool, e.g. Ninja.

Leave it undocumented for now, let's first test it internally for a while.
2018-08-09 16:15:15 +02:00
Dennis Klein
aee2ba7b9b Increase sample size to catch time sensitive branches
and stabilize coverage diff reports.
2018-08-09 16:15:15 +02:00
Dennis Klein
9184d5bdae clean 2018-08-09 16:15:15 +02:00
Dennis Klein
5e6f3a5430 Enable color output with Ninja 2018-08-09 16:15:15 +02:00
Dennis Klein
d0fe175cab Print global cxx flags 2018-08-09 16:15:15 +02:00
Dennis Klein
6f22ccf4c1 Fix -Wsign-compare 2018-08-09 16:15:15 +02:00
Dennis Klein
b2034c20cf Fix -Wshadow 2018-08-09 16:15:15 +02:00
Dennis Klein
ab6fd35a86 Add header-only target for msgpack 2018-08-09 16:15:15 +02:00
Dennis Klein
4a8e46c65c Fix -Wunused-parameter 2018-08-09 16:15:15 +02:00
Dennis Klein
90e00730b1 Update clang-format 2018-08-09 16:15:15 +02:00
Dennis Klein
924c8ac5f6 Add hint how to change build type and change color of selected type 2018-08-09 16:15:15 +02:00
Dennis Klein
1e0159b775 Link against system threads library 2018-08-08 16:13:41 +02:00
Alexey Rybalchenko
ef3eb5f83e Simplify structure in DeviceRunner and plugin classes 2018-08-08 16:13:41 +02:00
Alexey Rybalchenko
ee8afd7d2b Fix race in plugin manager/services 2018-08-08 16:13:41 +02:00
Alexey Rybalchenko
a53ef79552 Run state handlers on the main thread (breaking change for control). 2018-08-08 16:13:41 +02:00
Dennis Klein
c064da91df Add ThreadSan/AddressSan build types and print table 2018-07-27 17:09:52 +02:00
Dennis Klein
f5e3212cbf Align with repo subtitle on github 2018-07-27 16:21:24 +02:00
Dennis Klein
c1d61007a1 Add Introduction header 2018-07-27 16:21:24 +02:00
Dennis Klein
93fb407af6 Compact dependency list 2018-07-27 16:21:24 +02:00
Dennis Klein
8e7e23e2d0 Add Copyright statement in separate file instead of README 2018-07-27 16:21:24 +02:00
Dennis Klein
f0ec5fa2be Refactor license section 2018-07-27 16:21:24 +02:00
Dennis Klein
aaaadf0a0b Switch to faster shields host 2018-07-23 20:34:23 +02:00
Dennis Klein
daec266341 Improve visibility of release and docs links 2018-07-23 15:47:04 +02:00
Dennis Klein
38a149d50c Make badges hyperlinks 2018-07-23 15:47:04 +02:00
Dennis Klein
cfebfb3407 Add codecov badges 2018-07-23 15:47:04 +02:00
Dennis Klein
e403d18cb9 Add codecov reports to PRs 2018-07-20 17:21:23 +02:00
Dennis Klein
9bab3f9f4c Support msgpack 3.x
Fixes #32
2018-07-18 16:13:18 +02:00
Dennis Klein
ee3a84ce7a Add Matthias as CONTRIBUTOR
To acknowledge his countless hours of consulting which benefited
this project significantly.
2018-06-19 14:08:32 +02:00
mkrzewic
f05118f4eb Make ";" the separateor in multi-point channel config
This is to avoid parsing problems using "," in e.g. multi-point configuration using Suboptparser
2018-06-18 15:26:31 +02:00
Alexey Rybalchenko
21419adb40 Change unregistered options warning to debug 2018-06-16 17:40:05 +02:00
Alexey Rybalchenko
1554c1c273 Change missing options in transport from warning to debug
Transport has meaningful defaults if FairMQProgOptions is missing
2018-06-13 18:03:16 +02:00
Alexey Rybalchenko
59b04a1a64 Handle Receive differently when switching transports
No need for buffer+size message on Receive.
2018-06-12 13:55:18 +02:00
Alexey Rybalchenko
653e82cab4 Avoid copy (where possible) when switching transports 2018-06-08 13:10:06 +02:00
Dennis Klein
96e2076300 Only install public header files
Resolves #15
2018-06-08 11:25:03 +02:00
Alexey Rybalchenko
2894af803b Add getter for cmd line args & align channel names in log 2018-06-06 16:04:08 +02:00
Alexey Rybalchenko
8b88e67360 Refactor FairMQProgOptions 2018-06-06 16:04:08 +02:00
Alexey Rybalchenko
ca694e4054 add privacy info link to doxygen 2018-05-24 16:06:28 +02:00
Dennis Klein
3f96181ffd Define nn tests only when nn transport is built 2018-05-24 15:54:35 +02:00
Dennis Klein
72f5cdef58 Fix various warnings
-Wunused-parameter
-Wreorder
-Wsign-compare
-Wunused-private-field
2018-05-24 13:03:06 +02:00
Dennis Klein
811e716731 Add missing header 2018-05-23 08:26:23 +02:00
101 changed files with 5784 additions and 2596 deletions

33
.clang-format Normal file
View 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
...

27
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,27 @@
---
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.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**System information (please complete the following information):**
- OS: [e.g. MacOS, Fedora28, Ubuntu14.04]
- Environment: [e.g. FairSoft version, alfadist revision]
**Additional context**
Add any other context about the problem here.

View 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
View File

@@ -0,0 +1,7 @@
---
name: Question / Support
about: Any FairMQ related matter you are interested in
---

View File

@@ -1,4 +1,6 @@
Replace me with your description. Describe your proposal.
Mention any issue this PR is resolves or is related to.
--- ---

View File

@@ -34,10 +34,30 @@ 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_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF)
cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF) cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
option(BUILD_DOCS "Build FairMQ documentation." OFF) option(BUILD_DOCS "Build FairMQ documentation." OFF)
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
################################################################################ ################################################################################
# Dependencies ################################################################# # Dependencies #################################################################
if(FAST_BUILD)
include(cotire)
endif()
macro(find_msgpack)
if(NOT msgpack_FOUND)
find_package2(PRIVATE msgpack VERSION 3.0.0)
set(PROJECT_msgpack_VERSION 2.1.5)
if(NOT msgpack_FOUND)
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
endif()
set(msgpack_ROOT ${PACKAGE_PREFIX_DIR})
endif()
endmacro()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
if(BUILD_FAIRMQ) if(BUILD_FAIRMQ)
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
COMPONENTS program_options thread system filesystem regex date_time signals COMPONENTS program_options thread system filesystem regex date_time signals
@@ -48,7 +68,11 @@ endif()
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED) find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED)
find_package2(PRIVATE msgpack VERSION 3.0.0)
set(PROJECT_msgpack_VERSION 2.1.5)
if(NOT msgpack_FOUND)
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED) find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
endif()
set(msgpack_ROOT ${PACKAGE_PREFIX_DIR}) set(msgpack_ROOT ${PACKAGE_PREFIX_DIR})
endif() endif()
@@ -94,6 +118,7 @@ if(BUILD_DOCS)
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_GIT_VERSION}) set(DOXYGEN_PROJECT_NUMBER ${PROJECT_GIT_VERSION})
set(DOXYGEN_PROJECT_BRIEF "C++ Message Passing Framework") set(DOXYGEN_PROJECT_BRIEF "C++ Message Passing Framework")
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md) set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md)
set(DOXYGEN_HTML_FOOTER docs/footer.html)
doxygen_add_docs(doxygen README.md fairmq) doxygen_add_docs(doxygen README.md fairmq)
add_custom_target(docs ALL DEPENDS doxygen) add_custom_target(docs ALL DEPENDS doxygen)
endif() endif()
@@ -161,6 +186,29 @@ install_cmake_package()
# Summary ###################################################################### # 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) if(PROJECT_PACKAGE_DEPENDENCIES)
message(STATUS " ") message(STATUS " ")
message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}") message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}")

View File

@@ -2,6 +2,7 @@ Aphecetche, Laurent
Binet, Sebastien Binet, Sebastien
Eulisse, Giulio Eulisse, Giulio
Karabowicz, Radoslaw Karabowicz, Radoslaw
Kretz, Matthias <kretz@kde.org>
Krzewicki, Mikolaj Krzewicki, Mikolaj
Neskovic, Gvozden Neskovic, Gvozden
Richter, Matthias Richter, Matthias

41
COPYRIGHT Normal file
View 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.

26
Dart.sh
View File

@@ -41,13 +41,15 @@ if [ "$#" -lt "2" ]; then
fi fi
# test if a valid ctest model is defined # 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 case "$1" in
echo "" Experimental|Nightly|Continuous|Profile|alfa_ci|codecov)
else ;;
*)
echo "-- Error -- This ctest model is not supported." echo "-- Error -- This ctest model is not supported."
echo "-- Error -- Possible arguments are Nightly, Experimental, Continuous or Profile." echo "-- Error -- Possible arguments are Nightly, Experimental, Continuous or Profile."
exit 1 exit 1
fi ;;
esac
# test if the input file exists and execute it # test if the input file exists and execute it
if [ -e "$2" ];then if [ -e "$2" ];then
@@ -61,6 +63,9 @@ fi
# set the ctest model to command line parameter # set the ctest model to command line parameter
if [ "$1" == "alfa_ci" ]; then if [ "$1" == "alfa_ci" ]; then
export ctest_model=Experimental export ctest_model=Experimental
elif [ "$1" == "codecov" ]; then
export ctest_model=Profile
export do_codecov_upload=1
else else
export ctest_model=$1 export ctest_model=$1
fi fi
@@ -83,13 +88,20 @@ else
COMPILER=$CXX$($CXX -dumpversion) COMPILER=$CXX$($CXX -dumpversion)
fi fi
if [ "$1" == "alfa_ci" ]; then case "$1" in
alfa_ci)
export LABEL1=alfa_ci-$COMPILER-FairMQ_$GIT_BRANCH export LABEL1=alfa_ci-$COMPILER-FairMQ_$GIT_BRANCH
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g') export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
else ;;
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 LABEL1=${LINUX_FLAVOUR}-$chip-$COMPILER-FairMQ_$GIT_BRANCH
export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g') export LABEL=$(echo $LABEL1 | sed -e 's#/#_#g')
fi ;;
esac
# get the number of processors # get the number of processors
# and information about the host # and information about the host

View File

@@ -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};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON") Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON")
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=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}) Set(EXTRA_FLAGS $ENV{EXTRA_FLAGS})
If(EXTRA_FLAGS) If(EXTRA_FLAGS)
Set(configure_options "${configure_options};${EXTRA_FLAGS}") Set(configure_options "${configure_options};${EXTRA_FLAGS}")
EndIf() EndIf()
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile) If($ENV{ctest_model} MATCHES Profile)
Find_Program(GCOV_COMMAND gcov) Find_Program(GCOV_COMMAND gcov)
If(GCOV_COMMAND) If(GCOV_COMMAND)
Message("Found GCOV: ${GCOV_COMMAND}") Message("Found GCOV: ${GCOV_COMMAND}")
Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND}) Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND})
EndIf(GCOV_COMMAND) EndIf(GCOV_COMMAND)
EndIf()
Set(ENV{ctest_model} Nightly) If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
Ctest_Empty_Binary_Directory(${CTEST_BINARY_DIRECTORY})
CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
EndIf() EndIf()
Ctest_Start($ENV{ctest_model}) Ctest_Start($ENV{ctest_model})
@@ -60,9 +60,26 @@ Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL $ENV{number_of_processors} PARALLEL_LEVEL $ENV{number_of_processors}
RETURN_VALUE _ctest_test_ret_val 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) 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() EndIf()
Ctest_Submit() Ctest_Submit()

40
Jenkinsfile vendored
View File

@@ -4,24 +4,31 @@ def specToLabel(Map spec) {
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}" 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 = [:] def nodes = [:]
for (spec in specs) { for (spec in specs) {
def label = specToLabel(spec) def label = specToLabel(spec)
nodes[label] = { nodes["${prefix}/${label}"] = {
node(label) { node(label) {
githubNotify(context: "alfa-ci/${label}", description: 'Building ...', status: 'PENDING') githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
try { try {
deleteDir() deleteDir()
checkout scm 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) callback.call(spec, label)
deleteDir() deleteDir()
githubNotify(context: "alfa-ci/${label}", description: 'Success', status: 'SUCCESS') githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
} catch (e) { } catch (e) {
deleteDir() deleteDir()
githubNotify(context: "alfa-ci/${label}", description: 'Error', status: 'ERROR') githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
throw e throw e
} }
} }
@@ -33,22 +40,25 @@ def buildMatrix(List specs, Closure callback) {
pipeline{ pipeline{
agent none agent none
stages { stages {
stage("Run Build/Test Matrix") { stage("Run CI Matrix") {
steps{ steps{
script { script {
parallel(buildMatrix([ def build_jobs = jobMatrix('alfa-ci/build', [
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'], [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'], [os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
]) { spec, label -> ]) { 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' 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)
} }
} }
} }

View File

@@ -1,12 +1,14 @@
<!-- {#mainpage} --> <!-- {#mainpage} -->
# FairMQ # FairMQ [![license](https://alfa-ci.gsi.de/shields/github/license/FairRootGroup/FairMQ.svg)](COPYRIGHT)
C++ Message passing framework C++ Message Queuing Library and Framework
| Branch | Build Status | | Branch | Version | Docs | Status |
| :---: | :--- | | :---: | :--- | :--- | :--- |
| `master` | ![build status master branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/master) | | `master` | [![release](https://alfa-ci.gsi.de/shields/github/release/FairRootGroup/FairMQ.svg)](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) | [![build status master branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/master)](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [![test coverage master branch](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master/graph/badge.svg)](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) |
| `dev` | ![build status dev branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/dev) | | `dev` | [![dev tag](https://alfa-ci.gsi.de/shields/github/tag/FairRootGroup/FairMQ.svg)](https://github.com/FairRootGroup/FairMQ/tags) | [Book](https://github.com/FairRootGroup/FairMQ/blob/dev/README.md#documentation) | [![build status dev branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/dev)](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [![test coverage dev branch](https://codecov.io/gh/FairRootGroup/FairMQ/branch/dev/graph/badge.svg)](https://codecov.io/gh/FairRootGroup/FairMQ/branch/dev) |
## 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 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, * provide **an asynchronous message passing abstraction** of different data transport technologies,
@@ -29,32 +31,17 @@ configuration and control services.
FairMQ has been developed in the context of its mother project [FairRoot](https://github.com/FairRootGroup/FairRoot) - FairMQ has been developed in the context of its mother project [FairRoot](https://github.com/FairRootGroup/FairRoot) -
a simulation, reconstruction and analysis framework. a simulation, reconstruction and analysis framework.
Find all FairMQ releases and development tags [here](https://github.com/FairRootGroup/FairMQ/releases).
## Dependencies ## Dependencies
* [**Boost**](https://www.boost.org/) (PUBLIC) * PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger)
* [**FairLogger**](https://github.com/FairRootGroup/FairLogger) (PUBLIC) * BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/)
* [CMake](https://cmake.org/) (BUILD) * PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/),
* [GTest](https://github.com/google/googletest) (BUILD, optional, `tests`) [OFI](https://ofiwg.github.io/libfabric/), [Protobuf](https://developers.google.com/protocol-buffers/), [DDS](http://dds.gsi.de)
* [Doxygen](http://www.doxygen.org/) (BUILD, optional, `docs`)
* [ZeroMQ](http://zeromq.org/) (PRIVATE)
* [Msgpack](https://msgpack.org/index.html) (PRIVATE, optional, `nanomsg_transport`)
* [nanomsg](http://nanomsg.org/) (PRIVATE, optional, `nanomsg_transport`)
* [OFI](https://ofiwg.github.io/libfabric/) (PRIVATE, optional, `ofi_transport`)
* [Protobuf](https://developers.google.com/protocol-buffers/) (PRIVATE, optional, `ofi_transport`)
* [DDS](http://dds.gsi.de) (PRIVATE, optional, `dds_plugin`)
Supported platforms: Linux and MacOS. 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 ## Installation from Source
```bash ```bash
@@ -89,7 +76,7 @@ In order to succesfully compile and link against the `FairMQ::FairMQ` target, yo
find_package(FairMQ) find_package(FairMQ)
if(FairMQ_FOUND) if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION}) 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() 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) find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin)
if(FairMQ_FOUND) if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION}) 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() 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) 4. [File output](docs/Logging.md#54-file-output)
5. [Custom sinks](docs/Logging.md#55-custom-sinks) 5. [Custom sinks](docs/Logging.md#55-custom-sinks)
6. [Examples](docs/Examples.md#6-examples) 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

View File

@@ -112,7 +112,6 @@ macro(set_fairmq_defaults)
set(CMAKE_BUILD_TYPE RelWithDebInfo) set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif() endif()
# Handle C++ standard level # Handle C++ standard level
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_CXX_STANDARD) if(NOT CMAKE_CXX_STANDARD)
@@ -158,9 +157,23 @@ macro(set_fairmq_defaults)
# Define export set, only one for now # Define export set, only one for now
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets) set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
# Override CMake defaults # Configure build types
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "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_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
set(CMAKE_CXX_FLAGS_PROFILE "-g3 -fno-inline -ftest-coverage -fprofile-arcs -Wshadow -Wall -Wextra -Wunused-variable") set(CMAKE_CXX_FLAGS_PROFILE "-g3 -Wshadow -Wall -Wextra -fno-inline -ftest-coverage -fprofile-arcs")
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()
endmacro() endmacro()
function(join VALUES GLUE OUTPUT) function(join VALUES GLUE OUTPUT)
@@ -237,7 +250,7 @@ endfunction()
macro(install_cmake_package) macro(install_cmake_package)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
set(PACKAGE_INSTALL_DESTINATION set(PACKAGE_INSTALL_DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION} ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_GIT_VERSION}
) )
if(BUILD_FAIRMQ) if(BUILD_FAIRMQ)
install(EXPORT ${PROJECT_EXPORT_SET} install(EXPORT ${PROJECT_EXPORT_SET}
@@ -280,6 +293,7 @@ macro(find_package2 qualifier pkgname)
set(CMAKE_PREFIX_PATH ${old_CPP}) set(CMAKE_PREFIX_PATH ${old_CPP})
unset(old_CPP) unset(old_CPP)
if(${pkgname}_FOUND)
if(${qualifier} STREQUAL PRIVATE) if(${qualifier} STREQUAL PRIVATE)
set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION}) set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION})
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS}) set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
@@ -296,4 +310,5 @@ macro(find_package2 qualifier pkgname)
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS}) set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname}) set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
endif() endif()
endif()
endmacro() endmacro()

46
cmake/Findmsgpack.cmake Normal file
View File

@@ -0,0 +1,46 @@
################################################################################
# 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" #
################################################################################
unset(_args)
if(msgpack_FIND_VERSION)
list(APPEND _args ${msgpack_FIND_VERSION})
endif()
if(msgpack_FIND_EXACT)
list(APPEND _args "EXACT")
endif()
if(msgpack_FIND_QUIETLY)
list(APPEND _args "QUIET")
endif()
if(msgpack_FIND_REQUIRED)
list(APPEND _args "REQUIRED")
endif()
if(msgpack_FIND_COMPONENTS)
list(APPEND _args "COMPONENTS" ${msgpack_FIND_COMPONENTS})
endif()
find_package(msgpack ${_args} CONFIG)
if(msgpack_FOUND AND NOT TARGET msgpack::msgpack)
# config mode find_package does not set $msgpack_ROOT, workaround by extracting
# root path from library target
unset(_msgpack_lib)
unset(_prefix)
get_target_property(_msgpack_lib msgpackc INTERFACE_LOCATION)
get_filename_component(_prefix ${_msgpack_lib} DIRECTORY)
get_filename_component(_prefix ${_prefix}/.. ABSOLUTE)
add_library(msgpack::msgpack INTERFACE IMPORTED)
set_target_properties(msgpack::msgpack PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${_prefix}/include"
)
endif()

4190
cmake/cotire.cmake Normal file

File diff suppressed because it is too large Load Diff

1
docs/footer.html Normal file
View File

@@ -0,0 +1 @@
<p style="margin: 0 12px 10px 12px;"><a href="https://help.github.com/articles/github-privacy-statement/">privacy</a></p>

View File

@@ -34,8 +34,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-1.sh.in ${CMAKE_CURRENT_BIN
add_test(NAME Example-1-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq) add_test(NAME Example-1-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
set_tests_properties(Example-1-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") set_tests_properties(Example-1-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
add_test(NAME Example-1-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") add_test(NAME Example-1-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
endif()
add_test(NAME Example-1-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem) add_test(NAME Example-1-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
set_tests_properties(Example-1-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") set_tests_properties(Example-1-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")

View File

@@ -42,8 +42,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-n-1.sh.in ${CMAKE_CURRENT_B
add_test(NAME Example-1-n-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq) add_test(NAME Example-1-n-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
set_tests_properties(Example-1-n-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") set_tests_properties(Example-1-n-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
add_test(NAME Example-1-n-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") add_test(NAME Example-1-n-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
endif()
add_test(NAME Example-1-n-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem) add_test(NAME Example-1-n-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
set_tests_properties(Example-1-n-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ") set_tests_properties(Example-1-n-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")

View File

@@ -12,6 +12,8 @@ add_subdirectory(copypush)
add_subdirectory(dds) add_subdirectory(dds)
add_subdirectory(multipart) add_subdirectory(multipart)
add_subdirectory(multiple-channels) add_subdirectory(multiple-channels)
add_subdirectory(multiple-transports) if(BUILD_NANOMSG_TRANSPORT)
add_subdirectory(multiple-transports)
endif()
add_subdirectory(region) add_subdirectory(region)
add_subdirectory(req-rep) add_subdirectory(req-rep)

View File

@@ -35,8 +35,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-copypush.sh.in ${CMAKE_CURREN
add_test(NAME Example-CopyPush-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq) add_test(NAME Example-CopyPush-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
set_tests_properties(Example-CopyPush-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ") set_tests_properties(Example-CopyPush-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
add_test(NAME Example-CopyPush-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ") add_test(NAME Example-CopyPush-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
endif()
add_test(NAME Example-CopyPush-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem) add_test(NAME Example-CopyPush-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
set_tests_properties(Example-CopyPush-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ") set_tests_properties(Example-CopyPush-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")

View File

@@ -34,8 +34,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRE
add_test(NAME Example-Multipart-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq) add_test(NAME Example-Multipart-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
set_tests_properties(Example-Multipart-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts") set_tests_properties(Example-Multipart-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
add_test(NAME Example-Multipart-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts") add_test(NAME Example-Multipart-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
endif()
add_test(NAME Example-Multipart-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem) add_test(NAME Example-Multipart-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
set_tests_properties(Example-Multipart-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts") set_tests_properties(Example-Multipart-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")

View File

@@ -39,8 +39,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-channels.sh.in ${CMA
add_test(NAME Example-Multiple-Channels-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq) add_test(NAME Example-Multiple-Channels-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
set_tests_properties(Example-Multiple-Channels-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.") set_tests_properties(Example-Multiple-Channels-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
add_test(NAME Example-Multiple-Channels-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-Multiple-Channels-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.") add_test(NAME Example-Multiple-Channels-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
set_tests_properties(Example-Multiple-Channels-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
endif()
# install # install

View File

@@ -23,8 +23,6 @@ Sink::Sink()
: fMaxIterations(0) : fMaxIterations(0)
, fNumIterations1(0) , fNumIterations1(0)
, fNumIterations2(0) , fNumIterations2(0)
, fReceived1(false)
, fReceived2(false)
{ {
// register a handler for data arriving on "data" channel // register a handler for data arriving on "data" channel
OnData("data1", &Sink::HandleData1); OnData("data1", &Sink::HandleData1);

View File

@@ -36,8 +36,6 @@ class Sink : public FairMQDevice
uint64_t fMaxIterations; uint64_t fMaxIterations;
uint64_t fNumIterations1; uint64_t fNumIterations1;
uint64_t fNumIterations2; uint64_t fNumIterations2;
bool fReceived1;
bool fReceived2;
}; };
} // namespace example_multiple_transports } // namespace example_multiple_transports

View File

@@ -24,4 +24,4 @@ SINK+=" --transport shmem"
SINK+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:5555" SINK+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:5555"
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=nanomsg" SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=nanomsg"
SINK+=" name=ack,type=pub,method=connect,address=tcp://127.0.0.1:5557,transport=zeromq" SINK+=" name=ack,type=pub,method=connect,address=tcp://127.0.0.1:5557,transport=zeromq"
xterm -geometry 80x30+500+0 -hold -e @EX_BIN_DIR@/$SINK & xterm -geometry 80x30+500+225 -hold -e @EX_BIN_DIR@/$SINK &

View File

@@ -35,8 +35,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-region.sh.in ${CMAKE_CURRENT_
add_test(NAME Example-Region-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq) add_test(NAME Example-Region-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
set_tests_properties(Example-Region-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack") set_tests_properties(Example-Region-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
add_test(NAME Example-Region-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack") add_test(NAME Example-Region-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
endif()
add_test(NAME Example-Region-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem) add_test(NAME Example-Region-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
set_tests_properties(Example-Region-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack") set_tests_properties(Example-Region-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")

View File

@@ -38,7 +38,7 @@ void Sampler::InitTask()
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data", fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
0, 0,
10000000, 10000000,
[this](void* data, size_t size, void* hint) { // callback to be called when message buffers no longer needed by transport [this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
--fNumUnackedMsgs; --fNumUnackedMsgs;
if (fMaxIterations > 0) if (fMaxIterations > 0)
{ {

View File

@@ -35,8 +35,10 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-req-rep.sh.in ${CMAKE_CURRENT
add_test(NAME Example-ReqRep-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq) add_test(NAME Example-ReqRep-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
set_tests_properties(Example-ReqRep-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ") set_tests_properties(Example-ReqRep-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
add_test(NAME Example-ReqRep-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg) if(BUILD_NANOMSG_TRANSPORT)
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ") add_test(NAME Example-ReqRep-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
endif()
add_test(NAME Example-ReqRep-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem) add_test(NAME Example-ReqRep-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
set_tests_properties(Example-ReqRep-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ") set_tests_properties(Example-ReqRep-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")

View File

@@ -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
...

View File

@@ -37,7 +37,7 @@ endif()
########################## ##########################
# libFairMQ header files # # libFairMQ header files #
########################## ##########################
set(FAIRMQ_HEADER_FILES set(FAIRMQ_PUBLIC_HEADER_FILES
DeviceRunner.h DeviceRunner.h
EventManager.h EventManager.h
FairMQChannel.h FairMQChannel.h
@@ -52,6 +52,21 @@ set(FAIRMQ_HEADER_FILES
FairMQTransportFactory.h FairMQTransportFactory.h
Tools.h Tools.h
Transports.h Transports.h
options/FairMQProgOptions.h
options/FairProgOptions.h
Plugin.h
PluginManager.h
PluginServices.h
runFairMQDevice.h
tools/CppSTL.h
tools/Network.h
tools/Process.h
tools/Strings.h
tools/Unique.h
tools/Version.h
)
set(FAIRMQ_PRIVATE_HEADER_FILES
devices/FairMQBenchmarkSampler.h devices/FairMQBenchmarkSampler.h
devices/FairMQMerger.h devices/FairMQMerger.h
devices/FairMQMultiplier.h devices/FairMQMultiplier.h
@@ -59,16 +74,10 @@ set(FAIRMQ_HEADER_FILES
devices/FairMQSink.h devices/FairMQSink.h
devices/FairMQSplitter.h devices/FairMQSplitter.h
options/FairMQParser.h options/FairMQParser.h
options/FairMQProgOptions.h
options/FairMQSuboptParser.h options/FairMQSuboptParser.h
options/FairProgOptions.h
options/FairProgOptionsHelper.h options/FairProgOptionsHelper.h
Plugin.h
PluginManager.h
PluginServices.h
plugins/Builtin.h plugins/Builtin.h
plugins/Control.h plugins/Control.h
runFairMQDevice.h
StateMachine.h StateMachine.h
shmem/FairMQMessageSHM.h shmem/FairMQMessageSHM.h
shmem/FairMQPollerSHM.h shmem/FairMQPollerSHM.h
@@ -79,12 +88,6 @@ set(FAIRMQ_HEADER_FILES
shmem/Manager.h shmem/Manager.h
shmem/Monitor.h shmem/Monitor.h
shmem/Region.h shmem/Region.h
tools/CppSTL.h
tools/Network.h
tools/Process.h
tools/Strings.h
tools/Unique.h
tools/Version.h
zeromq/FairMQMessageZMQ.h zeromq/FairMQMessageZMQ.h
zeromq/FairMQPollerZMQ.h zeromq/FairMQPollerZMQ.h
zeromq/FairMQUnmanagedRegionZMQ.h zeromq/FairMQUnmanagedRegionZMQ.h
@@ -93,7 +96,7 @@ set(FAIRMQ_HEADER_FILES
) )
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_HEADER_FILES ${FAIRMQ_HEADER_FILES} set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
nanomsg/FairMQMessageNN.h nanomsg/FairMQMessageNN.h
nanomsg/FairMQPollerNN.h nanomsg/FairMQPollerNN.h
nanomsg/FairMQUnmanagedRegionNN.h nanomsg/FairMQUnmanagedRegionNN.h
@@ -103,7 +106,7 @@ if(BUILD_NANOMSG_TRANSPORT)
endif() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_HEADER_FILES ${FAIRMQ_HEADER_FILES} set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
ofi/Context.h ofi/Context.h
ofi/Message.h ofi/Message.h
ofi/Poller.h ofi/Poller.h
@@ -129,12 +132,10 @@ set(FAIRMQ_SOURCE_FILES
devices/FairMQMerger.cxx devices/FairMQMerger.cxx
devices/FairMQMultiplier.cxx devices/FairMQMultiplier.cxx
devices/FairMQProxy.cxx devices/FairMQProxy.cxx
# devices/FairMQSink.cxx
devices/FairMQSplitter.cxx devices/FairMQSplitter.cxx
options/FairMQParser.cxx options/FairMQParser.cxx
options/FairMQProgOptions.cxx options/FairMQProgOptions.cxx
options/FairMQSuboptParser.cxx options/FairMQSuboptParser.cxx
options/FairProgOptions.cxx
Plugin.cxx Plugin.cxx
PluginManager.cxx PluginManager.cxx
PluginServices.cxx PluginServices.cxx
@@ -190,15 +191,25 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/options/startConfigExample.sh.in ${CM
################################# #################################
# define libFairMQ build target # # define libFairMQ build target #
################################# #################################
add_library(FairMQ SHARED if(FAST_BUILD)
set(_target FairMQ_)
else()
set(_target FairMQ)
endif()
add_library(${_target} SHARED
${FAIRMQ_SOURCE_FILES} ${FAIRMQ_SOURCE_FILES}
${FAIRMQ_HEADER_FILES} # for IDE integration ${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 # # include directories #
####################### #######################
target_include_directories(FairMQ target_include_directories(${_target}
PUBLIC # consumers inherit public include directories PUBLIC # consumers inherit public include directories
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
@@ -211,15 +222,21 @@ target_include_directories(FairMQ
# link libraries # # link libraries #
################## ##################
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
set(NANOMSG_DEPS nanomsg msgpackc) set(NANOMSG_DEPS nanomsg msgpack::msgpack)
endif() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>) set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>)
endif() endif()
target_link_libraries(FairMQ set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
if(optional_deps)
list(REMOVE_DUPLICATES optional_deps)
endif()
target_link_libraries(${_target}
INTERFACE # only consumers link against interface dependencies INTERFACE # only consumers link against interface dependencies
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
Threads::Threads
dl dl
Boost::boost Boost::boost
Boost::program_options Boost::program_options
@@ -236,15 +253,30 @@ target_link_libraries(FairMQ
${NANOMSG_DEPS} ${NANOMSG_DEPS}
${OFI_DEPS} ${OFI_DEPS}
) )
set_target_properties(FairMQ PROPERTIES set_target_properties(${_target} PROPERTIES
VERSION ${PROJECT_VERSION} VERSION ${PROJECT_GIT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" 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 # # executables #
############### ###############
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx) add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
target_link_libraries(fairmq-bsampler FairMQ) target_link_libraries(fairmq-bsampler FairMQ)
@@ -272,11 +304,12 @@ target_link_libraries(fairmq-shmmonitor FairMQ)
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx) add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen FairMQ) target_link_libraries(fairmq-uuid-gen FairMQ)
########### ###########
# install # # install #
########### ###########
install( install(
TARGETS # FairMQFull, tests are not installed TARGETS
FairMQ FairMQ
fairmq-bsampler fairmq-bsampler
fairmq-merger fairmq-merger
@@ -288,12 +321,12 @@ install(
fairmq-uuid-gen fairmq-uuid-gen
EXPORT ${PROJECT_EXPORT_SET} EXPORT ${PROJECT_EXPORT_SET}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR} RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
) )
# preserve relative path and prepend fairmq # preserve relative path and prepend fairmq
foreach(HEADER ${FAIRMQ_HEADER_FILES}) foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY) get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination) file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER} install(FILES ${HEADER}

View File

@@ -13,11 +13,12 @@
using namespace fair::mq; using namespace fair::mq;
DeviceRunner::DeviceRunner(int argc, char* const argv[]) DeviceRunner::DeviceRunner(int argc, char* const argv[])
: fRawCmdLineArgs{tools::ToStrVector(argc, argv, false)} : fRawCmdLineArgs(tools::ToStrVector(argc, argv, false))
, fPluginManager{PluginManager::MakeFromCommandLineOptions(fRawCmdLineArgs)} , fConfig()
, fDevice{nullptr} , fDevice(nullptr)
{ , fPluginManager(fRawCmdLineArgs)
} , fEvents()
{}
auto DeviceRunner::Run() -> int auto DeviceRunner::Run() -> int
{ {
@@ -26,16 +27,16 @@ auto DeviceRunner::Run() -> int
//////////////////////// ////////////////////////
// Load builtin plugins last // Load builtin plugins last
fPluginManager->LoadPlugin("s:control"); fPluginManager.LoadPlugin("s:control");
////// CALL HOOK /////// ////// CALL HOOK ///////
fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this); fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this);
//////////////////////// ////////////////////////
fPluginManager->ForEachPluginProgOptions([&](boost::program_options::options_description options){ fPluginManager.ForEachPluginProgOptions([&](boost::program_options::options_description options){
fConfig.AddToCmdLineOptions(options); fConfig.AddToCmdLineOptions(options);
}); });
fConfig.AddToCmdLineOptions(fPluginManager->ProgramOptions()); fConfig.AddToCmdLineOptions(fPluginManager.ProgramOptions());
////// CALL HOOK /////// ////// CALL HOOK ///////
fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this); fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this);
@@ -56,6 +57,8 @@ auto DeviceRunner::Run() -> int
return 1; return 1;
} }
fDevice->SetRawCmdLineArgs(fRawCmdLineArgs);
// Handle --print-channels // Handle --print-channels
fDevice->RegisterChannelEndpoints(); fDevice->RegisterChannelEndpoints();
if (fConfig.Count("print-channels")) if (fConfig.Count("print-channels"))
@@ -80,13 +83,16 @@ auto DeviceRunner::Run() -> int
fDevice->SetConfig(fConfig); fDevice->SetConfig(fConfig);
// Initialize plugin services // Initialize plugin services
fPluginManager->EmplacePluginServices(&fConfig, fDevice); fPluginManager.EmplacePluginServices(fConfig, *fDevice);
// Instantiate and run plugins // Instantiate and run plugins
fPluginManager->InstantiatePlugins(); fPluginManager.InstantiatePlugins();
// Run the device
fDevice->RunStateMachine();
// Wait for control plugin to release device control // Wait for control plugin to release device control
fPluginManager->WaitForPluginsToReleaseDeviceControl(); fPluginManager.WaitForPluginsToReleaseDeviceControl();
return 0; return 0;
} }

View File

@@ -62,9 +62,9 @@ class DeviceRunner
auto RemoveHook() -> void { fEvents.Unsubscribe<H>("runner"); } auto RemoveHook() -> void { fEvents.Unsubscribe<H>("runner"); }
std::vector<std::string> fRawCmdLineArgs; std::vector<std::string> fRawCmdLineArgs;
std::shared_ptr<PluginManager> fPluginManager;
FairMQProgOptions fConfig; FairMQProgOptions fConfig;
std::shared_ptr<FairMQDevice> fDevice; std::unique_ptr<FairMQDevice> fDevice;
PluginManager fPluginManager;
private: private:
EventManager fEvents; EventManager fEvents;

View File

@@ -28,6 +28,7 @@ FairMQChannel::FairMQChannel()
, fType("unspecified") , fType("unspecified")
, fMethod("unspecified") , fMethod("unspecified")
, fAddress("unspecified") , fAddress("unspecified")
, fTransportType(fair::mq::Transport::DEFAULT)
, fSndBufSize(1000) , fSndBufSize(1000)
, fRcvBufSize(1000) , fRcvBufSize(1000)
, fSndKernelSize(0) , fSndKernelSize(0)
@@ -35,7 +36,6 @@ FairMQChannel::FairMQChannel()
, fRateLogging(1) , fRateLogging(1)
, fName("") , fName("")
, fIsValid(false) , fIsValid(false)
, fTransportType(fair::mq::Transport::DEFAULT)
, fTransportFactory(nullptr) , fTransportFactory(nullptr)
, fMultipart(false) , fMultipart(false)
, fModified(true) , fModified(true)
@@ -48,6 +48,7 @@ FairMQChannel::FairMQChannel(const string& type, const string& method, const str
, fType(type) , fType(type)
, fMethod(method) , fMethod(method)
, fAddress(address) , fAddress(address)
, fTransportType(fair::mq::Transport::DEFAULT)
, fSndBufSize(1000) , fSndBufSize(1000)
, fRcvBufSize(1000) , fRcvBufSize(1000)
, fSndKernelSize(0) , fSndKernelSize(0)
@@ -55,7 +56,6 @@ FairMQChannel::FairMQChannel(const string& type, const string& method, const str
, fRateLogging(1) , fRateLogging(1)
, fName("") , fName("")
, fIsValid(false) , fIsValid(false)
, fTransportType(fair::mq::Transport::DEFAULT)
, fTransportFactory(nullptr) , fTransportFactory(nullptr)
, fMultipart(false) , fMultipart(false)
, fModified(true) , fModified(true)
@@ -68,6 +68,7 @@ FairMQChannel::FairMQChannel(const string& name, const string& type, std::shared
, fType(type) , fType(type)
, fMethod("unspecified") , fMethod("unspecified")
, fAddress("unspecified") , fAddress("unspecified")
, fTransportType(factory->GetType())
, fSndBufSize(1000) , fSndBufSize(1000)
, fRcvBufSize(1000) , fRcvBufSize(1000)
, fSndKernelSize(0) , fSndKernelSize(0)
@@ -75,7 +76,6 @@ FairMQChannel::FairMQChannel(const string& name, const string& type, std::shared
, fRateLogging(1) , fRateLogging(1)
, fName(name) , fName(name)
, fIsValid(false) , fIsValid(false)
, fTransportType(factory->GetType())
, fTransportFactory(factory) , fTransportFactory(factory)
, fMultipart(false) , fMultipart(false)
, fModified(true) , fModified(true)
@@ -88,6 +88,7 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
, fType(chan.fType) , fType(chan.fType)
, fMethod(chan.fMethod) , fMethod(chan.fMethod)
, fAddress(chan.fAddress) , fAddress(chan.fAddress)
, fTransportType(chan.fTransportType)
, fSndBufSize(chan.fSndBufSize) , fSndBufSize(chan.fSndBufSize)
, fRcvBufSize(chan.fRcvBufSize) , fRcvBufSize(chan.fRcvBufSize)
, fSndKernelSize(chan.fSndKernelSize) , fSndKernelSize(chan.fSndKernelSize)
@@ -95,7 +96,6 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
, fRateLogging(chan.fRateLogging) , fRateLogging(chan.fRateLogging)
, fName(chan.fName) , fName(chan.fName)
, fIsValid(false) , fIsValid(false)
, fTransportType(chan.fTransportType)
, fTransportFactory(nullptr) , fTransportFactory(nullptr)
, fMultipart(chan.fMultipart) , fMultipart(chan.fMultipart)
, fModified(chan.fModified) , fModified(chan.fModified)
@@ -327,9 +327,7 @@ void FairMQChannel::UpdateTransport(const string& transport)
{ {
unique_lock<mutex> lock(fChannelMutex); unique_lock<mutex> lock(fChannelMutex);
fIsValid = false; fIsValid = false;
LOG(WARN) << fName << ": " << transport;
fTransportType = fair::mq::TransportTypes.at(transport); fTransportType = fair::mq::TransportTypes.at(transport);
LOG(WARN) << fName << ": " << fair::mq::TransportNames.at(fTransportType);
fModified = true; fModified = true;
} }
catch (exception& e) catch (exception& e)
@@ -501,7 +499,7 @@ bool FairMQChannel::ValidateChannel()
else else
{ {
vector<string> endpoints; 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) for (const auto endpoint : endpoints)
{ {
string address; string address;
@@ -655,13 +653,13 @@ void FairMQChannel::ResetChannel()
int FairMQChannel::Send(unique_ptr<FairMQMessage>& msg) const int FairMQChannel::Send(unique_ptr<FairMQMessage>& msg) const
{ {
CheckCompatibility(msg); CheckSendCompatibility(msg);
return fSocket->Send(msg); return fSocket->Send(msg);
} }
int FairMQChannel::Receive(unique_ptr<FairMQMessage>& msg) const int FairMQChannel::Receive(unique_ptr<FairMQMessage>& msg) const
{ {
CheckCompatibility(msg); CheckReceiveCompatibility(msg);
return fSocket->Receive(msg); return fSocket->Receive(msg);
} }
@@ -677,25 +675,25 @@ int FairMQChannel::Receive(unique_ptr<FairMQMessage>& msg, int rcvTimeoutInMs) c
int FairMQChannel::SendAsync(unique_ptr<FairMQMessage>& msg) const int FairMQChannel::SendAsync(unique_ptr<FairMQMessage>& msg) const
{ {
CheckCompatibility(msg); CheckSendCompatibility(msg);
return fSocket->TrySend(msg); return fSocket->TrySend(msg);
} }
int FairMQChannel::ReceiveAsync(unique_ptr<FairMQMessage>& msg) const int FairMQChannel::ReceiveAsync(unique_ptr<FairMQMessage>& msg) const
{ {
CheckCompatibility(msg); CheckReceiveCompatibility(msg);
return fSocket->TryReceive(msg); return fSocket->TryReceive(msg);
} }
int64_t FairMQChannel::Send(vector<unique_ptr<FairMQMessage>>& msgVec) const int64_t FairMQChannel::Send(vector<unique_ptr<FairMQMessage>>& msgVec) const
{ {
CheckCompatibility(msgVec); CheckSendCompatibility(msgVec);
return fSocket->Send(msgVec); return fSocket->Send(msgVec);
} }
int64_t FairMQChannel::Receive(vector<unique_ptr<FairMQMessage>>& msgVec) const int64_t FairMQChannel::Receive(vector<unique_ptr<FairMQMessage>>& msgVec) const
{ {
CheckCompatibility(msgVec); CheckReceiveCompatibility(msgVec);
return fSocket->Receive(msgVec); return fSocket->Receive(msgVec);
} }
@@ -711,7 +709,7 @@ int64_t FairMQChannel::Receive(vector<unique_ptr<FairMQMessage>>& msgVec, int rc
int64_t FairMQChannel::SendAsync(vector<unique_ptr<FairMQMessage>>& msgVec) const int64_t FairMQChannel::SendAsync(vector<unique_ptr<FairMQMessage>>& msgVec) const
{ {
CheckCompatibility(msgVec); CheckSendCompatibility(msgVec);
return fSocket->TrySend(msgVec); return fSocket->TrySend(msgVec);
} }
@@ -722,7 +720,7 @@ int64_t FairMQChannel::SendAsync(vector<unique_ptr<FairMQMessage>>& msgVec) cons
/// In case of errors, returns -1. /// In case of errors, returns -1.
int64_t FairMQChannel::ReceiveAsync(vector<unique_ptr<FairMQMessage>>& msgVec) const int64_t FairMQChannel::ReceiveAsync(vector<unique_ptr<FairMQMessage>>& msgVec) const
{ {
CheckCompatibility(msgVec); CheckReceiveCompatibility(msgVec);
return fSocket->TryReceive(msgVec); return fSocket->TryReceive(msgVec);
} }
@@ -750,44 +748,58 @@ unsigned long FairMQChannel::GetMessagesRx() const
return fSocket->GetMessagesRx(); return fSocket->GetMessagesRx();
} }
bool FairMQChannel::CheckCompatibility(unique_ptr<FairMQMessage>& msg) const void FairMQChannel::CheckSendCompatibility(FairMQMessagePtr& msg) const
{ {
if (fTransportType == msg->GetType()) if (fTransportType != msg->GetType())
{ {
return true; // LOG(debug) << "Channel type does not match message type. Creating wrapper";
} FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
else msg->GetSize(),
{ [](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
// LOG(warn) << "Channel type does not match message type. Copying..."; msg.get()
FairMQMessagePtr msgCopy(fTransportFactory->CreateMessage(msg->GetSize())); ));
memcpy(msgCopy->GetData(), msg->GetData(), msg->GetSize()); msg.release();
msg = move(msgCopy); msg = move(msgWrapper);
return false;
} }
} }
bool FairMQChannel::CheckCompatibility(vector<unique_ptr<FairMQMessage>>& msgVec) const void FairMQChannel::CheckSendCompatibility(vector<FairMQMessagePtr>& msgVec) const
{ {
bool match = true; for (auto& msg : msgVec)
if (msgVec.size() > 0)
{ {
for (unsigned int i = 0; i < msgVec.size(); ++i) if (fTransportType != msg->GetType())
{ {
if (fTransportType != msgVec.at(i)->GetType()) // LOG(debug) << "Channel type does not match message type. Creating wrapper";
{ FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
// LOG(warn) << "Channel type does not match message type. Copying..."; msg->GetSize(),
FairMQMessagePtr newMsg(fTransportFactory->CreateMessage(msgVec[i]->GetSize())); [](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
memcpy(newMsg->GetData(), msgVec[i]->GetData(), msgVec[i]->GetSize()); msg.get()
msgVec[i] = move(newMsg); ));
match = false; msg.release();
msg = move(msgWrapper);
}
}
}
void FairMQChannel::CheckReceiveCompatibility(FairMQMessagePtr& msg) const
{
if (fTransportType != msg->GetType())
{
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
void FairMQChannel::CheckReceiveCompatibility(vector<FairMQMessagePtr>& msgVec) const
{
for (auto& msg : msgVec)
{
if (fTransportType != msg->GetType())
{
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
} }
} }
}
else
{
return true;
}
return match;
} }

View File

@@ -20,6 +20,7 @@
#include <fairmq/Transports.h> #include <fairmq/Transports.h>
#include <FairMQLogger.h> #include <FairMQLogger.h>
#include <FairMQParts.h> #include <FairMQParts.h>
#include <FairMQMessage.h>
class FairMQChannel class FairMQChannel
{ {
@@ -165,8 +166,8 @@ class FairMQChannel
/// Resets the channel (requires validation to be used again). /// Resets the channel (requires validation to be used again).
void ResetChannel(); void ResetChannel();
int Send(std::unique_ptr<FairMQMessage>& msg) const; int Send(FairMQMessagePtr& msg) const;
int Receive(std::unique_ptr<FairMQMessage>& msg) const; int Receive(FairMQMessagePtr& msg) const;
/// Sends a message to the socket queue. /// Sends a message to the socket queue.
/// @details Send method attempts to send a message by /// @details Send method attempts to send a message by
@@ -176,7 +177,7 @@ class FairMQChannel
/// @param msg Constant reference of unique_ptr to a FairMQMessage /// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. /// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int Send(std::unique_ptr<FairMQMessage>& msg, int sndTimeoutInMs) const; int Send(FairMQMessagePtr& msg, int sndTimeoutInMs) const;
/// Receives a message from the socket queue. /// Receives a message from the socket queue.
/// @details Receive method attempts to receive a message from the input queue. /// @details Receive method attempts to receive a message from the input queue.
@@ -185,7 +186,7 @@ class FairMQChannel
/// @param msg Constant reference of unique_ptr to a FairMQMessage /// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out. /// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int Receive(std::unique_ptr<FairMQMessage>& msg, int rcvTimeoutInMs) const; int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs) const;
/// Sends a message in non-blocking mode. /// Sends a message in non-blocking mode.
/// @details SendAsync method attempts to send a message without blocking by /// @details SendAsync method attempts to send a message without blocking by
@@ -195,31 +196,31 @@ class FairMQChannel
/// @return Number of bytes that have been queued. If queueing failed due to /// @return Number of bytes that have been queued. If queueing failed due to
/// full queue or no connected peers (when binding), returns -2. /// full queue or no connected peers (when binding), returns -2.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int SendAsync(std::unique_ptr<FairMQMessage>& msg) const; int SendAsync(FairMQMessagePtr& msg) const;
/// Receives a message in non-blocking mode. /// Receives a message in non-blocking mode.
/// ///
/// @param msg Constant reference of unique_ptr to a FairMQMessage /// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @return Number of bytes that have been received. If queue is empty, returns -2. /// @return Number of bytes that have been received. If queue is empty, returns -2.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int ReceiveAsync(std::unique_ptr<FairMQMessage>& msg) const; int ReceiveAsync(FairMQMessagePtr& msg) const;
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const; int64_t Send(std::vector<FairMQMessagePtr>& msgVec) const;
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const; int64_t Receive(std::vector<FairMQMessagePtr>& msgVec) const;
/// Send a vector of messages /// Send a vector of messages
/// ///
/// @param msgVec message vector reference /// @param msgVec message vector reference
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. /// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int sndTimeoutInMs) const; int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs) const;
/// Receive a vector of messages /// Receive a vector of messages
/// ///
/// @param msgVec message vector reference /// @param msgVec message vector reference
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out. /// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int rcvTimeoutInMs) const; int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs) const;
/// Sends a vector of message in non-blocking mode. /// Sends a vector of message in non-blocking mode.
/// @details SendAsync method attempts to send a vector of messages without blocking by /// @details SendAsync method attempts to send a vector of messages without blocking by
@@ -228,14 +229,14 @@ class FairMQChannel
/// @param msgVec message vector reference /// @param msgVec message vector reference
/// @return Number of bytes that have been queued. If queueing failed due to /// @return Number of bytes that have been queued. If queueing failed due to
/// full queue or no connected peers (when binding), returns -2. In case of errors, returns -1. /// full queue or no connected peers (when binding), returns -2. In case of errors, returns -1.
int64_t SendAsync(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const; int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) const;
/// Receives a vector of messages in non-blocking mode. /// Receives a vector of messages in non-blocking mode.
/// ///
/// @param msgVec message vector reference /// @param msgVec message vector reference
/// @return Number of bytes that have been received. If queue is empty, returns -2. /// @return Number of bytes that have been received. If queue is empty, returns -2.
/// In case of errors, returns -1. /// In case of errors, returns -1.
int64_t ReceiveAsync(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const; int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) const;
int64_t Send(FairMQParts& parts) const int64_t Send(FairMQParts& parts) const
{ {
@@ -313,8 +314,10 @@ class FairMQChannel
std::shared_ptr<FairMQTransportFactory> fTransportFactory; std::shared_ptr<FairMQTransportFactory> fTransportFactory;
bool CheckCompatibility(std::unique_ptr<FairMQMessage>& msg) const; void CheckSendCompatibility(FairMQMessagePtr& msg) const;
bool CheckCompatibility(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const; void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
void CheckReceiveCompatibility(FairMQMessagePtr& msg) const;
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory); void InitTransport(std::shared_ptr<FairMQTransportFactory> factory);

View File

@@ -26,6 +26,8 @@
#include <thread> #include <thread>
#include <functional> #include <functional>
#include <sstream> #include <sstream>
#include <iomanip>
#include <algorithm> // std::max
using namespace std; using namespace std;
@@ -57,6 +59,7 @@ FairMQDevice::FairMQDevice()
, fVersion({0, 0, 0}) , fVersion({0, 0, 0})
, fRate(0.) , fRate(0.)
, fLastTime(0) , fLastTime(0)
, fRawCmdLineArgs()
{ {
} }
@@ -87,6 +90,7 @@ FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
, fVersion(version) , fVersion(version)
, fRate(0.) , fRate(0.)
, fLastTime(0) , fLastTime(0)
, fRawCmdLineArgs()
{ {
} }
@@ -144,7 +148,8 @@ void FairMQDevice::InitWrapper()
else else
{ {
LOG(error) << "Cannot update configuration. Socket method (bind/connect) not specified."; LOG(error) << "Cannot update configuration. Socket method (bind/connect) not specified.";
throw runtime_error("Cannot update configuration. Socket method (bind/connect) not specified."); ChangeState(ERROR_FOUND);
// throw runtime_error("Cannot update configuration. Socket method (bind/connect) not specified.");
} }
// } // }
} }
@@ -157,7 +162,8 @@ void FairMQDevice::InitWrapper()
if (uninitializedBindingChannels.size() > 0) if (uninitializedBindingChannels.size() > 0)
{ {
LOG(error) << uninitializedBindingChannels.size() << " of the binding channels could not initialize. Initial configuration incomplete."; LOG(error) << uninitializedBindingChannels.size() << " of the binding channels could not initialize. Initial configuration incomplete.";
throw runtime_error(fair::mq::tools::ToString(uninitializedBindingChannels.size(), " of the binding channels could not initialize. Initial configuration incomplete.")); ChangeState(ERROR_FOUND);
// throw runtime_error(fair::mq::tools::ToString(uninitializedBindingChannels.size(), " of the binding channels could not initialize. Initial configuration incomplete."));
} }
CallStateChangeCallbacks(INITIALIZING_DEVICE); CallStateChangeCallbacks(INITIALIZING_DEVICE);
@@ -196,7 +202,8 @@ void FairMQDevice::InitWrapper()
if (numAttempts++ > maxAttempts) if (numAttempts++ > maxAttempts)
{ {
LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts"; LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts";
throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts")); ChangeState(ERROR_FOUND);
// throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts"));
} }
AttachChannels(uninitializedConnectingChannels); AttachChannels(uninitializedConnectingChannels);
@@ -266,9 +273,17 @@ bool FairMQDevice::AttachChannel(FairMQChannel& ch)
{ {
//(re-)init socket //(re-)init socket
if (!ch.fSocket) if (!ch.fSocket)
{
try
{ {
ch.fSocket = ch.fTransportFactory->CreateSocket(ch.fType, ch.fName); ch.fSocket = ch.fTransportFactory->CreateSocket(ch.fType, ch.fName);
} }
catch (fair::mq::SocketError& se)
{
LOG(error) << se.what();
return false;
}
}
// set high water marks // set high water marks
ch.fSocket->SetOption("snd-hwm", &(ch.fSndBufSize), sizeof(ch.fSndBufSize)); ch.fSocket->SetOption("snd-hwm", &(ch.fSndBufSize), sizeof(ch.fSndBufSize));
@@ -501,7 +516,7 @@ void FairMQDevice::RunWrapper()
while (CheckCurrentState(RUNNING) && ConditionalRun()) while (CheckCurrentState(RUNNING) && ConditionalRun())
{ {
if (fRate > 0.001) { if (fRate > 0.001) {
auto timespan = chrono::duration_cast<TimeScale>(Clock::now() - reftime).count() - fLastTime; auto timespan = static_cast<TimeScale::rep>(chrono::duration_cast<TimeScale>(Clock::now() - reftime).count() - fLastTime);
if (timespan < period) { if (timespan < period) {
TimeScale sleepfor(period - timespan); TimeScale sleepfor(period - timespan);
this_thread::sleep_for(sleepfor); this_thread::sleep_for(sleepfor);
@@ -808,7 +823,7 @@ void FairMQDevice::CreateOwnConfig()
try { try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport")); fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} catch(const exception& e) { } catch(const exception& e) {
LOG(ERROR) << "invalid transport type provided: " << fConfig->GetValue<string>("transport"); LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
} }
} }
@@ -837,22 +852,22 @@ void FairMQDevice::SetConfig(FairMQProgOptions& config)
{ {
fExternalConfig = true; fExternalConfig = true;
fConfig = &config; fConfig = &config;
for (auto& c : config.GetFairMQMap()) for (auto& c : fConfig->GetFairMQMap())
{ {
if (!fChannels.insert(c).second) if (!fChannels.insert(c).second)
{ {
LOG(warn) << "did not insert channel '" << c.first << "', it is already in the device."; LOG(warn) << "did not insert channel '" << c.first << "', it is already in the device.";
} }
} }
fId = config.GetValue<string>("id"); fId = fConfig->GetValue<string>("id");
fNetworkInterface = config.GetValue<string>("network-interface"); fNetworkInterface = fConfig->GetValue<string>("network-interface");
fNumIoThreads = config.GetValue<int>("io-threads"); fNumIoThreads = fConfig->GetValue<int>("io-threads");
fInitializationTimeoutInS = config.GetValue<int>("initialization-timeout"); fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
fRate = fConfig->GetValue<float>("rate"); fRate = fConfig->GetValue<float>("rate");
try { try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport")); fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} catch(const exception& e) { } catch(const exception& e) {
LOG(ERROR) << "invalid transport type provided: " << fConfig->GetValue<string>("transport"); LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
} }
SetTransport(fConfig->GetValue<string>("transport")); SetTransport(fConfig->GetValue<string>("transport"));
} }
@@ -869,6 +884,8 @@ void FairMQDevice::LogSocketRates()
vector<int> logIntervals; vector<int> logIntervals;
vector<int> intervalCounters; vector<int> intervalCounters;
size_t chanNameLen = 0;
// iterate over the channels map // iterate over the channels map
for (const auto& mi : fChannels) for (const auto& mi : fChannels)
{ {
@@ -881,6 +898,7 @@ void FairMQDevice::LogSocketRates()
logIntervals.push_back(vi->fRateLogging); logIntervals.push_back(vi->fRateLogging);
intervalCounters.push_back(0); intervalCounters.push_back(0);
filteredChannelNames.push_back(fair::mq::tools::ToString(mi.first, "[", vi - (mi.second).begin(), "]")); filteredChannelNames.push_back(fair::mq::tools::ToString(mi.first, "[", vi - (mi.second).begin(), "]"));
chanNameLen = max(chanNameLen, filteredChannelNames.back().length());
} }
} }
} }
@@ -949,7 +967,7 @@ void FairMQDevice::LogSocketRates()
bytesOut.at(i) = bytesOutNew.at(i); bytesOut.at(i) = bytesOutNew.at(i);
msgOut.at(i) = msgOutNew.at(i); msgOut.at(i) = msgOutNew.at(i);
LOG(info) << filteredChannelNames.at(i) << ": " LOG(info) << setw(chanNameLen) << filteredChannelNames.at(i) << ": "
<< "in: " << msgPerSecIn.at(i) << " (" << mbPerSecIn.at(i) << " MB) " << "in: " << msgPerSecIn.at(i) << " (" << mbPerSecIn.at(i) << " MB) "
<< "out: " << msgPerSecOut.at(i) << " (" << mbPerSecOut.at(i) << " MB)"; << "out: " << msgPerSecOut.at(i) << " (" << mbPerSecOut.at(i) << " MB)";
} }

View File

@@ -208,7 +208,7 @@ class FairMQDevice : public FairMQStateMachine
template<typename... Args> template<typename... Args>
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args) const FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args) const
{ {
return fChannels.at(channel).at(index).Transport()->CreateMessage(std::forward<Args>(args)...); return fChannels.at(channel).at(index).NewMessage(std::forward<Args>(args)...);
} }
template<typename T> template<typename T>
@@ -413,6 +413,11 @@ class FairMQDevice : public FairMQStateMachine
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; } void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; }
int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; } int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine() { ProcessWork(); };
protected: protected:
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports
@@ -532,6 +537,7 @@ class FairMQDevice : public FairMQStateMachine
const fair::mq::tools::Version fVersion; const fair::mq::tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun float fRate; ///< Rate limiting for ConditionalRun
size_t fLastTime; ///< Rate limiting for ConditionalRun size_t fLastTime; ///< Rate limiting for ConditionalRun
std::vector<std::string> fRawCmdLineArgs;
}; };
#endif /* FAIRMQDEVICE_H_ */ #endif /* FAIRMQDEVICE_H_ */

View File

@@ -13,6 +13,7 @@
*/ */
#include "FairMQStateMachine.h" #include "FairMQStateMachine.h"
#include <fairmq/Tools.h>
// Increase maximum number of boost::msm states (default is 10) // Increase maximum number of boost::msm states (default is 10)
// This #define has to be before any msm header includes // This #define has to be before any msm header includes
@@ -24,18 +25,25 @@
#include <boost/msm/back/metafunctions.hpp> #include <boost/msm/back/metafunctions.hpp>
#include <boost/msm/front/state_machine_def.hpp> #include <boost/msm/front/state_machine_def.hpp>
#include <boost/msm/front/functor_row.hpp> #include <boost/msm/front/functor_row.hpp>
#include <boost/core/demangle.hpp>
#include <boost/signals2.hpp> // signal/slot for onStateChange callbacks #include <boost/signals2.hpp> // signal/slot for onStateChange callbacks
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <thread>
#include <chrono> #include <chrono>
#include <array>
#include <unordered_map> #include <unordered_map>
using namespace std; 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 namespace fair
{ {
@@ -44,35 +52,110 @@ namespace mq
namespace fsm namespace fsm
{ {
// defining events for the boost MSM state machine // list of FSM states
struct INIT_DEVICE_E { string name() const { return "INIT_DEVICE"; } }; struct OK_FSM_STATE : public state<> { static string Name() { return "OK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::OK; } };
struct internal_DEVICE_READY_E { string name() const { return "internal_DEVICE_READY"; } }; struct ERROR_FSM_STATE : public terminate_state<> { static string Name() { return "ERROR"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::Error; } };
struct INIT_TASK_E { string name() const { return "INIT_TASK"; } };
struct internal_READY_E { string name() const { return "internal_READY"; } };
struct RUN_E { string name() const { return "RUN"; } };
struct PAUSE_E { string name() const { return "PAUSE"; } };
struct STOP_E { string name() const { return "STOP"; } };
struct RESET_TASK_E { string name() const { return "RESET_TASK"; } };
struct RESET_DEVICE_E { string name() const { return "RESET_DEVICE"; } };
struct internal_IDLE_E { string name() const { return "internal_IDLE"; } };
struct END_E { string name() const { return "END"; } };
struct ERROR_FOUND_E { string name() const { return "ERROR_FOUND"; } };
// deactivate the warning for non-virtual destructor thrown in the boost library struct IDLE_FSM_STATE : public state<> { static string Name() { return "IDLE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::IDLE; } };
#if defined(__clang__) struct INITIALIZING_DEVICE_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_DEVICE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_DEVICE; } };
_Pragma("clang diagnostic push") struct DEVICE_READY_FSM_STATE : public state<> { static string Name() { return "DEVICE_READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::DEVICE_READY; } };
_Pragma("clang diagnostic ignored \"-Wnon-virtual-dtor\"") struct INITIALIZING_TASK_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_TASK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_TASK; } };
#elif defined(__GNUC__) || defined(__GNUG__) struct READY_FSM_STATE : public state<> { static string Name() { return "READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::READY; } };
_Pragma("GCC diagnostic push") struct RUNNING_FSM_STATE : public state<> { static string Name() { return "RUNNING"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RUNNING; } };
_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"") struct PAUSED_FSM_STATE : public state<> { static string Name() { return "PAUSED"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::PAUSED; } };
#endif 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 // defining the boost MSM state machine
struct Machine_ : public msmf::state_machine_def<Machine_> struct Machine_ : public state_machine_def<Machine_>
{ {
public: public:
Machine_() Machine_()
: fState() : fUnblockHandler()
, fStateHandlers()
, fWork() , fWork()
, fWorkAvailableCondition() , fWorkAvailableCondition()
, fWorkDoneCondition() , fWorkDoneCondition()
@@ -82,22 +165,22 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
, fWorkAvailable(false) , fWorkAvailable(false)
, fStateChangeSignal() , fStateChangeSignal()
, fStateChangeSignalsMap() , fStateChangeSignalsMap()
, fTerminationRequested(false) , fState()
, fWorkerThread()
{} {}
virtual ~Machine_() virtual ~Machine_()
{} {}
// initial states
using initial_state = boost::mpl::vector<IDLE_FSM_STATE, OK_FSM_STATE>;
template<typename Event, typename FSM> template<typename Event, typename FSM>
void on_entry(Event const&, FSM& fsm) void on_entry(Event const&, FSM& fsm)
{ {
LOG(state) << "Starting FairMQ state machine"; LOG(state) << "Starting FairMQ state machine";
fState = FairMQStateMachine::IDLE; fState = FairMQStateMachine::IDLE;
LOG(state) << "Entering IDLE state";
fsm.CallStateChangeCallbacks(FairMQStateMachine::IDLE); fsm.CallStateChangeCallbacks(FairMQStateMachine::IDLE);
// start a worker thread to execute user states in.
fsm.fWorkerThread = thread(&Machine_::Worker, &fsm);
} }
template<typename Event, typename FSM> template<typename Event, typename FSM>
@@ -106,41 +189,23 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
LOG(state) << "Exiting FairMQ state 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 // actions
struct IdleFct struct AutomaticFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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 = ts.Type();
fsm.fState = FairMQStateMachine::IDLE; LOG(state) << "Entering " << ts.Name() << " state";
} }
}; };
struct InitDeviceFct struct DefaultFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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); unique_lock<mutex> lock(fsm.fWorkMutex);
while (fsm.fWorkActive) while (fsm.fWorkActive)
@@ -148,66 +213,8 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
fsm.fWorkDoneCondition.wait(lock); fsm.fWorkDoneCondition.wait(lock);
} }
fsm.fWorkAvailable = true; fsm.fWorkAvailable = true;
LOG(state) << "Entering INITIALIZING DEVICE state"; LOG(state) << "Entering " << ts.Name() << " state";
fsm.fWork = fsm.fInitWrapperHandler; fsm.fWork = fsm.fStateHandlers.at(e.Type());
fsm.fWorkAvailableCondition.notify_one();
}
};
struct DeviceReadyFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
LOG(state) << "Entering DEVICE READY state";
fsm.fState = FairMQStateMachine::DEVICE_READY;
}
};
struct InitTaskFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
fsm.fState = FairMQStateMachine::INITIALIZING_TASK;
unique_lock<mutex> lock(fsm.fWorkMutex);
while (fsm.fWorkActive)
{
fsm.fWorkDoneCondition.wait(lock);
}
fsm.fWorkAvailable = true;
LOG(state) << "Entering INITIALIZING TASK state";
fsm.fWork = fsm.fInitTaskWrapperHandler;
fsm.fWorkAvailableCondition.notify_one();
}
};
struct ReadyFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
LOG(state) << "Entering READY state";
fsm.fState = FairMQStateMachine::READY;
}
};
struct RunFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
fsm.fState = FairMQStateMachine::RUNNING;
unique_lock<mutex> lock(fsm.fWorkMutex);
while (fsm.fWorkActive)
{
fsm.fWorkDoneCondition.wait(lock);
}
fsm.fWorkAvailable = true;
LOG(state) << "Entering RUNNING state";
fsm.fWork = fsm.fRunWrapperHandler;
fsm.fWorkAvailableCondition.notify_one(); fsm.fWorkAvailableCondition.notify_one();
} }
}; };
@@ -215,9 +222,9 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
struct PauseFct struct PauseFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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(); fsm.fUnblockHandler();
unique_lock<mutex> lock(fsm.fWorkMutex); unique_lock<mutex> lock(fsm.fWorkMutex);
@@ -226,37 +233,18 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
fsm.fWorkDoneCondition.wait(lock); fsm.fWorkDoneCondition.wait(lock);
} }
fsm.fWorkAvailable = true; fsm.fWorkAvailable = true;
LOG(state) << "Entering PAUSED state"; LOG(state) << "Entering " << ts.Name() << " state";
fsm.fWork = fsm.fPauseWrapperHandler; fsm.fWork = fsm.fPauseWrapperHandler;
fsm.fWorkAvailableCondition.notify_one(); 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 struct StopFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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(); fsm.fUnblockHandler();
unique_lock<mutex> lock(fsm.fWorkMutex); unique_lock<mutex> lock(fsm.fWorkMutex);
@@ -264,93 +252,48 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
{ {
fsm.fWorkDoneCondition.wait(lock); fsm.fWorkDoneCondition.wait(lock);
} }
LOG(state) << "Entering READY state"; LOG(state) << "Entering " << ts.Name() << " state";
} }
}; };
struct InternalStopFct struct InternalStopFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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(); fsm.fUnblockHandler();
LOG(state) << "RUNNING state finished without an external event, entering READY state"; LOG(state) << "RUNNING state finished without an external event, entering " << ts.Name() << " state";
}
};
struct ResetTaskFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
fsm.fState = FairMQStateMachine::RESETTING_TASK;
unique_lock<mutex> lock(fsm.fWorkMutex);
while (fsm.fWorkActive)
{
fsm.fWorkDoneCondition.wait(lock);
}
fsm.fWorkAvailable = true;
LOG(state) << "Entering RESETTING TASK state";
fsm.fWork = fsm.fResetTaskWrapperHandler;
fsm.fWorkAvailableCondition.notify_one();
}
};
struct ResetDeviceFct
{
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
void operator()(EVT const&, FSM& fsm, SourceState&, TargetState&)
{
fsm.fState = FairMQStateMachine::RESETTING_DEVICE;
unique_lock<mutex> lock(fsm.fWorkMutex);
while (fsm.fWorkActive)
{
fsm.fWorkDoneCondition.wait(lock);
}
fsm.fWorkAvailable = true;
LOG(state) << "Entering RESETTING DEVICE state";
fsm.fWork = fsm.fResetWrapperHandler;
fsm.fWorkAvailableCondition.notify_one();
} }
}; };
struct ExitingFct struct ExitingFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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"; LOG(state) << "Entering " << ts.Name() << " state";
fsm.fState = FairMQStateMachine::EXITING; fsm.fState = ts.Type();
fsm.fTerminationRequested = true;
fsm.CallStateChangeCallbacks(FairMQStateMachine::EXITING); fsm.CallStateChangeCallbacks(FairMQStateMachine::EXITING);
// terminate worker thread // Stop ProcessWork()
{ {
lock_guard<mutex> lock(fsm.fWorkMutex); lock_guard<mutex> lock(fsm.fWorkMutex);
fsm.fWorkerTerminated = true; fsm.fWorkerTerminated = true;
fsm.fWorkAvailableCondition.notify_one(); fsm.fWorkAvailableCondition.notify_one();
} }
// join the worker thread (executing user states) fsm.fStateHandlers.at(e.Type())();
if (fsm.fWorkerThread.joinable())
{
fsm.fWorkerThread.join();
}
fsm.fExitHandler();
} }
}; };
struct ErrorFoundFct struct ErrorFoundFct
{ {
template<typename EVT, typename FSM, typename SourceState, typename TargetState> 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 = ts.Type();
fsm.fState = FairMQStateMachine::Error; LOG(state) << "Entering " << ts.Name() << " state";
fsm.CallStateChangeCallbacks(FairMQStateMachine::Error); fsm.CallStateChangeCallbacks(FairMQStateMachine::Error);
} }
}; };
@@ -358,21 +301,21 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
// Transition table for Machine_ // Transition table for Machine_
struct transition_table : boost::mpl::vector< struct transition_table : boost::mpl::vector<
// Start Event Next Action Guard // Start Event Next Action Guard
msmf::Row<IDLE_FSM, INIT_DEVICE_E, INITIALIZING_DEVICE_FSM, InitDeviceFct, msmf::none>, Row<IDLE_FSM_STATE, INIT_DEVICE_FSM_EVENT, INITIALIZING_DEVICE_FSM_STATE, DefaultFct, none>,
msmf::Row<IDLE_FSM, END_E, EXITING_FSM, ExitingFct, msmf::none>, Row<IDLE_FSM_STATE, END_FSM_EVENT, EXITING_FSM_STATE, ExitingFct, none>,
msmf::Row<INITIALIZING_DEVICE_FSM, internal_DEVICE_READY_E, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>, Row<INITIALIZING_DEVICE_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
msmf::Row<DEVICE_READY_FSM, INIT_TASK_E, INITIALIZING_TASK_FSM, InitTaskFct, msmf::none>, Row<DEVICE_READY_FSM_STATE, INIT_TASK_FSM_EVENT, INITIALIZING_TASK_FSM_STATE, DefaultFct, none>,
msmf::Row<DEVICE_READY_FSM, RESET_DEVICE_E, RESETTING_DEVICE_FSM, ResetDeviceFct, msmf::none>, Row<DEVICE_READY_FSM_STATE, RESET_DEVICE_FSM_EVENT, RESETTING_DEVICE_FSM_STATE, DefaultFct, none>,
msmf::Row<INITIALIZING_TASK_FSM, internal_READY_E, READY_FSM, ReadyFct, msmf::none>, Row<INITIALIZING_TASK_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, AutomaticFct, none>,
msmf::Row<READY_FSM, RUN_E, RUNNING_FSM, RunFct, msmf::none>, Row<READY_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
msmf::Row<READY_FSM, RESET_TASK_E, RESETTING_TASK_FSM, ResetTaskFct, msmf::none>, Row<READY_FSM_STATE, RESET_TASK_FSM_EVENT, RESETTING_TASK_FSM_STATE, DefaultFct, none>,
msmf::Row<RUNNING_FSM, PAUSE_E, PAUSED_FSM, PauseFct, msmf::none>, Row<RUNNING_FSM_STATE, PAUSE_FSM_EVENT, PAUSED_FSM_STATE, DefaultFct, none>,
msmf::Row<RUNNING_FSM, STOP_E, READY_FSM, StopFct, msmf::none>, Row<RUNNING_FSM_STATE, STOP_FSM_EVENT, READY_FSM_STATE, StopFct, none>,
msmf::Row<RUNNING_FSM, internal_READY_E, READY_FSM, InternalStopFct, msmf::none>, Row<RUNNING_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, InternalStopFct, none>,
msmf::Row<PAUSED_FSM, RUN_E, RUNNING_FSM, ResumeFct, msmf::none>, Row<PAUSED_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
msmf::Row<RESETTING_TASK_FSM, internal_DEVICE_READY_E, DEVICE_READY_FSM, DeviceReadyFct, msmf::none>, Row<RESETTING_TASK_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
msmf::Row<RESETTING_DEVICE_FSM, internal_IDLE_E, IDLE_FSM, IdleFct, msmf::none>, Row<RESETTING_DEVICE_FSM_STATE, internal_IDLE_FSM_EVENT, IDLE_FSM_STATE, AutomaticFct, none>,
msmf::Row<OK_FSM, ERROR_FOUND_E, ERROR_FSM, ErrorFoundFct, msmf::none>> Row<OK_FSM_STATE, ERROR_FOUND_FSM_EVENT, ERROR_FSM_STATE, ErrorFoundFct, none>>
{}; {};
// replaces the default no-transition response. // replaces the default no-transition response.
@@ -386,53 +329,17 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
boost::mpl::for_each<all_states, boost::msm::wrap<boost::mpl::placeholders::_1>>(boost::msm::back::get_state_name<recursive_stt>(stateName, state)); boost::mpl::for_each<all_states, boost::msm::wrap<boost::mpl::placeholders::_1>>(boost::msm::back::get_state_name<recursive_stt>(stateName, state));
stateName = stateName.substr(24); stateName = boost::core::demangle(stateName.c_str());
size_t pos = stateName.find("_FSME"); size_t pos = stateName.rfind(":");
stateName.erase(pos); if (pos != string::npos)
if (stateName == "1RUNNING" || stateName == "6DEVICE_READY" || stateName == "0PAUSED" || stateName == "8RESETTING_TASK" || stateName == "0RESETTING_DEVICE")
{ {
stateName = stateName.substr(1); stateName = stateName.substr(pos + 1);
stateName = stateName.substr(0, stateName.size() - 10);
} }
if (stateName != "OK") if (stateName != "OK")
{ {
LOG(state) << "No transition from state " << stateName << " on event " << e.name(); LOG(state) << "No transition from state " << stateName << " on event " << e.Name();
}
// LOG(state) << "no transition from state " << GetStateName(state) << " (" << state << ") 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...";
} }
} }
@@ -444,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; function<void(void)> fUnblockHandler;
unordered_map<FairMQStateMachine::Event, function<void(void)>> fStateHandlers;
// function to execute user states in a worker thread // function to execute user states in a worker thread
function<void(void)> fWork; function<void(void)> fWork;
@@ -464,12 +365,10 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
boost::signals2::signal<void(const FairMQStateMachine::State)> fStateChangeSignal; boost::signals2::signal<void(const FairMQStateMachine::State)> fStateChangeSignal;
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap; unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
atomic<bool> fTerminationRequested;
atomic<FairMQStateMachine::State> fState; atomic<FairMQStateMachine::State> fState;
private: void ProcessWork()
void Worker()
{ {
while (true) while (true)
{ {
@@ -478,7 +377,7 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
// Wait for work to be done. // Wait for work to be done.
while (!fWorkAvailable && !fWorkerTerminated) while (!fWorkAvailable && !fWorkerTerminated)
{ {
fWorkAvailableCondition.wait(lock); fWorkAvailableCondition.wait_for(lock, chrono::milliseconds(100));
} }
if (fWorkerTerminated) if (fWorkerTerminated)
@@ -500,20 +399,10 @@ struct Machine_ : public msmf::state_machine_def<Machine_>
CallStateChangeCallbacks(fState); CallStateChangeCallbacks(fState);
} }
} }
// run state handlers in a separate thread
thread fWorkerThread;
}; // Machine_ }; // Machine_
using FairMQFSM = boost::msm::back::state_machine<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 fsm
} // namespace mq } // namespace mq
} // namespace fair } // namespace fair
@@ -521,16 +410,16 @@ _Pragma("GCC diagnostic pop")
using namespace fair::mq::fsm; using namespace fair::mq::fsm;
FairMQStateMachine::FairMQStateMachine() FairMQStateMachine::FairMQStateMachine()
: fFsm(new FairMQFSM) : fChangeStateMutex()
, fChangeStateMutex() , fFsm(new FairMQFSM)
{ {
static_pointer_cast<FairMQFSM>(fFsm)->fInitWrapperHandler = bind(&FairMQStateMachine::InitWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(INIT_DEVICE, bind(&FairMQStateMachine::InitWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fInitTaskWrapperHandler = bind(&FairMQStateMachine::InitTaskWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(INIT_TASK, bind(&FairMQStateMachine::InitTaskWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fRunWrapperHandler = bind(&FairMQStateMachine::RunWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RUN, bind(&FairMQStateMachine::RunWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fPauseWrapperHandler = bind(&FairMQStateMachine::PauseWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(PAUSE, bind(&FairMQStateMachine::PauseWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fResetWrapperHandler = bind(&FairMQStateMachine::ResetWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_TASK, bind(&FairMQStateMachine::ResetTaskWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fResetTaskWrapperHandler = bind(&FairMQStateMachine::ResetTaskWrapper, this); static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_DEVICE, bind(&FairMQStateMachine::ResetWrapper, this));
static_pointer_cast<FairMQFSM>(fFsm)->fExitHandler = bind(&FairMQStateMachine::Exit, 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)->fUnblockHandler = bind(&FairMQStateMachine::Unblock, this);
static_pointer_cast<FairMQFSM>(fFsm)->start(); static_pointer_cast<FairMQFSM>(fFsm)->start();
@@ -555,73 +444,73 @@ bool FairMQStateMachine::ChangeState(int event)
case INIT_DEVICE: case INIT_DEVICE:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case internal_DEVICE_READY: case internal_DEVICE_READY:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case INIT_TASK: case INIT_TASK:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case internal_READY: case internal_READY:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case RUN: case RUN:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case PAUSE: case PAUSE:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case STOP: case STOP:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case RESET_DEVICE: case RESET_DEVICE:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case RESET_TASK: case RESET_TASK:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case internal_IDLE: case internal_IDLE:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case END: case END:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
case ERROR_FOUND: case ERROR_FOUND:
{ {
lock_guard<mutex> lock(fChangeStateMutex); 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; return true;
} }
default: default:
@@ -741,7 +630,11 @@ void FairMQStateMachine::CallStateChangeCallbacks(const State state) const
string FairMQStateMachine::GetCurrentStateName() 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 int FairMQStateMachine::GetCurrentState() const
{ {
@@ -756,23 +649,12 @@ bool FairMQStateMachine::CheckCurrentState(string state) const
return state == GetCurrentStateName(); return state == GetCurrentStateName();
} }
bool FairMQStateMachine::Terminated() void FairMQStateMachine::ProcessWork()
{ {
return static_pointer_cast<FairMQFSM>(fFsm)->fTerminationRequested; static_pointer_cast<FairMQFSM>(fFsm)->ProcessWork();
} }
int FairMQStateMachine::GetEventNumber(const string& event) int FairMQStateMachine::GetEventNumber(const string& event)
{ {
if (event == "INIT_DEVICE") return INIT_DEVICE; return eventNumbers.at(event);
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;
} }

View File

@@ -79,10 +79,10 @@ class FairMQStateMachine
void CallStateChangeCallbacks(const State state) const; void CallStateChangeCallbacks(const State state) const;
std::string GetCurrentStateName() const; std::string GetCurrentStateName() const;
static std::string GetStateName(const State);
int GetCurrentState() const; int GetCurrentState() const;
bool CheckCurrentState(int state) const; bool CheckCurrentState(int state) const;
bool CheckCurrentState(std::string state) const; bool CheckCurrentState(std::string state) const;
bool Terminated();
// actions to be overwritten by derived classes // actions to be overwritten by derived classes
virtual void InitWrapper() {} virtual void InitWrapper() {}
@@ -94,8 +94,10 @@ class FairMQStateMachine
virtual void Exit() {} virtual void Exit() {}
virtual void Unblock() {} virtual void Unblock() {}
void ProcessWork();
private: private:
int GetEventNumber(const std::string& event); static int GetEventNumber(const std::string& event);
std::mutex fChangeStateMutex; std::mutex fChangeStateMutex;

View File

@@ -116,9 +116,9 @@ class Plugin
} /* namespace fair */ } /* namespace fair */
#define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \ #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(Make_##NAME##_Plugin, make_##NAME##_plugin) \
BOOST_DLL_ALIAS(PROGOPTIONS, get_##NAME##_plugin_progoptions) BOOST_DLL_ALIAS(PROGOPTIONS, get_##NAME##_plugin_progoptions)

View File

@@ -6,6 +6,7 @@
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include <fairmq/plugins/Builtin.h>
#include <fairmq/PluginManager.h> #include <fairmq/PluginManager.h>
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
@@ -30,13 +31,55 @@ const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
fair::mq::PluginManager::PluginManager() fair::mq::PluginManager::PluginManager()
: fSearchPaths{{"."}} : fSearchPaths{{"."}}
, fPluginFactories() , fPluginFactories()
, fPluginServices()
, fPlugins() , fPlugins()
, fPluginOrder() , fPluginOrder()
, fPluginProgOptions() , 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 auto fair::mq::PluginManager::ValidateSearchPath(const fs::path& path) -> void
{ {
if (path.empty()) throw BadSearchPath{"Specified path is empty."}; if (path.empty()) throw BadSearchPath{"Specified path is empty."};
@@ -80,46 +123,6 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
return plugin_options; 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 auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
{ {
if (pluginName.substr(0,2) == "p:") if (pluginName.substr(0,2) == "p:")

View File

@@ -11,7 +11,6 @@
#include <fairmq/Plugin.h> #include <fairmq/Plugin.h>
#include <fairmq/PluginServices.h> #include <fairmq/PluginServices.h>
#include <fairmq/plugins/Builtin.h>
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
#include <FairMQDevice.h> #include <FairMQDevice.h>
#define BOOST_FILESYSTEM_VERSION 3 #define BOOST_FILESYSTEM_VERSION 3
@@ -48,9 +47,15 @@ namespace mq
class PluginManager class PluginManager
{ {
public: public:
using PluginFactory = std::shared_ptr<fair::mq::Plugin>(PluginServices&); using PluginFactory = std::unique_ptr<fair::mq::Plugin>(PluginServices&);
PluginManager(); 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 SetSearchPaths(const std::vector<boost::filesystem::path>&) -> void;
auto AppendSearchPath(const boost::filesystem::path&) -> void; auto AppendSearchPath(const boost::filesystem::path&) -> void;
@@ -65,7 +70,6 @@ class PluginManager
struct PluginInstantiationError : std::runtime_error { using std::runtime_error::runtime_error; }; struct PluginInstantiationError : std::runtime_error { using std::runtime_error::runtime_error; };
static auto ProgramOptions() -> boost::program_options::options_description; 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; }; struct ProgramOptionsParseError : std::runtime_error { using std::runtime_error::runtime_error; };
static auto LibPrefix() -> const std::string& { return fgkLibPrefix; } static auto LibPrefix() -> const std::string& { return fgkLibPrefix; }
@@ -112,10 +116,10 @@ class PluginManager
static const std::string fgkLibPrefix; static const std::string fgkLibPrefix;
std::vector<boost::filesystem::path> fSearchPaths; std::vector<boost::filesystem::path> fSearchPaths;
std::map<std::string, std::function<PluginFactory>> fPluginFactories; 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::vector<std::string> fPluginOrder;
std::map<std::string, boost::program_options::options_description> fPluginProgOptions; std::map<std::string, boost::program_options::options_description> fPluginProgOptions;
std::unique_ptr<PluginServices> fPluginServices;
}; /* class PluginManager */ }; /* class PluginManager */
} /* namespace mq */ } /* namespace mq */

View File

@@ -98,7 +98,7 @@ auto PluginServices::ChangeDeviceState(const std::string& controller, const Devi
if (fDeviceController == controller) if (fDeviceController == controller)
{ {
fDevice->ChangeState(fkDeviceStateTransitionMap.at(next)); fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
} }
else else
{ {

View File

@@ -38,15 +38,20 @@ class PluginServices
{ {
public: public:
PluginServices() = delete; PluginServices() = delete;
PluginServices(FairMQProgOptions* config, std::shared_ptr<FairMQDevice> device) PluginServices(FairMQProgOptions& config, FairMQDevice& device)
: fConfig{config} : fConfig(config)
, fDevice{device} , fDevice(device)
, fDeviceController() , fDeviceController()
, fDeviceControllerMutex() , fDeviceControllerMutex()
, fReleaseDeviceControlCondition() , fReleaseDeviceControlCondition()
{ {
} }
~PluginServices()
{
LOG(debug) << "Shutting down Plugin Services";
}
PluginServices(const PluginServices&) = delete; PluginServices(const PluginServices&) = delete;
PluginServices operator=(const PluginServices&) = delete; PluginServices operator=(const PluginServices&) = delete;
@@ -109,7 +114,7 @@ class PluginServices
friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); } friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
/// @return current device state /// @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 /// @brief Become device controller
/// @param controller id /// @param controller id
@@ -155,19 +160,19 @@ class PluginServices
/// the state is running in. /// the state is running in.
auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function<void(DeviceState /*newState*/)> callback) -> void 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)); callback(fkDeviceStateMap.at(newState));
}); });
} }
/// @brief Unsubscribe from device state changes /// @brief Unsubscribe from device state changes
/// @param subscriber id /// @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 // Config API
struct PropertyNotFoundError : std::runtime_error { using std::runtime_error::runtime_error; }; 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 /// @brief Set config property
/// @param key /// @param key
@@ -182,7 +187,7 @@ class PluginServices
auto currentState = GetCurrentDeviceState(); auto currentState = GetCurrentDeviceState();
if (currentState == DeviceState::InitializingDevice) if (currentState == DeviceState::InitializingDevice)
{ {
fConfig->SetValue(key, val); fConfig.SetValue(key, val);
} }
else else
{ {
@@ -200,7 +205,7 @@ class PluginServices
template<typename T> template<typename T>
auto GetProperty(const std::string& key) const -> T { auto GetProperty(const std::string& key) const -> T {
if (PropertyExists(key)) { if (PropertyExists(key)) {
return fConfig->GetValue<T>(key); return fConfig.GetValue<T>(key);
} }
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key)); throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", key));
} }
@@ -212,16 +217,16 @@ class PluginServices
/// If a type is not supported, the user can provide support by overloading the ostream operator for this type /// 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 { auto GetPropertyAsString(const std::string& key) const -> std::string {
if (PropertyExists(key)) { if (PropertyExists(key)) {
return fConfig->GetStringValue(key); return fConfig.GetStringValue(key);
} }
throw PropertyNotFoundError(fair::mq::tools::ToString("Config has no key: ", 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 /// @brief Discover the list of property keys
/// @return 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 /// @brief Subscribe to property updates of type T
/// @param subscriber /// @param subscriber
@@ -231,13 +236,13 @@ class PluginServices
template<typename T> template<typename T>
auto SubscribeToPropertyChange(const std::string& subscriber, std::function<void(const std::string& key, T)> callback) const -> void 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 /// @brief Unsubscribe from property updates of type T
/// @param subscriber /// @param subscriber
template<typename T> 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 /// @brief Subscribe to property updates
/// @param subscriber /// @param subscriber
@@ -246,12 +251,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. /// 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 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 /// @brief Unsubscribe from property updates that convert to string
/// @param subscriber /// @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 CycleLogConsoleSeverityUp() -> void { Logger::CycleConsoleSeverityUp(); }
auto CycleLogConsoleSeverityDown() -> void { Logger::CycleConsoleSeverityDown(); } auto CycleLogConsoleSeverityDown() -> void { Logger::CycleConsoleSeverityDown(); }
@@ -266,8 +271,8 @@ class PluginServices
static const std::unordered_map<DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap; static const std::unordered_map<DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
private: private:
FairMQProgOptions* fConfig; // TODO make it a shared pointer, once old AliceO2 code is cleaned up FairMQProgOptions& fConfig;
std::shared_ptr<FairMQDevice> fDevice; FairMQDevice& fDevice;
boost::optional<std::string> fDeviceController; boost::optional<std::string> fDeviceController;
mutable std::mutex fDeviceControllerMutex; mutable std::mutex fDeviceControllerMutex;
std::condition_variable fReleaseDeviceControlCondition; std::condition_variable fReleaseDeviceControlCondition;

View File

@@ -57,7 +57,7 @@ void FairMQBenchmarkSampler::Run()
// store the channel reference to avoid traversing the map on every loop iteration // store the channel reference to avoid traversing the map on every loop iteration
FairMQChannel& dataOutChannel = fChannels.at(fOutChannelName).at(0); FairMQChannel& dataOutChannel = fChannels.at(fOutChannelName).at(0);
FairMQMessagePtr baseMsg(dataOutChannel.Transport()->CreateMessage(fMsgSize)); FairMQMessagePtr baseMsg(dataOutChannel.NewMessage(fMsgSize));
LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations."; LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations.";
auto tStart = chrono::high_resolution_clock::now(); auto tStart = chrono::high_resolution_clock::now();
@@ -66,7 +66,7 @@ void FairMQBenchmarkSampler::Run()
{ {
if (fSameMessage) if (fSameMessage)
{ {
FairMQMessagePtr msg(dataOutChannel.Transport()->CreateMessage()); FairMQMessagePtr msg(dataOutChannel.NewMessage());
msg->Copy(*baseMsg); msg->Copy(*baseMsg);
if (dataOutChannel.Send(msg) >= 0) if (dataOutChannel.Send(msg) >= 0)
@@ -83,7 +83,7 @@ void FairMQBenchmarkSampler::Run()
} }
else else
{ {
FairMQMessagePtr msg(dataOutChannel.Transport()->CreateMessage(fMsgSize)); FairMQMessagePtr msg(dataOutChannel.NewMessage(fMsgSize));
if (dataOutChannel.Send(msg) >= 0) if (dataOutChannel.Send(msg) >= 0)
{ {

View File

@@ -17,6 +17,7 @@
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include "FairMQDevice.h" #include "FairMQDevice.h"
@@ -38,7 +39,7 @@ class FairMQBenchmarkSampler : public FairMQDevice
protected: protected:
bool fSameMessage; bool fSameMessage;
int fMsgSize; int fMsgSize;
int fMsgCounter; std::atomic<int> fMsgCounter;
int fMsgRate; int fMsgRate;
uint64_t fNumIterations; uint64_t fNumIterations;
uint64_t fMaxIterations; uint64_t fMaxIterations;

View File

@@ -1,69 +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" *
********************************************************************************/
/**
* FairMQSink.cxx
*
* @since 2013-01-09
* @author D. Klein, A. Rybalchenko
*/
#include "FairMQSink.h"
#include <chrono>
#include "../FairMQLogger.h"
#include "../options/FairMQProgOptions.h"
using namespace std;
FairMQSink::FairMQSink()
: fNumMsgs(0)
, fInChannelName()
{
}
void FairMQSink::InitTask()
{
fNumMsgs = fConfig->GetValue<uint64_t>("num-msgs");
fInChannelName = fConfig->GetValue<string>("in-channel");
}
void FairMQSink::Run()
{
uint64_t numReceivedMsgs = 0;
// store the channel reference to avoid traversing the map on every loop iteration
FairMQChannel& dataInChannel = fChannels.at(fInChannelName).at(0);
LOG(info) << "Starting the benchmark and expecting to receive " << fNumMsgs << " messages.";
auto tStart = chrono::high_resolution_clock::now();
while (CheckCurrentState(RUNNING))
{
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
if (dataInChannel.Receive(msg) >= 0)
{
if (fNumMsgs > 0)
{
if (numReceivedMsgs >= fNumMsgs)
{
break;
}
}
numReceivedMsgs++;
}
}
auto tEnd = chrono::high_resolution_clock::now();
LOG(info) << "Leaving RUNNING state. Received " << numReceivedMsgs << " messages in " << chrono::duration<double, milli>(tEnd - tStart).count() << "ms.";
}
FairMQSink::~FairMQSink()
{
}

View File

@@ -56,7 +56,7 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
while (CheckCurrentState(RUNNING)) while (CheckCurrentState(RUNNING))
{ {
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage()); FairMQMessagePtr msg(dataInChannel.NewMessage());
if (dataInChannel.Receive(msg) >= 0) if (dataInChannel.Receive(msg) >= 0)
{ {

View File

@@ -10,6 +10,7 @@
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
#include <FairMQLogger.h> #include <FairMQLogger.h>
#include <cassert>
#include <cstdlib> #include <cstdlib>
#include <zmq.h> #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."}; throw MessageError{"Not yet implemented."};
} }
@@ -91,7 +92,7 @@ auto Message::Rebuild(const size_t size) -> void
fHint = nullptr; 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) { if (fFreeFunction) {
fFreeFunction(fData, fHint); 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."}; 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."}; throw MessageError{"Not yet implemented."};
} }

View File

@@ -27,11 +27,16 @@ namespace parser
{ {
// TODO : add key-value map<string,string> parameter for replacing/updating values from keys // TODO : add key-value map<string,string> parameter for replacing/updating values from keys
// function that convert property tree (given the json structure) to FairMQMap // function that convert property tree (given the json structure) to FairMQChannelMap
FairMQMap ptreeToMQMap(const boost::property_tree::ptree& pt, const string& id, const string& rootNode) FairMQChannelMap ptreeToMQMap(const boost::property_tree::ptree& pt, const string& id, const string& rootNode)
{ {
if (id == "")
{
throw ParserError("no device ID provided. Provide with `--id` cmd option");
}
// Create fair mq map // Create fair mq map
FairMQMap channelMap; FairMQChannelMap channelMap;
// boost::property_tree::json_parser::write_json(std::cout, pt); // boost::property_tree::json_parser::write_json(std::cout, pt);
// Helper::PrintDeviceList(pt.get_child(rootNode)); // Helper::PrintDeviceList(pt.get_child(rootNode));
// Extract value from boost::property_tree // Extract value from boost::property_tree
@@ -46,20 +51,13 @@ FairMQMap ptreeToMQMap(const boost::property_tree::ptree& pt, const string& id,
return channelMap; return channelMap;
} }
FairMQMap JSON::UserParser(const string& filename, const string& deviceId, const string& rootNode) FairMQChannelMap JSON::UserParser(const string& filename, const string& deviceId, const string& rootNode)
{ {
boost::property_tree::ptree pt; boost::property_tree::ptree pt;
boost::property_tree::read_json(filename, pt); boost::property_tree::read_json(filename, pt);
return ptreeToMQMap(pt, deviceId, rootNode); return ptreeToMQMap(pt, deviceId, rootNode);
} }
FairMQMap JSON::UserParser(stringstream& input, const string& deviceId, const string& rootNode)
{
boost::property_tree::ptree pt;
boost::property_tree::read_json(input, pt);
return ptreeToMQMap(pt, deviceId, rootNode);
}
namespace Helper namespace Helper
{ {
@@ -90,7 +88,7 @@ void PrintDeviceList(const boost::property_tree::ptree& tree)
} }
} }
void DeviceParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap, const string& deviceId) void DeviceParser(const boost::property_tree::ptree& tree, FairMQChannelMap& channelMap, const string& deviceId)
{ {
string deviceIdKey; string deviceIdKey;
@@ -129,7 +127,7 @@ void DeviceParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap
} }
} }
void ChannelParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap) void ChannelParser(const boost::property_tree::ptree& tree, FairMQChannelMap& channelMap)
{ {
string channelKey; string channelKey;

View File

@@ -10,8 +10,8 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <map>
#include <unordered_map> #include <unordered_map>
#include <exception>
#include <boost/property_tree/ptree_fwd.hpp> #include <boost/property_tree/ptree_fwd.hpp>
@@ -24,22 +24,23 @@ namespace mq
namespace parser namespace parser
{ {
using FairMQMap = std::unordered_map<std::string, std::vector<FairMQChannel>>; using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
FairMQMap ptreeToMQMap(const boost::property_tree::ptree& pt, const std::string& deviceId, const std::string& rootNode); struct ParserError : std::runtime_error { using std::runtime_error::runtime_error; };
FairMQChannelMap ptreeToMQMap(const boost::property_tree::ptree& pt, const std::string& deviceId, const std::string& rootNode);
struct JSON struct JSON
{ {
FairMQMap UserParser(const std::string& filename, const std::string& deviceId, const std::string& rootNode = "fairMQOptions"); FairMQChannelMap UserParser(const std::string& filename, const std::string& deviceId, const std::string& rootNode = "fairMQOptions");
FairMQMap UserParser(std::stringstream& input, const std::string& deviceId, const std::string& rootNode = "fairMQOptions");
}; };
namespace Helper namespace Helper
{ {
void PrintDeviceList(const boost::property_tree::ptree& tree); void PrintDeviceList(const boost::property_tree::ptree& tree);
void DeviceParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap, const std::string& deviceId); void DeviceParser(const boost::property_tree::ptree& tree, FairMQChannelMap& channelMap, const std::string& deviceId);
void ChannelParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap); void ChannelParser(const boost::property_tree::ptree& tree, FairMQChannelMap& channelMap);
void SocketParser(const boost::property_tree::ptree& tree, std::vector<FairMQChannel>& channelList, const std::string& channelName, const FairMQChannel& commonChannel); void SocketParser(const boost::property_tree::ptree& tree, std::vector<FairMQChannel>& channelList, const std::string& channelName, const FairMQChannel& commonChannel);
} // Helper namespace } // Helper namespace

View File

@@ -12,25 +12,70 @@
* Created on March 11, 2015, 10:20 PM * Created on March 11, 2015, 10:20 PM
*/ */
#include "FairMQLogger.h"
#include "FairMQProgOptions.h" #include "FairMQProgOptions.h"
#include "FairProgOptionsHelper.h"
#include "FairMQParser.h" #include "FairMQParser.h"
#include "FairMQSuboptParser.h" #include "FairMQSuboptParser.h"
#include "FairMQLogger.h"
#include <boost/algorithm/string.hpp> // join/split
#include <algorithm> #include <algorithm>
#include <iomanip>
#include <iostream> #include <iostream>
#include <exception>
using namespace std; using namespace std;
using namespace fair::mq;
namespace po = boost::program_options;
FairMQProgOptions::FairMQProgOptions() FairMQProgOptions::FairMQProgOptions()
: FairProgOptions() : fVarMap()
, fMQCmdOptions("FairMQ device options") , fFairMQChannelMap()
, fMQParserOptions("FairMQ config parser options") , fAllOptions("FairMQ Command Line Options")
, fFairMQMap() , fGeneralOptions("General options")
, fMQOptions("FairMQ device options")
, fParserOptions("FairMQ channel config parser options")
, fConfigMutex()
, fChannelInfo() , fChannelInfo()
, fMQKeyMap() , fChannelKeyMap()
, fUnregisteredOptions()
, fEvents()
{ {
InitOptionDescription(); fGeneralOptions.add_options()
("help,h", "Print help")
("version,v", "Print version")
("severity", po::value<string>()->default_value("debug"), "Log severity level: trace, debug, info, state, warn, error, fatal, nolog")
("verbosity", po::value<string>()->default_value("medium"), "Log verbosity level: veryhigh, high, medium, low")
("color", po::value<bool >()->default_value(true), "Log color (true/false)")
("log-to-file", po::value<string>()->default_value(""), "Log output to a file.")
("print-options", po::value<bool >()->implicit_value(true), "Print options in machine-readable format (<option>:<computed-value>:<type>:<description>)");
fMQOptions.add_options()
("id", po::value<string>(), "Device ID (required argument).")
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
("transport", po::value<string>()->default_value("zeromq"), "Transport ('zeromq'/'nanomsg'/'shmem') .")
("network-interface", po::value<string>()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
("config-key", po::value<string>(), "Use provided value instead of device id for fetching the configuration from the config file.")
("initialization-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
("port-range-min", po::value<int >()->default_value(22000), "Start of the port range for dynamic initialization.")
("port-range-max", po::value<int >()->default_value(32000), "End of the port range for dynamic initialization.")
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
("shm-segment-size", po::value<size_t>()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
("shm-monitor", po::value<bool >()->default_value(true), "Shared memory: run monitor daemon.")
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
("session", po::value<string>()->default_value("default"), "Session name.");
fParserOptions.add_options()
("mq-config", po::value<string>(), "JSON input as file.")
("channel-config", po::value<vector<string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list");
fAllOptions.add(fGeneralOptions);
fAllOptions.add(fMQOptions);
fAllOptions.add(fParserOptions);
ParseDefaults(); ParseDefaults();
} }
@@ -52,12 +97,20 @@ int FairMQProgOptions::ParseAll(const vector<string>& cmdLineArgs, bool allowUnr
int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered) int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool allowUnregistered)
{ {
if (FairProgOptions::ParseCmdLine(argc, argv, allowUnregistered)) ParseCmdLine(argc, argv, allowUnregistered);
// if this option is provided, handle them and return stop value
if (fVarMap.count("help"))
{ {
// ParseCmdLine returns 0 if no immediate switches found. cout << fAllOptions << endl;
return 1;
}
// if this option is provided, handle them and return stop value
if (fVarMap.count("print-options"))
{
PrintOptionsRaw();
return 1; return 1;
} }
// if these options are provided, do no further checks and let the device handle them // if these options are provided, do no further checks and let the device handle them
if (fVarMap.count("print-channels") || fVarMap.count("version")) if (fVarMap.count("print-channels") || fVarMap.count("version"))
{ {
@@ -90,7 +143,7 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
{ {
id = fVarMap["config-key"].as<string>(); id = fVarMap["config-key"].as<string>();
} }
else else if (fVarMap.count("id"))
{ {
id = fVarMap["id"].as<string>(); id = fVarMap["id"].as<string>();
} }
@@ -101,54 +154,84 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
if (fVarMap.count("mq-config")) if (fVarMap.count("mq-config"))
{ {
LOG(debug) << "mq-config: Using default JSON parser"; LOG(debug) << "mq-config: Using default JSON parser";
Store(fair::mq::parser::JSON().UserParser(fVarMap["mq-config"].as<string>(), id)); UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), id));
}
else if (fVarMap.count("config-json-string"))
{
LOG(debug) << "config-json-string: Parsing JSON string";
string value = fair::mq::ConvertVariableValue<fair::mq::VarInfoToString>()(fVarMap.at("config-json-string"));
stringstream ss;
ss << value;
Store(fair::mq::parser::JSON().UserParser(ss, id));
} }
else if (fVarMap.count("channel-config")) else if (fVarMap.count("channel-config"))
{ {
LOG(debug) << "channel-config: Parsing channel configuration"; LOG(debug) << "channel-config: Parsing channel configuration";
Store(fair::mq::parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), id)); UpdateChannelMap(parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), id));
} }
else else
{ {
LOG(warn) << "FairMQProgOptions: no channels configuration provided via neither of:"; LOG(warn) << "FairMQProgOptions: no channels configuration provided via neither of:";
for (const auto& p : fMQParserOptions.options()) for (const auto& p : fParserOptions.options())
{ {
LOG(warn) << "--" << p->canonical_display_name(); LOG(warn) << "--" << p->canonical_display_name();
} }
LOG(warn) << "No channels will be created (You can create them manually)."; LOG(warn) << "No channels will be created (You can create them manually).";
} }
} }
catch (std::exception& e) catch (exception& e)
{ {
LOG(error) << e.what(); LOG(error) << e.what();
return 1; return 1;
} }
FairProgOptions::PrintOptions(); PrintOptions();
return 0; return 0;
} }
int FairMQProgOptions::Store(const FairMQMap& channels) void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered)
{ {
fFairMQMap = channels; // get options from cmd line and store in variable map
UpdateChannelInfo(); // here we use command_line_parser instead of parse_command_line, to allow unregistered and positional options
UpdateMQValues(); if (allowUnregistered)
return 0; {
po::command_line_parser parser{argc, argv};
parser.options(fAllOptions).allow_unregistered();
po::parsed_options parsed = parser.run();
fUnregisteredOptions = po::collect_unrecognized(parsed.options, po::include_positional);
po::store(parsed, fVarMap);
}
else
{
po::store(po::parse_command_line(argc, argv, fAllOptions), fVarMap);
}
po::notify(fVarMap);
}
void FairMQProgOptions::ParseDefaults()
{
vector<string> emptyArgs;
emptyArgs.push_back("dummy");
vector<const char*> argv(emptyArgs.size());
transform(emptyArgs.begin(), emptyArgs.end(), argv.begin(), [](const string& str)
{
return str.c_str();
});
po::store(po::parse_command_line(argv.size(), const_cast<char**>(argv.data()), fAllOptions), fVarMap);
}
unordered_map<string, vector<FairMQChannel>> FairMQProgOptions::GetFairMQMap() const
{
return fFairMQChannelMap;
}
unordered_map<string, int> FairMQProgOptions::GetChannelInfo() const
{
return fChannelInfo;
} }
// replace FairMQChannelMap, and update variable map accordingly // replace FairMQChannelMap, and update variable map accordingly
int FairMQProgOptions::UpdateChannelMap(const FairMQMap& channels) int FairMQProgOptions::UpdateChannelMap(const unordered_map<string, vector<FairMQChannel>>& channels)
{ {
fFairMQMap = channels; fFairMQChannelMap = channels;
UpdateChannelInfo(); UpdateChannelInfo();
UpdateMQValues(); UpdateMQValues();
return 0; return 0;
@@ -157,7 +240,7 @@ int FairMQProgOptions::UpdateChannelMap(const FairMQMap& channels)
void FairMQProgOptions::UpdateChannelInfo() void FairMQProgOptions::UpdateChannelInfo()
{ {
fChannelInfo.clear(); fChannelInfo.clear();
for (const auto& c : fFairMQMap) for (const auto& c : fFairMQChannelMap)
{ {
fChannelInfo.insert(make_pair(c.first, c.second.size())); fChannelInfo.insert(make_pair(c.first, c.second.size()));
} }
@@ -167,7 +250,7 @@ void FairMQProgOptions::UpdateChannelInfo()
// create key for variable map as follow : channelName.index.memberName // create key for variable map as follow : channelName.index.memberName
void FairMQProgOptions::UpdateMQValues() void FairMQProgOptions::UpdateMQValues()
{ {
for (const auto& p : fFairMQMap) for (const auto& p : fFairMQChannelMap)
{ {
int index = 0; int index = 0;
@@ -183,15 +266,15 @@ void FairMQProgOptions::UpdateMQValues()
string rcvKernelSizeKey = "chans." + p.first + "." + to_string(index) + ".rcvKernelSize"; string rcvKernelSizeKey = "chans." + p.first + "." + to_string(index) + ".rcvKernelSize";
string rateLoggingKey = "chans." + p.first + "." + to_string(index) + ".rateLogging"; string rateLoggingKey = "chans." + p.first + "." + to_string(index) + ".rateLogging";
fMQKeyMap[typeKey] = MQKey{p.first, index, "type"}; fChannelKeyMap[typeKey] = ChannelKey{p.first, index, "type"};
fMQKeyMap[methodKey] = MQKey{p.first, index, "method"}; fChannelKeyMap[methodKey] = ChannelKey{p.first, index, "method"};
fMQKeyMap[addressKey] = MQKey{p.first, index, "address"}; fChannelKeyMap[addressKey] = ChannelKey{p.first, index, "address"};
fMQKeyMap[transportKey] = MQKey{p.first, index, "transport"}; fChannelKeyMap[transportKey] = ChannelKey{p.first, index, "transport"};
fMQKeyMap[sndBufSizeKey] = MQKey{p.first, index, "sndBufSize"}; fChannelKeyMap[sndBufSizeKey] = ChannelKey{p.first, index, "sndBufSize"};
fMQKeyMap[rcvBufSizeKey] = MQKey{p.first, index, "rcvBufSize"}; fChannelKeyMap[rcvBufSizeKey] = ChannelKey{p.first, index, "rcvBufSize"};
fMQKeyMap[sndKernelSizeKey] = MQKey{p.first, index, "sndKernelSize"}; fChannelKeyMap[sndKernelSizeKey] = ChannelKey{p.first, index, "sndKernelSize"};
fMQKeyMap[rcvKernelSizeKey] = MQKey{p.first, index, "rcvkernelSize"}; fChannelKeyMap[rcvKernelSizeKey] = ChannelKey{p.first, index, "rcvkernelSize"};
fMQKeyMap[rateLoggingKey] = MQKey{p.first, index, "rateLogging"}; fChannelKeyMap[rateLoggingKey] = ChannelKey{p.first, index, "rateLogging"};
UpdateVarMap<string>(typeKey, channel.GetType()); UpdateVarMap<string>(typeKey, channel.GetType());
UpdateVarMap<string>(methodKey, channel.GetMethod()); UpdateVarMap<string>(methodKey, channel.GetMethod());
@@ -209,103 +292,56 @@ void FairMQProgOptions::UpdateMQValues()
} }
} }
int FairMQProgOptions::ImmediateOptions() int FairMQProgOptions::UpdateChannelValue(const string& channelName, int index, const string& member, const string& val)
{
if (fVarMap.count("help"))
{
cout << "===== FairMQ Program Options =====" << endl << fAllOptions;
return 1;
}
if (fVarMap.count("print-options"))
{
PrintOptionsRaw();
return 1;
}
return 0;
}
void FairMQProgOptions::InitOptionDescription()
{
fMQCmdOptions.add_options()
("id", po::value<string>(), "Device ID (required argument).")
("io-threads", po::value<int >()->default_value(1), "Number of I/O threads.")
("transport", po::value<string>()->default_value("zeromq"), "Transport ('zeromq'/'nanomsg').")
("config", po::value<string>()->default_value("static"), "Config source ('static'/<config library filename>).")
("network-interface", po::value<string>()->default_value("default"), "Network interface to bind on (e.g. eth0, ib0..., default will try to detect the interface of the default route).")
("config-key", po::value<string>(), "Use provided value instead of device id for fetching the configuration from the config file.")
("initialization-timeout", po::value<int >()->default_value(120), "Timeout for the initialization in seconds (when expecting dynamic initialization).")
("port-range-min", po::value<int >()->default_value(22000), "Start of the port range for dynamic initialization.")
("port-range-max", po::value<int >()->default_value(32000), "End of the port range for dynamic initialization.")
("print-channels", po::value<bool >()->implicit_value(true), "Print registered channel endpoints in a machine-readable format (<channel name>:<min num subchannels>:<max num subchannels>)")
("shm-segment-size", po::value<size_t>()->default_value(2000000000), "Shared memory: size of the shared memory segment (in bytes).")
("shm-monitor", po::value<bool >()->default_value(true), "Shared memory: run monitor daemon.")
("rate", po::value<float >()->default_value(0.), "Rate for conditional run loop (Hz).")
("session", po::value<string>()->default_value("default"), "Session name.")
;
fMQParserOptions.add_options()
("config-json-string", po::value<vector<string>>()->multitoken(), "JSON input as command line string.")
("mq-config", po::value<string>(), "JSON/XML input as file. The configuration object will check xml or json file extention and will call the json or xml parser accordingly")
("channel-config", po::value<vector<string>>()->multitoken()->composing(), "Configuration of single or multiple channel(s) by comma separated key=value list")
;
AddToCmdLineOptions(fMQCmdOptions);
AddToCmdLineOptions(fMQParserOptions);
}
int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, const string& member, const string& val)
{ {
if (member == "type") if (member == "type")
{ {
fFairMQMap.at(channelName).at(index).UpdateType(val); fFairMQChannelMap.at(channelName).at(index).UpdateType(val);
return 0; return 0;
} }
if (member == "method") if (member == "method")
{ {
fFairMQMap.at(channelName).at(index).UpdateMethod(val); fFairMQChannelMap.at(channelName).at(index).UpdateMethod(val);
return 0; return 0;
} }
if (member == "address") if (member == "address")
{ {
fFairMQMap.at(channelName).at(index).UpdateAddress(val); fFairMQChannelMap.at(channelName).at(index).UpdateAddress(val);
return 0; return 0;
} }
if (member == "transport") if (member == "transport")
{ {
fFairMQMap.at(channelName).at(index).UpdateTransport(val); fFairMQChannelMap.at(channelName).at(index).UpdateTransport(val);
return 0; return 0;
} }
else else
{ {
//if we get there it means something is wrong //if we get there it means something is wrong
LOG(error) << "update of FairMQChannel map failed for the following key: " LOG(error) << "update of FairMQChannel map failed for the following key: " << channelName << "." << index << "." << member;
<< channelName << "." << index << "." << member;
return 1; return 1;
} }
} }
int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, const string& member, int val) int FairMQProgOptions::UpdateChannelValue(const string& channelName, int index, const string& member, int val)
{ {
if (member == "sndBufSize") if (member == "sndBufSize")
{ {
fFairMQMap.at(channelName).at(index).UpdateSndBufSize(val); fFairMQChannelMap.at(channelName).at(index).UpdateSndBufSize(val);
return 0; return 0;
} }
if (member == "rcvBufSize") if (member == "rcvBufSize")
{ {
fFairMQMap.at(channelName).at(index).UpdateRcvBufSize(val); fFairMQChannelMap.at(channelName).at(index).UpdateRcvBufSize(val);
return 0; return 0;
} }
if (member == "rateLogging") if (member == "rateLogging")
{ {
fFairMQMap.at(channelName).at(index).UpdateRateLogging(val); fFairMQChannelMap.at(channelName).at(index).UpdateRateLogging(val);
return 0; return 0;
} }
else else
@@ -315,3 +351,135 @@ int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, co
return 1; return 1;
} }
} }
vector<string> FairMQProgOptions::GetPropertyKeys() const
{
lock_guard<mutex> lock{fConfigMutex};
vector<string> result;
for (const auto& it : fVarMap)
{
result.push_back(it.first.c_str());
}
return result;
}
/// Add option descriptions
int FairMQProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool /* visible */)
{
fAllOptions.add(optDesc);
return 0;
}
po::options_description& FairMQProgOptions::GetCmdLineOptions()
{
return fAllOptions;
}
int FairMQProgOptions::PrintOptions()
{
// -> loop over variable map and print its content
// -> In this example the following types are supported:
// string, int, float, double, short, boost::filesystem::path
// vector<string>, vector<int>, vector<float>, vector<double>, vector<short>
map<string, VarValInfo> mapinfo;
// get string length for formatting and convert varmap values into string
int maxLenKey = 0;
int maxLenValue = 0;
int maxLenType = 0;
int maxLenDefault = 0;
for (const auto& m : fVarMap)
{
maxLenKey = max(maxLenKey, static_cast<int>(m.first.length()));
VarValInfo valinfo = ConvertVariableValue<options::ToVarValInfo>()((m.second));
mapinfo[m.first] = valinfo;
maxLenValue = max(maxLenValue, static_cast<int>(valinfo.value.length()));
maxLenType = max(maxLenType, static_cast<int>(valinfo.type.length()));
maxLenDefault = max(maxLenDefault, static_cast<int>(valinfo.defaulted.length()));
}
// TODO : limit the value len field in a better way
if (maxLenValue > 100)
{
maxLenValue = 100;
}
for (const auto& o : fUnregisteredOptions)
{
LOG(debug) << "detected unregistered option: " << o;
}
stringstream ss;
ss << "Configuration: \n";
for (const auto& p : mapinfo)
{
ss << setfill(' ') << left
<< setw(maxLenKey) << p.first << " = "
<< setw(maxLenValue) << p.second.value
<< setw(maxLenType) << p.second.type
<< setw(maxLenDefault) << p.second.defaulted
<< "\n";
}
LOG(info) << ss.str();
return 0;
}
int FairMQProgOptions::PrintOptionsRaw()
{
const vector<boost::shared_ptr<po::option_description>>& options = fAllOptions.options();
for (const auto& o : options)
{
VarValInfo value;
if (fVarMap.count(o->canonical_display_name()))
{
value = ConvertVariableValue<options::ToVarValInfo>()((fVarMap[o->canonical_display_name()]));
}
string description = o->description();
replace(description.begin(), description.end(), '\n', ' ');
cout << o->long_name() << ":" << value.value << ":" << (value.type == "" ? "<unknown>" : value.type) << ":" << description << endl;
}
return 0;
}
string FairMQProgOptions::GetStringValue(const string& key)
{
unique_lock<mutex> lock(fConfigMutex);
string valueStr;
try
{
if (fVarMap.count(key))
{
valueStr = ConvertVariableValue<options::ToString>()(fVarMap.at(key));
}
}
catch (exception& e)
{
LOG(error) << "Exception thrown for the key '" << key << "'";
LOG(error) << e.what();
}
return valueStr;
}
int FairMQProgOptions::Count(const string& key) const
{
unique_lock<mutex> lock(fConfigMutex);
return fVarMap.count(key);
}

View File

@@ -6,26 +6,22 @@
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
/*
* File: FairMQProgOptions.h
* Author: winckler
*
* Created on March 11, 2015, 10:20 PM
*/
#ifndef FAIRMQPROGOPTIONS_H #ifndef FAIRMQPROGOPTIONS_H
#define FAIRMQPROGOPTIONS_H #define FAIRMQPROGOPTIONS_H
#include <fairmq/EventManager.h> #include <fairmq/EventManager.h>
#include "FairMQLogger.h"
#include "FairProgOptions.h"
#include "FairMQChannel.h" #include "FairMQChannel.h"
#include <fairmq/Tools.h>
#include <boost/program_options.hpp>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
#include <map>
#include <mutex>
#include <string> #include <string>
#include <vector>
#include <mutex>
#include <sstream>
namespace fair namespace fair
{ {
@@ -38,10 +34,10 @@ struct PropertyChangeAsString : Event<std::string> {};
} /* namespace mq */ } /* namespace mq */
} /* namespace fair */ } /* namespace fair */
class FairMQProgOptions : public FairProgOptions class FairMQProgOptions
{ {
protected: private:
using FairMQMap = std::unordered_map<std::string, std::vector<FairMQChannel>>; using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
public: public:
FairMQProgOptions(); FairMQProgOptions();
@@ -49,52 +45,11 @@ class FairMQProgOptions : public FairProgOptions
int ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered); int ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered);
// parse command line. // parse command line.
// default parser for the mq-configuration file (JSON/XML) is called if command line key mq-config is called // default parser for the mq-configuration file (JSON) is called if command line key mq-config is called
int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) override; int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = true);
FairMQMap GetFairMQMap() const FairMQChannelMap GetFairMQMap() const;
{ std::unordered_map<std::string, int> GetChannelInfo() const;
return fFairMQMap;
}
std::unordered_map<std::string, int> GetChannelInfo() const
{
return fChannelInfo;
}
template<typename T>
int UpdateValue(const std::string& key, T val)
{
std::unique_lock<std::mutex> lock(fConfigMutex);
if (fVarMap.count(key))
{
// update variable map
UpdateVarMap<typename std::decay<T>::type>(key, val);
// update FairMQChannel map, check first if data are int or string
if (std::is_same<T, int>::value || std::is_same<T, std::string>::value)
{
if (fMQKeyMap.count(key))
{
UpdateChannelMap(fMQKeyMap.at(key).channel, fMQKeyMap.at(key).index, fMQKeyMap.at(key).member, val);
}
}
lock.unlock();
//if (std::is_same<T, int>::value || std::is_same<T, std::string>::value)//if one wants to restrict type
fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetStringValue(key));
return 0;
}
else
{
LOG(error) << "UpdateValue failed: key '" << key << "' not found in the variable map";
return 1;
}
return 0;
}
template<typename T> template<typename T>
int SetValue(const std::string& key, T val) int SetValue(const std::string& key, T val)
@@ -104,12 +59,12 @@ class FairMQProgOptions : public FairProgOptions
// update variable map // update variable map
UpdateVarMap<typename std::decay<T>::type>(key, val); UpdateVarMap<typename std::decay<T>::type>(key, val);
// update FairMQChannel map, check first if data are int or string // update FairMQChannel map if the key is a channel key
if (std::is_same<T, int>::value || std::is_same<T, std::string>::value) if (std::is_same<T, int>::value || std::is_same<T, std::string>::value)
{ {
if (fMQKeyMap.count(key)) if (fChannelKeyMap.count(key))
{ {
UpdateChannelMap(fMQKeyMap.at(key).channel, fMQKeyMap.at(key).index, fMQKeyMap.at(key).member, val); UpdateChannelValue(fChannelKeyMap.at(key).channel, fChannelKeyMap.at(key).index, fChannelKeyMap.at(key).member, val);
} }
} }
@@ -155,57 +110,114 @@ class FairMQProgOptions : public FairProgOptions
fEvents.Unsubscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber); fEvents.Unsubscribe<fair::mq::PropertyChangeAsString, std::string>(subscriber);
} }
// replace FairMQChannelMap, and update variable map accordingly std::vector<std::string> GetPropertyKeys() const;
int UpdateChannelMap(const FairMQMap& map);
protected: // get value corresponding to the key
struct MQKey template<typename T>
T GetValue(const std::string& key) const
{
std::unique_lock<std::mutex> lock(fConfigMutex);
T val = T();
if (fVarMap.count(key))
{
val = fVarMap[key].as<T>();
}
else
{
LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";
}
return val;
}
// Given a key, convert the variable value to string
std::string GetStringValue(const std::string& key);
int Count(const std::string& key) const;
template<typename T>
T ConvertTo(const std::string& strValue)
{
if (std::is_arithmetic<T>::value)
{
std::istringstream iss(strValue);
T val;
iss >> val;
return val;
}
else
{
LOG(error) << "the provided string " << strValue << " cannot be converted to the requested type. The target type must be arithmetic type.";
}
}
// add options_description
int AddToCmdLineOptions(const boost::program_options::options_description optDesc, bool visible = true);
boost::program_options::options_description& GetCmdLineOptions();
const boost::program_options::variables_map& GetVarMap() const { return fVarMap; }
int PrintOptions();
int PrintOptionsRaw();
private:
struct ChannelKey
{ {
std::string channel; std::string channel;
int index; int index;
std::string member; std::string member;
}; };
po::options_description fMQCmdOptions; boost::program_options::variables_map fVarMap; ///< options container
po::options_description fMQParserOptions; FairMQChannelMap fFairMQChannelMap;
FairMQMap fFairMQMap;
// map of read channel info - channel name - number of subchannels boost::program_options::options_description fAllOptions; ///< all options descriptions
std::unordered_map<std::string, int> fChannelInfo; boost::program_options::options_description fGeneralOptions; ///< general options descriptions
boost::program_options::options_description fMQOptions; ///< MQ options descriptions
boost::program_options::options_description fParserOptions; ///< MQ Parser options descriptions
std::map<std::string, MQKey> fMQKeyMap;// key=full path - val=key info mutable std::mutex fConfigMutex;
int ImmediateOptions() override; // for custom help & version printing std::unordered_map<std::string, int> fChannelInfo; ///< channel name - number of subchannels
void InitOptionDescription(); std::unordered_map<std::string, ChannelKey> fChannelKeyMap;// key=full path - val=key info
std::vector<std::string> fUnregisteredOptions; ///< container with unregistered options
fair::mq::EventManager fEvents;
void ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered = true);
void ParseDefaults();
// read FairMQChannelMap and insert/update corresponding values in variable map // read FairMQChannelMap and insert/update corresponding values in variable map
// create key for variable map as follow : channelName.index.memberName // create key for variable map as follow : channelName.index.memberName
void UpdateMQValues(); void UpdateMQValues();
int Store(const FairMQMap& channels); int Store(const FairMQChannelMap& channels);
private:
template<typename T> template<typename T>
void EmitUpdate(const std::string& key, T val) void EmitUpdate(const std::string& key, T val)
{ {
//compile time check whether T is const char* or char*, and in that case a compile time error is thrown. // compile time check whether T is const char* or char*, and in that case a compile time error is thrown.
static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value, static_assert(!std::is_same<T,const char*>::value || !std::is_same<T, char*>::value,
"In template member FairMQProgOptions::EmitUpdate<T>(key,val) the types const char* or char* for the calback signatures are not supported."); "In template member FairMQProgOptions::EmitUpdate<T>(key,val) the types const char* or char* for the calback signatures are not supported.");
fEvents.Emit<fair::mq::PropertyChange, T>(key, val); fEvents.Emit<fair::mq::PropertyChange, T>(key, val);
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetStringValue(key)); fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetStringValue(key));
} }
int UpdateChannelMap(const std::string& channelName, int index, const std::string& member, const std::string& val); int UpdateChannelMap(const FairMQChannelMap& map);
int UpdateChannelMap(const std::string& channelName, int index, const std::string& member, int val); int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, const std::string& val);
// for cases other than int and string int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, int val);
template<typename T>
int UpdateChannelMap(const std::string& /*channelName*/, int /*index*/, const std::string& /*member*/, T /*val*/)
{
return 0;
}
void UpdateChannelInfo(); void UpdateChannelInfo();
fair::mq::EventManager fEvents; // helper to modify the value of variable map after calling boost::program_options::store
template<typename T>
void UpdateVarMap(const std::string& key, const T& val)
{
std::map<std::string, boost::program_options::variable_value>& vm = fVarMap;
vm[key].value() = boost::any(val);
}
}; };
#endif /* FAIRMQPROGOPTIONS_H */ #endif /* FAIRMQPROGOPTIONS_H */

View File

@@ -29,7 +29,7 @@ namespace parser
constexpr const char* SUBOPT::channelOptionKeys[]; constexpr const char* SUBOPT::channelOptionKeys[];
FairMQMap SUBOPT::UserParser(const vector<string>& channelConfig, const string& deviceId, const string& rootNode) FairMQChannelMap SUBOPT::UserParser(const vector<string>& channelConfig, const string& deviceId, const string& rootNode)
{ {
ptree pt; ptree pt;

View File

@@ -14,14 +14,12 @@
#ifndef FAIRMQPARSER_SUBOPT_H #ifndef FAIRMQPARSER_SUBOPT_H
#define FAIRMQPARSER_SUBOPT_H #define FAIRMQPARSER_SUBOPT_H
#include "FairMQParser.h" // for FairMQMap #include "FairMQParser.h" // for FairMQChannelMap
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <cstring> #include <cstring>
#include <vector> #include <vector>
#include <string> #include <string>
namespace po = boost::program_options;
namespace fair namespace fair
{ {
namespace mq namespace mq
@@ -78,7 +76,7 @@ struct SUBOPT
nullptr nullptr
}; };
FairMQMap UserParser(const std::vector<std::string>& channelConfig, const std::string& deviceId, const std::string& rootNode = "fairMQOptions"); FairMQChannelMap UserParser(const std::vector<std::string>& channelConfig, const std::string& deviceId, const std::string& rootNode = "fairMQOptions");
}; };
} }

View File

@@ -1,178 +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" *
********************************************************************************/
/*
* File: FairProgOptions.cxx
* Author: winckler
*
* Created on March 11, 2015, 5:38 PM
*/
#include "FairProgOptions.h"
#include <iomanip>
#include <sstream>
#include <algorithm>
using namespace std;
using namespace fair::mq;
FairProgOptions::FairProgOptions()
: fVarMap()
, fGeneralOptions("General options")
, fAllOptions("Command line options")
, fConfigMutex()
{
fGeneralOptions.add_options()
("help,h", "produce help")
("version,v", "print version")
("severity", po::value<string>()->default_value("debug"), "Log severity level: trace, debug, info, state, warn, error, fatal, nolog")
("verbosity", po::value<string>()->default_value("medium"), "Log verbosity level: veryhigh, high, medium, low")
("color", po::value<bool>()->default_value(true), "Log color (true/false)")
("log-to-file", po::value<string>()->default_value(""), "Log output to a file.")
("print-options", po::value<bool>()->implicit_value(true), "print options in machine-readable format (<option>:<computed-value>:<type>:<description>)");
fAllOptions.add(fGeneralOptions);
}
FairProgOptions::~FairProgOptions()
{
}
/// Add option descriptions
int FairProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool /* visible */)
{
fAllOptions.add(optDesc);
return 0;
}
po::options_description& FairProgOptions::GetCmdLineOptions()
{
return fAllOptions;
}
int FairProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered)
{
// 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)
{
po::command_line_parser parser{argc, argv};
parser.options(fAllOptions).allow_unregistered();
po::parsed_options parsedOptions = parser.run();
po::store(parsedOptions, fVarMap);
}
else
{
po::store(po::parse_command_line(argc, argv, fAllOptions), fVarMap);
}
// Handles options like "--help" or "--version"
// return 1 if switch options found in fVarMap
if (ImmediateOptions())
{
return 1;
}
po::notify(fVarMap);
return 0;
}
void FairProgOptions::ParseDefaults()
{
vector<string> emptyArgs;
emptyArgs.push_back("dummy");
vector<const char*> argv(emptyArgs.size());
transform(emptyArgs.begin(), emptyArgs.end(), argv.begin(), [](const string& str)
{
return str.c_str();
});
po::store(po::parse_command_line(argv.size(), const_cast<char**>(argv.data()), fAllOptions), fVarMap);
}
int FairProgOptions::PrintOptions()
{
// -> loop over variable map and print its content
// -> In this example the following types are supported:
// string, int, float, double, short, boost::filesystem::path
// vector<string>, vector<int>, vector<float>, vector<double>, vector<short>
map<string, VarValInfo> mapinfo;
// get string length for formatting and convert varmap values into string
int maxLen1st = 0;
int maxLen2nd = 0;
int maxLenTypeInfo = 0;
int maxLenDefault = 0;
int maxLenEmpty = 0;
for (const auto& m : fVarMap)
{
Max(maxLen1st, m.first.length());
VarValInfo valinfo = GetVariableValueInfo(m.second);
mapinfo[m.first] = valinfo;
Max(maxLen2nd, valinfo.value.length());
Max(maxLenTypeInfo, valinfo.type.length());
Max(maxLenDefault, valinfo.defaulted.length());
Max(maxLenEmpty, valinfo.empty.length());
}
// TODO : limit the value len field in a better way
if (maxLen2nd > 100)
{
maxLen2nd = 100;
}
stringstream ss;
ss << "Configuration: \n";
for (const auto& p : mapinfo)
{
ss << setfill(' ')
<< setw(maxLen1st) << left << p.first << " = "
<< setw(maxLen2nd) << p.second.value
<< setw(maxLenTypeInfo) << p.second.type
<< setw(maxLenDefault) << p.second.defaulted
<< setw(maxLenEmpty) << p.second.empty
<< "\n";
}
LOG(info) << ss.str();
return 0;
}
int FairProgOptions::PrintOptionsRaw()
{
const std::vector<boost::shared_ptr<po::option_description>>& options = fAllOptions.options();
for (const auto& o : options)
{
VarValInfo value;
if (fVarMap.count(o->canonical_display_name()))
{
value = GetVariableValueInfo(fVarMap[o->canonical_display_name()]);
}
string description = o->description();
replace(description.begin(), description.end(), '\n', ' ');
cout << o->long_name() << ":" << value.value << ":" << (value.type == "" ? "<unknown>" : value.type) << ":" << description << endl;
}
return 0;
}
VarValInfo FairProgOptions::GetVariableValueInfo(const po::variable_value& varValue)
{
return ConvertVariableValue<ToVarValInfo>()(varValue);
}

View File

@@ -1,172 +1 @@
/******************************************************************************** #warning "This header file is deprecated. Use FairMQProgOptions class directly which now contains all FairProgOptions functionality. Note, that FairMQProgOptions is also available if you include FairMQDevice."
* 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" *
********************************************************************************/
/*
* File: FairProgOptions.h
* Author: winckler
*
* Created on March 11, 2015, 5:38 PM
*/
#ifndef FAIRPROGOPTIONS_H
#define FAIRPROGOPTIONS_H
#include "FairMQLogger.h"
#include "FairProgOptionsHelper.h"
#include <fairmq/Tools.h>
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <fstream>
#include <mutex>
#include <exception>
namespace po = boost::program_options;
namespace fs = boost::filesystem;
class FairProgOptions
{
public:
FairProgOptions();
virtual ~FairProgOptions();
auto GetPropertyKeys() const -> std::vector<std::string>
{
std::lock_guard<std::mutex> lock{fConfigMutex};
std::vector<std::string> result;
for (const auto& it : fVarMap)
{
result.push_back(it.first.c_str());
}
return result;
}
// add options_description
int AddToCmdLineOptions(const po::options_description optDesc, bool visible = true);
po::options_description& GetCmdLineOptions();
// get value corresponding to the key
template<typename T>
T GetValue(const std::string& key) const
{
std::unique_lock<std::mutex> lock(fConfigMutex);
T val = T();
if (fVarMap.count(key))
{
val = fVarMap[key].as<T>();
}
else
{
LOG(warn) << "Config has no key: " << key << ". Returning default constructed object.";
}
return val;
}
// Given a key, convert the variable value to string
std::string GetStringValue(const std::string& key)
{
std::unique_lock<std::mutex> lock(fConfigMutex);
std::string valueStr;
try
{
if (fVarMap.count(key))
{
valueStr = fair::mq::ConvertVariableValue<fair::mq::VarInfoToString>()(fVarMap.at(key));
}
}
catch (std::exception& e)
{
LOG(error) << "Exception thrown for the key '" << key << "'";
LOG(error) << e.what();
}
return valueStr;
}
int Count(const std::string& key) const
{
std::unique_lock<std::mutex> lock(fConfigMutex);
return fVarMap.count(key);
}
//restrict conversion to fundamental types
template<typename T>
T ConvertTo(const std::string& strValue)
{
if (std::is_arithmetic<T>::value)
{
std::istringstream iss(strValue);
T val;
iss >> val;
return val;
}
else
{
LOG(error) << "the provided string " << strValue << " cannot be converted in the requested type. The target types must be arithmetic types";
}
}
const po::variables_map& GetVarMap() const { return fVarMap; }
int ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered = false);
void ParseDefaults();
virtual int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) = 0;
virtual int PrintOptions();
virtual int PrintOptionsRaw();
protected:
// options container
po::variables_map fVarMap;
// options descriptions
po::options_description fGeneralOptions;
po::options_description fAllOptions;
mutable std::mutex fConfigMutex;
virtual int ImmediateOptions() = 0;
// UpdateVarMap() and Replace() --> helper functions to modify the value of variable map after calling po::store
template<typename T>
void UpdateVarMap(const std::string& key, const T& val)
{
Replace(fVarMap, key, val);
}
template<typename T>
void Replace(std::map<std::string, po::variable_value>& vm, const std::string& key, const T& val)
{
vm[key].value() = boost::any(val);
}
private:
fair::mq::VarValInfo GetVariableValueInfo(const po::variable_value& varValue);
static void Max(int& val, const int& comp)
{
if (comp > val)
{
val = comp;
}
}
};
#endif /* FAIRPROGOPTIONS_H */

View File

@@ -17,137 +17,95 @@
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <boost/filesystem.hpp> #include <boost/filesystem.hpp>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
#include <iostream> #include <iostream>
#include <ostream> #include <ostream>
#include <iterator> #include <iterator>
#include <typeinfo>
namespace fair namespace fair
{ {
namespace mq namespace mq
{ {
template<class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
for (const auto& i : v)
{
os << i << " ";
}
return os;
}
struct VarValInfo struct VarValInfo
{ {
std::string value; std::string value;
std::string type; std::string type;
std::string defaulted; std::string defaulted;
std::string empty;
}; };
template<class T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v)
{
std::copy(v.begin(), v.end(), std::ostream_iterator<T>(os, " "));
return os;
}
template<typename T> template<typename T>
bool typeIs(const boost::program_options::variable_value& varValue) std::string ConvertVariableValueToString(const boost::program_options::variable_value& varVal)
{ {
auto& value = varValue.value(); std::ostringstream oss;
if (auto q = boost::any_cast<T>(&value)) if (auto q = boost::any_cast<T>(&varVal.value())) {
{ oss << *q;
return true;
}
else
{
return false;
} }
return oss.str();
} }
template<typename T> namespace options
std::string ConvertVariableValueToString(const boost::program_options::variable_value& varValue)
{ {
auto& value = varValue.value();
std::ostringstream ostr;
if (auto q = boost::any_cast<T>(&value))
{
ostr << *q;
}
std::string valueStr = ostr.str();
return valueStr;
}
// string specialization
template<>
inline std::string ConvertVariableValueToString<std::string>(const boost::program_options::variable_value& varValue)
{
auto& value = varValue.value();
std::string valueStr;
if (auto q = boost::any_cast<std::string>(&value))
{
valueStr = *q;
}
return valueStr;
}
// boost::filesystem::path specialization
template<>
inline std::string ConvertVariableValueToString<boost::filesystem::path>(const boost::program_options::variable_value& varValue)
{
auto& value = varValue.value();
std::string valueStr;
if (auto q = boost::any_cast<boost::filesystem::path>(&value))
{
valueStr = (*q).string();
}
return valueStr;
}
// policy to convert boost variable value into string // policy to convert boost variable value into string
struct VarInfoToString struct ToString
{ {
using returned_type = std::string; using returned_type = std::string;
template<typename T> template<typename T>
std::string Value(const boost::program_options::variable_value& varValue, const std::string&, const std::string&, const std::string&) std::string Value(const boost::program_options::variable_value& varVal, const std::string&, const std::string&)
{ {
return ConvertVariableValueToString<T>(varValue); return ConvertVariableValueToString<T>(varVal);
} }
returned_type DefaultValue(const std::string&, const std::string&) returned_type DefaultValue(const std::string&)
{ {
return std::string("empty value"); return std::string("[unidentified]");
} }
}; };
// policy to convert variable value content into VarValInfo // policy to convert variable value content into VarValInfo
struct ToVarValInfo struct ToVarValInfo
{ {
using returned_type = fair::mq::VarValInfo; using returned_type = VarValInfo;
template<typename T> template<typename T>
returned_type Value(const boost::program_options::variable_value& varValue, const std::string& type, const std::string& defaulted, const std::string& empty) returned_type Value(const boost::program_options::variable_value& varVal, const std::string& type, const std::string& defaulted)
{ {
std::string valueStr = ConvertVariableValueToString<T>(varValue); return VarValInfo{ConvertVariableValueToString<T>(varVal), type, defaulted};
return fair::mq::VarValInfo{valueStr, type, defaulted, empty};
} }
returned_type DefaultValue(const std::string& defaulted, const std::string& empty) returned_type DefaultValue(const std::string& defaulted)
{ {
return fair::mq::VarValInfo{std::string("Unknown value"), std::string(" [Unknown]"), defaulted, empty}; return VarValInfo{std::string("[unidentified]"), std::string("[unidentified]"), defaulted};
} }
}; };
} // namespace options
// host class that take one of the two policy defined above // host class that take one of the two policy defined above
template<typename T> template<typename T>
struct ConvertVariableValue : T struct ConvertVariableValue : T
{ {
auto operator()(const boost::program_options::variable_value& varValue) -> typename T::returned_type auto operator()(const boost::program_options::variable_value& varVal) -> typename T::returned_type
{ {
std::string defaulted; std::string defaulted;
std::string empty;
if (varValue.empty()) if (varVal.defaulted())
{
empty = " [empty]";
}
else
{
if (varValue.defaulted())
{ {
defaulted = " [default]"; defaulted = " [default]";
} }
@@ -155,73 +113,75 @@ struct ConvertVariableValue : T
{ {
defaulted = " [provided]"; defaulted = " [provided]";
} }
}
if (typeIs<std::string>(varValue)) if (typeid(std::string) == varVal.value().type())
return T::template Value<std::string>(varValue, std::string("<string>"), defaulted, empty); return T::template Value<std::string>(varVal, std::string("<string>"), defaulted);
if (typeIs<std::vector<std::string>>(varValue)) if (typeid(std::vector<std::string>) == varVal.value().type())
return T::template Value<std::vector<std::string>>(varValue, std::string("<vector<string>>"), defaulted, empty); return T::template Value<std::vector<std::string>>(varVal, std::string("<vector<string>>"), defaulted);
if (typeIs<int>(varValue)) if (typeid(int) == varVal.value().type())
return T::template Value<int>(varValue, std::string("<int>"), defaulted, empty); return T::template Value<int>(varVal, std::string("<int>"), defaulted);
if (typeIs<std::vector<int>>(varValue)) if (typeid(std::vector<int>) == varVal.value().type())
return T::template Value<std::vector<int>>(varValue, std::string("<vector<int>>"), defaulted, empty); return T::template Value<std::vector<int>>(varVal, std::string("<vector<int>>"), defaulted);
if (typeIs<float>(varValue)) if (typeid(float) == varVal.value().type())
return T::template Value<float>(varValue, std::string("<float>"), defaulted, empty); return T::template Value<float>(varVal, std::string("<float>"), defaulted);
if (typeIs<std::vector<float>>(varValue)) if (typeid(std::vector<float>) == varVal.value().type())
return T::template Value<std::vector<float>>(varValue, std::string("<vector<float>>"), defaulted, empty); return T::template Value<std::vector<float>>(varVal, std::string("<vector<float>>"), defaulted);
if (typeIs<double>(varValue)) if (typeid(double) == varVal.value().type())
return T::template Value<double>(varValue, std::string("<double>"), defaulted, empty); return T::template Value<double>(varVal, std::string("<double>"), defaulted);
if (typeIs<std::vector<double>>(varValue)) if (typeid(std::vector<double>) == varVal.value().type())
return T::template Value<std::vector<double>>(varValue, std::string("<vector<double>>"), defaulted, empty); return T::template Value<std::vector<double>>(varVal, std::string("<vector<double>>"), defaulted);
if (typeIs<short>(varValue)) if (typeid(short) == varVal.value().type())
return T::template Value<short>(varValue, std::string("<short>"), defaulted, empty); return T::template Value<short>(varVal, std::string("<short>"), defaulted);
if (typeIs<std::vector<short>>(varValue)) if (typeid(std::vector<short>) == varVal.value().type())
return T::template Value<std::vector<short>>(varValue, std::string("<vector<short>>"), defaulted, empty); return T::template Value<std::vector<short>>(varVal, std::string("<vector<short>>"), defaulted);
if (typeIs<long>(varValue)) if (typeid(long) == varVal.value().type())
return T::template Value<long>(varValue, std::string("<long>"), defaulted, empty); return T::template Value<long>(varVal, std::string("<long>"), defaulted);
if (typeIs<std::vector<long>>(varValue)) if (typeid(std::vector<long>) == varVal.value().type())
return T::template Value<std::vector<long>>(varValue, std::string("<vector<long>>"), defaulted, empty); return T::template Value<std::vector<long>>(varVal, std::string("<vector<long>>"), defaulted);
if (typeIs<std::size_t>(varValue)) if (typeid(std::size_t) == varVal.value().type())
return T::template Value<std::size_t>(varValue, std::string("<std::size_t>"), defaulted, empty); return T::template Value<std::size_t>(varVal, std::string("<std::size_t>"), defaulted);
if (typeIs<std::vector<std::size_t>>(varValue)) if (typeid(std::vector<std::size_t>) == varVal.value().type())
return T::template Value<std::vector<std::size_t>>(varValue, std::string("<vector<std::size_t>>"), defaulted, empty); return T::template Value<std::vector<std::size_t>>(varVal, std::string("<vector<std::size_t>>"), defaulted);
if (typeIs<std::uint32_t>(varValue)) if (typeid(std::uint32_t) == varVal.value().type())
return T::template Value<std::uint32_t>(varValue, std::string("<std::uint32_t>"), defaulted, empty); return T::template Value<std::uint32_t>(varVal, std::string("<std::uint32_t>"), defaulted);
if (typeIs<std::vector<std::uint32_t>>(varValue)) if (typeid(std::vector<std::uint32_t>) == varVal.value().type())
return T::template Value<std::vector<std::uint32_t>>(varValue, std::string("<vector<std::uint32_t>>"), defaulted, empty); return T::template Value<std::vector<std::uint32_t>>(varVal, std::string("<vector<std::uint32_t>>"), defaulted);
if (typeIs<std::uint64_t>(varValue)) if (typeid(std::uint64_t) == varVal.value().type())
return T::template Value<std::uint64_t>(varValue, std::string("<std::uint64_t>"), defaulted, empty); return T::template Value<std::uint64_t>(varVal, std::string("<std::uint64_t>"), defaulted);
if (typeIs<std::vector<std::uint64_t>>(varValue)) if (typeid(std::vector<std::uint64_t>) == varVal.value().type())
return T::template Value<std::vector<std::uint64_t>>(varValue, std::string("<vector<std::uint64_t>>"), defaulted, empty); return T::template Value<std::vector<std::uint64_t>>(varVal, std::string("<vector<std::uint64_t>>"), defaulted);
if (typeIs<bool>(varValue)) if (typeid(bool) == varVal.value().type())
return T::template Value<bool>(varValue, std::string("<bool>"), defaulted, empty); return T::template Value<bool>(varVal, std::string("<bool>"), defaulted);
if (typeIs<std::vector<bool>>(varValue)) if (typeid(std::vector<bool>) == varVal.value().type())
return T::template Value<std::vector<bool>>(varValue, std::string("<vector<bool>>"), defaulted, empty); return T::template Value<std::vector<bool>>(varVal, std::string("<vector<bool>>"), defaulted);
if (typeIs<boost::filesystem::path>(varValue)) if (typeid(boost::filesystem::path) == varVal.value().type())
return T::template Value<boost::filesystem::path>(varValue, std::string("<boost::filesystem::path>"), defaulted, empty); return T::template Value<boost::filesystem::path>(varVal, std::string("<boost::filesystem::path>"), defaulted);
if (typeid(std::vector<boost::filesystem::path>) == varVal.value().type())
return T::template Value<std::vector<boost::filesystem::path>>(varVal, std::string("<std::vector<boost::filesystem::path>>"), defaulted);
// if we get here, the type is not supported return unknown info // if we get here, the type is not supported return unknown info
return T::DefaultValue(defaulted, empty); return T::DefaultValue(defaulted);
} }
}; };

View File

@@ -1,98 +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" #
################################################################################
# Create a library called "ProgOptionTest"
# Test fair-prog-opt
# scripts
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions1.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions1.sh )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions2.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions2.sh )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions3.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions3.sh )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions4.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions4.sh )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testMQOptions5.sh.in ${CMAKE_BINARY_DIR}/bin/testMQOptions5.sh )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/start-bsampler-sink.sh.in ${CMAKE_BINARY_DIR}/bin/start-bsampler-sink.sh )
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions1.sh")
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions2.sh")
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions3.sh")
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions4.sh")
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/testMQOptions5.sh")
EXEC_PROGRAM(/bin/chmod ARGS "u+x ${CMAKE_BINARY_DIR}/bin/start-bsampler-sink.sh")
# Config/xml/json example file
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/ConfigFileTest.cfg.in ${CMAKE_BINARY_DIR}/bin/ConfigFileTest.cfg)
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testXML.xml ${CMAKE_BINARY_DIR}/bin/testXML.xml )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/testJSON.json ${CMAKE_BINARY_DIR}/bin/testJSON.json )
configure_file( ${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/macro/bsampler-sink.json ${CMAKE_BINARY_DIR}/bin/bsampler-sink.json )
set(INCLUDE_DIRECTORIES
${CMAKE_SOURCE_DIR}/fairmq
${CMAKE_SOURCE_DIR}/fairmq/options
${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/lib
${CMAKE_SOURCE_DIR}/fairmq/options/ProgOptionTest/run
)
Set(SYSTEM_INCLUDE_DIRECTORIES
${SYSTEM_INCLUDE_DIRECTORIES}
)
include_directories(${INCLUDE_DIRECTORIES})
include_directories(${SYSTEM_INCLUDE_DIRECTORIES})
set(LINK_DIRECTORIES
${Boost_LIBRARY_DIRS}
)
link_directories(${LINK_DIRECTORIES})
Set(SRCS
lib/FairMQParserExample.cxx
)
Set(LIBRARY_NAME ProgOptionTest)
If (Boost_FOUND)
Set(DEPENDENCIES
${Boost_SYSTEM_LIBRARY}
${Boost_PROGRAM_OPTIONS_LIBRARY})
FairMQ
)
EndIf (Boost_FOUND)
GENERATE_LIBRARY()
If (Boost_FOUND)
Set(Exe_Names
runtestMQOption1
runtestMQOption2
runOptTestSampler
runOptTestSink
)
set(Exe_Source
run/testMQoptions1.cxx
run/testMQoptions2.cxx
run/runOptTestSampler.cxx
run/runOptTestSink.cxx
)
List(LENGTH Exe_Names _length)
Math(EXPR _length ${_length}-1)
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 ProgOptionTest)
GENERATE_EXECUTABLE()
EndForEach(_file RANGE 0 ${_length})
EndIf (Boost_FOUND)

View File

@@ -1,74 +0,0 @@
/*
* File: FairMQParserExample.cxx
* Author: winckler
*
* Created on May 14, 2015, 5:01 PM
*/
#include "FairMQParserExample.h"
#include "FairMQLogger.h"
#include <boost/property_tree/xml_parser.hpp>
namespace FairMQParser
{
// other xml examples
////////////////////////////////////////////////////////////////////////////
boost::property_tree::ptree MQXML2::UserParser(const std::string& filename)
{
boost::property_tree::ptree pt;
boost::property_tree::read_xml(filename, pt);
return pt;
}
// TODO : finish implementation
////////////////////////////////////////////////////////////////////////////
boost::property_tree::ptree MQXML3::UserParser(const std::string& filename, const std::string& devicename)
{
// Create an empty property tree object
boost::property_tree::ptree pt;
boost::property_tree::read_xml(filename, pt);
// Create fair mq map
auto xml = pt.get_child("");
std::vector<std::pair<std::string, boost::property_tree::ptree>> match;
std::pair<std::string, boost::property_tree::ptree> device_match;
ProcessTree(xml.begin (), xml.end (), std::back_inserter(match),
[] (const std::string& key) { return key == "device"; });
// for each device
for (const auto& pair: match)
{
if(pair.second.get<std::string>("<xmlattr>.name") == devicename)
{
device_match=pair;
}
else
{
//match.erase(std::remove(match.begin(), match.end(), pair), match.end());
continue;
}
//std::cout << "pair.first " << pair.first << std::endl;//device
//std::cout << "\t node = " << pair.first
// << "\t name = " << pair.second.get<std::string>("<xmlattr>.name")
// << "\t id = " << pair.second.get<std::string>("<xmlattr>.id");
//std::cout<<std::endl;
}
return device_match.second;
}
} // end FairMQParser namespace

View File

@@ -1,86 +0,0 @@
/*
* File: FairMQParserExample.h
* Author: winckler
*
* Created on May 14, 2015, 5:01 PM
*/
#ifndef FAIRMQPARSEREXAMPLE_H
#define FAIRMQPARSEREXAMPLE_H
// FairRoot
#include "FairMQChannel.h"
#include "FairMQParser.h"
// Boost
#include <boost/property_tree/ptree.hpp>
// std
#include <string>
#include <vector>
#include <map>
namespace FairMQParser
{
////////////////////////////////////////////////////////////////////////////
/////////////////////////////////// XML ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
// xml example 2
////////////////////////////////////////////////////////////////////////////
struct MQXML2
{
boost::property_tree::ptree UserParser(const std::string& filename);
};
// xml example 3
////////////////////////////////////////////////////////////////////////////
struct MQXML3
{
boost::property_tree::ptree UserParser(const std::string& filename, const std::string& root_node);
};
////////////////////////////////////////////////////////////////////////////
// template function iterating over the whole boost property tree
template <typename Input_tree_It, typename Output_tree_It, typename Compare_key>
void ProcessTree(Input_tree_It first, Input_tree_It last, Output_tree_It dest, Compare_key compare)
{
//typedef typename std::iterator_traits<Input_tree_It>::reference reference;
if (first == last)
{
return;
}
auto begin = first->second.begin ();
auto end = first->second.end ();
if (begin != end)
{
ProcessTree (begin, end, dest, compare);
}
if (compare (first->first))
{
dest = *first;
}
ProcessTree (++first, last, dest, compare);
}
class no_id_exception: public std::exception
{
virtual const char* what() const throw()
{
return "Empty string for the device-id in FairMQParser::ptreeToMQMap(...) function";
}
};
} // end FairMQParser namespace
#endif /* FAIRMQPARSEREXAMPLE_H */

View File

@@ -1,38 +0,0 @@
#----------------------------------------------------
# comments :
# brackets [] are used to group options. For example :
#
# [xml.config]
# node.root = fairMQOptions
#
# is equivalent to
# xml.config.node.root = fairMQOptions
#----------------------------------------------------
config-json-file = @CMAKE_BINARY_DIR@/bin/testJSON.json
config-xml-file = @CMAKE_BINARY_DIR@/bin/testXML.xml
#
device-id = merger
#-------------------
[xml.config]
#filename = @CMAKE_BINARY_DIR@/bin/testXML.xml
node.root = fairMQOptions
#-------------------
[input.file]
name = sampler_file_name.root
tree = sampler_tree
branch = sampler_branch
#-------------------
[output.file]
name = sink_filename.root
tree = sink_tree
branch = sink_branch

View File

@@ -1,18 +0,0 @@
#!/bin/bash
JSONFILE="@CMAKE_BINARY_DIR@/bin/bsampler-sink.json"
# Note: device-id value must correspond to the device id given in the json file
BSAMPLER="runOptTestSampler"
BSAMPLER+=" --config-json-file $JSONFILE"
BSAMPLER+=" --id bsampler1"
xterm -geometry 150x23+0+0 -hold -e @CMAKE_BINARY_DIR@/bin/$BSAMPLER &
SINK="runOptTestSink"
SINK+=" --config-json-file $JSONFILE"
SINK+=" --id sink1"
xterm -geometry 150x23+0+350 -hold -e @CMAKE_BINARY_DIR@/bin/$SINK &

View File

@@ -1,63 +0,0 @@
{
"fairMQOptions": {
"devices": [
{
"id": "merger1",
"channels": [
{
"name": "two_inputs_channel",
"sockets": [
{
"type": "pull",
"method": "",
"address": "tcp://*:5569",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"rateLogging": 1
},
{
"type": "pull",
"method": "bind",
"address": "tcp://*:5570",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"rateLogging": 1
}
]
},
{
"name": "one_output_channel",
"sockets": [
{
"type": "push",
"method": "connect",
"address": "tcp://*:5571",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"rateLogging": 1
}
]
}
]
},
{
"id": "sink1",
"channels": [
{
"name": "one_input",
"sockets": [
{
"type": "pull",
"method": "bind",
"address": "tcp://localhost:5571",
"sndBufSize": 1000,
"rcvBufSize": 1000,
"rateLogging": 1
}
]
}
]
}
]
}
}

View File

@@ -1,11 +0,0 @@
#!/bin/bash
RUN_TEST="runtestMQOption1"
if [ "$#" -gt 0 ]; then
RUN_TEST+=" $*"
fi
RUN_TEST+=" --config-xml-file @CMAKE_BINARY_DIR@/bin/testXML.xml"
@CMAKE_BINARY_DIR@/bin/$RUN_TEST

View File

@@ -1,59 +0,0 @@
#!/bin/bash
RUN_TEST="runtestMQOption1"
if [ "$#" -gt 0 ]; then
RUN_TEST+=" $*"
fi
XML_CMD_LINE="<fairMQOptions>"
XML_CMD_LINE+="<device name=\"merger\" id=\"1234\" >"
XML_CMD_LINE+=" <channel name=\"two_inputs_channel\" >"
XML_CMD_LINE+=" <socket name=\"input1\" >"
XML_CMD_LINE+=" <type>pull</type>"
XML_CMD_LINE+=" <method>bind</method>"
XML_CMD_LINE+=" <address>tcp://*:5569</address>"
XML_CMD_LINE+=" <sndBufSize>1000</sndBufSize>"
XML_CMD_LINE+=" <rcvBufSize>1000</rcvBufSize>"
XML_CMD_LINE+=" <rateLogging>1</rateLogging>"
XML_CMD_LINE+=" </socket>"
XML_CMD_LINE+=" <socket name=\"input2\" >"
XML_CMD_LINE+=" <type>pull</type>"
XML_CMD_LINE+=" <method>bind</method>"
XML_CMD_LINE+=" <address>tcp://*:5570</address>"
XML_CMD_LINE+=" <sndBufSize>1000</sndBufSize>"
XML_CMD_LINE+=" <rcvBufSize>1000</rcvBufSize>"
XML_CMD_LINE+=" <rateLogging>1</rateLogging>"
XML_CMD_LINE+=" </socket>"
XML_CMD_LINE+=" </channel>"
XML_CMD_LINE+=" <channel name=\"one_output_channel\" >"
XML_CMD_LINE+=" <socket name=\"output1\" >"
XML_CMD_LINE+=" <type>push</type>"
XML_CMD_LINE+=" <method>connect</method>"
XML_CMD_LINE+=" <address>tcp://*:5571</address>"
XML_CMD_LINE+=" <sndBufSize>1000</sndBufSize>"
XML_CMD_LINE+=" <rcvBufSize>1000</rcvBufSize>"
XML_CMD_LINE+=" <rateLogging>1</rateLogging>"
XML_CMD_LINE+=" </socket>"
XML_CMD_LINE+=" </channel>"
XML_CMD_LINE+=" </device>"
XML_CMD_LINE+=" <device name=\"sink\" id=\"4567\" >"
XML_CMD_LINE+=" <channel name=\"one_input\" >"
XML_CMD_LINE+=" <socket name=\"input1\" >"
XML_CMD_LINE+=" <type>pull</type>"
XML_CMD_LINE+=" <method>bind</method>"
XML_CMD_LINE+=" <address>tcp://localhost:5571</address>"
XML_CMD_LINE+=" <sndBufSize>1000</sndBufSize>"
XML_CMD_LINE+=" <rcvBufSize>1000</rcvBufSize>"
XML_CMD_LINE+=" <rateLogging>1</rateLogging>"
XML_CMD_LINE+=" </socket>"
XML_CMD_LINE+=" </channel>"
XML_CMD_LINE+=" </device>"
XML_CMD_LINE+="</fairmq_option>"
RUN_TEST+=" --config-xml-string $XML_CMD_LINE"
@CMAKE_BINARY_DIR@/bin/$RUN_TEST

View File

@@ -1,10 +0,0 @@
#!/bin/bash
RUN_TEST="runtestMQOption2"
if [ "$#" -gt 0 ]; then
RUN_TEST+=" $*"
fi
RUN_TEST+=" --config @CMAKE_BINARY_DIR@/bin/ConfigFileTest.cfg"
@CMAKE_BINARY_DIR@/bin/$RUN_TEST

View File

@@ -1,11 +0,0 @@
#!/bin/bash
RUN_TEST="runtestMQOption1"
if [ "$#" -gt 0 ]; then
RUN_TEST+=" $*"
fi
RUN_TEST+=" --config-json-file @CMAKE_BINARY_DIR@/bin/testJSON.json"
@CMAKE_BINARY_DIR@/bin/$RUN_TEST

View File

@@ -1,77 +0,0 @@
#!/bin/bash
RUN_TEST="runtestMQOption1"
if [ "$#" -gt 0 ]; then
RUN_TEST+=" $*"
fi
JSON_CMD_LINE="{"
JSON_CMD_LINE+=" \"fairMQOptions\": {"
JSON_CMD_LINE+=" \"device\": "
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"merger\","
JSON_CMD_LINE+=" \"id\": \"1234\","
JSON_CMD_LINE+=" \"channel\": "
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"two_inputs_channel\","
JSON_CMD_LINE+=" \"socket\": "
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"input1\","
JSON_CMD_LINE+=" \"type\": \"pull\","
JSON_CMD_LINE+=" \"method\": \"bind\","
JSON_CMD_LINE+=" \"address\": \"tcp://*:5569\","
JSON_CMD_LINE+=" \"sndBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rateLogging\": \"1\" "
JSON_CMD_LINE+=" },"
JSON_CMD_LINE+=" \"socket\": "
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"input2\","
JSON_CMD_LINE+=" \"type\": \"pull\","
JSON_CMD_LINE+=" \"method\": \"bind\","
JSON_CMD_LINE+=" \"address\": \"tcp://*:5570\","
JSON_CMD_LINE+=" \"sndBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rateLogging\": \"1\" "
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" },"
JSON_CMD_LINE+=" \"channel\":"
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"one_output_channel\","
JSON_CMD_LINE+=" \"socket\": {"
JSON_CMD_LINE+=" \"name\": \"output1\","
JSON_CMD_LINE+=" \"type\": \"push\","
JSON_CMD_LINE+=" \"method\": \"connect\","
JSON_CMD_LINE+=" \"address\": \"tcp://*:5571\","
JSON_CMD_LINE+=" \"sndBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rateLogging\": \"1\" "
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" },"
JSON_CMD_LINE+=" \"device\":"
JSON_CMD_LINE+=" {"
JSON_CMD_LINE+=" \"name\": \"sink\","
JSON_CMD_LINE+=" \"id\": \"4567\","
JSON_CMD_LINE+=" \"channel\": {"
JSON_CMD_LINE+=" \"name\": \"one_input\","
JSON_CMD_LINE+=" \"socket\": {"
JSON_CMD_LINE+=" \"name\": \"input1\","
JSON_CMD_LINE+=" \"type\": \"pull\","
JSON_CMD_LINE+=" \"method\": \"bind\","
JSON_CMD_LINE+=" \"address\": \"tcp://localhost:5571\","
JSON_CMD_LINE+=" \"sndBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rcvBufSize\": \"1000\","
JSON_CMD_LINE+=" \"rateLogging\": \"1\" "
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+=" }"
JSON_CMD_LINE+="}"
RUN_TEST+=" --config-json-string $JSON_CMD_LINE"
@CMAKE_BINARY_DIR@/bin/$RUN_TEST

View File

@@ -1,44 +0,0 @@
<fairMQOptions>
<device name="merger" id="merger">
<channel name="two_inputs_channel">
<socket name="input1">
<type>pull</type>
<method>bind</method>
<address>tcp://*:5569</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
<socket name="input2">
<type>pull</type>
<method>bind</method>
<address>tcp://*:5570</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
<channel name="one_output_channel">
<socket name="output1">
<type>push</type>
<method>connect</method>
<address>tcp://*:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
</device>
<device name="sink" id="sink">
<channel name="one_input">
<socket name="input1">
<type>pull</type>
<method>bind</method>
<address>tcp://localhost:5571</address>
<sndBufSize>1000</sndBufSize>
<rcvBufSize>1000</rcvBufSize>
<rateLogging>1</rateLogging>
</socket>
</channel>
</device>
</fairMQOptions>

View File

@@ -1,83 +0,0 @@
/*
* File: runOptTestSampler.cxx
* Author: winckler
*
* Created on June 10, 2015, 3:34 PM
*/
#include <cstdlib>
/// std
#include <iostream>
#include <string>
/// boost
#include "boost/program_options.hpp"
/// FairRoot/FairMQ
#include "FairMQLogger.h"
#include "FairMQParser.h"
#include "FairMQProgOptions.h"
//////////////////////////////////////////////////////////////
/// main
//////////////////////////////////////////////////////////////
using namespace std;
using namespace FairMQParser;
using namespace boost::program_options;
int main(int argc, char** argv)
{
FairMQProgOptions config;
try
{
// //////////////////////////////////////////////////////////////
// define key specific to the BenchmarkSampler in options_description
int eventSize;
int eventRate;
int ioThreads;
options_description sampler_options("Sampler options");
sampler_options.add_options()
("event-size", value<int>(&eventSize)->default_value(1000), "Event size in bytes")
("event-rate", value<int>(&eventRate)->default_value(0), "Event rate limit in maximum number of events per second")
("io-threads", value<int>(&ioThreads)->default_value(1), "Number of I/O threads");
// and add it to cmdline option of FairMQProgOptions
config.AddToCmdLineOptions(sampler_options);
// //////////////////////////////////////////////////////////////
// enable simple config txt/INI file
//config.EnableCfgFile();
//config.AddToCfgFileOptions(sampler_options,false);
// //////////////////////////////////////////////////////////////
// Parse command line options and store in variable map
if(config.ParseAll(argc,argv,true))
return 0;
// keys defined in FairMQProgOptions
string filename=config.GetValue<string>("config-json-file");
string deviceID=config.GetValue<string>("id");
// //////////////////////////////////////////////////////////////
// User defined parsing method.
config.UserParser<JSON>(filename,deviceID);
FairMQMap channels=config.GetFairMQMap();
//set device here
}
catch (exception& e)
{
LOG(error) << e.what();
LOG(info) << "Command line options are the following : ";
config.PrintHelp();
return 1;
}
return 0;
}

View File

@@ -1,77 +0,0 @@
/*
* File: runOptTestSink.cxx
* Author: winckler
*
* Created on June 10, 2015, 3:34 PM
*/
#include <cstdlib>
/// std
#include <iostream>
#include <string>
/// boost
#include "boost/program_options.hpp"
/// FairRoot/FairMQ
#include "FairMQLogger.h"
#include "FairMQParser.h"
#include "FairMQProgOptions.h"
//////////////////////////////////////////////////////////////
/// main
//////////////////////////////////////////////////////////////
using namespace std;
using namespace FairMQParser;
using namespace boost::program_options;
int main(int argc, char** argv)
{
FairMQProgOptions config;
try
{
// //////////////////////////////////////////////////////////////
// define key specific to the BenchmarkSampler in options_description
int eventSize;
int eventRate;
int ioThreads;
options_description Sink_options("Sink options");
Sink_options.add_options()
("io-threads", value<int>(&ioThreads)->default_value(1), "Number of I/O threads");
// and add it to cmdline option of FairMQProgOptions
config.AddToCmdLineOptions(Sink_options);
// //////////////////////////////////////////////////////////////
// Parse command line options and store in variable map
if(config.ParseAll(argc,argv,true))
return 0;
// keys defined in FairMQProgOptions
string filename=config.GetValue<string>("config-json-file");
string deviceID=config.GetValue<string>("id");
// //////////////////////////////////////////////////////////////
// User defined parsing method.
config.UserParser<JSON>(filename,deviceID);
FairMQMap channels=config.GetFairMQMap();
//set device here
}
catch (exception& e)
{
LOG(error) << e.what();
LOG(info) << "Command line options are the following : ";
config.PrintHelp();
return 1;
}
return 0;
}

View File

@@ -1,141 +0,0 @@
/// std
#include <iostream>
#include <string>
/// boost
#include "boost/program_options.hpp"
/// FairRoot/FairMQ
#include "FairMQLogger.h"
#include "FairMQParser.h"
#include "FairMQProgOptions.h"
// Parse xml from file
int testXML1(FairMQProgOptions* config)
{
LOG(info)<<"--------- test XML1 ---------\n";
std::string filename;
std::string XMLrootNode;
filename=config->GetValue<std::string>("config-xml-file");
XMLrootNode=config->GetValue<std::string>("xml.config.node.root");
std::string id=config->GetValue<std::string>("id");
config->UserParser<FairMQParser::XML>(filename,id,XMLrootNode);
// other xml parser test
config->UserParser<FairMQParser::MQXML2>(filename);
config->UserParser<FairMQParser::MQXML3>(filename,"merger");
LOG(info)<<"--------- test XML1 end ---------\n";
return 0;
}
// Parse xml from command line
int testXML2(FairMQProgOptions* config)
{
LOG(info)<<"--------- test XML2 ---------\n";
std::string XML;
std::string XMLrootNode;
std::string id=config->GetValue<std::string>("id");
XMLrootNode=config->GetValue<std::string>("xml.config.node.root");
// Note: convert the vector<string> into one string with GetStringValue(key)
XML=config->GetStringValue("config-xml-string");
std::stringstream iss;
iss << XML;
config->UserParser<FairMQParser::XML>(iss,id,XMLrootNode);
LOG(info)<<"--------- test XML2 end ---------\n";
return 0;
}
// Parse json from file
int testJSON1(FairMQProgOptions* config)
{
LOG(info)<<"--------- test JSON1 ---------\n";
std::string filename;
std::string JSONrootNode;
std::string id=config->GetValue<std::string>("id");
filename=config->GetValue<std::string>("config-json-file");
JSONrootNode=config->GetValue<std::string>("json.config.node.root");
config->UserParser<FairMQParser::JSON>(filename,id,JSONrootNode);
LOG(info)<<"--------- test JSON1 end ---------\n";
return 0;
}
// Parse json from command line
int testJSON2(FairMQProgOptions* config)
{
LOG(info)<<"--------- test JSON2 ---------\n";
std::string JSON;
std::string JSONrootNode;
std::string id=config->GetValue<std::string>("id");
JSONrootNode=config->GetValue<std::string>("json.config.node.root");
// Note: convert the vector<string> into one string with GetStringValue(key)
JSON=config->GetStringValue("config-json-string");
std::stringstream iss;
iss << JSON;
config->UserParser<FairMQParser::JSON>(iss,id,JSONrootNode);
LOG(info)<<"--------- test JSON2 end ---------\n";
return 0;
}
int main(int argc, char** argv)
{
FairMQProgOptions* config= new FairMQProgOptions();
try
{
po::options_description format_desc("XML or JSON input");
format_desc.add_options()
("xml.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "xml root node ")
("json.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "json root node ")
;
config->AddToCmdLineOptions(format_desc);
// Parse command line
if (config->ParseAll(argc,argv))
{
return 0;
}
// Set severity level (Default is 0=DEBUG)
int severity = config->GetValue<int>("severity");
FairMQLogger::Level lvl=static_cast<FairMQLogger::Level>(severity);
SET_LOGGER_LEVEL(lvl);
// Parse xml or json from cmd line or file
if (config->GetVarMap().count("config-xml-file"))
{
testXML1(config);
}
if (config->GetVarMap().count("config-xml-string"))
{
testXML2(config);
}
if (config->GetVarMap().count("config-json-file"))
{
testJSON1(config);
}
if (config->GetVarMap().count("config-json-string"))
{
testJSON2(config);
}
}
catch (std::exception& e)
{
LOG(error) << e.what();
return 1;
}
return 0;
}

View File

@@ -1,69 +0,0 @@
/// std
#include <iostream>
#include <string>
/// boost
#include "boost/program_options.hpp"
/// FairRoot/FairMQ
#include "FairMQLogger.h"
#include "FairMQParser.h"
#include "FairMQProgOptions.h"
//////////////////////////////////////////////////////////////
/// main
//////////////////////////////////////////////////////////////
int main(int argc, char** argv)
{
try
{
FairMQProgOptions config;
po::options_description format_desc("XML input");
format_desc.add_options()
("xml.config.node.root", po::value<std::string>()->default_value("fairMQOptions"), "xml root node ")
;
po::options_description io_file_opt_desc("I/O file Options");
io_file_opt_desc.add_options()
("input.file.name", po::value<std::string>(), "input file name")
("input.file.tree", po::value<std::string>(), "input tree name")
("input.file.branch", po::value<std::string>(), "input branch name")
("output.file.name", po::value<std::string>(), "output file name")
("output.file.tree", po::value<std::string>(), "output tree name")
("output.file.branch", po::value<std::string>(), "output branch name")
;
config.AddToCmdLineOptions(format_desc);
config.AddToCmdLineOptions(io_file_opt_desc);
config.EnableCfgFile();// UseConfigFile (by default config file is not defined)
config.AddToCfgFileOptions(format_desc,false);//false because already added to visible
config.AddToCfgFileOptions(io_file_opt_desc,false);
// Parse command line and config file
if(config.ParseAll(argc,argv))
return 0;
// Set severity level (Default is 0=DEBUG)
int severity = config.GetValue<int>("severity");
FairMQLogger::Level lvl = static_cast<FairMQLogger::Level>(severity);
SET_LOGGER_LEVEL(lvl);
// parse XML file
std::string filename;
std::string XMLrootNode;
filename=config.GetValue<std::string>("config-xml-file");
XMLrootNode=config.GetValue<std::string>("xml.config.node.root");
std::string id=config.GetValue<std::string>("id");
config.UserParser<FairMQParser::XML>(filename,id,XMLrootNode);
}
catch (std::exception& e)
{
LOG(error) << e.what();
return 1;
}
return 0;
}

View File

@@ -63,21 +63,18 @@ int main(int argc, char** argv)
{ {
try try
{ {
// create option manager object
FairMQProgOptions config; FairMQProgOptions config;
// add key description to cmd line options
config.GetCmdLineOptions().add_options() config.GetCmdLineOptions().add_options()
("data-rate", po::value<double>()->default_value(0.5), "Data rate"); ("data-rate", boost::program_options::value<double>()->default_value(0.5), "Data rate");
// parse command lines, parse json file and init FairMQMap
config.ParseAll(argc, argv, true); config.ParseAll(argc, argv, true);
// // get FairMQMap // // get FairMQMap
// auto map1 = config.GetFairMQMap(); // auto map1 = config.GetFairMQMap();
// // update value in variable map, and propagate the update to the FairMQMap // // update value in variable map, and propagate the update to the FairMQMap
// config.UpdateValue<string>("chans.data.0.address","tcp://localhost:1234"); // config.SetValue<string>("chans.data.0.address","tcp://localhost:1234");
// // get the updated FairMQMap // // get the updated FairMQMap
// auto map2 = config.GetFairMQMap(); // auto map2 = config.GetFairMQMap();
@@ -89,7 +86,6 @@ int main(int argc, char** argv)
// config.UpdateChannelMap(map2); // config.UpdateChannelMap(map2);
MyDevice device; MyDevice device;
// device.CatchSignals();
device.SetConfig(config); device.SetConfig(config);
// getting as string and conversion helpers // getting as string and conversion helpers
@@ -130,45 +126,30 @@ int main(int argc, char** argv)
LOG(info) << "Starting value updates...\n"; LOG(info) << "Starting value updates...\n";
config.UpdateValue<string>("chans.data.0.address", "tcp://localhost:4321"); config.SetValue<string>("chans.data.0.address", "tcp://localhost:4321");
LOG(info) << "config: " << config.GetValue<string>("chans.data.0.address"); LOG(info) << "config: " << config.GetValue<string>("chans.data.0.address");
LOG(info) << "device: " << device.fChannels.at("data").at(0).GetAddress() << endl; LOG(info) << "device: " << device.fChannels.at("data").at(0).GetAddress() << endl;
config.UpdateValue<int>("chans.data.0.rcvBufSize", 100); config.SetValue<int>("chans.data.0.rcvBufSize", 100);
LOG(info) << "config: " << config.GetValue<int>("chans.data.0.rcvBufSize"); LOG(info) << "config: " << config.GetValue<int>("chans.data.0.rcvBufSize");
LOG(info) << "device: " << device.fChannels.at("data").at(0).GetRcvBufSize() << endl; LOG(info) << "device: " << device.fChannels.at("data").at(0).GetRcvBufSize() << endl;
config.UpdateValue<double>("data-rate", 0.9); config.SetValue<double>("data-rate", 0.9);
LOG(info) << "config: " << config.GetValue<double>("data-rate"); LOG(info) << "config: " << config.GetValue<double>("data-rate");
LOG(info) << "device: " << device.GetRate() << endl; LOG(info) << "device: " << device.GetRate() << endl;
// device.Print(); device.Print();
LOG(info) << "nase: " << config.GetValue<double>("nase"); LOG(info) << "nase: " << config.GetValue<double>("nase");
config.Unsubscribe<string>("test"); config.Unsubscribe<string>("test");
config.Unsubscribe<int>("test"); config.Unsubscribe<int>("test");
config.Unsubscribe<double>("test"); config.Unsubscribe<double>("test");
// advanced commands
// LOG(info) << "-------------------- start custom 1"; device.ChangeState("END");
// config.Connect<EventId::Custom, MyDevice&, double>("myNewKey", [](MyDevice& d, double val)
// {
// d.SetRate(val);
// d.Print();
// });
// config.Emit<EventId::Custom, MyDevice&, double>("myNewKey", device, 0.123);
// LOG(info) << "-------------------- start custom 2 with function";
// config.Connect<EventId::Custom, MyDevice&, double>("function example", &MyCallBack);
// config.Emit<EventId::Custom, MyDevice&, double>("function example", device, 6.66);
} }
catch (exception& e) catch (exception& e)
{ {
LOG(error) << "Unhandled Exception reached the top of main: " LOG(error) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit";
<< e.what() << ", application will now exit";
return 1; return 1;
} }
return 0; return 0;

View File

@@ -1,11 +1,5 @@
#!/bin/bash #!/bin/bash
TRANSPORT="zeromq" DEVICE="runConfigExample"
VERBOSE="DEBUG" DEVICE+=" --id sampler1 --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$DEVICE
JSONCONFIGFILE="@CMAKE_BINARY_DIR@/bin/config/ex1-sampler-sink.json"
########################## start DEVICE
DEVICE="runConfigExample --transport $TRANSPORT --severity $VERBOSE"
DEVICE+=" --id sampler1 --mq-config $JSONCONFIGFILE"
@CMAKE_BINARY_DIR@/bin/$DEVICE

View File

@@ -17,12 +17,11 @@ using namespace std;
namespace namespace
{ {
// ugly global state, but std::signal gives us no other choice volatile sig_atomic_t gSignalStatus = 0;
std::function<void(int)> gSignalHandlerClosure;
extern "C" auto signal_handler(int signal) -> void extern "C" auto signal_handler(int signal) -> void
{ {
gSignalHandlerClosure(signal); gSignalStatus = signal;
} }
} }
@@ -37,10 +36,13 @@ Control::Control(const string name, const Plugin::Version version, const string
: Plugin(name, version, maintainer, homepage, pluginServices) : Plugin(name, version, maintainer, homepage, pluginServices)
, fControllerThread() , fControllerThread()
, fSignalHandlerThread() , fSignalHandlerThread()
, fShutdownThread()
, fEvents() , fEvents()
, fEventsMutex() , fEventsMutex()
, fShutdownMutex()
, fNewEvent() , fNewEvent()
, fDeviceTerminationRequested{false} , fDeviceTerminationRequested(false)
, fHasShutdown(false)
{ {
try try
{ {
@@ -73,7 +75,7 @@ Control::Control(const string name, const Plugin::Version version, const string
LOG(debug) << "catch-signals: " << GetProperty<int>("catch-signals"); LOG(debug) << "catch-signals: " << GetProperty<int>("catch-signals");
if (GetProperty<int>("catch-signals") > 0) if (GetProperty<int>("catch-signals") > 0)
{ {
gSignalHandlerClosure = bind(&Control::SignalHandler, this, placeholders::_1); fSignalHandlerThread = thread(&Control::SignalHandler, this);
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
} }
@@ -263,17 +265,41 @@ auto Control::StaticMode() -> void
} }
} }
auto Control::SignalHandler(int signal) -> void auto Control::SignalHandler() -> void
{ {
while (true)
{
if (gSignalStatus != 0 && !fHasShutdown)
{
LOG(info) << "Received device shutdown request (signal " << gSignalStatus << ").";
LOG(info) << "Waiting for graceful device shutdown. Hit Ctrl-C again to abort immediately.";
if (!fDeviceTerminationRequested) if (!fDeviceTerminationRequested)
{ {
fDeviceTerminationRequested = true; fDeviceTerminationRequested = true;
gSignalStatus = 0;
fShutdownThread = thread(&Control::HandleShutdownSignal, this);
}
else
{
LOG(warn) << "Received 2nd device shutdown request (signal " << gSignalStatus << ").";
LOG(warn) << "Aborting immediately!";
abort();
}
}
else if (fHasShutdown)
{
break;
}
this_thread::sleep_for(chrono::milliseconds(100));
}
}
auto Control::HandleShutdownSignal() -> void
{
StealDeviceControl(); StealDeviceControl();
LOG(info) << "Received device shutdown request (signal " << signal << ").";
LOG(info) << "Waiting for graceful device shutdown. Hit Ctrl-C again to abort immediately.";
UnsubscribeFromDeviceStateChange(); // In case, static or interactive mode have subscribed already UnsubscribeFromDeviceStateChange(); // In case, static or interactive mode have subscribed already
SubscribeToDeviceStateChange([&](DeviceState newState) SubscribeToDeviceStateChange([&](DeviceState newState)
{ {
@@ -284,18 +310,14 @@ auto Control::SignalHandler(int signal) -> void
fNewEvent.notify_one(); fNewEvent.notify_one();
}); });
fSignalHandlerThread = thread(&Control::RunShutdownSequence, this); RunShutdownSequence();
}
else
{
LOG(warn) << "Received 2nd device shutdown request (signal " << signal << ").";
LOG(warn) << "Aborting immediately !";
abort();
}
} }
auto Control::RunShutdownSequence() -> void auto Control::RunShutdownSequence() -> void
{ {
lock_guard<mutex> lock(fShutdownMutex);
if (!fHasShutdown)
{
auto nextState = GetCurrentDeviceState(); auto nextState = GetCurrentDeviceState();
EmptyEventQueue(); EmptyEventQueue();
while (nextState != DeviceState::Exiting) while (nextState != DeviceState::Exiting)
@@ -318,14 +340,17 @@ auto Control::RunShutdownSequence() -> void
ChangeDeviceState(DeviceStateTransition::Resume); ChangeDeviceState(DeviceStateTransition::Resume);
break; break;
default: default:
// ignore other states
break; break;
} }
nextState = WaitForNextState(); nextState = WaitForNextState();
} }
fHasShutdown = true;
UnsubscribeFromDeviceStateChange(); UnsubscribeFromDeviceStateChange();
ReleaseDeviceControl(); ReleaseDeviceControl();
}
} }
auto Control::RunStartupSequence() -> void auto Control::RunStartupSequence() -> void
@@ -357,6 +382,7 @@ Control::~Control()
{ {
if (fControllerThread.joinable()) fControllerThread.join(); if (fControllerThread.joinable()) fControllerThread.join();
if (fSignalHandlerThread.joinable()) fSignalHandlerThread.join(); if (fSignalHandlerThread.joinable()) fSignalHandlerThread.join();
if (fShutdownThread.joinable()) fShutdownThread.join();
} }
} /* namespace plugins */ } /* namespace plugins */

View File

@@ -37,17 +37,21 @@ class Control : public Plugin
auto PrintInteractiveHelp() -> void; auto PrintInteractiveHelp() -> void;
auto StaticMode() -> void; auto StaticMode() -> void;
auto WaitForNextState() -> DeviceState; auto WaitForNextState() -> DeviceState;
auto SignalHandler(int signal) -> void; auto SignalHandler() -> void;
auto HandleShutdownSignal() -> void;
auto RunShutdownSequence() -> void; auto RunShutdownSequence() -> void;
auto RunStartupSequence() -> void; auto RunStartupSequence() -> void;
auto EmptyEventQueue() -> void; auto EmptyEventQueue() -> void;
std::thread fControllerThread; std::thread fControllerThread;
std::thread fSignalHandlerThread; std::thread fSignalHandlerThread;
std::thread fShutdownThread;
std::queue<DeviceState> fEvents; std::queue<DeviceState> fEvents;
std::mutex fEventsMutex; std::mutex fEventsMutex;
std::mutex fShutdownMutex;
std::condition_variable fNewEvent; std::condition_variable fNewEvent;
std::atomic<bool> fDeviceTerminationRequested; std::atomic<bool> fDeviceTerminationRequested;
std::atomic<bool> fHasShutdown;
}; /* class Control */ }; /* class Control */
auto ControlPluginProgramOptions() -> Plugin::ProgOptions; auto ControlPluginProgramOptions() -> Plugin::ProgOptions;

View File

@@ -110,12 +110,12 @@ auto DDS::HandleControl() -> void
// and propagate addresses of bound channels to DDS. // and propagate addresses of bound channels to DDS.
FillChannelContainers(); FillChannelContainers();
LOG(DEBUG) << "$DDS_TASK_PATH: " << getenv("DDS_TASK_PATH"); LOG(debug) << "$DDS_TASK_PATH: " << getenv("DDS_TASK_PATH");
LOG(DEBUG) << "$DDS_GROUP_NAME: " << getenv("DDS_GROUP_NAME"); LOG(debug) << "$DDS_GROUP_NAME: " << getenv("DDS_GROUP_NAME");
LOG(DEBUG) << "$DDS_COLLECTION_NAME: " << getenv("DDS_COLLECTION_NAME"); LOG(debug) << "$DDS_COLLECTION_NAME: " << getenv("DDS_COLLECTION_NAME");
LOG(DEBUG) << "$DDS_TASK_NAME: " << getenv("DDS_TASK_NAME"); LOG(debug) << "$DDS_TASK_NAME: " << getenv("DDS_TASK_NAME");
LOG(DEBUG) << "$DDS_TASK_INDEX: " << getenv("DDS_TASK_INDEX"); LOG(debug) << "$DDS_TASK_INDEX: " << getenv("DDS_TASK_INDEX");
LOG(DEBUG) << "$DDS_COLLECTION_INDEX: " << getenv("DDS_COLLECTION_INDEX"); LOG(debug) << "$DDS_COLLECTION_INDEX: " << getenv("DDS_COLLECTION_INDEX");
// start DDS service - subscriptions will only start firing after this step // start DDS service - subscriptions will only start firing after this step
fService.start(); fService.start();

View File

@@ -52,8 +52,8 @@ struct IofN
, fEntries() , fEntries()
{} {}
int fI; unsigned int fI;
int fN; unsigned int fN;
std::vector<std::string> fEntries; std::vector<std::string> fEntries;
}; };

View File

@@ -15,8 +15,8 @@ void addCustomOptions(bpo::options_description& options)
{ {
options.add_options() options.add_options()
("out-channel", bpo::value<std::string>()->default_value("data"), "Name of the output channel") ("out-channel", bpo::value<std::string>()->default_value("data"), "Name of the output channel")
("same-msg", bpo::value<bool>()->default_value(true), "Re-send the same message (default), or recreate for each iteration") ("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(1000), "Message size in bytes") ("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)") ("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<int>()->default_value(0), "Msg rate limit in maximum number of messages per second");
} }

View File

@@ -72,7 +72,7 @@ SAMPLER+=" --msg-size $msgSize"
SAMPLER+=" --same-msg $sameMsg" SAMPLER+=" --same-msg $sameMsg"
# SAMPLER+=" --msg-rate 1000" # SAMPLER+=" --msg-rate 1000"
SAMPLER+=" --max-iterations $maxIterations" SAMPLER+=" --max-iterations $maxIterations"
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.01:5555" SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:5555"
xterm -geometry 90x50+0+0 -hold -e $affinitySamp @CMAKE_CURRENT_BINARY_DIR@/$SAMPLER & xterm -geometry 90x50+0+0 -hold -e $affinitySamp @CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
echo "" echo ""
echo "started: xterm -geometry 90x50+0+0 -hold -e $affinitySamp @CMAKE_CURRENT_BINARY_DIR@/$SAMPLER" echo "started: xterm -geometry 90x50+0+0 -hold -e $affinitySamp @CMAKE_CURRENT_BINARY_DIR@/$SAMPLER"
@@ -85,7 +85,7 @@ SINK+=" --id sink1"
SINK+=" --transport $transport" SINK+=" --transport $transport"
SINK+=" --severity debug" SINK+=" --severity debug"
SINK+=" --max-iterations $maxIterations" SINK+=" --max-iterations $maxIterations"
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.01:5555" SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:5555"
xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK & xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK &
echo "" echo ""
echo "started: xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK" echo "started: xterm -geometry 90x50+550+0 -hold -e $affinitySink @CMAKE_CURRENT_BINARY_DIR@/$SINK"

View File

@@ -46,7 +46,7 @@ int main(int argc, char* argv[])
// }); // });
runner.AddHook<InstantiateDevice>([](DeviceRunner& r){ 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(); return runner.Run();

View File

@@ -19,8 +19,8 @@
using namespace std; using namespace std;
using namespace fair::mq::shmem; using namespace fair::mq::shmem;
namespace bipc = boost::interprocess; namespace bipc = ::boost::interprocess;
namespace bpt = boost::posix_time; namespace bpt = ::boost::posix_time;
atomic<bool> FairMQMessageSHM::fInterrupted(false); atomic<bool> FairMQMessageSHM::fInterrupted(false);
fair::mq::Transport FairMQMessageSHM::fTransportType = fair::mq::Transport::SHM; fair::mq::Transport FairMQMessageSHM::fTransportType = fair::mq::Transport::SHM;

View File

@@ -14,6 +14,8 @@
#include <zmq.h> #include <zmq.h>
#include <stdexcept>
using namespace std; using namespace std;
using namespace fair::mq::shmem; using namespace fair::mq::shmem;
@@ -62,12 +64,18 @@ FairMQSocketSHM::FairMQSocketSHM(Manager& manager, const string& type, const str
LOG(error) << "Failed setting ZMQ_RCVTIMEO socket option, reason: " << zmq_strerror(errno); LOG(error) << "Failed setting ZMQ_RCVTIMEO socket option, reason: " << zmq_strerror(errno);
} }
if (type == "sub") // if (type == "sub")
// {
// if (zmq_setsockopt(fSocket, ZMQ_SUBSCRIBE, nullptr, 0) != 0)
// {
// LOG(error) << "Failed setting ZMQ_SUBSCRIBE socket option, reason: " << zmq_strerror(errno);
// }
// }
if (type == "sub" || type == "pub")
{ {
if (zmq_setsockopt(fSocket, ZMQ_SUBSCRIBE, nullptr, 0) != 0) LOG(error) << "PUB/SUB socket type is not supported for shared memory transport";
{ throw fair::mq::SocketError("PUB/SUB socket type is not supported for shared memory transport");
LOG(error) << "Failed setting ZMQ_SUBSCRIBE socket option, reason: " << zmq_strerror(errno);
}
} }
// LOG(info) << "created socket " << fId; // LOG(info) << "created socket " << fId;
@@ -188,7 +196,7 @@ int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
const auto numMsgs = nbytes / sizeof(MetaHeader); const auto numMsgs = nbytes / sizeof(MetaHeader);
if (numMsgs > 1) 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); assert (numMsgs == 1);
@@ -238,7 +246,7 @@ 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(); const unsigned int vecSize = msgVec.size();
int64_t totalSize = 0; int64_t totalSize = 0;
@@ -303,13 +311,13 @@ int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
else if (zmq_errno() == ETERM) else if (zmq_errno() == ETERM)
{ {
zmq_msg_close (&lZmqMsg); zmq_msg_close (&lZmqMsg);
LOG(INFO) << "terminating socket " << fId; LOG(info) << "terminating socket " << fId;
return -1; return -1;
} }
else else
{ {
zmq_msg_close (&lZmqMsg); zmq_msg_close (&lZmqMsg);
LOG(ERROR) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno); LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes; return nbytes;
} }
} }
@@ -318,7 +326,7 @@ int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
} }
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; int64_t totalSize = 0;
@@ -343,7 +351,7 @@ int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int
msgVec.reserve(lNumMessages); msgVec.reserve(lNumMessages);
for (auto m = 0; m < lNumMessages; m++) for (size_t m = 0; m < lNumMessages; m++)
{ {
MetaHeader lMetaHeader; MetaHeader lMetaHeader;
memcpy(&lMetaHeader, &lHdrVec[m], sizeof(MetaHeader)); memcpy(&lMetaHeader, &lHdrVec[m], sizeof(MetaHeader));

View File

@@ -28,9 +28,9 @@
using namespace std; using namespace std;
using namespace fair::mq::shmem; using namespace fair::mq::shmem;
namespace bfs = boost::filesystem; namespace bfs = ::boost::filesystem;
namespace bpt = boost::posix_time; namespace bpt = ::boost::posix_time;
namespace bipc = boost::interprocess; namespace bipc = ::boost::interprocess;
fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM; fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM;
@@ -69,7 +69,7 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const Fai
} }
else 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) fSessionName.resize(8, '_'); // shorten the session name, to accommodate for name size limit on some systems (MacOS)
@@ -149,14 +149,14 @@ void FairMQTransportFactorySHM::StartMonitor()
auto env = boost::this_process::environment(); auto env = boost::this_process::environment();
vector<boost::filesystem::path> ownPath = boost::this_process::path(); vector<bfs::path> ownPath = boost::this_process::path();
if (const char* fmqp = getenv("FAIRMQ_PATH")) if (const char* fmqp = getenv("FAIRMQ_PATH"))
{ {
ownPath.insert(ownPath.begin(), boost::filesystem::path(fmqp)); ownPath.insert(ownPath.begin(), bfs::path(fmqp));
} }
boost::filesystem::path p = boost::process::search_path("fairmq-shmmonitor", ownPath); bfs::path p = boost::process::search_path("fairmq-shmmonitor", ownPath);
if (!p.empty()) if (!p.empty())
{ {
@@ -184,7 +184,7 @@ void FairMQTransportFactorySHM::StartMonitor()
} }
else else
{ {
LOG(WARN) << "could not find fairmq-shmmonitor in the path"; LOG(warn) << "could not find fairmq-shmmonitor in the path";
} }
} }

View File

@@ -13,7 +13,7 @@
using namespace std; using namespace std;
using namespace fair::mq::shmem; using namespace fair::mq::shmem;
namespace bipc = boost::interprocess; namespace bipc = ::boost::interprocess;
FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_t size, FairMQRegionCallback callback) FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_t size, FairMQRegionCallback callback)
: fManager(manager) : fManager(manager)

View File

@@ -9,6 +9,9 @@
#include <fairmq/shmem/Manager.h> #include <fairmq/shmem/Manager.h>
#include <fairmq/shmem/Common.h> #include <fairmq/shmem/Common.h>
using namespace std;
namespace bipc = ::boost::interprocess;
namespace fair namespace fair
{ {
namespace mq namespace mq
@@ -16,9 +19,6 @@ namespace mq
namespace shmem namespace shmem
{ {
using namespace std;
namespace bipc = boost::interprocess;
std::unordered_map<uint64_t, Region> Manager::fRegions; std::unordered_map<uint64_t, Region> Manager::fRegions;
Manager::Manager(const string& name, size_t size) Manager::Manager(const string& name, size_t size)

View File

@@ -26,8 +26,8 @@
#include <poll.h> #include <poll.h>
using namespace std; using namespace std;
namespace bipc = boost::interprocess; namespace bipc = ::boost::interprocess;
namespace bpt = boost::posix_time; namespace bpt = ::boost::posix_time;
using CharAllocator = bipc::allocator<char, bipc::managed_shared_memory::segment_manager>; using CharAllocator = bipc::allocator<char, bipc::managed_shared_memory::segment_manager>;
using String = bipc::basic_string<char, char_traits<char>, CharAllocator>; using String = bipc::basic_string<char, char_traits<char>, CharAllocator>;

View File

@@ -12,6 +12,11 @@
#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/date_time/posix_time/posix_time.hpp>
using namespace std;
namespace bipc = ::boost::interprocess;
namespace bpt = ::boost::posix_time;
namespace fair namespace fair
{ {
namespace mq namespace mq
@@ -19,11 +24,6 @@ namespace mq
namespace shmem 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) Region::Region(Manager& manager, uint64_t id, uint64_t size, bool remote, FairMQRegionCallback callback)
: fManager(manager) : fManager(manager)
, fRemote(remote) , fRemote(remote)
@@ -53,7 +53,7 @@ Region::Region(Manager& manager, uint64_t id, uint64_t size, bool remote, FairMQ
LOG(debug) << "shmem: created region queue: " << fQueueName; LOG(debug) << "shmem: created region queue: " << fQueueName;
} }
fRegion = bipc::mapped_region(fShmemObject, bipc::read_write); // TODO: add HUGEPAGES flag here fRegion = bipc::mapped_region(fShmemObject, bipc::read_write); // TODO: add HUGEPAGES flag here
// fRegion = bipc::mapped_region(fShmemObject, bipc::read_write, 0, 0, 0, MAP_HUGETLB | MAP_HUGE_1GB); // fRegion = bipc::mapped_region(fShmemObject, bipc::read_write, 0, 0, 0, MAP_ANONYMOUS | MAP_HUGETLB);
} }
void Region::StartReceivingAcks() void Region::StartReceivingAcks()

View File

@@ -11,6 +11,7 @@
#include <boost/process.hpp> #include <boost/process.hpp>
#include <iostream> #include <iostream>
#include <sstream>
using namespace std; using namespace std;

View File

@@ -39,7 +39,7 @@ FairMQTransportFactoryZMQ::FairMQTransportFactoryZMQ(const string& id, const Fai
} }
else 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) if (zmq_ctx_set(fContext, ZMQ_IO_THREADS, numIoThreads) != 0)

View File

@@ -12,6 +12,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
#include <thread>
#include <future> // std::async, std::future #include <future> // std::async, std::future
namespace namespace
@@ -19,6 +20,24 @@ namespace
using namespace std; 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 { class MultipleDevices : public ::testing::Test {
public: public:
MultipleDevices() MultipleDevices()
@@ -34,20 +53,14 @@ class MultipleDevices : public ::testing::Test {
channel.UpdateRateLogging(0); channel.UpdateRateLogging(0);
sender.fChannels["data"].push_back(channel); sender.fChannels["data"].push_back(channel);
sender.ChangeState("INIT_DEVICE"); thread t(control, std::ref(sender));
sender.WaitForEndOfState("INIT_DEVICE");
sender.ChangeState("INIT_TASK");
sender.WaitForEndOfState("INIT_TASK");
sender.ChangeState("RUN"); sender.RunStateMachine();
sender.WaitForEndOfState("RUN");
sender.ChangeState("RESET_TASK"); if (t.joinable())
sender.WaitForEndOfState("RESET_TASK"); {
sender.ChangeState("RESET_DEVICE"); t.join();
sender.WaitForEndOfState("RESET_DEVICE"); }
sender.ChangeState("END");
return true; return true;
} }
@@ -62,20 +75,14 @@ class MultipleDevices : public ::testing::Test {
channel.UpdateRateLogging(0); channel.UpdateRateLogging(0);
receiver.fChannels["data"].push_back(channel); receiver.fChannels["data"].push_back(channel);
receiver.ChangeState("INIT_DEVICE"); thread t(control, std::ref(receiver));
receiver.WaitForEndOfState("INIT_DEVICE");
receiver.ChangeState("INIT_TASK");
receiver.WaitForEndOfState("INIT_TASK");
receiver.ChangeState("RUN"); receiver.RunStateMachine();
receiver.WaitForEndOfState("RUN");
receiver.ChangeState("RESET_TASK"); if (t.joinable())
receiver.WaitForEndOfState("RESET_TASK"); {
receiver.ChangeState("RESET_DEVICE"); t.join();
receiver.WaitForEndOfState("RESET_DEVICE"); }
receiver.ChangeState("END");
return true; return true;
} }

View File

@@ -8,6 +8,7 @@
#include <FairMQDevice.h> #include <FairMQDevice.h>
#include <cstddef>
#include <thread> #include <thread>
namespace fair namespace fair
@@ -53,7 +54,7 @@ class PairLeft : public FairMQDevice
if (ret > 0) { if (ret > 0) {
auto content = std::string{static_cast<char*>(msg6->GetData()), msg6->GetSize()}; auto content = std::string{static_cast<char*>(msg6->GetData()), msg6->GetSize()};
LOG(info) << ret << ", " << msg6->GetSize() << ", '" << content << "'"; LOG(info) << ret << ", " << msg6->GetSize() << ", '" << content << "'";
if (msg6->GetSize() == ret && content == "testdata1234") counter++; if (msg6->GetSize() == static_cast<std::size_t>(ret) && content == "testdata1234") counter++;
} }
if (counter == 6) LOG(info) << "Simple message with short text data successfull"; if (counter == 6) LOG(info) << "Simple message with short text data successfull";

View File

@@ -7,6 +7,7 @@
********************************************************************************/ ********************************************************************************/
#include <FairMQDevice.h> #include <FairMQDevice.h>
#include <cstddef>
#include <string> #include <string>
#include <thread> #include <thread>
@@ -51,7 +52,7 @@ class PairRight : public FairMQDevice
if (ret > 0) { if (ret > 0) {
auto content = std::string{static_cast<char*>(msg5->GetData()), msg5->GetSize()}; auto content = std::string{static_cast<char*>(msg5->GetData()), msg5->GetSize()};
LOG(info) << ret << ", " << msg5->GetSize() << ", '" << content << "'"; LOG(info) << ret << ", " << msg5->GetSize() << ", '" << content << "'";
if (msg5->GetSize() == ret && content == "testdata1234") counter++; if (msg5->GetSize() == static_cast<std::size_t>(ret) && content == "testdata1234") counter++;
} }
auto msg6(NewSimpleMessageFor("data", 0, "testdata1234")); auto msg6(NewSimpleMessageFor("data", 0, "testdata1234"));
if (Send(msg6, "data") >= 0) counter++; if (Send(msg6, "data") >= 0) counter++;

View File

@@ -14,6 +14,7 @@
#include <FairMQDevice.h> #include <FairMQDevice.h>
#include <options/FairMQProgOptions.h> #include <options/FairMQProgOptions.h>
#include <memory> #include <memory>
#include <thread>
namespace fair namespace fair
{ {
@@ -22,35 +23,41 @@ namespace mq
namespace test namespace test
{ {
inline auto control(std::shared_ptr<FairMQDevice> device) -> void inline auto control(FairMQDevice& device) -> void
{ {
for (const auto event : { for (const auto event : {
FairMQDevice::INIT_DEVICE, FairMQDevice::INIT_DEVICE,
FairMQDevice::RESET_DEVICE, FairMQDevice::RESET_DEVICE,
FairMQDevice::END, FairMQDevice::END,
}) { }) {
device->ChangeState(event); device.ChangeState(event);
if (event != FairMQDevice::END) device->WaitForEndOfState(event); if (event != FairMQDevice::END) device.WaitForEndOfState(event);
} }
} }
struct PluginServices : ::testing::Test { struct PluginServices : ::testing::Test {
PluginServices() PluginServices()
: mConfig() : mConfig()
, mDevice{std::make_shared<FairMQDevice>()} , mDevice()
, mServices{&mConfig, mDevice} , mServices(mConfig, mDevice)
, fRunStateMachineThread()
{ {
mDevice->SetTransport("zeromq"); fRunStateMachineThread = std::thread(&FairMQDevice::RunStateMachine, &mDevice);
mDevice.SetTransport("zeromq");
} }
~PluginServices() ~PluginServices()
{ {
if(mDevice->GetCurrentState() == FairMQDevice::IDLE) control(mDevice); if (mDevice.GetCurrentState() == FairMQDevice::IDLE) control(mDevice);
if (fRunStateMachineThread.joinable()) {
fRunStateMachineThread.join();
}
} }
FairMQProgOptions mConfig; FairMQProgOptions mConfig;
std::shared_ptr<FairMQDevice> mDevice; FairMQDevice mDevice;
fair::mq::PluginServices mServices; fair::mq::PluginServices mServices;
std::thread fRunStateMachineThread;
}; };
} /* namespace test */ } /* namespace test */

View File

@@ -63,7 +63,7 @@ TEST_F(PluginServices, ConfigCallbacks)
if (key == "chans.data.0.address") { ASSERT_EQ(value, "tcp://localhost:4321"); } if (key == "chans.data.0.address") { ASSERT_EQ(value, "tcp://localhost:4321"); }
}); });
mServices.SubscribeToPropertyChange<int>("test", [](const string& key, int value) { mServices.SubscribeToPropertyChange<int>("test", [](const string& key, int /*value*/) {
if(key == "chans.data.0.rcvBufSize") { if(key == "chans.data.0.rcvBufSize") {
FAIL(); // should not be called because we unsubscribed FAIL(); // should not be called because we unsubscribed
} }

View File

@@ -39,9 +39,9 @@ TEST_F(PluginServices, OnlySingleController)
EXPECT_EQ(mServices.GetDeviceController(), string{"foo"}); EXPECT_EQ(mServices.GetDeviceController(), string{"foo"});
// park device // park device
mDevice->WaitForEndOfState(FairMQDevice::DEVICE_READY); mDevice.WaitForEndOfState(FairMQDevice::DEVICE_READY);
mServices.ChangeDeviceState("foo", DeviceStateTransition::ResetDevice); mServices.ChangeDeviceState("foo", DeviceStateTransition::ResetDevice);
mDevice->WaitForEndOfState(FairMQDevice::RESET_DEVICE); mDevice.WaitForEndOfState(FairMQDevice::RESET_DEVICE);
mServices.ChangeDeviceState("foo", DeviceStateTransition::End); mServices.ChangeDeviceState("foo", DeviceStateTransition::End);
} }
@@ -72,7 +72,7 @@ TEST_F(PluginServices, Control)
ASSERT_EQ(mServices.GetCurrentDeviceState(), DeviceState::DeviceReady); ASSERT_EQ(mServices.GetCurrentDeviceState(), DeviceState::DeviceReady);
mServices.ChangeDeviceState("foo", DeviceStateTransition::ResetDevice); mServices.ChangeDeviceState("foo", DeviceStateTransition::ResetDevice);
mDevice->WaitForEndOfState(FairMQDevice::RESET_DEVICE); mDevice.WaitForEndOfState(FairMQDevice::RESET_DEVICE);
mServices.ChangeDeviceState("foo", DeviceStateTransition::End); mServices.ChangeDeviceState("foo", DeviceStateTransition::End);
} }

View File

@@ -16,6 +16,7 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
#include <thread>
namespace namespace
{ {
@@ -23,42 +24,50 @@ namespace
using namespace std; using namespace std;
using namespace fair::mq; using namespace fair::mq;
auto control(shared_ptr<FairMQDevice> device) -> void auto control(FairMQDevice& device) -> void
{ {
device->SetTransport("zeromq"); device.SetTransport("zeromq");
for (const auto event : { for (const auto event : {
FairMQDevice::INIT_DEVICE, FairMQDevice::INIT_DEVICE,
FairMQDevice::RESET_DEVICE, FairMQDevice::RESET_DEVICE,
FairMQDevice::END, FairMQDevice::END,
}) { }) {
device->ChangeState(event); device.ChangeState(event);
if (event != FairMQDevice::END) device->WaitForEndOfState(event); if (event != FairMQDevice::END) device.WaitForEndOfState(event);
} }
} }
TEST(Plugin, Operators) TEST(Plugin, Operators)
{ {
FairMQProgOptions config{}; FairMQProgOptions config;
auto device = make_shared<FairMQDevice>(); FairMQDevice device;
PluginServices services{&config, device}; PluginServices services{config, device};
Plugin p1{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services}; Plugin p1{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services};
Plugin p2{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services}; Plugin p2{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services};
Plugin p3{"file", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/file.git", &services}; Plugin p3{"file", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/file.git", &services};
EXPECT_EQ(p1, p2); EXPECT_EQ(p1, p2);
EXPECT_NE(p1, p3); EXPECT_NE(p1, p3);
control(device); thread t(control, std::ref(device));
device.RunStateMachine();
if (t.joinable()) {
t.join();
}
} }
TEST(Plugin, OstreamOperators) TEST(Plugin, OstreamOperators)
{ {
FairMQProgOptions config{}; FairMQProgOptions config;
auto device = make_shared<FairMQDevice>(); FairMQDevice device;
PluginServices services{&config, device}; PluginServices services{config, device};
Plugin p1{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services}; Plugin p1{"dds", {1, 0, 0}, "Foo Bar <foo.bar@test.net>", "https://git.test.net/dds.git", &services};
stringstream ss; stringstream ss;
ss << p1; ss << p1;
EXPECT_EQ(ss.str(), string{"'dds', version '1.0.0', maintainer 'Foo Bar <foo.bar@test.net>', homepage 'https://git.test.net/dds.git'"}); EXPECT_EQ(ss.str(), string{"'dds', version '1.0.0', maintainer 'Foo Bar <foo.bar@test.net>', homepage 'https://git.test.net/dds.git'"});
control(device); thread t(control, std::ref(device));
device.RunStateMachine();
if (t.joinable()) {
t.join();
}
} }
TEST(PluginVersion, Operators) TEST(PluginVersion, Operators)

View File

@@ -15,6 +15,7 @@
#include <fstream> #include <fstream>
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <thread>
namespace namespace
{ {
@@ -24,25 +25,25 @@ using namespace boost::filesystem;
using namespace boost::program_options; using namespace boost::program_options;
using namespace std; using namespace std;
auto control(shared_ptr<FairMQDevice> device) -> void auto control(FairMQDevice& device) -> void
{ {
device->SetTransport("zeromq"); device.SetTransport("zeromq");
for (const auto event : { for (const auto event : {
FairMQDevice::INIT_DEVICE, FairMQDevice::INIT_DEVICE,
FairMQDevice::RESET_DEVICE, FairMQDevice::RESET_DEVICE,
FairMQDevice::END, FairMQDevice::END,
}) { }) {
device->ChangeState(event); device.ChangeState(event);
if (event != FairMQDevice::END) device->WaitForEndOfState(event); if (event != FairMQDevice::END) device.WaitForEndOfState(event);
} }
} }
TEST(PluginManager, LoadPluginDynamic) TEST(PluginManager, LoadPluginDynamic)
{ {
FairMQProgOptions config{}; FairMQProgOptions config;
auto mgr = PluginManager{}; FairMQDevice device;
auto device = make_shared<FairMQDevice>(); PluginManager mgr;
mgr.EmplacePluginServices(&config, device); mgr.EmplacePluginServices(config, device);
mgr.PrependSearchPath("./test"); mgr.PrependSearchPath("./test");
@@ -53,7 +54,7 @@ TEST(PluginManager, LoadPluginDynamic)
// check order // check order
const auto expected = vector<string>{"test_dummy", "test_dummy2"}; const auto expected = vector<string>{"test_dummy", "test_dummy2"};
auto actual = vector<string>{}; auto actual = vector<string>();
mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); }); mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); });
ASSERT_TRUE(actual == expected); ASSERT_TRUE(actual == expected);
@@ -62,49 +63,55 @@ TEST(PluginManager, LoadPluginDynamic)
mgr.ForEachPluginProgOptions([&count](const options_description& /*d*/){ ++count; }); mgr.ForEachPluginProgOptions([&count](const options_description& /*d*/){ ++count; });
ASSERT_EQ(count, 1); ASSERT_EQ(count, 1);
control(device); thread t(control, std::ref(device));
device.RunStateMachine();
if (t.joinable()) {
t.join();
}
} }
TEST(PluginManager, LoadPluginStatic) TEST(PluginManager, LoadPluginStatic)
{ {
auto mgr = PluginManager{}; FairMQDevice device;
auto device = make_shared<FairMQDevice>(); PluginManager mgr;
device->SetTransport("zeromq"); device.SetTransport("zeromq");
ASSERT_NO_THROW(mgr.LoadPlugin("s:control")); ASSERT_NO_THROW(mgr.LoadPlugin("s:control"));
FairMQProgOptions config{}; FairMQProgOptions config;
config.SetValue<string>("control", "static"); config.SetValue<string>("control", "static");
config.SetValue("catch-signals", 0); config.SetValue("catch-signals", 0);
mgr.EmplacePluginServices(&config, device); mgr.EmplacePluginServices(config, device);
ASSERT_NO_THROW(mgr.InstantiatePlugins()); ASSERT_NO_THROW(mgr.InstantiatePlugins());
// check order // check order
const auto expected = vector<string>{"control"}; const auto expected = vector<string>{"control"};
auto actual = vector<string>{}; auto actual = vector<string>();
mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); }); mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); });
ASSERT_TRUE(actual == expected); ASSERT_TRUE(actual == expected);
// program options // program options
auto count = 0; auto count = 0;
mgr.ForEachPluginProgOptions([&count](const options_description& d){ ++count; }); mgr.ForEachPluginProgOptions([&count](const options_description&){ ++count; });
ASSERT_EQ(count, 1); ASSERT_EQ(count, 1);
device.RunStateMachine();
mgr.WaitForPluginsToReleaseDeviceControl(); mgr.WaitForPluginsToReleaseDeviceControl();
} }
TEST(PluginManager, Factory) TEST(PluginManager, Factory)
{ {
const auto args = vector<string>{"-l", "debug", "--help", "-S", ">/lib", "</home/user/lib", "/usr/local/lib", "/usr/lib"}; const auto args = vector<string>{"-l", "debug", "--help", "-S", ">/lib", "</home/user/lib", "/usr/local/lib", "/usr/lib"};
auto mgr = PluginManager::MakeFromCommandLineOptions(args); PluginManager mgr(args);
const auto path1 = path{"/home/user/lib"}; const auto path1 = path{"/home/user/lib"};
const auto path2 = path{"/usr/local/lib"}; const auto path2 = path{"/usr/local/lib"};
const auto path3 = path{"/usr/lib"}; const auto path3 = path{"/usr/lib"};
const auto path4 = path{"/lib"}; const auto path4 = path{"/lib"};
const auto expected = vector<path>{path1, path2, path3, path4}; const auto expected = vector<path>{path1, path2, path3, path4};
ASSERT_TRUE(static_cast<bool>(mgr)); // ASSERT_TRUE(static_cast<bool>(mgr));
ASSERT_TRUE(mgr->SearchPaths() == expected); ASSERT_TRUE(mgr.SearchPaths() == expected);
} }
TEST(PluginManager, SearchPathValidation) TEST(PluginManager, SearchPathValidation)
@@ -112,7 +119,7 @@ TEST(PluginManager, SearchPathValidation)
const auto path1 = path{"/tmp/test1"}; const auto path1 = path{"/tmp/test1"};
const auto path2 = path{"/tmp/test2"}; const auto path2 = path{"/tmp/test2"};
const auto path3 = path{"/tmp/test3"}; const auto path3 = path{"/tmp/test3"};
auto mgr = PluginManager{}; PluginManager mgr;
mgr.SetSearchPaths({path1, path2}); mgr.SetSearchPaths({path1, path2});
auto expected = vector<path>{path1, path2}; auto expected = vector<path>{path1, path2};
@@ -140,7 +147,7 @@ TEST(PluginManager, SearchPaths)
fs.close(); fs.close();
const auto empty_path = path{""}; const auto empty_path = path{""};
auto mgr = PluginManager{}; PluginManager mgr;
ASSERT_NO_THROW(mgr.AppendSearchPath(non_existing_dir)); ASSERT_NO_THROW(mgr.AppendSearchPath(non_existing_dir));
ASSERT_NO_THROW(mgr.AppendSearchPath(existing_dir)); ASSERT_NO_THROW(mgr.AppendSearchPath(existing_dir));
ASSERT_THROW(mgr.AppendSearchPath(existing_file), PluginManager::BadSearchPath); ASSERT_THROW(mgr.AppendSearchPath(existing_file), PluginManager::BadSearchPath);

View File

@@ -17,7 +17,7 @@ using namespace std;
TEST(PluginManager, LoadPluginPrelinkedDynamic) TEST(PluginManager, LoadPluginPrelinkedDynamic)
{ {
auto mgr = PluginManager{}; PluginManager mgr;
ASSERT_NO_THROW(mgr.LoadPlugin("p:test_dummy")); ASSERT_NO_THROW(mgr.LoadPlugin("p:test_dummy"));
ASSERT_NO_THROW(mgr.LoadPlugin("p:test_dummy2")); ASSERT_NO_THROW(mgr.LoadPlugin("p:test_dummy2"));

Some files were not shown because too many files have changed in this diff Show More