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_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
option(BUILD_DOCS "Build FairMQ documentation." OFF)
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
################################################################################
# Dependencies #################################################################
if(FAST_BUILD)
include(cotire)
endif()
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)
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
COMPONENTS program_options thread system filesystem regex date_time signals
@@ -48,7 +68,11 @@ endif()
if(BUILD_NANOMSG_TRANSPORT)
find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED)
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
find_package2(PRIVATE msgpack VERSION 3.0.0)
set(PROJECT_msgpack_VERSION 2.1.5)
if(NOT msgpack_FOUND)
find_package2(PRIVATE msgpack VERSION 2.1.5 REQUIRED)
endif()
set(msgpack_ROOT ${PACKAGE_PREFIX_DIR})
endif()
@@ -94,6 +118,7 @@ if(BUILD_DOCS)
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_GIT_VERSION})
set(DOXYGEN_PROJECT_BRIEF "C++ Message Passing Framework")
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md)
set(DOXYGEN_HTML_FOOTER docs/footer.html)
doxygen_add_docs(doxygen README.md fairmq)
add_custom_target(docs ALL DEPENDS doxygen)
endif()
@@ -161,6 +186,29 @@ install_cmake_package()
# Summary ######################################################################
if(CMAKE_CXX_FLAGS)
message(STATUS " ")
message(STATUS " ${Cyan}GLOBAL CXX FLAGS${CR} ${BGreen}${CMAKE_CXX_FLAGS}${CR}")
endif()
if(CMAKE_CONFIGURATION_TYPES)
message(STATUS " ")
message(STATUS " ${Cyan}BUILD TYPE CXX FLAGS${CR}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" selected_type)
foreach(type IN LISTS CMAKE_CONFIGURATION_TYPES)
string(TOUPPER "${type}" type_upper)
if(type_upper STREQUAL selected_type)
pad("${type}" 18 " " type_padded)
message(STATUS "${BGreen}* ${type_padded}${CMAKE_CXX_FLAGS_${type_upper}}${CR}")
else()
pad("${type}" 18 " " type_padded)
message(STATUS " ${BWhite}${type_padded}${CR}${CMAKE_CXX_FLAGS_${type_upper}}")
endif()
unset(type_padded)
unset(type_upper)
endforeach()
message(STATUS " ")
message(STATUS " (Change the build type with ${BMagenta}-DCMAKE_BUILD_TYPE=...${CR})")
endif()
if(PROJECT_PACKAGE_DEPENDENCIES)
message(STATUS " ")
message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}")

View File

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

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

40
Dart.sh
View File

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

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};-DBUILD_NANOMSG_TRANSPORT=ON")
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=ON")
Set(configure_options "${configure_options};-DFAST_BUILD=ON")
Set(configure_options "${configure_options};-DCOTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES=-j$ENV{number_of_processors}")
Set(EXTRA_FLAGS $ENV{EXTRA_FLAGS})
If(EXTRA_FLAGS)
Set(configure_options "${configure_options};${EXTRA_FLAGS}")
EndIf()
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
If($ENV{ctest_model} MATCHES Profile)
Find_Program(GCOV_COMMAND gcov)
If(GCOV_COMMAND)
Message("Found GCOV: ${GCOV_COMMAND}")
Set(CTEST_COVERAGE_COMMAND ${GCOV_COMMAND})
EndIf(GCOV_COMMAND)
EndIf()
Set(ENV{ctest_model} Nightly)
CTEST_EMPTY_BINARY_DIRECTORY(${CTEST_BINARY_DIRECTORY})
If($ENV{ctest_model} MATCHES Nightly OR $ENV{ctest_model} MATCHES Profile)
Ctest_Empty_Binary_Directory(${CTEST_BINARY_DIRECTORY})
EndIf()
Ctest_Start($ENV{ctest_model})
@@ -60,9 +60,26 @@ Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL $ENV{number_of_processors}
RETURN_VALUE _ctest_test_ret_val
)
If("$ENV{do_codecov_upload}")
ForEach(i RANGE 4)
# Gather statistics to catch time sensitive branches
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL $ENV{number_of_processors}
)
EndForEach()
EndIf()
If(GCOV_COMMAND)
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}")
Ctest_Coverage(BUILD "${CTEST_BINARY_DIRECTORY}" LABELS coverage)
EndIf()
If("$ENV{do_codecov_upload}")
Execute_Process(COMMAND curl https://codecov.io/bash -o codecov_uploader.sh
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
TIMEOUT 60)
Execute_Process(COMMAND bash ./codecov_uploader.sh -X gcov
WORKING_DIRECTORY ${CTEST_BINARY_DIRECTORY}
TIMEOUT 60)
EndIf()
Ctest_Submit()

40
Jenkinsfile vendored
View File

@@ -4,24 +4,31 @@ def specToLabel(Map spec) {
return "${spec.os}-${spec.arch}-${spec.compiler}-FairSoft_${spec.fairsoft}"
}
def buildMatrix(List specs, Closure callback) {
def jobMatrix(String prefix, List specs, Closure callback) {
def nodes = [:]
for (spec in specs) {
def label = specToLabel(spec)
nodes[label] = {
nodes["${prefix}/${label}"] = {
node(label) {
githubNotify(context: "alfa-ci/${label}", description: 'Building ...', status: 'PENDING')
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
try {
deleteDir()
checkout scm
sh '''\
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
echo "export SOURCEDIR=$PWD" >> Dart.cfg
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
'''
callback.call(spec, label)
deleteDir()
githubNotify(context: "alfa-ci/${label}", description: 'Success', status: 'SUCCESS')
githubNotify(context: "${prefix}/${label}", description: 'Success', status: 'SUCCESS')
} catch (e) {
deleteDir()
githubNotify(context: "alfa-ci/${label}", description: 'Error', status: 'ERROR')
githubNotify(context: "${prefix}/${label}", description: 'Error', status: 'ERROR')
throw e
}
}
@@ -33,22 +40,25 @@ def buildMatrix(List specs, Closure callback) {
pipeline{
agent none
stages {
stage("Run Build/Test Matrix") {
stage("Run CI Matrix") {
steps{
script {
parallel(buildMatrix([
def build_jobs = jobMatrix('alfa-ci/build', [
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
[os: 'MacOS10.11', arch: 'x86_64', compiler: 'AppleLLVM8.0.0', fairsoft: 'may18'],
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
]) { spec, label ->
sh '''\
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
echo "export SOURCEDIR=$PWD" >> Dart.cfg
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
'''
sh './Dart.sh alfa_ci Dart.cfg'
})
}
def profile_jobs = jobMatrix('alfa-ci/codecov', [
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
]) { spec, label ->
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
sh './Dart.sh codecov Dart.cfg'
}
}
parallel(build_jobs + profile_jobs)
}
}
}

View File

@@ -1,12 +1,14 @@
<!-- {#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 |
| :---: | :--- |
| `master` | ![build status master branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/master) |
| `dev` | ![build status dev branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/dev) |
| Branch | Version | Docs | Status |
| :---: | :--- | :--- | :--- |
| `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` | [![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
* 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) -
a simulation, reconstruction and analysis framework.
Find all FairMQ releases and development tags [here](https://github.com/FairRootGroup/FairMQ/releases).
## Dependencies
* [**Boost**](https://www.boost.org/) (PUBLIC)
* [**FairLogger**](https://github.com/FairRootGroup/FairLogger) (PUBLIC)
* [CMake](https://cmake.org/) (BUILD)
* [GTest](https://github.com/google/googletest) (BUILD, optional, `tests`)
* [Doxygen](http://www.doxygen.org/) (BUILD, optional, `docs`)
* [ZeroMQ](http://zeromq.org/) (PRIVATE)
* [Msgpack](https://msgpack.org/index.html) (PRIVATE, optional, `nanomsg_transport`)
* [nanomsg](http://nanomsg.org/) (PRIVATE, optional, `nanomsg_transport`)
* [OFI](https://ofiwg.github.io/libfabric/) (PRIVATE, optional, `ofi_transport`)
* [Protobuf](https://developers.google.com/protocol-buffers/) (PRIVATE, optional, `ofi_transport`)
* [DDS](http://dds.gsi.de) (PRIVATE, optional, `dds_plugin`)
* PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger)
* BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/)
* PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/),
[OFI](https://ofiwg.github.io/libfabric/), [Protobuf](https://developers.google.com/protocol-buffers/), [DDS](http://dds.gsi.de)
Supported platforms: Linux and MacOS.
## Releases
| Stable release | Date | API Docs |
| --- | --- | --- |
| [**1.2.3**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.3) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.3/index.html) |
| [**1.2.1**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.1) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.1/index.html) |
| [**1.2.0**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.0) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.0/index.html) |
Find all FairMQ stable and development releases [here](https://github.com/FairRootGroup/FairMQ/releases).
## Installation from Source
```bash
@@ -89,7 +76,7 @@ In order to succesfully compile and link against the `FairMQ::FairMQ` target, yo
find_package(FairMQ)
if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS})
endif()
```
@@ -101,7 +88,7 @@ Optionally, you can require certain FairMQ package components and a minimum vers
find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin)
if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS})
endif()
```
@@ -169,9 +156,3 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
4. [File output](docs/Logging.md#54-file-output)
5. [Custom sinks](docs/Logging.md#55-custom-sinks)
6. [Examples](docs/Examples.md#6-examples)
## License
GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE).
Copyright (C) 2013-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH

View File

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

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)
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)
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-1-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
endif()
add_test(NAME Example-1-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
set_tests_properties(Example-1-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")

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)
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)
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-1-n-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
endif()
add_test(NAME Example-1-n-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
set_tests_properties(Example-1-n-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")

View File

@@ -12,6 +12,8 @@ add_subdirectory(copypush)
add_subdirectory(dds)
add_subdirectory(multipart)
add_subdirectory(multiple-channels)
add_subdirectory(multiple-transports)
if(BUILD_NANOMSG_TRANSPORT)
add_subdirectory(multiple-transports)
endif()
add_subdirectory(region)
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)
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)
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-CopyPush-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
endif()
add_test(NAME Example-CopyPush-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
set_tests_properties(Example-CopyPush-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")

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)
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)
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-Multipart-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
endif()
add_test(NAME Example-Multipart-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
set_tests_properties(Example-Multipart-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 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)
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)
set_tests_properties(Example-Multiple-Channels-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
if(BUILD_NANOMSG_TRANSPORT)
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

View File

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

View File

@@ -36,8 +36,6 @@ class Sink : public FairMQDevice
uint64_t fMaxIterations;
uint64_t fNumIterations1;
uint64_t fNumIterations2;
bool fReceived1;
bool fReceived2;
};
} // 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+=" 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"
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)
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)
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-Region-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
endif()
add_test(NAME Example-Region-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
set_tests_properties(Example-Region-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")

View File

@@ -38,7 +38,7 @@ void Sampler::InitTask()
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data",
0,
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;
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)
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)
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
if(BUILD_NANOMSG_TRANSPORT)
add_test(NAME Example-ReqRep-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
endif()
add_test(NAME Example-ReqRep-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
set_tests_properties(Example-ReqRep-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")

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

View File

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

View File

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

View File

@@ -28,6 +28,7 @@ FairMQChannel::FairMQChannel()
, fType("unspecified")
, fMethod("unspecified")
, fAddress("unspecified")
, fTransportType(fair::mq::Transport::DEFAULT)
, fSndBufSize(1000)
, fRcvBufSize(1000)
, fSndKernelSize(0)
@@ -35,7 +36,6 @@ FairMQChannel::FairMQChannel()
, fRateLogging(1)
, fName("")
, fIsValid(false)
, fTransportType(fair::mq::Transport::DEFAULT)
, fTransportFactory(nullptr)
, fMultipart(false)
, fModified(true)
@@ -48,6 +48,7 @@ FairMQChannel::FairMQChannel(const string& type, const string& method, const str
, fType(type)
, fMethod(method)
, fAddress(address)
, fTransportType(fair::mq::Transport::DEFAULT)
, fSndBufSize(1000)
, fRcvBufSize(1000)
, fSndKernelSize(0)
@@ -55,7 +56,6 @@ FairMQChannel::FairMQChannel(const string& type, const string& method, const str
, fRateLogging(1)
, fName("")
, fIsValid(false)
, fTransportType(fair::mq::Transport::DEFAULT)
, fTransportFactory(nullptr)
, fMultipart(false)
, fModified(true)
@@ -68,6 +68,7 @@ FairMQChannel::FairMQChannel(const string& name, const string& type, std::shared
, fType(type)
, fMethod("unspecified")
, fAddress("unspecified")
, fTransportType(factory->GetType())
, fSndBufSize(1000)
, fRcvBufSize(1000)
, fSndKernelSize(0)
@@ -75,7 +76,6 @@ FairMQChannel::FairMQChannel(const string& name, const string& type, std::shared
, fRateLogging(1)
, fName(name)
, fIsValid(false)
, fTransportType(factory->GetType())
, fTransportFactory(factory)
, fMultipart(false)
, fModified(true)
@@ -88,6 +88,7 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
, fType(chan.fType)
, fMethod(chan.fMethod)
, fAddress(chan.fAddress)
, fTransportType(chan.fTransportType)
, fSndBufSize(chan.fSndBufSize)
, fRcvBufSize(chan.fRcvBufSize)
, fSndKernelSize(chan.fSndKernelSize)
@@ -95,7 +96,6 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan)
, fRateLogging(chan.fRateLogging)
, fName(chan.fName)
, fIsValid(false)
, fTransportType(chan.fTransportType)
, fTransportFactory(nullptr)
, fMultipart(chan.fMultipart)
, fModified(chan.fModified)
@@ -327,9 +327,7 @@ void FairMQChannel::UpdateTransport(const string& transport)
{
unique_lock<mutex> lock(fChannelMutex);
fIsValid = false;
LOG(WARN) << fName << ": " << transport;
fTransportType = fair::mq::TransportTypes.at(transport);
LOG(WARN) << fName << ": " << fair::mq::TransportNames.at(fTransportType);
fModified = true;
}
catch (exception& e)
@@ -501,7 +499,7 @@ bool FairMQChannel::ValidateChannel()
else
{
vector<string> endpoints;
boost::algorithm::split(endpoints, fAddress, boost::algorithm::is_any_of(","));
boost::algorithm::split(endpoints, fAddress, boost::algorithm::is_any_of(";"));
for (const auto endpoint : endpoints)
{
string address;
@@ -655,13 +653,13 @@ void FairMQChannel::ResetChannel()
int FairMQChannel::Send(unique_ptr<FairMQMessage>& msg) const
{
CheckCompatibility(msg);
CheckSendCompatibility(msg);
return fSocket->Send(msg);
}
int FairMQChannel::Receive(unique_ptr<FairMQMessage>& msg) const
{
CheckCompatibility(msg);
CheckReceiveCompatibility(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
{
CheckCompatibility(msg);
CheckSendCompatibility(msg);
return fSocket->TrySend(msg);
}
int FairMQChannel::ReceiveAsync(unique_ptr<FairMQMessage>& msg) const
{
CheckCompatibility(msg);
CheckReceiveCompatibility(msg);
return fSocket->TryReceive(msg);
}
int64_t FairMQChannel::Send(vector<unique_ptr<FairMQMessage>>& msgVec) const
{
CheckCompatibility(msgVec);
CheckSendCompatibility(msgVec);
return fSocket->Send(msgVec);
}
int64_t FairMQChannel::Receive(vector<unique_ptr<FairMQMessage>>& msgVec) const
{
CheckCompatibility(msgVec);
CheckReceiveCompatibility(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
{
CheckCompatibility(msgVec);
CheckSendCompatibility(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.
int64_t FairMQChannel::ReceiveAsync(vector<unique_ptr<FairMQMessage>>& msgVec) const
{
CheckCompatibility(msgVec);
CheckReceiveCompatibility(msgVec);
return fSocket->TryReceive(msgVec);
}
@@ -750,44 +748,58 @@ unsigned long FairMQChannel::GetMessagesRx() const
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;
}
else
{
// LOG(warn) << "Channel type does not match message type. Copying...";
FairMQMessagePtr msgCopy(fTransportFactory->CreateMessage(msg->GetSize()));
memcpy(msgCopy->GetData(), msg->GetData(), msg->GetSize());
msg = move(msgCopy);
return false;
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
}
}
bool FairMQChannel::CheckCompatibility(vector<unique_ptr<FairMQMessage>>& msgVec) const
void FairMQChannel::CheckSendCompatibility(vector<FairMQMessagePtr>& msgVec) const
{
bool match = true;
if (msgVec.size() > 0)
for (auto& msg : msgVec)
{
for (unsigned int i = 0; i < msgVec.size(); ++i)
if (fTransportType != msg->GetType())
{
if (fTransportType != msgVec.at(i)->GetType())
{
// LOG(warn) << "Channel type does not match message type. Copying...";
FairMQMessagePtr newMsg(fTransportFactory->CreateMessage(msgVec[i]->GetSize()));
memcpy(newMsg->GetData(), msgVec[i]->GetData(), msgVec[i]->GetSize());
msgVec[i] = move(newMsg);
match = false;
}
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
}
}
}
void 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 <FairMQLogger.h>
#include <FairMQParts.h>
#include <FairMQMessage.h>
class FairMQChannel
{
@@ -165,8 +166,8 @@ class FairMQChannel
/// Resets the channel (requires validation to be used again).
void ResetChannel();
int Send(std::unique_ptr<FairMQMessage>& msg) const;
int Receive(std::unique_ptr<FairMQMessage>& msg) const;
int Send(FairMQMessagePtr& msg) const;
int Receive(FairMQMessagePtr& msg) const;
/// Sends a message to the socket queue.
/// @details Send method attempts to send a message by
@@ -176,7 +177,7 @@ class FairMQChannel
/// @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.
/// 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.
/// @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
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
/// In case of errors, returns -1.
int Receive(std::unique_ptr<FairMQMessage>& msg, int rcvTimeoutInMs) const;
int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs) const;
/// Sends a message in non-blocking mode.
/// @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
/// full queue or no connected peers (when binding), returns -2.
/// 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.
///
/// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @return Number of bytes that have been received. If queue is empty, returns -2.
/// In case of errors, returns -1.
int ReceiveAsync(std::unique_ptr<FairMQMessage>& msg) const;
int ReceiveAsync(FairMQMessagePtr& msg) const;
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const;
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const;
int64_t Send(std::vector<FairMQMessagePtr>& msgVec) const;
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec) const;
/// Send a vector of messages
///
/// @param msgVec message vector reference
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
/// In case of errors, returns -1.
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int sndTimeoutInMs) const;
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs) const;
/// Receive a vector of messages
///
/// @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.
/// 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.
/// @details SendAsync method attempts to send a vector of messages without blocking by
@@ -228,14 +229,14 @@ class FairMQChannel
/// @param msgVec message vector reference
/// @return Number of bytes that have been queued. If queueing failed due to
/// full queue or no connected peers (when binding), returns -2. In case of errors, returns -1.
int64_t SendAsync(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const;
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) const;
/// Receives a vector of messages in non-blocking mode.
///
/// @param msgVec message vector reference
/// @return Number of bytes that have been received. If queue is empty, returns -2.
/// In case of errors, returns -1.
int64_t ReceiveAsync(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const;
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) const;
int64_t Send(FairMQParts& parts) const
{
@@ -313,8 +314,10 @@ class FairMQChannel
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
bool CheckCompatibility(std::unique_ptr<FairMQMessage>& msg) const;
bool CheckCompatibility(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) const;
void CheckSendCompatibility(FairMQMessagePtr& msg) const;
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
void CheckReceiveCompatibility(FairMQMessagePtr& msg) const;
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory);

View File

@@ -26,6 +26,8 @@
#include <thread>
#include <functional>
#include <sstream>
#include <iomanip>
#include <algorithm> // std::max
using namespace std;
@@ -57,6 +59,7 @@ FairMQDevice::FairMQDevice()
, fVersion({0, 0, 0})
, fRate(0.)
, fLastTime(0)
, fRawCmdLineArgs()
{
}
@@ -87,6 +90,7 @@ FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
, fVersion(version)
, fRate(0.)
, fLastTime(0)
, fRawCmdLineArgs()
{
}
@@ -144,7 +148,8 @@ void FairMQDevice::InitWrapper()
else
{
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)
{
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);
@@ -196,7 +202,8 @@ void FairMQDevice::InitWrapper()
if (numAttempts++ > maxAttempts)
{
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);
@@ -267,7 +274,15 @@ bool FairMQDevice::AttachChannel(FairMQChannel& ch)
//(re-)init socket
if (!ch.fSocket)
{
ch.fSocket = ch.fTransportFactory->CreateSocket(ch.fType, ch.fName);
try
{
ch.fSocket = ch.fTransportFactory->CreateSocket(ch.fType, ch.fName);
}
catch (fair::mq::SocketError& se)
{
LOG(error) << se.what();
return false;
}
}
// set high water marks
@@ -501,7 +516,7 @@ void FairMQDevice::RunWrapper()
while (CheckCurrentState(RUNNING) && ConditionalRun())
{
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) {
TimeScale sleepfor(period - timespan);
this_thread::sleep_for(sleepfor);
@@ -808,7 +823,7 @@ void FairMQDevice::CreateOwnConfig()
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} 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;
fConfig = &config;
for (auto& c : config.GetFairMQMap())
for (auto& c : fConfig->GetFairMQMap())
{
if (!fChannels.insert(c).second)
{
LOG(warn) << "did not insert channel '" << c.first << "', it is already in the device.";
}
}
fId = config.GetValue<string>("id");
fNetworkInterface = config.GetValue<string>("network-interface");
fNumIoThreads = config.GetValue<int>("io-threads");
fInitializationTimeoutInS = config.GetValue<int>("initialization-timeout");
fId = fConfig->GetValue<string>("id");
fNetworkInterface = fConfig->GetValue<string>("network-interface");
fNumIoThreads = fConfig->GetValue<int>("io-threads");
fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
fRate = fConfig->GetValue<float>("rate");
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} catch(const exception& e) {
LOG(ERROR) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
}
SetTransport(fConfig->GetValue<string>("transport"));
}
@@ -869,6 +884,8 @@ void FairMQDevice::LogSocketRates()
vector<int> logIntervals;
vector<int> intervalCounters;
size_t chanNameLen = 0;
// iterate over the channels map
for (const auto& mi : fChannels)
{
@@ -881,6 +898,7 @@ void FairMQDevice::LogSocketRates()
logIntervals.push_back(vi->fRateLogging);
intervalCounters.push_back(0);
filteredChannelNames.push_back(fair::mq::tools::ToString(mi.first, "[", vi - (mi.second).begin(), "]"));
chanNameLen = max(chanNameLen, filteredChannelNames.back().length());
}
}
}
@@ -949,9 +967,9 @@ void FairMQDevice::LogSocketRates()
bytesOut.at(i) = bytesOutNew.at(i);
msgOut.at(i) = msgOutNew.at(i);
LOG(info) << filteredChannelNames.at(i) << ": "
<< "in: " << msgPerSecIn.at(i) << " (" << mbPerSecIn.at(i) << " MB) "
<< "out: " << msgPerSecOut.at(i) << " (" << mbPerSecOut.at(i) << " MB)";
LOG(info) << setw(chanNameLen) << filteredChannelNames.at(i) << ": "
<< "in: " << msgPerSecIn.at(i) << " (" << mbPerSecIn.at(i) << " MB) "
<< "out: " << msgPerSecOut.at(i) << " (" << mbPerSecOut.at(i) << " MB)";
}
++i;

View File

@@ -208,7 +208,7 @@ class FairMQDevice : public FairMQStateMachine
template<typename... Args>
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>
@@ -413,6 +413,11 @@ class FairMQDevice : public FairMQStateMachine
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; }
int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine() { ProcessWork(); };
protected:
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
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;
float fRate; ///< Rate limiting for ConditionalRun
size_t fLastTime; ///< Rate limiting for ConditionalRun
std::vector<std::string> fRawCmdLineArgs;
};
#endif /* FAIRMQDEVICE_H_ */

View File

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

View File

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

View File

@@ -116,9 +116,9 @@ class Plugin
} /* namespace fair */
#define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr<fair::mq::Plugin> \
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::unique_ptr<fair::mq::Plugin> \
{ \
return std::make_shared<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
return fair::mq::tools::make_unique<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
} \
BOOST_DLL_ALIAS(Make_##NAME##_Plugin, make_##NAME##_plugin) \
BOOST_DLL_ALIAS(PROGOPTIONS, get_##NAME##_plugin_progoptions)

View File

@@ -6,6 +6,7 @@
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <fairmq/plugins/Builtin.h>
#include <fairmq/PluginManager.h>
#include <fairmq/Tools.h>
#include <boost/program_options.hpp>
@@ -30,13 +31,55 @@ const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
fair::mq::PluginManager::PluginManager()
: fSearchPaths{{"."}}
, fPluginFactories()
, fPluginServices()
, fPlugins()
, fPluginOrder()
, fPluginProgOptions()
, fPluginServices()
{
}
fair::mq::PluginManager::PluginManager(const vector<string> args)
: fSearchPaths{{"."}}
, fPluginFactories()
, fPluginServices()
, fPlugins()
, fPluginOrder()
, fPluginProgOptions()
{
// Parse command line options
auto options = ProgramOptions();
auto vm = po::variables_map{};
try
{
auto parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
} catch (const po::error& e)
{
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
}
// Process plugin search paths
auto append = vector<fs::path>{};
auto prepend = vector<fs::path>{};
auto searchPaths = vector<fs::path>{};
if (vm.count("plugin-search-path"))
{
for (const auto& path : vm["plugin-search-path"].as<vector<string>>())
{
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
else { searchPaths.emplace_back(path); }
}
}
// Set supplied options
SetSearchPaths(searchPaths);
for(const auto& path : prepend) { PrependSearchPath(path); }
for(const auto& path : append) { AppendSearchPath(path); }
if (vm.count("plugin")) { LoadPlugins(vm["plugin"].as<vector<string>>()); }
}
auto fair::mq::PluginManager::ValidateSearchPath(const fs::path& path) -> void
{
if (path.empty()) throw BadSearchPath{"Specified path is empty."};
@@ -80,46 +123,6 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
return plugin_options;
}
auto fair::mq::PluginManager::MakeFromCommandLineOptions(const vector<string> args) -> shared_ptr<PluginManager>
{
// Parse command line options
auto options = ProgramOptions();
auto vm = po::variables_map{};
try
{
auto parsed = po::command_line_parser(args).options(options).allow_unregistered().run();
po::store(parsed, vm);
po::notify(vm);
} catch (const po::error& e)
{
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
}
// Process plugin search paths
auto append = vector<fs::path>{};
auto prepend = vector<fs::path>{};
auto searchPaths = vector<fs::path>{};
if (vm.count("plugin-search-path"))
{
for (const auto& path : vm["plugin-search-path"].as<vector<string>>())
{
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
else { searchPaths.emplace_back(path); }
}
}
// Create PluginManager with supplied options
auto mgr = make_shared<PluginManager>();
mgr->SetSearchPaths(searchPaths);
for(const auto& path : prepend) { mgr->PrependSearchPath(path); }
for(const auto& path : append) { mgr->AppendSearchPath(path); }
if (vm.count("plugin")) { mgr->LoadPlugins(vm["plugin"].as<vector<string>>()); }
// Return the plugin manager and command line options, that have not been recognized.
return mgr;
}
auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
{
if (pluginName.substr(0,2) == "p:")

View File

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

View File

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

View File

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

View File

@@ -57,7 +57,7 @@ void FairMQBenchmarkSampler::Run()
// store the channel reference to avoid traversing the map on every loop iteration
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.";
auto tStart = chrono::high_resolution_clock::now();
@@ -66,7 +66,7 @@ void FairMQBenchmarkSampler::Run()
{
if (fSameMessage)
{
FairMQMessagePtr msg(dataOutChannel.Transport()->CreateMessage());
FairMQMessagePtr msg(dataOutChannel.NewMessage());
msg->Copy(*baseMsg);
if (dataOutChannel.Send(msg) >= 0)
@@ -83,7 +83,7 @@ void FairMQBenchmarkSampler::Run()
}
else
{
FairMQMessagePtr msg(dataOutChannel.Transport()->CreateMessage(fMsgSize));
FairMQMessagePtr msg(dataOutChannel.NewMessage(fMsgSize));
if (dataOutChannel.Send(msg) >= 0)
{

View File

@@ -17,6 +17,7 @@
#include <string>
#include <thread>
#include <atomic>
#include "FairMQDevice.h"
@@ -38,7 +39,7 @@ class FairMQBenchmarkSampler : public FairMQDevice
protected:
bool fSameMessage;
int fMsgSize;
int fMsgCounter;
std::atomic<int> fMsgCounter;
int fMsgRate;
uint64_t fNumIterations;
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))
{
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
FairMQMessagePtr msg(dataInChannel.NewMessage());
if (dataInChannel.Receive(msg) >= 0)
{

View File

@@ -10,6 +10,7 @@
#include <fairmq/Tools.h>
#include <FairMQLogger.h>
#include <cassert>
#include <cstdlib>
#include <zmq.h>
@@ -53,7 +54,7 @@ Message::Message(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
{
}
Message::Message(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint)
Message::Message(FairMQUnmanagedRegionPtr& /*region*/, void* /*data*/, const size_t /*size*/, void* /*hint*/)
{
throw MessageError{"Not yet implemented."};
}
@@ -91,7 +92,7 @@ auto Message::Rebuild(const size_t size) -> void
fHint = nullptr;
}
auto Message::Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint) -> void
auto Message::Rebuild(void* /*data*/, const size_t size, fairmq_free_fn* ffn, void* hint) -> void
{
if (fFreeFunction) {
fFreeFunction(fData, fHint);
@@ -132,12 +133,12 @@ auto Message::SetUsedSize(const size_t size) -> bool
}
}
auto Message::Copy(const fair::mq::Message& msg) -> void
auto Message::Copy(const fair::mq::Message& /*msg*/) -> void
{
throw MessageError{"Not yet implemented."};
}
auto Message::Copy(const fair::mq::MessagePtr& msg) -> void
auto Message::Copy(const fair::mq::MessagePtr& /*msg*/) -> void
{
throw MessageError{"Not yet implemented."};
}

View File

@@ -27,11 +27,16 @@ namespace parser
{
// 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
FairMQMap ptreeToMQMap(const boost::property_tree::ptree& pt, const string& id, const string& rootNode)
// function that convert property tree (given the json structure) to FairMQChannelMap
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
FairMQMap channelMap;
FairMQChannelMap channelMap;
// boost::property_tree::json_parser::write_json(std::cout, pt);
// Helper::PrintDeviceList(pt.get_child(rootNode));
// Extract value from boost::property_tree
@@ -46,20 +51,13 @@ FairMQMap ptreeToMQMap(const boost::property_tree::ptree& pt, const string& id,
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::read_json(filename, pt);
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
{
@@ -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;
@@ -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;

View File

@@ -10,8 +10,8 @@
#include <string>
#include <vector>
#include <map>
#include <unordered_map>
#include <exception>
#include <boost/property_tree/ptree_fwd.hpp>
@@ -24,22 +24,23 @@ namespace mq
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
{
FairMQMap 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");
FairMQChannelMap UserParser(const std::string& filename, const std::string& deviceId, const std::string& rootNode = "fairMQOptions");
};
namespace Helper
{
void PrintDeviceList(const boost::property_tree::ptree& tree);
void DeviceParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap, const std::string& deviceId);
void ChannelParser(const boost::property_tree::ptree& tree, FairMQMap& channelMap);
void DeviceParser(const boost::property_tree::ptree& tree, FairMQChannelMap& channelMap, const std::string& deviceId);
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);
} // Helper namespace

View File

@@ -12,25 +12,70 @@
* Created on March 11, 2015, 10:20 PM
*/
#include "FairMQLogger.h"
#include "FairMQProgOptions.h"
#include "FairProgOptionsHelper.h"
#include "FairMQParser.h"
#include "FairMQSuboptParser.h"
#include "FairMQLogger.h"
#include <boost/algorithm/string.hpp> // join/split
#include <algorithm>
#include <iomanip>
#include <iostream>
#include <exception>
using namespace std;
using namespace fair::mq;
namespace po = boost::program_options;
FairMQProgOptions::FairMQProgOptions()
: FairProgOptions()
, fMQCmdOptions("FairMQ device options")
, fMQParserOptions("FairMQ config parser options")
, fFairMQMap()
: fVarMap()
, fFairMQChannelMap()
, fAllOptions("FairMQ Command Line Options")
, fGeneralOptions("General options")
, fMQOptions("FairMQ device options")
, fParserOptions("FairMQ channel config parser options")
, fConfigMutex()
, 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();
}
@@ -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)
{
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;
}
// if these options are provided, do no further checks and let the device handle them
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>();
}
else
else if (fVarMap.count("id"))
{
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"))
{
LOG(debug) << "mq-config: Using default JSON parser";
Store(fair::mq::parser::JSON().UserParser(fVarMap["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));
UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), id));
}
else if (fVarMap.count("channel-config"))
{
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
{
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) << "No channels will be created (You can create them manually).";
}
}
catch (std::exception& e)
catch (exception& e)
{
LOG(error) << e.what();
return 1;
}
FairProgOptions::PrintOptions();
PrintOptions();
return 0;
}
int FairMQProgOptions::Store(const FairMQMap& channels)
void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered)
{
fFairMQMap = channels;
UpdateChannelInfo();
UpdateMQValues();
return 0;
// 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 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
int FairMQProgOptions::UpdateChannelMap(const FairMQMap& channels)
int FairMQProgOptions::UpdateChannelMap(const unordered_map<string, vector<FairMQChannel>>& channels)
{
fFairMQMap = channels;
fFairMQChannelMap = channels;
UpdateChannelInfo();
UpdateMQValues();
return 0;
@@ -157,7 +240,7 @@ int FairMQProgOptions::UpdateChannelMap(const FairMQMap& channels)
void FairMQProgOptions::UpdateChannelInfo()
{
fChannelInfo.clear();
for (const auto& c : fFairMQMap)
for (const auto& c : fFairMQChannelMap)
{
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
void FairMQProgOptions::UpdateMQValues()
{
for (const auto& p : fFairMQMap)
for (const auto& p : fFairMQChannelMap)
{
int index = 0;
@@ -183,15 +266,15 @@ void FairMQProgOptions::UpdateMQValues()
string rcvKernelSizeKey = "chans." + p.first + "." + to_string(index) + ".rcvKernelSize";
string rateLoggingKey = "chans." + p.first + "." + to_string(index) + ".rateLogging";
fMQKeyMap[typeKey] = MQKey{p.first, index, "type"};
fMQKeyMap[methodKey] = MQKey{p.first, index, "method"};
fMQKeyMap[addressKey] = MQKey{p.first, index, "address"};
fMQKeyMap[transportKey] = MQKey{p.first, index, "transport"};
fMQKeyMap[sndBufSizeKey] = MQKey{p.first, index, "sndBufSize"};
fMQKeyMap[rcvBufSizeKey] = MQKey{p.first, index, "rcvBufSize"};
fMQKeyMap[sndKernelSizeKey] = MQKey{p.first, index, "sndKernelSize"};
fMQKeyMap[rcvKernelSizeKey] = MQKey{p.first, index, "rcvkernelSize"};
fMQKeyMap[rateLoggingKey] = MQKey{p.first, index, "rateLogging"};
fChannelKeyMap[typeKey] = ChannelKey{p.first, index, "type"};
fChannelKeyMap[methodKey] = ChannelKey{p.first, index, "method"};
fChannelKeyMap[addressKey] = ChannelKey{p.first, index, "address"};
fChannelKeyMap[transportKey] = ChannelKey{p.first, index, "transport"};
fChannelKeyMap[sndBufSizeKey] = ChannelKey{p.first, index, "sndBufSize"};
fChannelKeyMap[rcvBufSizeKey] = ChannelKey{p.first, index, "rcvBufSize"};
fChannelKeyMap[sndKernelSizeKey] = ChannelKey{p.first, index, "sndKernelSize"};
fChannelKeyMap[rcvKernelSizeKey] = ChannelKey{p.first, index, "rcvkernelSize"};
fChannelKeyMap[rateLoggingKey] = ChannelKey{p.first, index, "rateLogging"};
UpdateVarMap<string>(typeKey, channel.GetType());
UpdateVarMap<string>(methodKey, channel.GetMethod());
@@ -209,103 +292,56 @@ void FairMQProgOptions::UpdateMQValues()
}
}
int FairMQProgOptions::ImmediateOptions()
{
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)
int FairMQProgOptions::UpdateChannelValue(const string& channelName, int index, const string& member, const string& val)
{
if (member == "type")
{
fFairMQMap.at(channelName).at(index).UpdateType(val);
fFairMQChannelMap.at(channelName).at(index).UpdateType(val);
return 0;
}
if (member == "method")
{
fFairMQMap.at(channelName).at(index).UpdateMethod(val);
fFairMQChannelMap.at(channelName).at(index).UpdateMethod(val);
return 0;
}
if (member == "address")
{
fFairMQMap.at(channelName).at(index).UpdateAddress(val);
fFairMQChannelMap.at(channelName).at(index).UpdateAddress(val);
return 0;
}
if (member == "transport")
{
fFairMQMap.at(channelName).at(index).UpdateTransport(val);
fFairMQChannelMap.at(channelName).at(index).UpdateTransport(val);
return 0;
}
else
{
//if we get there it means something is wrong
LOG(error) << "update of FairMQChannel map failed for the following key: "
<< channelName << "." << index << "." << member;
LOG(error) << "update of FairMQChannel map failed for the following key: " << channelName << "." << index << "." << member;
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")
{
fFairMQMap.at(channelName).at(index).UpdateSndBufSize(val);
fFairMQChannelMap.at(channelName).at(index).UpdateSndBufSize(val);
return 0;
}
if (member == "rcvBufSize")
{
fFairMQMap.at(channelName).at(index).UpdateRcvBufSize(val);
fFairMQChannelMap.at(channelName).at(index).UpdateRcvBufSize(val);
return 0;
}
if (member == "rateLogging")
{
fFairMQMap.at(channelName).at(index).UpdateRateLogging(val);
fFairMQChannelMap.at(channelName).at(index).UpdateRateLogging(val);
return 0;
}
else
@@ -315,3 +351,135 @@ int FairMQProgOptions::UpdateChannelMap(const string& channelName, int index, co
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" *
********************************************************************************/
/*
* File: FairMQProgOptions.h
* Author: winckler
*
* Created on March 11, 2015, 10:20 PM
*/
#ifndef FAIRMQPROGOPTIONS_H
#define FAIRMQPROGOPTIONS_H
#include <fairmq/EventManager.h>
#include "FairProgOptions.h"
#include "FairMQLogger.h"
#include "FairMQChannel.h"
#include <fairmq/Tools.h>
#include <boost/program_options.hpp>
#include <unordered_map>
#include <functional>
#include <map>
#include <mutex>
#include <string>
#include <vector>
#include <mutex>
#include <sstream>
namespace fair
{
@@ -38,10 +34,10 @@ struct PropertyChangeAsString : Event<std::string> {};
} /* namespace mq */
} /* namespace fair */
class FairMQProgOptions : public FairProgOptions
class FairMQProgOptions
{
protected:
using FairMQMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
private:
using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
public:
FairMQProgOptions();
@@ -49,52 +45,11 @@ class FairMQProgOptions : public FairProgOptions
int ParseAll(const std::vector<std::string>& cmdLineArgs, bool allowUnregistered);
// parse command line.
// default parser for the mq-configuration file (JSON/XML) is called if command line key mq-config is called
int ParseAll(const int argc, char const* const* argv, bool allowUnregistered = false) override;
// 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 = true);
FairMQMap GetFairMQMap() 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;
}
FairMQChannelMap GetFairMQMap() const;
std::unordered_map<std::string, int> GetChannelInfo() const;
template<typename T>
int SetValue(const std::string& key, T val)
@@ -104,12 +59,12 @@ class FairMQProgOptions : public FairProgOptions
// update variable map
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 (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);
}
// replace FairMQChannelMap, and update variable map accordingly
int UpdateChannelMap(const FairMQMap& map);
std::vector<std::string> GetPropertyKeys() const;
protected:
struct MQKey
// 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);
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;
int index;
std::string member;
};
po::options_description fMQCmdOptions;
po::options_description fMQParserOptions;
FairMQMap fFairMQMap;
boost::program_options::variables_map fVarMap; ///< options container
FairMQChannelMap fFairMQChannelMap;
// map of read channel info - channel name - number of subchannels
std::unordered_map<std::string, int> fChannelInfo;
boost::program_options::options_description fAllOptions; ///< all options descriptions
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
void InitOptionDescription();
std::unordered_map<std::string, int> fChannelInfo; ///< channel name - number of subchannels
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
// create key for variable map as follow : channelName.index.memberName
void UpdateMQValues();
int Store(const FairMQMap& channels);
int Store(const FairMQChannelMap& channels);
private:
template<typename T>
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,
"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::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 std::string& channelName, int index, const std::string& member, int val);
// for cases other than int and string
template<typename T>
int UpdateChannelMap(const std::string& /*channelName*/, int /*index*/, const std::string& /*member*/, T /*val*/)
{
return 0;
}
int UpdateChannelMap(const FairMQChannelMap& map);
int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, const std::string& val);
int UpdateChannelValue(const std::string& channelName, int index, const std::string& member, int val);
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 */

View File

@@ -29,7 +29,7 @@ namespace parser
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;

View File

@@ -14,14 +14,12 @@
#ifndef FAIRMQPARSER_SUBOPT_H
#define FAIRMQPARSER_SUBOPT_H
#include "FairMQParser.h" // for FairMQMap
#include "FairMQParser.h" // for FairMQChannelMap
#include <boost/program_options.hpp>
#include <cstring>
#include <vector>
#include <string>
namespace po = boost::program_options;
namespace fair
{
namespace mq
@@ -78,7 +76,7 @@ struct SUBOPT
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 @@
/********************************************************************************
* 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 */
#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."

View File

@@ -17,211 +17,171 @@
#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
#include <boost/spirit/home/support/detail/hold_any.hpp>
#include <string>
#include <vector>
#include <iostream>
#include <ostream>
#include <iterator>
#include <typeinfo>
namespace fair
{
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
{
std::string value;
std::string type;
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>
bool typeIs(const boost::program_options::variable_value& varValue)
std::string ConvertVariableValueToString(const boost::program_options::variable_value& varVal)
{
auto& value = varValue.value();
if (auto q = boost::any_cast<T>(&value))
{
return true;
}
else
{
return false;
std::ostringstream oss;
if (auto q = boost::any_cast<T>(&varVal.value())) {
oss << *q;
}
return oss.str();
}
template<typename T>
std::string ConvertVariableValueToString(const boost::program_options::variable_value& varValue)
namespace options
{
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
struct VarInfoToString
struct ToString
{
using returned_type = std::string;
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
struct ToVarValInfo
{
using returned_type = fair::mq::VarValInfo;
using returned_type = VarValInfo;
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 fair::mq::VarValInfo{valueStr, type, defaulted, empty};
return VarValInfo{ConvertVariableValueToString<T>(varVal), type, defaulted};
}
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
template<typename 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 empty;
if (varValue.empty())
if (varVal.defaulted())
{
empty = " [empty]";
defaulted = " [default]";
}
else
{
if (varValue.defaulted())
{
defaulted = " [default]";
}
else
{
defaulted = " [provided]";
}
defaulted = " [provided]";
}
if (typeIs<std::string>(varValue))
return T::template Value<std::string>(varValue, std::string("<string>"), defaulted, empty);
if (typeid(std::string) == varVal.value().type())
return T::template Value<std::string>(varVal, std::string("<string>"), defaulted);
if (typeIs<std::vector<std::string>>(varValue))
return T::template Value<std::vector<std::string>>(varValue, std::string("<vector<string>>"), defaulted, empty);
if (typeid(std::vector<std::string>) == varVal.value().type())
return T::template Value<std::vector<std::string>>(varVal, std::string("<vector<string>>"), defaulted);
if (typeIs<int>(varValue))
return T::template Value<int>(varValue, std::string("<int>"), defaulted, empty);
if (typeid(int) == varVal.value().type())
return T::template Value<int>(varVal, std::string("<int>"), defaulted);
if (typeIs<std::vector<int>>(varValue))
return T::template Value<std::vector<int>>(varValue, std::string("<vector<int>>"), defaulted, empty);
if (typeid(std::vector<int>) == varVal.value().type())
return T::template Value<std::vector<int>>(varVal, std::string("<vector<int>>"), defaulted);
if (typeIs<float>(varValue))
return T::template Value<float>(varValue, std::string("<float>"), defaulted, empty);
if (typeid(float) == varVal.value().type())
return T::template Value<float>(varVal, std::string("<float>"), defaulted);
if (typeIs<std::vector<float>>(varValue))
return T::template Value<std::vector<float>>(varValue, std::string("<vector<float>>"), defaulted, empty);
if (typeid(std::vector<float>) == varVal.value().type())
return T::template Value<std::vector<float>>(varVal, std::string("<vector<float>>"), defaulted);
if (typeIs<double>(varValue))
return T::template Value<double>(varValue, std::string("<double>"), defaulted, empty);
if (typeid(double) == varVal.value().type())
return T::template Value<double>(varVal, std::string("<double>"), defaulted);
if (typeIs<std::vector<double>>(varValue))
return T::template Value<std::vector<double>>(varValue, std::string("<vector<double>>"), defaulted, empty);
if (typeid(std::vector<double>) == varVal.value().type())
return T::template Value<std::vector<double>>(varVal, std::string("<vector<double>>"), defaulted);
if (typeIs<short>(varValue))
return T::template Value<short>(varValue, std::string("<short>"), defaulted, empty);
if (typeid(short) == varVal.value().type())
return T::template Value<short>(varVal, std::string("<short>"), defaulted);
if (typeIs<std::vector<short>>(varValue))
return T::template Value<std::vector<short>>(varValue, std::string("<vector<short>>"), defaulted, empty);
if (typeid(std::vector<short>) == varVal.value().type())
return T::template Value<std::vector<short>>(varVal, std::string("<vector<short>>"), defaulted);
if (typeIs<long>(varValue))
return T::template Value<long>(varValue, std::string("<long>"), defaulted, empty);
if (typeid(long) == varVal.value().type())
return T::template Value<long>(varVal, std::string("<long>"), defaulted);
if (typeIs<std::vector<long>>(varValue))
return T::template Value<std::vector<long>>(varValue, std::string("<vector<long>>"), defaulted, empty);
if (typeid(std::vector<long>) == varVal.value().type())
return T::template Value<std::vector<long>>(varVal, std::string("<vector<long>>"), defaulted);
if (typeIs<std::size_t>(varValue))
return T::template Value<std::size_t>(varValue, std::string("<std::size_t>"), defaulted, empty);
if (typeid(std::size_t) == varVal.value().type())
return T::template Value<std::size_t>(varVal, std::string("<std::size_t>"), defaulted);
if (typeIs<std::vector<std::size_t>>(varValue))
return T::template Value<std::vector<std::size_t>>(varValue, std::string("<vector<std::size_t>>"), defaulted, empty);
if (typeid(std::vector<std::size_t>) == varVal.value().type())
return T::template Value<std::vector<std::size_t>>(varVal, std::string("<vector<std::size_t>>"), defaulted);
if (typeIs<std::uint32_t>(varValue))
return T::template Value<std::uint32_t>(varValue, std::string("<std::uint32_t>"), defaulted, empty);
if (typeid(std::uint32_t) == varVal.value().type())
return T::template Value<std::uint32_t>(varVal, std::string("<std::uint32_t>"), defaulted);
if (typeIs<std::vector<std::uint32_t>>(varValue))
return T::template Value<std::vector<std::uint32_t>>(varValue, std::string("<vector<std::uint32_t>>"), defaulted, empty);
if (typeid(std::vector<std::uint32_t>) == varVal.value().type())
return T::template Value<std::vector<std::uint32_t>>(varVal, std::string("<vector<std::uint32_t>>"), defaulted);
if (typeIs<std::uint64_t>(varValue))
return T::template Value<std::uint64_t>(varValue, std::string("<std::uint64_t>"), defaulted, empty);
if (typeid(std::uint64_t) == varVal.value().type())
return T::template Value<std::uint64_t>(varVal, std::string("<std::uint64_t>"), defaulted);
if (typeIs<std::vector<std::uint64_t>>(varValue))
return T::template Value<std::vector<std::uint64_t>>(varValue, std::string("<vector<std::uint64_t>>"), defaulted, empty);
if (typeid(std::vector<std::uint64_t>) == varVal.value().type())
return T::template Value<std::vector<std::uint64_t>>(varVal, std::string("<vector<std::uint64_t>>"), defaulted);
if (typeIs<bool>(varValue))
return T::template Value<bool>(varValue, std::string("<bool>"), defaulted, empty);
if (typeid(bool) == varVal.value().type())
return T::template Value<bool>(varVal, std::string("<bool>"), defaulted);
if (typeIs<std::vector<bool>>(varValue))
return T::template Value<std::vector<bool>>(varValue, std::string("<vector<bool>>"), defaulted, empty);
if (typeid(std::vector<bool>) == varVal.value().type())
return T::template Value<std::vector<bool>>(varVal, std::string("<vector<bool>>"), defaulted);
if (typeIs<boost::filesystem::path>(varValue))
return T::template Value<boost::filesystem::path>(varValue, std::string("<boost::filesystem::path>"), defaulted, empty);
if (typeid(boost::filesystem::path) == varVal.value().type())
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
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
{
// create option manager object
FairMQProgOptions config;
// add key description to cmd line 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);
// // get FairMQMap
// auto map1 = config.GetFairMQMap();
// // 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
// auto map2 = config.GetFairMQMap();
@@ -89,7 +86,6 @@ int main(int argc, char** argv)
// config.UpdateChannelMap(map2);
MyDevice device;
// device.CatchSignals();
device.SetConfig(config);
// getting as string and conversion helpers
@@ -130,45 +126,30 @@ int main(int argc, char** argv)
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) << "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) << "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) << "device: " << device.GetRate() << endl;
// device.Print();
device.Print();
LOG(info) << "nase: " << config.GetValue<double>("nase");
config.Unsubscribe<string>("test");
config.Unsubscribe<int>("test");
config.Unsubscribe<double>("test");
// advanced commands
// LOG(info) << "-------------------- start custom 1";
// 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);
device.ChangeState("END");
}
catch (exception& e)
{
LOG(error) << "Unhandled Exception reached the top of main: "
<< e.what() << ", application will now exit";
LOG(error) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit";
return 1;
}
return 0;

View File

@@ -1,11 +1,5 @@
#!/bin/bash
TRANSPORT="zeromq"
VERBOSE="DEBUG"
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
DEVICE="runConfigExample"
DEVICE+=" --id sampler1 --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$DEVICE

View File

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

View File

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

View File

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

View File

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

View File

@@ -15,8 +15,8 @@ void addCustomOptions(bpo::options_description& options)
{
options.add_options()
("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")
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
("same-msg", bpo::value<bool>()->default_value(false), "Re-send the same message, or recreate for each iteration")
("msg-size", bpo::value<int>()->default_value(1000000), "Message size in bytes")
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Number of run iterations (0 - infinite)")
("msg-rate", bpo::value<int>()->default_value(0), "Msg rate limit in maximum number of messages per second");
}

View File

@@ -72,7 +72,7 @@ SAMPLER+=" --msg-size $msgSize"
SAMPLER+=" --same-msg $sameMsg"
# SAMPLER+=" --msg-rate 1000"
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 &
echo ""
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+=" --severity debug"
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 &
echo ""
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){
r.fDevice = std::shared_ptr<FairMQDevice>{getDevice(r.fConfig)};
r.fDevice = std::unique_ptr<FairMQDevice>{getDevice(r.fConfig)};
});
return runner.Run();

View File

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

View File

@@ -14,6 +14,8 @@
#include <zmq.h>
#include <stdexcept>
using namespace std;
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);
}
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) << "Failed setting ZMQ_SUBSCRIBE socket option, reason: " << zmq_strerror(errno);
}
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(info) << "created socket " << fId;
@@ -188,7 +196,7 @@ int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
const auto numMsgs = nbytes / sizeof(MetaHeader);
if (numMsgs > 1)
{
LOG(ERROR) << "Receiving SHM multipart with a single message receive call";
LOG(error) << "Receiving SHM multipart with a single message receive call";
}
assert (numMsgs == 1);
@@ -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();
int64_t totalSize = 0;
@@ -303,13 +311,13 @@ int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
else if (zmq_errno() == ETERM)
{
zmq_msg_close (&lZmqMsg);
LOG(INFO) << "terminating socket " << fId;
LOG(info) << "terminating socket " << fId;
return -1;
}
else
{
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;
}
}
@@ -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;
@@ -343,7 +351,7 @@ int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int
msgVec.reserve(lNumMessages);
for (auto m = 0; m < lNumMessages; m++)
for (size_t m = 0; m < lNumMessages; m++)
{
MetaHeader lMetaHeader;
memcpy(&lMetaHeader, &lHdrVec[m], sizeof(MetaHeader));

View File

@@ -28,9 +28,9 @@
using namespace std;
using namespace fair::mq::shmem;
namespace bfs = boost::filesystem;
namespace bpt = boost::posix_time;
namespace bipc = boost::interprocess;
namespace bfs = ::boost::filesystem;
namespace bpt = ::boost::posix_time;
namespace bipc = ::boost::interprocess;
fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM;
@@ -69,7 +69,7 @@ FairMQTransportFactorySHM::FairMQTransportFactorySHM(const string& id, const Fai
}
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)
@@ -149,14 +149,14 @@ void FairMQTransportFactorySHM::StartMonitor()
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"))
{
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())
{
@@ -184,7 +184,7 @@ void FairMQTransportFactorySHM::StartMonitor()
}
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 fair::mq::shmem;
namespace bipc = boost::interprocess;
namespace bipc = ::boost::interprocess;
FairMQUnmanagedRegionSHM::FairMQUnmanagedRegionSHM(Manager& manager, const size_t size, FairMQRegionCallback callback)
: fManager(manager)

View File

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

View File

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

View File

@@ -12,6 +12,11 @@
#include <boost/date_time/posix_time/posix_time.hpp>
using namespace std;
namespace bipc = ::boost::interprocess;
namespace bpt = ::boost::posix_time;
namespace fair
{
namespace mq
@@ -19,11 +24,6 @@ namespace mq
namespace shmem
{
using namespace std;
namespace bipc = boost::interprocess;
namespace bpt = boost::posix_time;
Region::Region(Manager& manager, uint64_t id, uint64_t size, bool remote, FairMQRegionCallback callback)
: fManager(manager)
, fRemote(remote)
@@ -53,7 +53,7 @@ Region::Region(Manager& manager, uint64_t id, uint64_t size, bool remote, FairMQ
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, 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()

View File

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

View File

@@ -39,7 +39,7 @@ FairMQTransportFactoryZMQ::FairMQTransportFactoryZMQ(const string& id, const Fai
}
else
{
LOG(warn) << "FairMQProgOptions not available! Using defaults.";
LOG(debug) << "FairMQProgOptions not available! Using defaults.";
}
if (zmq_ctx_set(fContext, ZMQ_IO_THREADS, numIoThreads) != 0)

View File

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

View File

@@ -8,6 +8,7 @@
#include <FairMQDevice.h>
#include <cstddef>
#include <thread>
namespace fair
@@ -53,7 +54,7 @@ class PairLeft : public FairMQDevice
if (ret > 0) {
auto content = std::string{static_cast<char*>(msg6->GetData()), msg6->GetSize()};
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";

View File

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

View File

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

View File

@@ -63,7 +63,7 @@ TEST_F(PluginServices, ConfigCallbacks)
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") {
FAIL(); // should not be called because we unsubscribed
}

View File

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

View File

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

View File

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

View File

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

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