Compare commits

..

1 Commits

Author SHA1 Message Date
Alexey Rybalchenko
e642262468 Fix race condition in the control plugin 2018-09-12 16:14:32 +02:00
84 changed files with 1442 additions and 6079 deletions

View File

@@ -1,33 +0,0 @@
---
Language: Cpp
BasedOnStyle: Mozilla
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: true
AllowShortFunctionsOnASingleLine: true
AllowShortIfStatementsOnASingleLine: false
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlwaysBreakAfterReturnType: None
AlwaysBreakAfterDefinitionReturnType: None
BinPackArguments: false
BinPackParameters: false
BreakBeforeBinaryOperators: NonAssignment
BreakConstructorInitializers: BeforeComma
ColumnLimit: 100
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
FixNamespaceComments: true
IndentWidth: 4
IndentWrappedFunctionNames: true
IncludeBlocks: Regroup
NamespaceIndentation: None
PointerAlignment: Left
SortIncludes: true
SpacesBeforeTrailingComments: 3
Standard: Cpp11
UseTab: Never
...

View File

@@ -1,2 +0,0 @@
comment:
layout: "diff, files"

View File

@@ -1,30 +0,0 @@
---
name: Bug report
about: Create a report to help us improve
---
**Describe the bug**
A clear and concise description of what the bug is.
**To Reproduce**
Steps to reproduce the behavior:
1. Describe environment
2. Describe compile options used
3. Give commands you invoked
**Expected behavior**
A clear and concise description of what you expected to happen.
**Logs / Screenshots**
If applicable, add logs or screenshots to help explain your problem.
**System information (please complete the following information):**
- OS: [e.g. MacOS 10.13, Fedora 28, Ubuntu 14.04]
- Compiler: [e.g. GCC 8.1, Clang 3.5]
- Environment: [e.g. FairSoft version, alfadist revision]
**Additional context**
Add any other context about the problem here.
See [github markdown cheatsheet](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet#code) on how to format inline codes examples and logs.

View File

@@ -1,17 +0,0 @@
---
name: Feature request
about: Suggest an idea for this project
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

View File

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

2
.gitignore vendored
View File

@@ -1,5 +1,3 @@
build build
.DS_Store .DS_Store
.vscode

View File

@@ -34,19 +34,10 @@ cmake_dependent_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport." O
cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF) cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF)
cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF) cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
option(BUILD_DOCS "Build FairMQ documentation." OFF) option(BUILD_DOCS "Build FairMQ documentation." OFF)
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
################################################################################ ################################################################################
# Dependencies ################################################################# # Dependencies #################################################################
if(FAST_BUILD)
include(cotire)
endif()
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package(Threads REQUIRED)
if(BUILD_FAIRMQ) if(BUILD_FAIRMQ)
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
COMPONENTS program_options thread system filesystem regex date_time signals COMPONENTS program_options thread system filesystem regex date_time signals
@@ -56,9 +47,13 @@ if(BUILD_FAIRMQ)
endif() endif()
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
find_package2(PRIVATE nanomsg REQUIRED) find_package2(PRIVATE nanomsg VERSION 1.0.0 REQUIRED)
set(PROJECT_nanomsg_VERSION 1.1.3) # Once upstream releases 1.1.5, we should bump again and use version check find_package2(PRIVATE msgpack VERSION 3.0.0)
find_package2(PRIVATE msgpack VERSION 3.1.0 REQUIRED) 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() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
@@ -150,6 +145,11 @@ if(BUILD_DDS_PLUGIN)
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR} DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
) )
endif() endif()
if(BUILD_NANOMSG_TRANSPORT)
install(FILES cmake/Findnanomsg.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
install(FILES cmake/FindOFI.cmake install(FILES cmake/FindOFI.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR} DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
@@ -166,29 +166,6 @@ install_cmake_package()
# Summary ###################################################################### # Summary ######################################################################
if(CMAKE_CXX_FLAGS)
message(STATUS " ")
message(STATUS " ${Cyan}GLOBAL CXX FLAGS${CR} ${BGreen}${CMAKE_CXX_FLAGS}${CR}")
endif()
if(CMAKE_CONFIGURATION_TYPES)
message(STATUS " ")
message(STATUS " ${Cyan}BUILD TYPE CXX FLAGS${CR}")
string(TOUPPER "${CMAKE_BUILD_TYPE}" selected_type)
foreach(type IN LISTS CMAKE_CONFIGURATION_TYPES)
string(TOUPPER "${type}" type_upper)
if(type_upper STREQUAL selected_type)
pad("${type}" 18 " " type_padded)
message(STATUS "${BGreen}* ${type_padded}${CMAKE_CXX_FLAGS_${type_upper}}${CR}")
else()
pad("${type}" 18 " " type_padded)
message(STATUS " ${BWhite}${type_padded}${CR}${CMAKE_CXX_FLAGS_${type_upper}}")
endif()
unset(type_padded)
unset(type_upper)
endforeach()
message(STATUS " ")
message(STATUS " (Change the build type with ${BMagenta}-DCMAKE_BUILD_TYPE=...${CR})")
endif()
if(PROJECT_PACKAGE_DEPENDENCIES) if(PROJECT_PACKAGE_DEPENDENCIES)
message(STATUS " ") message(STATUS " ")
message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}") message(STATUS " ${Cyan}DEPENDENCY FOUND VERSION PREFIX${CR}")
@@ -216,13 +193,9 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
elseif(${dep} STREQUAL GTest) elseif(${dep} STREQUAL GTest)
get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE) get_filename_component(prefix ${GTEST_INCLUDE_DIRS}/.. ABSOLUTE)
elseif(${dep} STREQUAL msgpack) elseif(${dep} STREQUAL msgpack)
get_target_property(msgpack_include msgpackc-cxx INTERFACE_INCLUDE_DIRECTORIES) set(prefix ${msgpack_ROOT})
get_filename_component(prefix ${msgpack_include}/.. ABSOLUTE)
elseif(${dep} STREQUAL OFI) elseif(${dep} STREQUAL OFI)
get_filename_component(prefix ${${dep}_INCLUDE_DIRS}/.. ABSOLUTE) get_filename_component(prefix ${${dep}_INCLUDE_DIRS}/.. ABSOLUTE)
elseif(${dep} STREQUAL nanomsg)
get_target_property(nn_include nanomsg INTERFACE_INCLUDE_DIRECTORIES)
get_filename_component(prefix ${nn_include}/.. ABSOLUTE)
elseif(${dep} STREQUAL Doxygen) elseif(${dep} STREQUAL Doxygen)
get_target_property(doxygen_bin Doxygen::doxygen INTERFACE_LOCATION) get_target_property(doxygen_bin Doxygen::doxygen INTERFACE_LOCATION)
get_filename_component(prefix ${doxygen_bin} DIRECTORY) get_filename_component(prefix ${doxygen_bin} DIRECTORY)

View File

@@ -1,41 +0,0 @@
Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: FairMQ
Upstream-Contact: Mohammad Al-Turany <m.al-turany@gsi.de>
Source: https://github.com/FairRootGroup/FairMQ
Files: *
Copyright: 2012-2018, GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
Copyright: 2012-2018, [see AUTHORS file]
Copyright: 2012-2018, [see CONTRIBUTORS file]
Comment: The copyright of individual contributors is documented in the
Git history.
License: LGPL-3.0-only
Files: cmake/cotire.cmake
Copyright: 2012-2018 Sascha Kratky
License: COTIRE
License: LGPL-3.0-only
[see LICENSE file]
License: COTIRE
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

40
Dart.sh
View File

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

View File

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

40
Jenkinsfile vendored
View File

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

View File

@@ -1,4 +1,4 @@
GNU LESSER GENERAL PUBLIC LICENSE GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007 Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>

View File

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

View File

@@ -1,16 +1,12 @@
<!-- {#mainpage} --> <!-- {#mainpage} -->
# FairMQ [![license](https://alfa-ci.gsi.de/shields/badge/license-LGPL--3.0-orange.svg)](COPYRIGHT) [![build status](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) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/6b648d95d68d4c4eae833b84f84d299c)](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=FairRootGroup/FairMQ&amp;utm_campaign=Badge_Grade) # FairMQ
C++ Message Queuing Library and Framework C++ Message passing framework
| Release | Version | Docs | | Branch | Build Status |
| :---: | :--- | :--- | | :---: | :--- |
| `stable` | [![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) | | `master` | ![build status master branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/master) |
| `testing` | [![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) | | `dev` | ![build status dev branch](https://alfa-ci.gsi.de/buildStatus/icon?job=FairRootGroup/FairMQ/dev) |
Find all FairMQ releases [here](https://github.com/FairRootGroup/FairMQ/releases).
## Introduction
FairMQ is designed to help implementing large-scale data processing workflows needed in next-generation Particle Physics experiments. FairMQ is written in C++ and aims to FairMQ is designed to help implementing large-scale data processing workflows needed in next-generation Particle Physics experiments. FairMQ is written in C++ and aims to
* provide **an asynchronous message passing abstraction** of different data transport technologies, * provide **an asynchronous message passing abstraction** of different data transport technologies,
@@ -35,13 +31,30 @@ a simulation, reconstruction and analysis framework.
## Dependencies ## Dependencies
* PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger) * [**Boost**](https://www.boost.org/) (PUBLIC)
* BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/) * [**FairLogger**](https://github.com/FairRootGroup/FairLogger) (PUBLIC)
* PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/), * [CMake](https://cmake.org/) (BUILD)
[OFI](https://ofiwg.github.io/libfabric/), [Protobuf](https://developers.google.com/protocol-buffers/), [DDS](http://dds.gsi.de) * [GTest](https://github.com/google/googletest) (BUILD, optional, `tests`)
* [Doxygen](http://www.doxygen.org/) (BUILD, optional, `docs`)
* [ZeroMQ](http://zeromq.org/) (PRIVATE)
* [Msgpack](https://msgpack.org/index.html) (PRIVATE, optional, `nanomsg_transport`)
* [nanomsg](http://nanomsg.org/) (PRIVATE, optional, `nanomsg_transport`)
* [OFI](https://ofiwg.github.io/libfabric/) (PRIVATE, optional, `ofi_transport`)
* [Protobuf](https://developers.google.com/protocol-buffers/) (PRIVATE, optional, `ofi_transport`)
* [DDS](http://dds.gsi.de) (PRIVATE, optional, `dds_plugin`)
Supported platforms: Linux and MacOS. Supported platforms: Linux and MacOS.
## Releases
| Stable release | Date | API Docs |
| --- | --- | --- |
| [**1.2.3**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.3) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.3/index.html) |
| [**1.2.1**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.1) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.1/index.html) |
| [**1.2.0**](https://github.com/FairRootGroup/FairMQ/releases/tag/v1.2.0) | May 2018 | [link](https://fairrootgroup.github.io/FairMQ/v1.2.0/index.html) |
Find all FairMQ stable and development releases [here](https://github.com/FairRootGroup/FairMQ/releases).
## Installation from Source ## Installation from Source
```bash ```bash
@@ -76,7 +89,7 @@ In order to succesfully compile and link against the `FairMQ::FairMQ` target, yo
find_package(FairMQ) find_package(FairMQ)
if(FairMQ_FOUND) if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION}) find_package(FairLogger ${FairMQ_FairLogger_VERSION})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS}) find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
endif() endif()
``` ```
@@ -88,7 +101,7 @@ Optionally, you can require certain FairMQ package components and a minimum vers
find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin) find_package(FairMQ 1.1.0 COMPONENTS nanomsg_transport dds_plugin)
if(FairMQ_FOUND) if(FairMQ_FOUND)
find_package(FairLogger ${FairMQ_FairLogger_VERSION}) find_package(FairLogger ${FairMQ_FairLogger_VERSION})
find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_Boost_COMPONENTS}) find_package(Boost ${FairMQ_Boost_VERSION} COMPONENTS ${FairMQ_BOOST_COMPONENTS})
endif() endif()
``` ```
@@ -156,3 +169,9 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
4. [File output](docs/Logging.md#54-file-output) 4. [File output](docs/Logging.md#54-file-output)
5. [Custom sinks](docs/Logging.md#55-custom-sinks) 5. [Custom sinks](docs/Logging.md#55-custom-sinks)
6. [Examples](docs/Examples.md#6-examples) 6. [Examples](docs/Examples.md#6-examples)
## License
GNU Lesser General Public Licence (LGPL) version 3, see [LICENSE](LICENSE).
Copyright (C) 2013-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH

View File

@@ -23,7 +23,6 @@ set_and_check(@PROJECT_NAME@_CMAKEMODDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT
set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@) set(@PROJECT_NAME@_CXX_STANDARD_REQUIRED @CMAKE_CXX_STANDARD_REQUIRED@)
set(@PROJECT_NAME@_CXX_STANDARD @CMAKE_CXX_STANDARD@) set(@PROJECT_NAME@_CXX_STANDARD @CMAKE_CXX_STANDARD@)
set(@PROJECT_NAME@_CXX_EXTENSIONS @CMAKE_CXX_EXTENSIONS@) set(@PROJECT_NAME@_CXX_EXTENSIONS @CMAKE_CXX_EXTENSIONS@)
set(@PROJECT_NAME@_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@)
### Import cmake modules ### Import cmake modules
set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKEMODDIR} ${CMAKE_MODULE_PATH}) set(CMAKE_MODULE_PATH ${@PROJECT_NAME@_CMAKEMODDIR} ${CMAKE_MODULE_PATH})

View File

@@ -112,6 +112,7 @@ macro(set_fairmq_defaults)
set(CMAKE_BUILD_TYPE RelWithDebInfo) set(CMAKE_BUILD_TYPE RelWithDebInfo)
endif() endif()
# Handle C++ standard level # Handle C++ standard level
set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(NOT CMAKE_CXX_STANDARD) if(NOT CMAKE_CXX_STANDARD)
@@ -123,14 +124,8 @@ macro(set_fairmq_defaults)
endif() endif()
set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_CXX_EXTENSIONS OFF)
if(NOT BUILD_SHARED_LIBS)
set(BUILD_SHARED_LIBS ON CACHE BOOL "Whether to build shared libraries or static archives")
endif()
# Set -fPIC as default for all library types # Set -fPIC as default for all library types
if(NOT CMAKE_POSITION_INDEPENDENT_CODE) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Generate compile_commands.json file (https://clang.llvm.org/docs/JSONCompilationDatabase.html) # Generate compile_commands.json file (https://clang.llvm.org/docs/JSONCompilationDatabase.html)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
@@ -163,29 +158,9 @@ macro(set_fairmq_defaults)
# Define export set, only one for now # Define export set, only one for now
set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets) set(PROJECT_EXPORT_SET ${PROJECT_NAME}Targets)
# Configure build types # Override CMake defaults
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo" "Nightly" "Profile" "AdressSan" "ThreadSan") set(CMAKE_CXX_FLAGS_NIGHTLY "-O2 -g -Wshadow -Wall -Wextra")
set(CMAKE_CXX_FLAGS_DEBUG "-g -Wshadow -Wall -Wextra") set(CMAKE_CXX_FLAGS_PROFILE "-g3 -fno-inline -ftest-coverage -fprofile-arcs -Wshadow -Wall -Wextra -Wunused-variable")
set(CMAKE_CXX_FLAGS_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()
if(NOT PROJECT_VERSION_TWEAK)
set(PROJECT_VERSION_HOTFIX 0)
else()
set(PROJECT_VERSION_HOTFIX ${PROJECT_VERSION_TWEAK})
endif()
endmacro() endmacro()
function(join VALUES GLUE OUTPUT) function(join VALUES GLUE OUTPUT)
@@ -262,7 +237,7 @@ endfunction()
macro(install_cmake_package) macro(install_cmake_package)
include(CMakePackageConfigHelpers) include(CMakePackageConfigHelpers)
set(PACKAGE_INSTALL_DESTINATION set(PACKAGE_INSTALL_DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_GIT_VERSION} ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}
) )
if(BUILD_FAIRMQ) if(BUILD_FAIRMQ)
install(EXPORT ${PROJECT_EXPORT_SET} install(EXPORT ${PROJECT_EXPORT_SET}

View File

@@ -89,7 +89,7 @@ endif()
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(ZeroMQ find_package_handle_standard_args(ZeroMQ
REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR REQUIRED_VARS ZeroMQ_LIBRARY_SHARED ZeroMQ_INCLUDE_DIR ZeroMQ_LIBRARY_STATIC
VERSION_VAR ZeroMQ_VERSION VERSION_VAR ZeroMQ_VERSION
) )

34
cmake/Findnanomsg.cmake Normal file
View File

@@ -0,0 +1,34 @@
################################################################################
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
find_path(nanomsg_INCLUDE_DIR
NAMES nanomsg/nn.h
HINTS ${NANOMSG_ROOT} $ENV{NANOMSG_ROOT}
PATH_SUFFIXES include
DOC "Path to nanomsg include header files."
)
find_library(nanomsg_LIBRARY_SHARED
NAMES libnanomsg.dylib libnanomsg.so
HINTS ${NANOMSG_ROOT} $ENV{NANOMSG_ROOT}
PATH_SUFFIXES lib
DOC "Path to libnanomsg.dylib libnanomsg.so."
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(nanomsg
REQUIRED_VARS nanomsg_LIBRARY_SHARED nanomsg_INCLUDE_DIR
)
if(NOT TARGET nanomsg AND nanomsg_FOUND)
add_library(nanomsg SHARED IMPORTED)
set_target_properties(nanomsg PROPERTIES
IMPORTED_LOCATION ${nanomsg_LIBRARY_SHARED}
INTERFACE_INCLUDE_DIRECTORIES ${nanomsg_INCLUDE_DIR}
)
endif()

View File

@@ -51,7 +51,7 @@ function(add_testsuite suitename)
cmake_parse_arguments(testsuite cmake_parse_arguments(testsuite
"" ""
"TIMEOUT;RUN_SERIAL" "TIMEOUT;RUN_SERIAL"
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS" "SOURCES;LINKS;DEPENDS;INCLUDES"
${ARGN} ${ARGN}
) )
@@ -69,9 +69,6 @@ function(add_testsuite suitename)
if(testsuite_INCLUDES) if(testsuite_INCLUDES)
target_include_directories(${target} PUBLIC ${testsuite_INCLUDES}) target_include_directories(${target} PUBLIC ${testsuite_INCLUDES})
endif() endif()
if(testsuite_DEFINITIONS)
target_compile_definitions("${target}" PUBLIC ${testsuite_DEFINITIONS})
endif()
add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target}) add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
if(testsuite_TIMEOUT) if(testsuite_TIMEOUT)
@@ -89,7 +86,7 @@ function(add_testhelper helpername)
cmake_parse_arguments(testhelper cmake_parse_arguments(testhelper
"" ""
"" ""
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS" "SOURCES;LINKS;DEPENDS;INCLUDES"
${ARGN} ${ARGN}
) )
@@ -105,9 +102,6 @@ function(add_testhelper helpername)
if(testhelper_INCLUDES) if(testhelper_INCLUDES)
target_include_directories(${target} PUBLIC ${testhelper_INCLUDES}) target_include_directories(${target} PUBLIC ${testhelper_INCLUDES})
endif() endif()
if(testhelper_DEFINITIONS)
target_compile_definitions(${target} PUBLIC ${testhelper_DEFINITIONS})
endif()
list(APPEND ALL_TEST_TARGETS ${target}) list(APPEND ALL_TEST_TARGETS ${target})
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE) set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
@@ -117,7 +111,7 @@ function(add_testlib libname)
cmake_parse_arguments(testlib cmake_parse_arguments(testlib
"HIDDEN" "HIDDEN"
"VERSION" "VERSION"
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS" "SOURCES;LINKS;DEPENDS;INCLUDES"
${ARGN} ${ARGN}
) )
@@ -139,9 +133,6 @@ function(add_testlib libname)
if(testlib_VERSION) if(testlib_VERSION)
set_target_properties(${target} PROPERTIES VERSION ${testlib_VERSION}) set_target_properties(${target} PROPERTIES VERSION ${testlib_VERSION})
endif() endif()
if(testlib_DEFINITIONS)
target_compile_definitions(${target} PUBLIC ${testlib_DEFINITIONS})
endif()
list(APPEND ALL_TEST_TARGETS ${target}) list(APPEND ALL_TEST_TARGETS ${target})
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE) set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)

File diff suppressed because it is too large Load Diff

View File

@@ -1,10 +1,16 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
/**
* Sampler.cpp
*
* @since 2014-10-10
* @author A. Rybalchenko
*/
#include <thread> // this_thread::sleep_for #include <thread> // this_thread::sleep_for
#include <chrono> #include <chrono>
@@ -58,6 +64,8 @@ bool Sampler::ConditionalRun()
return false; return false;
} }
this_thread::sleep_for(chrono::seconds(1));
return true; return true;
} }

View File

@@ -4,7 +4,6 @@ export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
SAMPLER="fairmq-ex-1-1-sampler" SAMPLER="fairmq-ex-1-1-sampler"
SAMPLER+=" --id sampler1" SAMPLER+=" --id sampler1"
SAMPLER+=" --rate 1"
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0" SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER & xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &

View File

@@ -13,7 +13,6 @@ trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SI
SAMPLER="fairmq-ex-1-1-sampler" SAMPLER="fairmq-ex-1-1-sampler"
SAMPLER+=" --id sampler1" SAMPLER+=" --id sampler1"
SAMPLER+=" --rate 1"
SAMPLER+=" --transport $transport" SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh" SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --control static --color false" SAMPLER+=" --control static --color false"

View File

@@ -1,17 +1,23 @@
DDS Example DDS Example
=========== ===========
This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to the one in Example 1-n-1, but now it can be easily distributed on different computing nodes without the need for manual addresses reconfiguration of the devices. This example demonstrates usage of the Dynamic Deployment System ([DDS](http://dds.gsi.de/)) to dynamically deploy and configure a topology of devices. The topology is similar to those of Example 2, but now it can be easily distributed on different computing nodes without the need for manual socket reconfiguration of the devices.
To make use of DDS functionality the example executables need to find the DDS plugin libraries that are compiled with FairRoot when FairRoot find DDS installed. Custom DDS location can be given to CMake as follows:
```bash
cmake -DDDS_ROOT="/path/to/dds/install/dir/" ..
```
The description below outlines the minimal steps needed to run the example with DDS. For general DDS help please refer to DDS documentation on [DDS Website](http://dds.gsi.de/). The description below outlines the minimal steps needed to run the example with DDS. For general DDS help please refer to DDS documentation on [DDS Website](http://dds.gsi.de/).
##### 1. The device handles the channel addresses and ports configuration via DDS Plugin. ##### 1. The device handles the socket addresses and ports configuration via DDS Plugin.
It is sufficient to provide the `-S "<@FAIRMQ_INSTALL_DIR@/lib" -P dds` (`<` prepends the following path to the default plugin search paths; put in the path which points to the library dir of your FairRoot installation) command line arguments to let the devices be configured dynamically. No code changes in the device are necessary. See the XML topology file for example of using the command line arguments. It is sufficient to provide the `-S "<@FAIRROOT_INSTALL_DIR@/lib" -P dds` (`<` prepends the following path to the default plugin search paths; put in the path which points to the library dir of your FairRoot installation) command line arguments to let the devices be configured dynamically. No code changes in the device are necessary. See the XML topology file for example of using the command line arguments.
##### 2a. Write DDS hosts file that contains a list of worker nodes to run the topology on (When deploying using the SSH plug-in). ##### 2a. Write DDS hosts file that contains a list of worker nodes to run the topology on (When deploying using the SSH plug-in).
We run this example on the local machine for simplicity. The file below defines 3 workers - sampler, processor and sink - with a total of 12 DDS agents (thus able to accept 12 tasks). The parameters for each worker node are: We run this example on the local machine for simplicity. The file below defines three workers, sampler, processor and sink, with a total of 12 DDS agents (thus able to accept 12 tasks). The parameters for each worker node are:
- user-chosen worker ID (must be unique) - user-chosen worker ID (must be unique)
- a host name with or without a login, in a form: login@host.fqdn (password-less SSH access to these hosts must be possible) - a host name with or without a login, in a form: login@host.fqdn (password-less SSH access to these hosts must be possible)
- additional SSH params (can be empty) - additional SSH params (can be empty)
@@ -34,27 +40,23 @@ If you want to deploy on a single host DDS 1.6+ provides a localhost rms plug-in
##### 3. Write DDS topology file that describes which tasks (processes) to run and their topology and configuration. ##### 3. Write DDS topology file that describes which tasks (processes) to run and their topology and configuration.
Take a look at `ex-dds-topology.xml`. It consists of a definition part (properties, tasks, collections and more) and execution part (main). In our example Sampler, Processor and Sink tasks are defined, containing their executables and exchanged properties. The `<main>` of the topology uses the defined tasks. Besides one Sampler and one Sink task, a group containing Processor task is defined. The group has a multiplicity of 10, meaninig 10 Processors will be executed. Each of the Processors will receive the properties with Sampler and Sink addresses. Take a look at `ex-dds-topology.xml`. It consists of a definition part (properties, tasks, collections and more) and execution part (main). In our example Sampler, Processor and Sink tasks are defines, containing their executables and exchanged properties. The `<main>` of the topology uses the defined tasks. Besides one Sampler and one Sink task, a group containing Processor task is defined. The group has a multiplicity of 10, meaninig 10 Processors will be executed. Each of the Processors will receive the properties with Sampler and Sink addresses.
The configuration of the channel connection addresses is done by the DDS plugin via the channel names. The task property names must correspond to the channel names (data1, data2), with binding channels writing the properties and connecting channel reading the properties. The configuration of the channel connection addresses is done by the DDS plugin via the channel names. The task property names must correspond to the channel names (data1, data2), with binding channels writing the properties and connecting channel reading the properties (see the example XML and JSON files).
**If you chose step 2b earlier**, then modify the provided `ex-dds-topology.xml` in the top that the following lines read as following: If `eth0` network interface (default for binding) is not available on your system, specify another one in the topology file for each task. For example: `--network-interface lo0`.
If you chose step 2b earlier, then modify the provided `ex-dds-topology.xml` in the top that the following lines read as following:
```xml ```xml
<declrequirement id="SamplerWorker" type="wnname" value=".*"/> <declrequirement id="SamplerWorker" type="wnname" value=".*"/>
<declrequirement id="ProcessorWorker" type="wnname" value=".*"/> <declrequirement id="ProcessorWorker" type="wnname" value=".*"/>
<declrequirement id="SinkWorker" type="wnname" value=".*"/> <declrequirement id="SinkWorker" type="wnname" value=".*"/>
``` ```
Note that the attributes `value` contain a different value. Note that the attributes `value` contain a different value.
##### 4. Start DDS server. ##### 4. Start DDS server.
First you need to initialize DDS environment:
```bash
source DDS_env.sh # this script is located in the DDS installation directory
```
The DDS server is started with: The DDS server is started with:
```bash ```bash
@@ -69,7 +71,7 @@ dds-submit --rms ssh --config ex-dds-hosts.cfg
``` ```
The `--rms` option defines a destination resource management system. The `--config` specifies an SSH plug-in resource definition file. The `--rms` option defines a destination resource management system. The `--config` specifies an SSH plug-in resource definition file.
**If you chose step 2b earlier**, run the following command instead: If you chose step 2b earlier, run the following command instead:
```bash ```bash
dds-submit --rms localhost -n 12 dds-submit --rms localhost -n 12
@@ -83,30 +85,13 @@ dds-topology --activate ex-dds-topology.xml
##### 7. Run ##### 7. Run
After activation, agents will execute the defined tasks on the worker nodes. Output of the tasks will be stored in the directory that was specified in the hosts file (or in the system temporary directory when using the localhost plugin). After activation, agents will execute the defined tasks on the worker nodes. Output of the tasks will be stored in the directory that was specified in the hosts file.
##### 8. (optional) Use example command UI to check state of the devices ##### 8. (optional) Use example command UI to check state of the devices
A simple utility (fairmq-dds-command-ui) is included with FairMQ to send commands to devices and receive replies from them. The utility uses the DDS intercom library to query state/config of devices and allows changing their state. To let the device listen to the commands from the utility, start the device with `-S "<@FAIRMQ_INSTALL_DIR@/lib" -P dds` cmd option (see example XML topology). A simple utility (fairmq-dds-command-ui) is included with FairRoot to send commands to devices and receive replies from them. The utility uses the DDS intercom library to send "check-state" string to all devices, to which they reply with their ID and state they are in. The utility also allows requesting state changes from devices. To let the device listen to the commands from the utility, start the device with `-S "<@FAIRROOT_INSTALL_DIR@/lib" -P dds` cmd option (see example XML topology).
To see it in action, start the fairmq-dds-command-ui while the topology is running. Run the utility with `-h` to see everything that it can do. To see it in action, start the fairmq-dds-command-ui while the topology is running.
The utility requires a session parameter to connect to appropriate DDS session. The session value is given when starting dds-server.
By default the command UI sends commands to all tasks. This can be further refined by giving a specific topology path via `-p` argument.
Given our topology file, here are some examples of valid paths:
```bash
# get state of all devices
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c
# get state of sampler
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/Sampler
# get state of sink
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/Sink
# get state all processors
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/ProcessorGroup/Processor
# get state of a specific processor
./fairmq/plugins/DDS/fairmq-dds-command-ui -s 937ffbca-b524-44d8-9898-1d69aedc3751 -c c -p main/ProcessorGroup/Processor_9
```
##### 9. Stop DDS server/topology. ##### 9. Stop DDS server/topology.

54
fairmq/.clang-format Normal file
View File

@@ -0,0 +1,54 @@
---
Language: Cpp
#AccessModifierOffset: -4
ConstructorInitializerIndentWidth: 4
AlignEscapedNewlinesLeft: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortIfStatementsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
AlwaysBreakTemplateDeclarations: true
# It is broken on windows. Breaks all #include "header.h"
#AlwaysBreakBeforeMultilineStrings: true
BreakBeforeBinaryOperators: false
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: true
BinPackParameters: false
ColumnLimit: 160
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
DerivePointerBinding: false
ExperimentalAutoDetectBinPacking: false
IndentCaseLabels: true
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: false
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakString: 1000
PenaltyBreakFirstLessLess: 120
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerBindsToType: true
SpacesBeforeTrailingComments: 1
Cpp11BracedListStyle: false
Standard: Cpp11
IndentWidth: 4
TabWidth: 4
UseTab: Never
BreakBeforeBraces: Allman
IndentFunctionDeclarationAfterType: true
SpacesInParentheses: false
SpacesInAngles: false
SpaceInEmptyParentheses: false
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: true
SpaceBeforeAssignmentOperators: true
ContinuationIndentWidth: 4
CommentPragmas: '^ IWYU pragma:'
SpaceBeforeParens: ControlStatements
...

View File

@@ -38,144 +38,145 @@ endif()
# libFairMQ header files # # libFairMQ header files #
########################## ##########################
set(FAIRMQ_PUBLIC_HEADER_FILES set(FAIRMQ_PUBLIC_HEADER_FILES
DeviceRunner.h DeviceRunner.h
EventManager.h EventManager.h
FairMQChannel.h FairMQChannel.h
FairMQDevice.h FairMQDevice.h
FairMQLogger.h FairMQLogger.h
FairMQMessage.h FairMQMessage.h
FairMQParts.h FairMQParts.h
FairMQPoller.h FairMQPoller.h
FairMQUnmanagedRegion.h FairMQUnmanagedRegion.h
FairMQSocket.h FairMQSocket.h
FairMQStateMachine.h FairMQStateMachine.h
FairMQTransportFactory.h FairMQTransportFactory.h
Tools.h Tools.h
Transports.h Transports.h
options/FairMQProgOptions.h options/FairMQProgOptions.h
options/FairProgOptions.h options/FairProgOptions.h
Plugin.h Plugin.h
PluginManager.h PluginManager.h
PluginServices.h PluginServices.h
runFairMQDevice.h runFairMQDevice.h
tools/CppSTL.h tools/CppSTL.h
tools/Network.h tools/Network.h
tools/Process.h tools/Process.h
tools/RateLimit.h tools/Strings.h
tools/Strings.h tools/Unique.h
tools/Unique.h tools/Version.h
tools/Version.h
) )
set(FAIRMQ_PRIVATE_HEADER_FILES set(FAIRMQ_PRIVATE_HEADER_FILES
devices/FairMQBenchmarkSampler.h devices/FairMQBenchmarkSampler.h
devices/FairMQMerger.h devices/FairMQMerger.h
devices/FairMQMultiplier.h devices/FairMQMultiplier.h
devices/FairMQProxy.h devices/FairMQProxy.h
devices/FairMQSink.h devices/FairMQSink.h
devices/FairMQSplitter.h devices/FairMQSplitter.h
options/FairMQParser.h options/FairMQParser.h
options/FairMQSuboptParser.h options/FairMQSuboptParser.h
options/FairProgOptionsHelper.h options/FairProgOptionsHelper.h
plugins/Builtin.h plugins/Builtin.h
plugins/Control.h plugins/Control.h
StateMachine.h StateMachine.h
shmem/FairMQMessageSHM.h shmem/FairMQMessageSHM.h
shmem/FairMQPollerSHM.h shmem/FairMQPollerSHM.h
shmem/FairMQUnmanagedRegionSHM.h shmem/FairMQUnmanagedRegionSHM.h
shmem/FairMQSocketSHM.h shmem/FairMQSocketSHM.h
shmem/FairMQTransportFactorySHM.h shmem/FairMQTransportFactorySHM.h
shmem/Common.h shmem/Common.h
shmem/Manager.h shmem/Manager.h
shmem/Region.h shmem/Monitor.h
zeromq/FairMQMessageZMQ.h shmem/Region.h
zeromq/FairMQPollerZMQ.h zeromq/FairMQMessageZMQ.h
zeromq/FairMQUnmanagedRegionZMQ.h zeromq/FairMQPollerZMQ.h
zeromq/FairMQSocketZMQ.h zeromq/FairMQUnmanagedRegionZMQ.h
zeromq/FairMQTransportFactoryZMQ.h zeromq/FairMQSocketZMQ.h
zeromq/FairMQTransportFactoryZMQ.h
) )
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES} set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
nanomsg/FairMQMessageNN.h nanomsg/FairMQMessageNN.h
nanomsg/FairMQPollerNN.h nanomsg/FairMQPollerNN.h
nanomsg/FairMQUnmanagedRegionNN.h nanomsg/FairMQUnmanagedRegionNN.h
nanomsg/FairMQSocketNN.h nanomsg/FairMQSocketNN.h
nanomsg/FairMQTransportFactoryNN.h nanomsg/FairMQTransportFactoryNN.h
) )
endif() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES} set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
ofi/Context.h ofi/Context.h
ofi/Message.h ofi/Message.h
ofi/Poller.h ofi/Poller.h
ofi/Socket.h ofi/Socket.h
ofi/TransportFactory.h ofi/TransportFactory.h
) )
endif() endif()
########################## ##########################
# libFairMQ source files # # libFairMQ source files #
########################## ##########################
set(FAIRMQ_SOURCE_FILES set(FAIRMQ_SOURCE_FILES
DeviceRunner.cxx DeviceRunner.cxx
FairMQChannel.cxx FairMQChannel.cxx
FairMQDevice.cxx FairMQDevice.cxx
FairMQLogger.cxx FairMQLogger.cxx
FairMQMessage.cxx FairMQMessage.cxx
FairMQPoller.cxx FairMQPoller.cxx
FairMQSocket.cxx FairMQSocket.cxx
FairMQStateMachine.cxx FairMQStateMachine.cxx
FairMQTransportFactory.cxx FairMQTransportFactory.cxx
devices/FairMQBenchmarkSampler.cxx devices/FairMQBenchmarkSampler.cxx
devices/FairMQMerger.cxx devices/FairMQMerger.cxx
devices/FairMQMultiplier.cxx devices/FairMQMultiplier.cxx
devices/FairMQProxy.cxx devices/FairMQProxy.cxx
devices/FairMQSplitter.cxx devices/FairMQSplitter.cxx
options/FairMQParser.cxx options/FairMQParser.cxx
options/FairMQProgOptions.cxx options/FairMQProgOptions.cxx
options/FairMQSuboptParser.cxx options/FairMQSuboptParser.cxx
Plugin.cxx Plugin.cxx
PluginManager.cxx PluginManager.cxx
PluginServices.cxx PluginServices.cxx
plugins/Control.cxx plugins/Control.cxx
StateMachine.cxx StateMachine.cxx
shmem/FairMQMessageSHM.cxx shmem/FairMQMessageSHM.cxx
shmem/FairMQPollerSHM.cxx shmem/FairMQPollerSHM.cxx
shmem/FairMQUnmanagedRegionSHM.cxx shmem/FairMQUnmanagedRegionSHM.cxx
shmem/FairMQSocketSHM.cxx shmem/FairMQSocketSHM.cxx
shmem/FairMQTransportFactorySHM.cxx shmem/FairMQTransportFactorySHM.cxx
shmem/Manager.cxx shmem/Manager.cxx
shmem/Region.cxx shmem/Monitor.cxx
tools/Network.cxx shmem/Region.cxx
tools/Process.cxx tools/Network.cxx
tools/Unique.cxx tools/Process.cxx
zeromq/FairMQMessageZMQ.cxx tools/Unique.cxx
zeromq/FairMQPollerZMQ.cxx zeromq/FairMQMessageZMQ.cxx
zeromq/FairMQUnmanagedRegionZMQ.cxx zeromq/FairMQPollerZMQ.cxx
zeromq/FairMQSocketZMQ.cxx zeromq/FairMQUnmanagedRegionZMQ.cxx
zeromq/FairMQTransportFactoryZMQ.cxx zeromq/FairMQSocketZMQ.cxx
zeromq/FairMQTransportFactoryZMQ.cxx
) )
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES} set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
nanomsg/FairMQMessageNN.cxx nanomsg/FairMQMessageNN.cxx
nanomsg/FairMQPollerNN.cxx nanomsg/FairMQPollerNN.cxx
nanomsg/FairMQUnmanagedRegionNN.cxx nanomsg/FairMQUnmanagedRegionNN.cxx
nanomsg/FairMQSocketNN.cxx nanomsg/FairMQSocketNN.cxx
nanomsg/FairMQTransportFactoryNN.cxx nanomsg/FairMQTransportFactoryNN.cxx
) )
endif() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES} set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
ofi/Context.cxx ofi/Context.cxx
ofi/Message.cxx ofi/Message.cxx
ofi/Poller.cxx ofi/Poller.cxx
ofi/Socket.cxx ofi/Socket.cxx
ofi/TransportFactory.cxx ofi/TransportFactory.cxx
) )
endif() endif()
@@ -190,93 +191,62 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/options/startConfigExample.sh.in ${CM
################################# #################################
# define libFairMQ build target # # define libFairMQ build target #
################################# #################################
if(FAST_BUILD) add_library(FairMQ SHARED
set(_target FairMQ_)
else()
set(_target FairMQ)
endif()
add_library(${_target}
${FAIRMQ_SOURCE_FILES} ${FAIRMQ_SOURCE_FILES}
${FAIRMQ_PUBLIC_HEADER_FILES} # for IDE integration ${FAIRMQ_PUBLIC_HEADER_FILES} # for IDE integration
${FAIRMQ_PRIVATE_HEADER_FILES} # for IDE integration ${FAIRMQ_PRIVATE_HEADER_FILES} # for IDE integration
) )
set_target_properties(${_target} PROPERTIES LABELS coverage)
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES OUTPUT_NAME FairMQ)
endif()
####################### #######################
# include directories # # include directories #
####################### #######################
target_include_directories(${_target} target_include_directories(FairMQ
PUBLIC # consumers inherit public include directories PUBLIC # consumers inherit public include directories
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}> $<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<BUILD_INTERFACE:${CMAKE_BINARY_DIR}> $<BUILD_INTERFACE:${CMAKE_BINARY_DIR}>
$<INSTALL_INTERFACE:include/fairmq> $<INSTALL_INTERFACE:include/fairmq>
$<INSTALL_INTERFACE:include> $<INSTALL_INTERFACE:include>
) )
################## ##################
# link libraries # # link libraries #
################## ##################
if(BUILD_NANOMSG_TRANSPORT) if(BUILD_NANOMSG_TRANSPORT)
set(NANOMSG_DEPS nanomsg msgpackc-cxx) set(NANOMSG_DEPS nanomsg msgpackc)
endif() endif()
if(BUILD_OFI_TRANSPORT) if(BUILD_OFI_TRANSPORT)
set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>) set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>)
endif() endif()
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS}) target_link_libraries(FairMQ
if(optional_deps) INTERFACE # only consumers link against interface dependencies
list(REMOVE_DUPLICATES optional_deps)
endif()
target_link_libraries(${_target} PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
INTERFACE # only consumers link against interface dependencies dl
Boost::boost
Boost::program_options
Boost::thread
Boost::system
Boost::filesystem
Boost::regex
Boost::date_time
Boost::signals
FairLogger::FairLogger
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies PRIVATE # only libFairMQ links against private dependencies
Threads::Threads libzmq
dl ${NANOMSG_DEPS}
$<$<PLATFORM_ID:Linux>:rt> ${OFI_DEPS}
Boost::boost
Boost::program_options
Boost::thread
Boost::system
Boost::filesystem
Boost::regex
Boost::date_time
Boost::signals
FairLogger::FairLogger
PRIVATE # only libFairMQ links against private dependencies
libzmq
${NANOMSG_DEPS}
${OFI_DEPS}
) )
set_target_properties(${_target} PROPERTIES set_target_properties(FairMQ PROPERTIES
VERSION ${PROJECT_GIT_VERSION} VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
) )
##############
# fast build #
##############
if(FAST_BUILD)
set_target_properties(${_target} PROPERTIES
COTIRE_UNITY_TARGET_NAME "FairMQ"
# COTIRE_ENABLE_PRECOMPILED_HEADER FALSE
EXCLUDE_FROM_ALL TRUE
)
cotire(${_target})
set_target_properties(FairMQ PROPERTIES EXCLUDE_FROM_ALL FALSE)
set_target_properties(FairMQ PROPERTIES LABELS coverage)
endif()
############### ###############
# executables # # executables #
############### ###############
add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx) add_executable(fairmq-bsampler run/runBenchmarkSampler.cxx)
target_link_libraries(fairmq-bsampler FairMQ) target_link_libraries(fairmq-bsampler FairMQ)
@@ -298,48 +268,37 @@ target_link_libraries(fairmq-splitter FairMQ)
add_executable(runConfigExample options/runConfigEx.cxx) add_executable(runConfigExample options/runConfigEx.cxx)
target_link_libraries(runConfigExample FairMQ) target_link_libraries(runConfigExample FairMQ)
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx) add_executable(fairmq-shmmonitor shmem/runMonitor.cxx)
target_link_libraries(fairmq-shmmonitor PUBLIC target_link_libraries(fairmq-shmmonitor FairMQ)
Threads::Threads
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::date_time
Boost::program_options
)
target_include_directories(fairmq-shmmonitor PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
)
add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx) add_executable(fairmq-uuid-gen run/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen FairMQ) target_link_libraries(fairmq-uuid-gen FairMQ)
########### ###########
# install # # install #
########### ###########
install( install(
TARGETS TARGETS # FairMQFull, tests are not installed
FairMQ FairMQ
fairmq-bsampler fairmq-bsampler
fairmq-merger fairmq-merger
fairmq-multiplier fairmq-multiplier
fairmq-proxy fairmq-proxy
fairmq-sink fairmq-sink
fairmq-splitter fairmq-splitter
fairmq-shmmonitor fairmq-shmmonitor
fairmq-uuid-gen fairmq-uuid-gen
EXPORT ${PROJECT_EXPORT_SET} EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR} LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR} RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
) )
# preserve relative path and prepend fairmq # preserve relative path and prepend fairmq
foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES}) foreach(HEADER ${FAIRMQ_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY) get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination) file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER} install(FILES ${HEADER}
DESTINATION ${_destination} DESTINATION ${_destination}
) )
endforeach() endforeach()

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -7,21 +7,17 @@
********************************************************************************/ ********************************************************************************/
#include "DeviceRunner.h" #include "DeviceRunner.h"
#include <exception>
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
#include <fairmq/Version.h> #include <exception>
using namespace fair::mq; using namespace fair::mq;
DeviceRunner::DeviceRunner(int argc, char* const argv[], bool printLogo) DeviceRunner::DeviceRunner(int argc, char* const argv[])
: fRawCmdLineArgs(tools::ToStrVector(argc, argv, false)) : fRawCmdLineArgs{tools::ToStrVector(argc, argv, false)}
, fConfig() , fPluginManager{PluginManager::MakeFromCommandLineOptions(fRawCmdLineArgs)}
, fDevice(nullptr) , fDevice{nullptr}
, fPluginManager(fRawCmdLineArgs) {
, fPrintLogo(printLogo) }
, fEvents()
{}
auto DeviceRunner::Run() -> int auto DeviceRunner::Run() -> int
{ {
@@ -30,40 +26,32 @@ auto DeviceRunner::Run() -> int
//////////////////////// ////////////////////////
// Load builtin plugins last // Load builtin plugins last
fPluginManager.LoadPlugin("s:control"); fPluginManager->LoadPlugin("s:control");
////// CALL HOOK /////// ////// CALL HOOK ///////
fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this); fEvents.Emit<hooks::SetCustomCmdLineOptions>(*this);
//////////////////////// ////////////////////////
fPluginManager.ForEachPluginProgOptions( fPluginManager->ForEachPluginProgOptions([&](boost::program_options::options_description options){
[&](boost::program_options::options_description options) { fConfig.AddToCmdLineOptions(options);
fConfig.AddToCmdLineOptions(options); });
}); fConfig.AddToCmdLineOptions(fPluginManager->ProgramOptions());
fConfig.AddToCmdLineOptions(fPluginManager.ProgramOptions());
////// CALL HOOK /////// ////// CALL HOOK ///////
fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this); fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this);
//////////////////////// ////////////////////////
if (fConfig.ParseAll(fRawCmdLineArgs, true)) { if (fConfig.ParseAll(fRawCmdLineArgs, true))
{
return 0; return 0;
} }
if (fPrintLogo) {
LOG(info) << std::endl
<< " ______ _ _______ _________ " << std::endl
<< " / ____/___ _(_)_______ |/ /_ __ \\ version " << FAIRMQ_GIT_VERSION << std::endl
<< " / /_ / __ `/ / ___/__ /|_/ /_ / / / build " << FAIRMQ_BUILD_TYPE << std::endl
<< " / __/ / /_/ / / / _ / / / / /_/ / " << FAIRMQ_REPO_URL << std::endl
<< " /_/ \\__,_/_/_/ /_/ /_/ \\___\\_\\ " << FAIRMQ_LICENSE << " © " << FAIRMQ_COPYRIGHT << std::endl;
}
////// CALL HOOK /////// ////// CALL HOOK ///////
fEvents.Emit<hooks::InstantiateDevice>(*this); fEvents.Emit<hooks::InstantiateDevice>(*this);
//////////////////////// ////////////////////////
if (!fDevice) { if (!fDevice)
{
LOG(error) << "getDevice(): no valid device provided. Exiting."; LOG(error) << "getDevice(): no valid device provided. Exiting.";
return 1; return 1;
} }
@@ -72,14 +60,16 @@ auto DeviceRunner::Run() -> int
// Handle --print-channels // Handle --print-channels
fDevice->RegisterChannelEndpoints(); fDevice->RegisterChannelEndpoints();
if (fConfig.Count("print-channels")) { if (fConfig.Count("print-channels"))
{
fDevice->PrintRegisteredChannels(); fDevice->PrintRegisteredChannels();
fDevice->ChangeState(FairMQDevice::END); fDevice->ChangeState(FairMQDevice::END);
return 0; return 0;
} }
// Handle --version // Handle --version
if (fConfig.Count("version")) { if (fConfig.Count("version"))
{
std::cout << "User device version: " << fDevice->GetVersion() << std::endl; std::cout << "User device version: " << fDevice->GetVersion() << std::endl;
std::cout << "FAIRMQ_INTERFACE_VERSION: " << FAIRMQ_INTERFACE_VERSION << std::endl; std::cout << "FAIRMQ_INTERFACE_VERSION: " << FAIRMQ_INTERFACE_VERSION << std::endl;
fDevice->ChangeState(FairMQDevice::END); fDevice->ChangeState(FairMQDevice::END);
@@ -92,31 +82,31 @@ auto DeviceRunner::Run() -> int
fDevice->SetConfig(fConfig); fDevice->SetConfig(fConfig);
// Initialize plugin services // Initialize plugin services
fPluginManager.EmplacePluginServices(fConfig, *fDevice); fPluginManager->EmplacePluginServices(&fConfig, fDevice);
// Instantiate and run plugins // Instantiate and run plugins
fPluginManager.InstantiatePlugins(); fPluginManager->InstantiatePlugins();
// Run the device
fDevice->RunStateMachine();
// Wait for control plugin to release device control // Wait for control plugin to release device control
fPluginManager.WaitForPluginsToReleaseDeviceControl(); fPluginManager->WaitForPluginsToReleaseDeviceControl();
return 0; return 0;
} }
auto DeviceRunner::RunWithExceptionHandlers() -> int auto DeviceRunner::RunWithExceptionHandlers() -> int
{ {
try { try
{
return Run(); return Run();
} catch (std::exception& e) { }
LOG(error) << "Unhandled exception reached the top of main: " << e.what() catch (std::exception& e)
<< ", application will now exit"; {
LOG(error) << "Unhandled exception reached the top of main: " << e.what() << ", application will now exit";
return 1; return 1;
} catch (...) { }
LOG(error) << "Non-exception instance being thrown. Please make sure you use " catch (...)
"std::runtime_exception() instead. Application will now exit."; {
LOG(error) << "Non-exception instance being thrown. Please make sure you use std::runtime_exception() instead. Application will now exit.";
return 1; return 1;
} }
} }

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -20,8 +20,10 @@
#include <string> #include <string>
#include <vector> #include <vector>
namespace fair { namespace fair
namespace mq { {
namespace mq
{
/** /**
* @class DeviceRunner DeviceRunner.h <fairmq/DeviceRunner.h> * @class DeviceRunner DeviceRunner.h <fairmq/DeviceRunner.h>
@@ -29,8 +31,7 @@ namespace mq {
* *
* Runs a single FairMQ device with config and plugin support. * Runs a single FairMQ device with config and plugin support.
* *
* For customization user hooks are executed at various steps during device launch/shutdown in the * For customization user hooks are executed at various steps during device launch/shutdown in the following sequence:
* following sequence:
* *
* LoadPlugins * LoadPlugins
* | * |
@@ -43,41 +44,34 @@ namespace mq {
* v * v
* InstatiateDevice * InstatiateDevice
* *
* Each hook has access to all members of the DeviceRunner and really only differs by the point in * Each hook has access to all members of the DeviceRunner and really only differs by the point in time it is called.
* time it is called.
* *
* For an example usage of this class see the fairmq/runFairMQDevice.h header. * For an example usage of this class see the fairmq/runFairMQDevice.h header.
*/ */
class DeviceRunner class DeviceRunner
{ {
public: public:
DeviceRunner(int argc, char* const argv[], bool printLogo = true); DeviceRunner(int argc, char* const argv[]);
auto Run() -> int; auto Run() -> int;
auto RunWithExceptionHandlers() -> int; auto RunWithExceptionHandlers() -> int;
template<typename H> template<typename H>
auto AddHook(std::function<void(DeviceRunner&)> hook) -> void auto AddHook(std::function<void(DeviceRunner&)> hook) -> void { fEvents.Subscribe<H>("runner", hook); }
{
fEvents.Subscribe<H>("runner", hook);
}
template<typename H> template<typename H>
auto RemoveHook() -> void auto RemoveHook() -> void { fEvents.Unsubscribe<H>("runner"); }
{
fEvents.Unsubscribe<H>("runner");
}
std::vector<std::string> fRawCmdLineArgs; std::vector<std::string> fRawCmdLineArgs;
std::shared_ptr<PluginManager> fPluginManager;
FairMQProgOptions fConfig; FairMQProgOptions fConfig;
std::unique_ptr<FairMQDevice> fDevice; std::shared_ptr<FairMQDevice> fDevice;
PluginManager fPluginManager;
const bool fPrintLogo;
private: private:
EventManager fEvents; EventManager fEvents;
}; };
namespace hooks { namespace hooks
{
struct LoadPlugins : Event<DeviceRunner&> {}; struct LoadPlugins : Event<DeviceRunner&> {};
struct SetCustomCmdLineOptions : Event<DeviceRunner&> {}; struct SetCustomCmdLineOptions : Event<DeviceRunner&> {};
struct ModifyRawCmdLineArgs : Event<DeviceRunner&> {}; struct ModifyRawCmdLineArgs : Event<DeviceRunner&> {};

View File

@@ -755,7 +755,7 @@ void FairMQChannel::CheckSendCompatibility(FairMQMessagePtr& msg) const
// LOG(debug) << "Channel type does not match message type. Creating wrapper"; // LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(), FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
msg->GetSize(), msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); }, [](void* /*data*/, void* msg) { delete static_cast<FairMQMessage*>(msg); },
msg.get() msg.get()
)); ));
msg.release(); msg.release();
@@ -772,7 +772,7 @@ void FairMQChannel::CheckSendCompatibility(vector<FairMQMessagePtr>& msgVec) con
// LOG(debug) << "Channel type does not match message type. Creating wrapper"; // LOG(debug) << "Channel type does not match message type. Creating wrapper";
FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(), FairMQMessagePtr msgWrapper(NewMessage(msg->GetData(),
msg->GetSize(), msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); }, [](void* /*data*/, void* msg) { delete static_cast<FairMQMessage*>(msg); },
msg.get() msg.get()
)); ));
msg.release(); msg.release();

View File

@@ -8,6 +8,9 @@
#include <FairMQDevice.h> #include <FairMQDevice.h>
#include <fairmq/Tools.h>
#include <fairmq/Transports.h>
#include <boost/algorithm/string.hpp> // join/split #include <boost/algorithm/string.hpp> // join/split
#include <boost/uuid/uuid.hpp> #include <boost/uuid/uuid.hpp>
@@ -28,39 +31,22 @@
using namespace std; using namespace std;
FairMQDevice::FairMQDevice() FairMQDevice::FairMQDevice()
: FairMQDevice(nullptr, {0, 0, 0})
{
}
FairMQDevice::FairMQDevice(FairMQProgOptions& config)
: FairMQDevice(&config, {0, 0, 0})
{
}
FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
: FairMQDevice(nullptr, version)
{
}
FairMQDevice::FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version)
: FairMQDevice(&config, version)
{
}
FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version)
: fTransportFactory(nullptr) : fTransportFactory(nullptr)
, fTransports() , fTransports()
, fChannels() , fChannels()
, fInternalConfig(config ? nullptr : fair::mq::tools::make_unique<FairMQProgOptions>()) , fConfig(nullptr)
, fConfig(config ? config : fInternalConfig.get())
, fId() , fId()
, fNumIoThreads(1)
, fInitialValidationFinished(false) , fInitialValidationFinished(false)
, fInitialValidationCondition() , fInitialValidationCondition()
, fInitialValidationMutex() , fInitialValidationMutex()
, fPortRangeMin(22000) , fPortRangeMin(22000)
, fPortRangeMax(32000) , fPortRangeMax(32000)
, fNetworkInterface()
, fDefaultTransportType(fair::mq::Transport::DEFAULT) , fDefaultTransportType(fair::mq::Transport::DEFAULT)
, fInitializationTimeoutInS(120)
, fDataCallbacks(false) , fDataCallbacks(false)
, fMsgInputs() , fMsgInputs()
, fMultipartInputs() , fMultipartInputs()
@@ -69,54 +55,57 @@ FairMQDevice::FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Ver
, fInputChannelKeys() , fInputChannelKeys()
, fMultitransportMutex() , fMultitransportMutex()
, fMultitransportProceed(false) , fMultitransportProceed(false)
, fExternalConfig(false)
, fVersion({0, 0, 0})
, fRate(0.)
, fLastTime(0)
, fRawCmdLineArgs()
{
}
FairMQDevice::FairMQDevice(const fair::mq::tools::Version version)
: fTransportFactory(nullptr)
, fTransports()
, fChannels()
, fConfig(nullptr)
, fId()
, fNumIoThreads(1)
, fInitialValidationFinished(false)
, fInitialValidationCondition()
, fInitialValidationMutex()
, fPortRangeMin(22000)
, fPortRangeMax(32000)
, fNetworkInterface()
, fDefaultTransportType(fair::mq::Transport::DEFAULT)
, fInitializationTimeoutInS(120)
, fDataCallbacks(false)
, fMsgInputs()
, fMultipartInputs()
, fMultitransportInputs()
, fChannelRegistry()
, fInputChannelKeys()
, fMultitransportMutex()
, fMultitransportProceed(false)
, fExternalConfig(false)
, fVersion(version) , fVersion(version)
, fRate(0.) , fRate(0.)
, fLastTime(0)
, fRawCmdLineArgs() , fRawCmdLineArgs()
, fInterrupted(false)
, fInterruptedCV()
, fInterruptedMtx()
{ {
} }
void FairMQDevice::InitWrapper() void FairMQDevice::InitWrapper()
{ {
fId = fConfig->GetValue<string>("id"); if (!fTransportFactory)
fRate = fConfig->GetValue<float>("rate");
fPortRangeMin = fConfig->GetValue<int>("port-range-min");
fPortRangeMax = fConfig->GetValue<int>("port-range-max");
try
{ {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport")); LOG(error) << "Transport not initialized. Did you call SetTransport()?";
exit(EXIT_FAILURE);
} }
catch (const exception& e)
{
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
}
for (auto& c : fConfig->GetFairMQMap())
{
if (fChannels.find(c.first) == fChannels.end())
{
LOG(debug) << "Inserting new device channel from config: " << c.first;
fChannels.insert(c);
}
else
{
LOG(debug) << "Updating existing device channel from config: " << c.first;
fChannels[c.first] = c.second;
}
}
LOG(debug) << "Requesting '" << fair::mq::TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
fTransportFactory = AddTransport(fDefaultTransportType);
// Containers to store the uninitialized channels. // Containers to store the uninitialized channels.
vector<FairMQChannel*> uninitializedBindingChannels; vector<FairMQChannel*> uninitializedBindingChannels;
vector<FairMQChannel*> uninitializedConnectingChannels; vector<FairMQChannel*> uninitializedConnectingChannels;
string networkInterface = fConfig->GetValue<string>("network-interface");
// Fill the uninitialized channel containers // Fill the uninitialized channel containers
for (auto& mi : fChannels) for (auto& mi : fChannels)
{ {
@@ -137,11 +126,11 @@ void FairMQDevice::InitWrapper()
if (vi->fAddress == "unspecified" || vi->fAddress == "") if (vi->fAddress == "unspecified" || vi->fAddress == "")
{ {
// if the configured network interface is default, get its name from the default route // if the configured network interface is default, get its name from the default route
if (networkInterface == "default") if (fNetworkInterface == "default")
{ {
networkInterface = fair::mq::tools::getDefaultRouteNetworkInterface(); fNetworkInterface = fair::mq::tools::getDefaultRouteNetworkInterface();
} }
vi->fAddress = "tcp://" + fair::mq::tools::getInterfaceIP(networkInterface) + ":1"; vi->fAddress = "tcp://" + fair::mq::tools::getInterfaceIP(fNetworkInterface) + ":1";
} }
// fill the uninitialized list // fill the uninitialized list
uninitializedBindingChannels.push_back(&(*vi)); uninitializedBindingChannels.push_back(&(*vi));
@@ -186,12 +175,10 @@ void FairMQDevice::InitWrapper()
fInitialValidationCondition.notify_one(); fInitialValidationCondition.notify_one();
} }
int initializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
// go over the list of channels until all are initialized (and removed from the uninitialized list) // go over the list of channels until all are initialized (and removed from the uninitialized list)
int numAttempts = 1; int numAttempts = 1;
auto sleepTimeInMS = 50; auto sleepTimeInMS = 50;
auto maxAttempts = initializationTimeoutInS * 1000 / sleepTimeInMS; auto maxAttempts = fInitializationTimeoutInS * 1000 / sleepTimeInMS;
// first attempt // first attempt
AttachChannels(uninitializedConnectingChannels); AttachChannels(uninitializedConnectingChannels);
// if not all channels could be connected, update their address values from config and retry // if not all channels could be connected, update their address values from config and retry
@@ -214,9 +201,9 @@ void FairMQDevice::InitWrapper()
if (numAttempts++ > maxAttempts) if (numAttempts++ > maxAttempts)
{ {
LOG(error) << "could not connect all channels after " << initializationTimeoutInS << " attempts"; LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts";
ChangeState(ERROR_FOUND); ChangeState(ERROR_FOUND);
// throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", initializationTimeoutInS, " attempts")); // throw runtime_error(fair::mq::tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts"));
} }
AttachChannels(uninitializedConnectingChannels); AttachChannels(uninitializedConnectingChannels);
@@ -265,15 +252,19 @@ void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
bool FairMQDevice::AttachChannel(FairMQChannel& ch) bool FairMQDevice::AttachChannel(FairMQChannel& ch)
{ {
if (ch.fTransportType == fair::mq::Transport::DEFAULT || ch.fTransportType == fTransportFactory->GetType()) if (!ch.fTransportFactory)
{ {
LOG(debug) << ch.fName << ": using default transport"; if (ch.fTransportType == fair::mq::Transport::DEFAULT || ch.fTransportType == fTransportFactory->GetType())
ch.InitTransport(fTransportFactory); {
} LOG(debug) << ch.fName << ": using default transport";
else ch.InitTransport(fTransportFactory);
{ }
LOG(debug) << ch.fName << ": channel transport (" << fair::mq::TransportNames.at(fDefaultTransportType) << ") overriden to " << fair::mq::TransportNames.at(ch.fTransportType); else
ch.InitTransport(AddTransport(ch.fTransportType)); {
LOG(debug) << ch.fName << ": channel transport (" << fair::mq::TransportNames.at(fDefaultTransportType) << ") overriden to " << fair::mq::TransportNames.at(ch.fTransportType);
ch.InitTransport(AddTransport(ch.fTransportType));
}
ch.fTransportType = ch.fTransportFactory->GetType();
} }
vector<string> endpoints; vector<string> endpoints;
@@ -494,10 +485,6 @@ void FairMQDevice::RunWrapper()
thread rateLogger(&FairMQDevice::LogSocketRates, this); thread rateLogger(&FairMQDevice::LogSocketRates, this);
// notify transports to resume transfers // notify transports to resume transfers
{
lock_guard<mutex> guard(fInterruptedMtx);
fInterrupted = false;
}
for (auto& t : fTransports) for (auto& t : fTransports)
{ {
t.second->Resume(); t.second->Resume();
@@ -522,14 +509,20 @@ void FairMQDevice::RunWrapper()
} }
else else
{ {
fair::mq::tools::RateLimiter rateLimiter(fRate); using Clock = chrono::steady_clock;
using TimeScale = chrono::microseconds;
const TimeScale::rep period = TimeScale::period::den / fRate;
const auto reftime = Clock::now();
while (CheckCurrentState(RUNNING) && ConditionalRun()) while (CheckCurrentState(RUNNING) && ConditionalRun())
{ {
if (fRate > 0.001) if (fRate > 0.001) {
{ auto timespan = static_cast<TimeScale::rep>(chrono::duration_cast<TimeScale>(Clock::now() - reftime).count() - fLastTime);
rateLimiter.maybe_sleep(); if (timespan < period) {
TimeScale sleepfor(period - timespan);
this_thread::sleep_for(sleepfor);
} }
fLastTime = chrono::duration_cast<TimeScale>(Clock::now() - reftime).count();
}
} }
Run(); Run();
@@ -805,10 +798,78 @@ shared_ptr<FairMQTransportFactory> FairMQDevice::AddTransport(const fair::mq::Tr
} }
} }
void FairMQDevice::CreateOwnConfig()
{
// TODO: make fConfig a shared_ptr when no old user code has FairMQProgOptions ptr*
fConfig = new FairMQProgOptions();
string id{boost::uuids::to_string(boost::uuids::random_generator()())};
LOG(warn) << "No FairMQProgOptions provided, creating one internally and setting device ID to " << id;
// dummy argc+argv
char arg0[] = "undefined"; // executable name
char arg1[] = "--id";
char* arg2 = const_cast<char*>(id.c_str()); // device ID
const char* argv[] = { &arg0[0], &arg1[0], arg2, nullptr };
int argc = static_cast<int>((sizeof(argv) / sizeof(argv[0])) - 1);
fConfig->ParseAll(argc, &argv[0]);
fId = fConfig->GetValue<string>("id");
fNetworkInterface = fConfig->GetValue<string>("network-interface");
fNumIoThreads = fConfig->GetValue<int>("io-threads");
fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
fRate = fConfig->GetValue<float>("rate");
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} catch(const exception& e) {
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
}
}
void FairMQDevice::SetTransport(const string& transport)
{
// This method is the first to be called, if FairMQProgOptions are not used (either SetTransport() or SetConfig() make sense, not both).
// Make sure here that at least internal config is available.
if (!fExternalConfig && !fConfig)
{
CreateOwnConfig();
}
if (fTransports.empty())
{
LOG(debug) << "Requesting '" << transport << "' as default transport for the device";
fTransportFactory = AddTransport(fair::mq::TransportTypes.at(transport));
}
else
{
LOG(error) << "Transports container is not empty when setting transport. Setting default twice?";
ChangeState(ERROR_FOUND);
}
}
void FairMQDevice::SetConfig(FairMQProgOptions& config) void FairMQDevice::SetConfig(FairMQProgOptions& config)
{ {
fInternalConfig.reset(); fExternalConfig = true;
fConfig = &config; fConfig = &config;
for (auto& c : fConfig->GetFairMQMap())
{
if (!fChannels.insert(c).second)
{
LOG(warn) << "did not insert channel '" << c.first << "', it is already in the device.";
}
}
fId = fConfig->GetValue<string>("id");
fNetworkInterface = fConfig->GetValue<string>("network-interface");
fNumIoThreads = fConfig->GetValue<int>("io-threads");
fInitializationTimeoutInS = fConfig->GetValue<int>("initialization-timeout");
fRate = fConfig->GetValue<float>("rate");
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetValue<string>("transport"));
} catch(const exception& e) {
LOG(error) << "invalid transport type provided: " << fConfig->GetValue<string>("transport");
}
SetTransport(fConfig->GetValue<string>("transport"));
} }
void FairMQDevice::LogSocketRates() void FairMQDevice::LogSocketRates()
@@ -916,7 +977,6 @@ void FairMQDevice::LogSocketRates()
t0 = t1; t0 = t1;
this_thread::sleep_for(chrono::milliseconds(1000)); this_thread::sleep_for(chrono::milliseconds(1000));
// WaitFor(chrono::milliseconds(1000)); TODO: enable this when nanomsg linger is fixed
} }
} }
} }
@@ -927,11 +987,6 @@ void FairMQDevice::Unblock()
{ {
t.second->Interrupt(); t.second->Interrupt();
} }
{
lock_guard<mutex> guard(fInterruptedMtx);
fInterrupted = true;
}
fInterruptedCV.notify_all();
} }
void FairMQDevice::ResetTaskWrapper() void FairMQDevice::ResetTaskWrapper()
@@ -965,7 +1020,7 @@ void FairMQDevice::Reset()
for (auto& vi : mi.second) for (auto& vi : mi.second)
{ {
// vi.fReset = true; // vi.fReset = true;
vi.fSocket.reset(); // destroy FairMQSocket vi.fSocket.reset();
} }
} }
} }
@@ -977,6 +1032,10 @@ const FairMQChannel& FairMQDevice::GetChannel(const string& channelName, const i
void FairMQDevice::Exit() void FairMQDevice::Exit()
{ {
if (!fExternalConfig && fConfig)
{
delete fConfig;
}
} }
FairMQDevice::~FairMQDevice() FairMQDevice::~FairMQDevice()

View File

@@ -25,7 +25,6 @@
#include <memory> // unique_ptr #include <memory> // unique_ptr
#include <algorithm> // std::sort() #include <algorithm> // std::sort()
#include <string> #include <string>
#include <chrono>
#include <iostream> #include <iostream>
#include <unordered_map> #include <unordered_map>
#include <functional> #include <functional>
@@ -49,19 +48,9 @@ class FairMQDevice : public FairMQStateMachine
public: public:
/// Default constructor /// Default constructor
FairMQDevice(); FairMQDevice();
/// Constructor with external FairMQProgOptions
FairMQDevice(FairMQProgOptions& config);
/// Constructor that sets the version /// Constructor that sets the version
FairMQDevice(const fair::mq::tools::Version version); FairMQDevice(const fair::mq::tools::Version version);
/// Constructor that sets the version and external FairMQProgOptions
FairMQDevice(FairMQProgOptions& config, const fair::mq::tools::Version version);
private:
FairMQDevice(FairMQProgOptions* config, const fair::mq::tools::Version version);
public:
/// Copy constructor (disabled) /// Copy constructor (disabled)
FairMQDevice(const FairMQDevice&) = delete; FairMQDevice(const FairMQDevice&) = delete;
/// Assignment operator (disabled) /// Assignment operator (disabled)
@@ -305,11 +294,12 @@ class FairMQDevice : public FairMQStateMachine
/// Adds a transport to the device if it doesn't exist /// Adds a transport to the device if it doesn't exist
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem") /// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport); std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
void SetTransport(const std::string& transport = "zeromq");
/// Assigns config to the device
void SetConfig(FairMQProgOptions& config); void SetConfig(FairMQProgOptions& config);
/// Get pointer to the config const FairMQProgOptions* GetConfig() const
FairMQProgOptions* GetConfig() const
{ {
return fConfig; return fConfig;
} }
@@ -405,62 +395,40 @@ class FairMQDevice : public FairMQStateMachine
const fair::mq::tools::Version GetVersion() const { return fVersion; } const fair::mq::tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);} void SetNumIoThreads(int numIoThreads) { fNumIoThreads = numIoThreads; }
int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); } int GetNumIoThreads() const { return fNumIoThreads; }
void SetPortRangeMin(int portRangeMin) { fConfig->SetValue<int>("port-range-min", portRangeMin); } void SetPortRangeMin(int portRangeMin) { fPortRangeMin = portRangeMin; }
int GetPortRangeMin() const { return fConfig->GetValue<int>("port-range-min"); } int GetPortRangeMin() const { return fPortRangeMin; }
void SetPortRangeMax(int portRangeMax) { fConfig->SetValue<int>("port-range-max", portRangeMax); } void SetPortRangeMax(int portRangeMax) { fPortRangeMax = portRangeMax; }
int GetPortRangeMax() const { return fConfig->GetValue<int>("port-range-max"); } int GetPortRangeMax() const { return fPortRangeMax; }
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetValue<std::string>("network-interface", networkInterface); } void SetNetworkInterface(const std::string& networkInterface) { fNetworkInterface = networkInterface; }
std::string GetNetworkInterface() const { return fConfig->GetValue<std::string>("network-interface"); } std::string GetNetworkInterface() const { return fNetworkInterface; }
void SetDefaultTransport(const std::string& name) { fConfig->SetValue<std::string>("transport", name); } void SetDefaultTransport(const std::string& name) { fDefaultTransportType = fair::mq::TransportTypes.at(name); }
std::string GetDefaultTransport() const { return fConfig->GetValue<std::string>("transport"); } std::string GetDefaultTransport() const { return fair::mq::TransportNames.at(fDefaultTransportType); }
void SetInitializationTimeoutInS(int initializationTimeoutInS) { fConfig->SetValue<int>("initialization-timeout", initializationTimeoutInS); } void SetInitializationTimeoutInS(int initializationTimeoutInS) { fInitializationTimeoutInS = initializationTimeoutInS; }
int GetInitializationTimeoutInS() const { return fConfig->GetValue<int>("initialization-timeout"); } int GetInitializationTimeoutInS() const { return fInitializationTimeoutInS; }
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
void SetTransport(const std::string& transport) { fConfig->SetValue<std::string>("transport", transport); }
/// Gets the default transport name
std::string GetTransportName() const { return fConfig->GetValue<std::string>("transport"); }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; } void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; } std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine() { ProcessWork(); };
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<class Rep, class Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
std::unique_lock<std::mutex> lock(fInterruptedMtx);
return !fInterruptedCV.wait_for(lock, duration, [&] { return fInterrupted.load(); }); // return true if no interruption happened
}
protected: protected:
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports
public: public:
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
std::unique_ptr<FairMQProgOptions> fInternalConfig; ///< Internal program options configuration FairMQProgOptions* fConfig; ///< Program options configuration
FairMQProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& channelName, const FairMQChannel& channel)
{
fConfig->AddChannel(channelName, channel);
}
protected: protected:
std::string fId; ///< Device ID std::string fId; ///< Device ID
int fNumIoThreads; ///< Number of ZeroMQ I/O threads
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask(). /// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
/// Executed in a worker thread /// Executed in a worker thread
virtual void Init(); virtual void Init();
@@ -506,8 +474,11 @@ class FairMQDevice : public FairMQStateMachine
int fPortRangeMin; ///< Minimum value for the port range (if dynamic) int fPortRangeMin; ///< Minimum value for the port range (if dynamic)
int fPortRangeMax; ///< Maximum value for the port range (if dynamic) int fPortRangeMax; ///< Maximum value for the port range (if dynamic)
std::string fNetworkInterface; ///< Network interface to use for dynamic binding
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
int fInitializationTimeoutInS; ///< Timeout for the initialization (in seconds)
/// Handles the initialization and the Init() method /// Handles the initialization and the Init() method
void InitWrapper(); void InitWrapper();
/// Handles the InitTask() method /// Handles the InitTask() method
@@ -559,13 +530,12 @@ class FairMQDevice : public FairMQStateMachine
std::mutex fMultitransportMutex; std::mutex fMultitransportMutex;
std::atomic<bool> fMultitransportProceed; std::atomic<bool> fMultitransportProceed;
bool fExternalConfig;
const fair::mq::tools::Version fVersion; const fair::mq::tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun float fRate; ///< Rate limiting for ConditionalRun
size_t fLastTime; ///< Rate limiting for ConditionalRun
std::vector<std::string> fRawCmdLineArgs; std::vector<std::string> fRawCmdLineArgs;
std::atomic<bool> fInterrupted;
std::condition_variable fInterruptedCV;
std::mutex fInterruptedMtx;
}; };
#endif /* FAIRMQDEVICE_H_ */ #endif /* FAIRMQDEVICE_H_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -13,7 +13,6 @@
#include <fairmq/tools/CppSTL.h> #include <fairmq/tools/CppSTL.h>
#include <fairmq/tools/Network.h> #include <fairmq/tools/Network.h>
#include <fairmq/tools/Process.h> #include <fairmq/tools/Process.h>
#include <fairmq/tools/RateLimit.h>
#include <fairmq/tools/Strings.h> #include <fairmq/tools/Strings.h>
#include <fairmq/tools/Unique.h> #include <fairmq/tools/Unique.h>
#include <fairmq/tools/Version.h> #include <fairmq/tools/Version.h>

View File

@@ -9,19 +9,11 @@
#ifndef FAIR_MQ_VERSION_H #ifndef FAIR_MQ_VERSION_H
#define FAIRMQ_VERSION "@PROJECT_VERSION@" #define FAIRMQ_VERSION "@PROJECT_VERSION@"
#define FAIRMQ_VERSION_DEC (@PROJECT_VERSION_MAJOR@ * 100000) \ #define FAIRMQ_VERSION_DEC (@PROJECT_VERSION_MAJOR@ * 10000) + (@PROJECT_VERSION_MINOR@ * 100) + @PROJECT_VERSION_PATCH@
+ (@PROJECT_VERSION_MINOR@ * 1000) \
+ (@PROJECT_VERSION_PATCH@ * 10) \
+ @PROJECT_VERSION_HOTFIX@
#define FAIRMQ_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ #define FAIRMQ_VERSION_MAJOR @PROJECT_VERSION_MAJOR@
#define FAIRMQ_VERSION_MINOR @PROJECT_VERSION_MINOR@ #define FAIRMQ_VERSION_MINOR @PROJECT_VERSION_MINOR@
#define FAIRMQ_VERSION_PATCH @PROJECT_VERSION_PATCH@ #define FAIRMQ_VERSION_PATCH @PROJECT_VERSION_PATCH@
#define FAIRMQ_VERSION_HOTFIX @PROJECT_VERSION_HOTFIX@
#define FAIRMQ_GIT_VERSION "@PROJECT_GIT_VERSION@" #define FAIRMQ_GIT_VERSION "@PROJECT_GIT_VERSION@"
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@" #define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
#define FAIRMQ_LICENSE "LGPL-3.0"
#define FAIRMQ_COPYRIGHT "2012-2018 GSI"
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
#endif // FAIR_MQ_VERSION_H #endif // FAIR_MQ_VERSION_H

View File

@@ -1,29 +1,36 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
/**
* FairMQBenchmarkSampler.cpp
*
* @since 2013-04-23
* @author D. Klein, A. Rybalchenko
*/
#include "FairMQBenchmarkSampler.h" #include "FairMQBenchmarkSampler.h"
#include <fairmq/Tools.h>
#include "../FairMQLogger.h"
#include "../options/FairMQProgOptions.h"
#include <vector> #include <vector>
#include <chrono> #include <chrono>
#include "../FairMQLogger.h"
#include "../options/FairMQProgOptions.h"
using namespace std; using namespace std;
FairMQBenchmarkSampler::FairMQBenchmarkSampler() FairMQBenchmarkSampler::FairMQBenchmarkSampler()
: fSameMessage(true) : fSameMessage(true)
, fMsgSize(10000) , fMsgSize(10000)
, fMsgRate(0) , fMsgCounter(0)
, fMsgRate(1)
, fNumIterations(0) , fNumIterations(0)
, fMaxIterations(0) , fMaxIterations(0)
, fOutChannelName() , fOutChannelName()
, fResetMsgCounter()
{ {
} }
@@ -35,11 +42,16 @@ void FairMQBenchmarkSampler::InitTask()
{ {
fSameMessage = fConfig->GetValue<bool>("same-msg"); fSameMessage = fConfig->GetValue<bool>("same-msg");
fMsgSize = fConfig->GetValue<int>("msg-size"); fMsgSize = fConfig->GetValue<int>("msg-size");
fMsgRate = fConfig->GetValue<float>("msg-rate"); fMsgRate = fConfig->GetValue<int>("msg-rate");
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations"); fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
fOutChannelName = fConfig->GetValue<string>("out-channel"); fOutChannelName = fConfig->GetValue<string>("out-channel");
} }
void FairMQBenchmarkSampler::PreRun()
{
fResetMsgCounter = std::thread(&FairMQBenchmarkSampler::ResetMsgCounter, this);
}
void FairMQBenchmarkSampler::Run() void FairMQBenchmarkSampler::Run()
{ {
// store the channel reference to avoid traversing the map on every loop iteration // store the channel reference to avoid traversing the map on every loop iteration
@@ -50,8 +62,6 @@ void FairMQBenchmarkSampler::Run()
LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations."; LOG(info) << "Starting the benchmark with message size of " << fMsgSize << " and " << fMaxIterations << " iterations.";
auto tStart = chrono::high_resolution_clock::now(); auto tStart = chrono::high_resolution_clock::now();
fair::mq::tools::RateLimiter rateLimiter(fMsgRate);
while (CheckCurrentState(RUNNING)) while (CheckCurrentState(RUNNING))
{ {
if (fSameMessage) if (fSameMessage)
@@ -88,14 +98,31 @@ void FairMQBenchmarkSampler::Run()
} }
} }
--fMsgCounter;
if (fMsgRate > 0) while (fMsgCounter == 0)
{ {
rateLimiter.maybe_sleep(); this_thread::sleep_for(chrono::milliseconds(1));
} }
} }
auto tEnd = chrono::high_resolution_clock::now(); auto tEnd = chrono::high_resolution_clock::now();
LOG(info) << "Done " << fNumIterations << " iterations in " << chrono::duration<double, milli>(tEnd - tStart).count() << "ms."; LOG(info) << "Done " << fNumIterations << " iterations in " << chrono::duration<double, milli>(tEnd - tStart).count() << "ms.";
}
void FairMQBenchmarkSampler::PostRun()
{
fResetMsgCounter.join();
}
void FairMQBenchmarkSampler::ResetMsgCounter()
{
while (CheckCurrentState(RUNNING))
{
fMsgCounter = fMsgRate / 100;
this_thread::sleep_for(chrono::milliseconds(10));
}
fMsgCounter = -1;
} }

View File

@@ -1,17 +1,22 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
/**
* FairMQBenchmarkSampler.h
*
* @since 2013-04-23
* @author D. Klein, A. Rybalchenko
*/
#ifndef FAIRMQBENCHMARKSAMPLER_H_ #ifndef FAIRMQBENCHMARKSAMPLER_H_
#define FAIRMQBENCHMARKSAMPLER_H_ #define FAIRMQBENCHMARKSAMPLER_H_
#include <string> #include <string>
#include <thread> #include <thread>
#include <atomic>
#include "FairMQDevice.h" #include "FairMQDevice.h"
@@ -25,14 +30,20 @@ class FairMQBenchmarkSampler : public FairMQDevice
FairMQBenchmarkSampler(); FairMQBenchmarkSampler();
virtual ~FairMQBenchmarkSampler(); virtual ~FairMQBenchmarkSampler();
void PreRun() override;
void PostRun() override;
void ResetMsgCounter();
protected: protected:
bool fSameMessage; bool fSameMessage;
int fMsgSize; int fMsgSize;
std::atomic<int> fMsgCounter; int fMsgCounter;
float fMsgRate; int fMsgRate;
uint64_t fNumIterations; uint64_t fNumIterations;
uint64_t fMaxIterations; uint64_t fMaxIterations;
std::string fOutChannelName; std::string fOutChannelName;
std::thread fResetMsgCounter;
virtual void InitTask() override; virtual void InitTask() override;
virtual void Run() override; virtual void Run() override;

View File

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

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -14,8 +14,6 @@
#include "FairMQParser.h" #include "FairMQParser.h"
#include "FairMQLogger.h" #include "FairMQLogger.h"
#include <fairmq/Tools.h>
#include <boost/property_tree/json_parser.hpp> #include <boost/property_tree/json_parser.hpp>
#include <boost/property_tree/ptree.hpp> #include <boost/property_tree/ptree.hpp>

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -20,9 +20,6 @@
#include "FairMQSuboptParser.h" #include "FairMQSuboptParser.h"
#include <boost/algorithm/string.hpp> // join/split #include <boost/algorithm/string.hpp> // join/split
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <algorithm> #include <algorithm>
#include <iomanip> #include <iomanip>
@@ -139,16 +136,16 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
fair::Logger::SetConsoleSeverity(severity); fair::Logger::SetConsoleSeverity(severity);
} }
string idForParser; string id;
// check if config-key for config parser is provided // check if config-key for config parser is provided
if (fVarMap.count("config-key")) if (fVarMap.count("config-key"))
{ {
idForParser = fVarMap["config-key"].as<string>(); id = fVarMap["config-key"].as<string>();
} }
else if (fVarMap.count("id")) else if (fVarMap.count("id"))
{ {
idForParser = fVarMap["id"].as<string>(); id = fVarMap["id"].as<string>();
} }
// check if any config parser is selected // check if any config parser is selected
@@ -157,12 +154,12 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
if (fVarMap.count("mq-config")) if (fVarMap.count("mq-config"))
{ {
LOG(debug) << "mq-config: Using default JSON parser"; LOG(debug) << "mq-config: Using default JSON parser";
UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), idForParser)); UpdateChannelMap(parser::JSON().UserParser(fVarMap.at("mq-config").as<string>(), id));
} }
else if (fVarMap.count("channel-config")) else if (fVarMap.count("channel-config"))
{ {
LOG(debug) << "channel-config: Parsing channel configuration"; LOG(debug) << "channel-config: Parsing channel configuration";
UpdateChannelMap(parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), idForParser)); UpdateChannelMap(parser::SUBOPT().UserParser(fVarMap.at("channel-config").as<vector<string>>(), id));
} }
else else
{ {
@@ -187,8 +184,6 @@ int FairMQProgOptions::ParseAll(const int argc, char const* const* argv, bool al
void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered) void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bool allowUnregistered)
{ {
fVarMap.clear();
// get options from cmd line and store in variable map // 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 // here we use command_line_parser instead of parse_command_line, to allow unregistered and positional options
if (allowUnregistered) if (allowUnregistered)
@@ -210,7 +205,8 @@ void FairMQProgOptions::ParseCmdLine(const int argc, char const* const* argv, bo
void FairMQProgOptions::ParseDefaults() void FairMQProgOptions::ParseDefaults()
{ {
vector<string> emptyArgs = {"dummy", "--id", boost::uuids::to_string(boost::uuids::random_generator()())}; vector<string> emptyArgs;
emptyArgs.push_back("dummy");
vector<const char*> argv(emptyArgs.size()); vector<const char*> argv(emptyArgs.size());
@@ -427,7 +423,7 @@ int FairMQProgOptions::PrintOptions()
{ {
ss << setfill(' ') << left ss << setfill(' ') << left
<< setw(maxLenKey) << p.first << " = " << setw(maxLenKey) << p.first << " = "
<< setw(maxLenValue) << p.second.value << " " << setw(maxLenValue) << p.second.value
<< setw(maxLenType) << p.second.type << setw(maxLenType) << p.second.type
<< setw(maxLenDefault) << p.second.defaulted << setw(maxLenDefault) << p.second.defaulted
<< "\n"; << "\n";

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -162,11 +162,6 @@ class FairMQProgOptions
int PrintOptions(); int PrintOptions();
int PrintOptionsRaw(); int PrintOptionsRaw();
void AddChannel(const std::string& channelName, const FairMQChannel& channel)
{
fFairMQChannelMap[channelName].push_back(channel);
}
private: private:
struct ChannelKey struct ChannelKey
{ {

View File

@@ -12,17 +12,17 @@
#include <poll.h> // for the interactive mode #include <poll.h> // for the interactive mode
#include <csignal> // catching system signals #include <csignal> // catching system signals
#include <functional> #include <functional>
#include <atomic>
using namespace std; using namespace std;
namespace namespace
{ {
std::atomic<sig_atomic_t> gSignalStatus(0); // ugly global state, but std::signal gives us no other choice
std::function<void(int)> gSignalHandlerClosure;
extern "C" auto signal_handler(int signal) -> void extern "C" auto signal_handler(int signal) -> void
{ {
gSignalStatus = signal; gSignalHandlerClosure(signal);
} }
} }
@@ -37,13 +37,10 @@ Control::Control(const string name, const Plugin::Version version, const string
: Plugin(name, version, maintainer, homepage, pluginServices) : Plugin(name, version, maintainer, homepage, pluginServices)
, fControllerThread() , fControllerThread()
, fSignalHandlerThread() , fSignalHandlerThread()
, fShutdownThread()
, fEvents() , fEvents()
, fEventsMutex() , fEventsMutex()
, fShutdownMutex()
, fNewEvent() , fNewEvent()
, fDeviceTerminationRequested(false) , fDeviceTerminationRequested{false}
, fHasShutdown(false)
{ {
try try
{ {
@@ -76,7 +73,7 @@ Control::Control(const string name, const Plugin::Version version, const string
LOG(debug) << "catch-signals: " << GetProperty<int>("catch-signals"); LOG(debug) << "catch-signals: " << GetProperty<int>("catch-signals");
if (GetProperty<int>("catch-signals") > 0) if (GetProperty<int>("catch-signals") > 0)
{ {
fSignalHandlerThread = thread(&Control::SignalHandler, this); gSignalHandlerClosure = bind(&Control::SignalHandler, this, placeholders::_1);
signal(SIGINT, signal_handler); signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler); signal(SIGTERM, signal_handler);
} }
@@ -266,92 +263,69 @@ auto Control::StaticMode() -> void
} }
} }
auto Control::SignalHandler() -> void auto Control::SignalHandler(int signal) -> void
{ {
while (true) if (!fDeviceTerminationRequested)
{ {
if (gSignalStatus != 0 && !fHasShutdown) fDeviceTerminationRequested = true;
{
LOG(info) << "Received device shutdown request (signal " << gSignalStatus << ").";
LOG(info) << "Waiting for graceful device shutdown. Hit Ctrl-C again to abort immediately.";
if (!fDeviceTerminationRequested) StealDeviceControl();
{
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)); 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)
{
{
lock_guard<mutex> lock{fEventsMutex};
fEvents.push(newState);
}
fNewEvent.notify_one();
});
fSignalHandlerThread = thread(&Control::RunShutdownSequence, this);
} }
} 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 << ").";
lock_guard<mutex> lock{fEventsMutex}; LOG(warn) << "Aborting immediately !";
fEvents.push(newState); abort();
} }
fNewEvent.notify_one();
});
RunShutdownSequence();
} }
auto Control::RunShutdownSequence() -> void auto Control::RunShutdownSequence() -> void
{ {
lock_guard<mutex> lock(fShutdownMutex); auto nextState = GetCurrentDeviceState();
if (!fHasShutdown) EmptyEventQueue();
while (nextState != DeviceState::Exiting)
{ {
auto nextState = GetCurrentDeviceState(); switch (nextState)
EmptyEventQueue();
while (nextState != DeviceState::Exiting)
{ {
switch (nextState) case DeviceState::Idle:
{ ChangeDeviceState(DeviceStateTransition::End);
case DeviceState::Idle: break;
ChangeDeviceState(DeviceStateTransition::End); case DeviceState::DeviceReady:
break; ChangeDeviceState(DeviceStateTransition::ResetDevice);
case DeviceState::DeviceReady: break;
ChangeDeviceState(DeviceStateTransition::ResetDevice); case DeviceState::Ready:
break; ChangeDeviceState(DeviceStateTransition::ResetTask);
case DeviceState::Ready: break;
ChangeDeviceState(DeviceStateTransition::ResetTask); case DeviceState::Running:
break; ChangeDeviceState(DeviceStateTransition::Stop);
case DeviceState::Running: break;
ChangeDeviceState(DeviceStateTransition::Stop); case DeviceState::Paused:
break; ChangeDeviceState(DeviceStateTransition::Resume);
case DeviceState::Paused: break;
ChangeDeviceState(DeviceStateTransition::Resume); default:
break; break;
default:
// ignore other states
break;
}
nextState = WaitForNextState();
} }
fHasShutdown = true; nextState = WaitForNextState();
UnsubscribeFromDeviceStateChange();
ReleaseDeviceControl();
} }
UnsubscribeFromDeviceStateChange();
ReleaseDeviceControl();
} }
auto Control::RunStartupSequence() -> void auto Control::RunStartupSequence() -> void
@@ -383,7 +357,6 @@ Control::~Control()
{ {
if (fControllerThread.joinable()) fControllerThread.join(); if (fControllerThread.joinable()) fControllerThread.join();
if (fSignalHandlerThread.joinable()) fSignalHandlerThread.join(); if (fSignalHandlerThread.joinable()) fSignalHandlerThread.join();
if (fShutdownThread.joinable()) fShutdownThread.join();
} }
} /* namespace plugins */ } /* namespace plugins */

View File

@@ -10,7 +10,6 @@
#define FAIR_MQ_PLUGINS_CONTROL #define FAIR_MQ_PLUGINS_CONTROL
#include <fairmq/Plugin.h> #include <fairmq/Plugin.h>
#include <fairmq/Version.h>
#include <condition_variable> #include <condition_variable>
#include <mutex> #include <mutex>
@@ -38,36 +37,29 @@ class Control : public Plugin
auto PrintInteractiveHelp() -> void; auto PrintInteractiveHelp() -> void;
auto StaticMode() -> void; auto StaticMode() -> void;
auto WaitForNextState() -> DeviceState; auto WaitForNextState() -> DeviceState;
auto SignalHandler() -> void; auto SignalHandler(int signal) -> void;
auto HandleShutdownSignal() -> void;
auto RunShutdownSequence() -> void; auto RunShutdownSequence() -> void;
auto RunStartupSequence() -> void; auto RunStartupSequence() -> void;
auto EmptyEventQueue() -> void; auto EmptyEventQueue() -> void;
std::thread fControllerThread; std::thread fControllerThread;
std::thread fSignalHandlerThread; std::thread fSignalHandlerThread;
std::thread fShutdownThread;
std::queue<DeviceState> fEvents; std::queue<DeviceState> fEvents;
std::mutex fEventsMutex; std::mutex fEventsMutex;
std::mutex fShutdownMutex;
std::condition_variable fNewEvent; std::condition_variable fNewEvent;
std::atomic<bool> fDeviceTerminationRequested; std::atomic<bool> fDeviceTerminationRequested;
std::atomic<bool> fHasShutdown;
}; /* class Control */ }; /* class Control */
auto ControlPluginProgramOptions() -> Plugin::ProgOptions; auto ControlPluginProgramOptions() -> Plugin::ProgOptions;
REGISTER_FAIRMQ_PLUGIN( REGISTER_FAIRMQ_PLUGIN(
Control, // Class name Control, // Class name
control, // Plugin name (string, lower case chars only) control, // Plugin name (string, lower case chars only)
(Plugin::Version{FAIRMQ_VERSION_MAJOR, (Plugin::Version{1,0,1}), // Version
FAIRMQ_VERSION_MINOR, "FairRootGroup <fairroot@gsi.de>", // Maintainer
FAIRMQ_VERSION_PATCH}), // Version "https://github.com/FairRootGroup/FairRoot", // Homepage
"FairRootGroup <fairroot@gsi.de>", // Maintainer ControlPluginProgramOptions // Free function which declares custom program options for the plugin
"https://github.com/FairRootGroup/FairRoot", // Homepage // signature: () -> boost::optional<boost::program_options::options_description>
ControlPluginProgramOptions // Free function which declares custom program options for the
// plugin signature: () ->
// boost::optional<boost::program_options::options_description>
) )
} /* namespace plugins */ } /* namespace plugins */

View File

@@ -12,6 +12,7 @@
#include <iostream> #include <iostream>
#include <exception> #include <exception>
#include <sstream>
#include <thread> #include <thread>
#include <atomic> #include <atomic>
#include <unistd.h> #include <unistd.h>
@@ -33,27 +34,24 @@ int main(int argc, char* argv[])
{ {
try { try {
string sessionID; string sessionID;
char command; char commandChar;
string topologyPath;
bpo::options_description options("fairmq-dds-command-ui options"); bpo::options_description options("fairmq-dds-command-ui options");
options.add_options() options.add_options()
("session,s", bpo::value<string> (&sessionID)->required(), "DDS Session ID") ("session,s", bpo::value<string>(&sessionID)->required(), "DDS Session ID")
("command,c", bpo::value<char> (&command)->default_value(' '), "Command character") ("command,c", bpo::value<char> (&commandChar)->default_value(' '), "Command character")
("path,p", bpo::value<string> (&topologyPath)->default_value(""), "DDS Topology path to send command to")
("help,h", "Produce help message"); ("help,h", "Produce help message");
bpo::variables_map vm; bpo::variables_map vm;
bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm); bpo::store(bpo::command_line_parser(argc, argv).options(options).run(), vm);
bpo::notify(vm);
if (vm.count("help")) { if (vm.count("help")) {
cout << "FairMQ DDS Command UI" << endl << options << endl; cout << "FairMQ DDS Command UI" << endl << options << endl;
cout << "Commands: [c] check state, [o] dump config, [h] help, [p] pause, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device" << endl; cout << "possible command characters: [c] check states, [o] dump config, [h] help, [p] pause, [r] run, [s] stop, [t] reset task, [d] reset device, [q] end, [j] init task, [i] init device" << endl;
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
bpo::notify(vm);
CIntercomService service; CIntercomService service;
CCustomCmd ddsCustomCmd(service); CCustomCmd ddsCustomCmd(service);
@@ -63,7 +61,7 @@ int main(int argc, char* argv[])
// subscribe to receive messages from DDS // subscribe to receive messages from DDS
ddsCustomCmd.subscribe([](const string& msg, const string& /*condition*/, uint64_t /*senderId*/) { ddsCustomCmd.subscribe([](const string& msg, const string& /*condition*/, uint64_t /*senderId*/) {
cout << "Received: " << endl << msg << endl; cout << "Received: " << msg << endl;
}); });
service.start(sessionID); service.start(sessionID);
@@ -76,8 +74,8 @@ int main(int argc, char* argv[])
t.c_lflag &= ~ICANON; // disable canonical input t.c_lflag &= ~ICANON; // disable canonical input
tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings tcsetattr(STDIN_FILENO, TCSANOW, &t); // apply the new settings
if (command != ' ') { if (commandChar != ' ') {
cin.putback(command); cin.putback(commandChar);
} else { } else {
PrintControlsHelp(); PrintControlsHelp();
} }
@@ -86,39 +84,39 @@ int main(int argc, char* argv[])
switch (c) { switch (c) {
case 'c': case 'c':
cout << " > checking state of the devices" << endl; cout << " > checking state of the devices" << endl;
ddsCustomCmd.send("check-state", topologyPath); ddsCustomCmd.send("check-state", "");
break; break;
case 'o': case 'o':
cout << " > dumping config of the devices" << endl; cout << " > dumping config of the devices" << endl;
ddsCustomCmd.send("dump-config", topologyPath); ddsCustomCmd.send("dump-config", "");
break; break;
case 'i': case 'i':
cout << " > init devices" << endl; cout << " > init devices" << endl;
ddsCustomCmd.send("INIT DEVICE", topologyPath); ddsCustomCmd.send("INIT DEVICE", "");
break; break;
case 'j': case 'j':
cout << " > init tasks" << endl; cout << " > init tasks" << endl;
ddsCustomCmd.send("INIT TASK", topologyPath); ddsCustomCmd.send("INIT TASK", "");
break; break;
case 'p': case 'p':
cout << " > pause devices" << endl; cout << " > pause devices" << endl;
ddsCustomCmd.send("PAUSE", topologyPath); ddsCustomCmd.send("PAUSE", "");
break; break;
case 'r': case 'r':
cout << " > run tasks" << endl; cout << " > run tasks" << endl;
ddsCustomCmd.send("RUN", topologyPath); ddsCustomCmd.send("RUN", "");
break; break;
case 's': case 's':
cout << " > stop devices" << endl; cout << " > stop devices" << endl;
ddsCustomCmd.send("STOP", topologyPath); ddsCustomCmd.send("STOP", "");
break; break;
case 't': case 't':
cout << " > reset tasks" << endl; cout << " > reset tasks" << endl;
ddsCustomCmd.send("RESET TASK", topologyPath); ddsCustomCmd.send("RESET TASK", "");
break; break;
case 'd': case 'd':
cout << " > reset devices" << endl; cout << " > reset devices" << endl;
ddsCustomCmd.send("RESET DEVICE", topologyPath); ddsCustomCmd.send("RESET DEVICE", "");
break; break;
case 'h': case 'h':
cout << " > help" << endl; cout << " > help" << endl;
@@ -126,7 +124,7 @@ int main(int argc, char* argv[])
break; break;
case 'q': case 'q':
cout << " > end" << endl; cout << " > end" << endl;
ddsCustomCmd.send("END", topologyPath); ddsCustomCmd.send("END", "");
break; break;
default: default:
cout << "Invalid input: [" << c << "]" << endl; cout << "Invalid input: [" << c << "]" << endl;
@@ -134,8 +132,8 @@ int main(int argc, char* argv[])
break; break;
} }
if (command != ' ') { if (commandChar != ' ') {
this_thread::sleep_for(chrono::milliseconds(100)); // give dds a chance to complete request usleep(50000);
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
} }

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -18,7 +18,7 @@ void addCustomOptions(bpo::options_description& options)
("same-msg", bpo::value<bool>()->default_value(false), "Re-send the same message, or recreate for each iteration") ("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") ("msg-size", bpo::value<int>()->default_value(1000000), "Message size in bytes")
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Number of run iterations (0 - infinite)") ("max-iterations", bpo::value<uint64_t>()->default_value(0), "Number of run iterations (0 - infinite)")
("msg-rate", bpo::value<float>()->default_value(0), "Msg rate limit in maximum number of messages per second"); ("msg-rate", bpo::value<int>()->default_value(0), "Msg rate limit in maximum number of messages per second");
} }
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/) FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)

View File

@@ -46,7 +46,7 @@ int main(int argc, char* argv[])
// }); // });
runner.AddHook<InstantiateDevice>([](DeviceRunner& r){ runner.AddHook<InstantiateDevice>([](DeviceRunner& r){
r.fDevice = std::unique_ptr<FairMQDevice>{getDevice(r.fConfig)}; r.fDevice = std::shared_ptr<FairMQDevice>{getDevice(r.fConfig)};
}); });
return runner.Run(); return runner.Run();

View File

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

View File

@@ -246,180 +246,157 @@ int FairMQSocketSHM::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const i
} }
} }
int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout) int64_t FairMQSocketSHM::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int /*timeout*/)
{ {
const unsigned int vecSize = msgVec.size(); const unsigned int vecSize = msgVec.size();
int64_t totalSize = 0; int64_t totalSize = 0;
int elapsed = 0;
if (vecSize == 1) { if (vecSize == 1) {
return SendImpl(msgVec.back(), flags, timeout); return Send(msgVec.back(), flags);
} }
// put it into zmq message // put it into zmq message
zmq_msg_t zmqMsg; zmq_msg_t lZmqMsg;
zmq_msg_init_size(&zmqMsg, vecSize * sizeof(MetaHeader)); zmq_msg_init_size(&lZmqMsg, vecSize * sizeof(MetaHeader));
// prepare the message with shm metas // prepare the message with shm metas
MetaHeader* metas = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg)); MetaHeader *lMetas = static_cast<MetaHeader*>(zmq_msg_data(&lZmqMsg));
for (auto &msg : msgVec) for (auto &lMsg : msgVec)
{ {
zmq_msg_t* metaMsg = static_cast<FairMQMessageSHM*>(msg.get())->GetMessage(); zmq_msg_t *lMetaMsg = static_cast<FairMQMessageSHM*>(lMsg.get())->GetMessage();
memcpy(metas++, zmq_msg_data(metaMsg), sizeof(MetaHeader)); memcpy(lMetas++, zmq_msg_data(lMetaMsg), sizeof(MetaHeader));
} }
while (!fInterrupted) while (!fInterrupted)
{ {
int nbytes = -1; int nbytes = -1;
nbytes = zmq_msg_send(&zmqMsg, fSocket, flags); nbytes = zmq_msg_send(&lZmqMsg, fSocket, flags);
if (nbytes == 0) if (nbytes == 0)
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lZmqMsg);
return nbytes; return nbytes;
} }
else if (nbytes > 0) else if (nbytes > 0)
{ {
assert(nbytes == (vecSize * sizeof(MetaHeader))); // all or nothing assert(nbytes == (vecSize * sizeof(MetaHeader))); // all or nothing
for (auto &msg : msgVec) for (auto &lMsg : msgVec)
{ {
FairMQMessageSHM* shmMsg = static_cast<FairMQMessageSHM*>(msg.get()); FairMQMessageSHM *lShmMsg = static_cast<FairMQMessageSHM*>(lMsg.get());
shmMsg->fQueued = true; lShmMsg->fQueued = true;
totalSize += shmMsg->fSize; totalSize += lShmMsg->fSize;
} }
// store statistics on how many messages have been sent // store statistics on how many messages have been sent
fMessagesTx++; fMessagesTx++;
fBytesTx += totalSize; fBytesTx += totalSize;
zmq_msg_close(&zmqMsg); zmq_msg_close (&lZmqMsg);
return totalSize; return totalSize;
} }
else if (zmq_errno() == EAGAIN) else if (zmq_errno() == EAGAIN)
{ {
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
{ {
if (timeout)
{
elapsed += fSndTimeout;
if (elapsed >= timeout)
{
zmq_msg_close(&zmqMsg);
return -2;
}
}
continue; continue;
} }
else else
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lZmqMsg);
return -2; return -2;
} }
} }
else if (zmq_errno() == ETERM) else if (zmq_errno() == ETERM)
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lZmqMsg);
LOG(info) << "terminating socket " << fId; LOG(info) << "terminating socket " << fId;
return -1; return -1;
} }
else else
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lZmqMsg);
LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno); LOG(error) << "Failed sending on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes; return nbytes;
} }
} }
zmq_msg_close(&zmqMsg);
return -1; return -1;
} }
int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
int64_t FairMQSocketSHM::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int /*timeout*/)
{ {
int64_t totalSize = 0; int64_t totalSize = 0;
int elapsed = 0;
zmq_msg_t zmqMsg;
zmq_msg_init(&zmqMsg);
while (!fInterrupted) while (!fInterrupted)
{ {
int nbytes = zmq_msg_recv(&zmqMsg, fSocket, flags); zmq_msg_t lRcvMsg;
zmq_msg_init(&lRcvMsg);
int nbytes = zmq_msg_recv(&lRcvMsg, fSocket, flags);
if (nbytes == 0) if (nbytes == 0)
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lRcvMsg);
return 0; return 0;
} }
else if (nbytes > 0) else if (nbytes > 0)
{ {
MetaHeader* hdrVec = static_cast<MetaHeader*>(zmq_msg_data(&zmqMsg)); MetaHeader* lHdrVec = static_cast<MetaHeader*>(zmq_msg_data(&lRcvMsg));
const auto hdrVecSize = zmq_msg_size(&zmqMsg); const auto lHdrVecSize = zmq_msg_size(&lRcvMsg);
assert(hdrVecSize > 0); assert(lHdrVecSize > 0);
assert(hdrVecSize % sizeof(MetaHeader) == 0); assert(lHdrVecSize % sizeof(MetaHeader) == 0);
const auto numMessages = hdrVecSize / sizeof(MetaHeader); const auto lNumMessages = lHdrVecSize / sizeof (MetaHeader);
msgVec.reserve(numMessages); msgVec.reserve(lNumMessages);
for (size_t m = 0; m < numMessages; m++) for (auto m = 0; m < lNumMessages; m++)
{ {
MetaHeader metaHeader; MetaHeader lMetaHeader;
memcpy(&metaHeader, &hdrVec[m], sizeof(MetaHeader)); memcpy(&lMetaHeader, &lHdrVec[m], sizeof(MetaHeader));
msgVec.emplace_back(fair::mq::tools::make_unique<FairMQMessageSHM>(fManager)); msgVec.emplace_back(fair::mq::tools::make_unique<FairMQMessageSHM>(fManager));
FairMQMessageSHM* msg = static_cast<FairMQMessageSHM*>(msgVec.back().get()); FairMQMessageSHM *lMsg = static_cast<FairMQMessageSHM*>(msgVec.back().get());
MetaHeader* msgHdr = static_cast<MetaHeader*>(zmq_msg_data(msg->GetMessage())); MetaHeader *lMsgHdr = static_cast<MetaHeader*>(zmq_msg_data(lMsg->GetMessage()));
memcpy(msgHdr, &metaHeader, sizeof(MetaHeader)); memcpy(lMsgHdr, &lMetaHeader, sizeof(MetaHeader));
msg->fHandle = metaHeader.fHandle; lMsg->fHandle = lMetaHeader.fHandle;
msg->fSize = metaHeader.fSize; lMsg->fSize = lMetaHeader.fSize;
msg->fRegionId = metaHeader.fRegionId; lMsg->fRegionId = lMetaHeader.fRegionId;
msg->fHint = metaHeader.fHint; lMsg->fHint = lMetaHeader.fHint;
totalSize += msg->GetSize(); totalSize += lMsg->GetSize();
} }
// store statistics on how many messages have been received (handle all parts as a single message) // store statistics on how many messages have been received (handle all parts as a single message)
fMessagesRx++; fMessagesRx++;
fBytesRx += totalSize; fBytesRx += totalSize;
zmq_msg_close(&zmqMsg); zmq_msg_close (&lRcvMsg);
return totalSize; return totalSize;
} }
else if (zmq_errno() == EAGAIN) else if (zmq_errno() == EAGAIN)
{ {
zmq_msg_close(&lRcvMsg);
if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0)) if (!fInterrupted && ((flags & ZMQ_DONTWAIT) == 0))
{ {
if (timeout)
{
elapsed += fRcvTimeout;
if (elapsed >= timeout)
{
zmq_msg_close(&zmqMsg);
return -2;
}
}
continue; continue;
} }
else else
{ {
zmq_msg_close(&zmqMsg);
return -2; return -2;
} }
} }
else else
{ {
zmq_msg_close(&zmqMsg); zmq_msg_close (&lRcvMsg);
LOG(error) << "Failed receiving on socket " << fId << ", reason: " << zmq_strerror(errno);
return nbytes; return nbytes;
} }
} }
zmq_msg_close(&zmqMsg);
return -1; return -1;
} }

View File

@@ -28,9 +28,9 @@
using namespace std; using namespace std;
using namespace fair::mq::shmem; using namespace fair::mq::shmem;
namespace bfs = ::boost::filesystem; namespace bfs = boost::filesystem;
namespace bpt = ::boost::posix_time; namespace bpt = boost::posix_time;
namespace bipc = ::boost::interprocess; namespace bipc = boost::interprocess;
fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM; fair::mq::Transport FairMQTransportFactorySHM::fTransportType = fair::mq::Transport::SHM;

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,136 +0,0 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_TOOLS_RATELIMIT_H
#define FAIR_MQ_TOOLS_RATELIMIT_H
#include <cassert>
#include <string>
#include <iostream>
#include <iomanip>
#include <thread>
#include <chrono>
namespace fair
{
namespace mq
{
namespace tools
{
/**
* Objects of type RateLimiter can be used to limit a loop to a given rate of iterations per second.
*
* Example:
* \code
* RateLimiter limit(100); // 100 Hz
* while (do_more_work()) {
* work();
* limit.maybe_sleep(); // this needs to be at the end of the loop for a
* // correct time measurement of the first iterations
* }
* \endcode
*/
class RateLimiter
{
using clock = std::chrono::steady_clock;
public:
/**
* Constructs a rate limiter.
*
* \param rate Work rate in Hz (calls to maybe_sleep per second). Values less than/equal
* to 0 set the rate to 1 GHz (which is impossible to achieve, even with a
* loop that only calls RateLimiter::maybe_sleep).
*/
RateLimiter(float rate) : tw_req(std::chrono::seconds(1)), start_time(clock::now())
{
if (rate <= 0) {
tw_req = std::chrono::nanoseconds(1);
} else {
tw_req = std::chrono::duration_cast<clock::duration>(tw_req / rate);
}
skip_check_count = std::max(1, int(std::chrono::milliseconds(5) / tw_req));
count = skip_check_count;
//std::cerr << "skip_check_count: " << skip_check_count << '\n';
}
/**
* Call this function at the end of the iteration rate limited loop.
*
* This function might use `std::this_thread::sleep_for` to limit the iteration rate. If no sleeps
* are necessary, the function will back off checking for the time to further allow increased
* iteration rates (until the requested rate or 1s between rechecks is reached).
*/
void maybe_sleep()
{
using namespace std::chrono;
if (--count == 0) {
auto now = clock::now();
if (tw == clock::duration::zero()) {
tw = (now - start_time) / skip_check_count;
} else {
tw = (1 * tw + 3 * (now - start_time) / skip_check_count) / 4;
}
//std::ostringstream s; s << "tw = " << std::setw(10) << duration_cast<nanoseconds>(tw).count() << "ns, req = " << duration_cast<nanoseconds>(tw_req).count() << "ns, ";
if (tw > tw_req * 65 / 64) {
// the time between maybe_sleep calls is more than 1% too long
// fix it by reducing ts towards 0 and if ts = 0 doesn't suffice, increase
// skip_check_count
if (ts > clock::duration::zero()) {
ts = std::max(clock::duration::zero(),
ts - (tw - tw_req) * skip_check_count * 1 / 2);
//std::cerr << s.str() << "maybe_sleep: going too slow; sleep less: " << duration_cast<microseconds>(ts).count() << "µs\n";
} else {
skip_check_count =
std::min(int(seconds(1) / tw_req), // recheck at least every second
(skip_check_count * 5 + 3) / 4);
//std::cerr << s.str() << "maybe_sleep: going too slow; work more: " << skip_check_count << "\n";
}
} else if (tw < tw_req * 63 / 64) {
// the time between maybe_sleep calls is more than 1% too short
// fix it by reducing skip_check_count towards 1 and if skip_check_count = 1
// doesn't suffice, increase ts
// The minimum work count is defined such that a typical sleep time is greater
// than 1ms.
// The user requested 1/tw_req work iterations per second. Divided by 1000, that's
// the count per ms.
const int min_skip_count = std::max(1, int(milliseconds(5) / tw_req));
if (skip_check_count > min_skip_count) {
assert(ts == clock::duration::zero());
skip_check_count = std::max(min_skip_count, skip_check_count * 3 / 4);
//std::cerr << s.str() << "maybe_sleep: going too fast; work less: " << skip_check_count << "\n";
} else {
ts += (tw_req - tw) * (skip_check_count * 7) / 8;
//std::cerr << s.str() << "maybe_sleep: going too fast; sleep more: " << duration_cast<microseconds>(ts).count() << "µs\n";
}
}
start_time = now;
count = skip_check_count;
if (ts > clock::duration::zero()) {
std::this_thread::sleep_for(ts);
}
}
}
private:
clock::duration tw{}, //! deduced duration between maybe_sleep calls
ts{}, //! sleep duration
tw_req; //! requested duration between maybe_sleep calls
clock::time_point start_time;
int count = 1;
int skip_check_count = 1;
};
} /* namespace tools */
} /* namespace mq */
} /* namespace fair */
#endif // FAIR_MQ_TOOLS_RATELIMIT_H

View File

@@ -283,7 +283,7 @@ int64_t FairMQSocketZMQ::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fl
} // If there's only one part, send it as a regular message } // If there's only one part, send it as a regular message
else if (vecSize == 1) else if (vecSize == 1)
{ {
return SendImpl(msgVec.back(), flags, timeout); return Send(msgVec.back(), flags);
} }
else // if the vector is empty, something might be wrong else // if the vector is empty, something might be wrong
{ {

View File

@@ -1,5 +1,5 @@
################################################################################ ################################################################################
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH # # Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# # # #
# This software is distributed under the terms of the # # This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, # # GNU Lesser General Public Licence (LGPL) version 3, #
@@ -26,80 +26,70 @@ add_testhelper(runTestDevice
helper/devices/TestReq.cxx helper/devices/TestReq.cxx
helper/devices/TestSub.cxx helper/devices/TestSub.cxx
helper/devices/TestTransferTimeout.cxx helper/devices/TestTransferTimeout.cxx
helper/devices/TestWaitFor.cxx
LINKS FairMQ LINKS FairMQ
) )
if(BUILD_NANOMSG_TRANSPORT)
set(definitions DEFINITIONS BUILD_NANOMSG_TRANSPORT)
endif()
set(MQ_CONFIG "${CMAKE_BINARY_DIR}/test/testsuite_FairMQ.IOPatterns_config.json") set(MQ_CONFIG "${CMAKE_BINARY_DIR}/test/testsuite_FairMQ.IOPatterns_config.json")
set(RUN_TEST_DEVICE "${CMAKE_BINARY_DIR}/test/testhelper_runTestDevice") set(RUN_TEST_DEVICE "${CMAKE_BINARY_DIR}/test/testhelper_runTestDevice")
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq) set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/protocols/config.json.in ${MQ_CONFIG}) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/protocols/config.json.in ${MQ_CONFIG})
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/runner.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/runner.cxx) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/protocols/runner.cxx.in ${CMAKE_CURRENT_BINARY_DIR}/protocols/runner.cxx)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestEnvironment.h.in ${CMAKE_CURRENT_BINARY_DIR}/TestEnvironment.h) configure_file(${CMAKE_CURRENT_SOURCE_DIR}/TestEnvironment.h.in ${CMAKE_CURRENT_BINARY_DIR}/TestEnvironment.h)
add_testsuite(FairMQ.Protocols add_testsuite(FairMQ.Protocols
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx ${CMAKE_CURRENT_BINARY_DIR}/protocols/runner.cxx
protocols/_pair.cxx protocols/_pair.cxx
protocols/_poller.cxx
protocols/_pub_sub.cxx protocols/_pub_sub.cxx
protocols/_push_pull.cxx protocols/_push_pull.cxx
protocols/_req_rep.cxx protocols/_req_rep.cxx
protocols/_transfer_timeout.cxx
protocols/_push_pull_multipart.cxx protocols/_push_pull_multipart.cxx
LINKS FairMQ LINKS FairMQ
DEPENDS testhelper_runTestDevice DEPENDS testhelper_runTestDevice
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/protocols
${CMAKE_CURRENT_SOURCE_DIR}/protocols
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 30 TIMEOUT 30
RUN_SERIAL ON RUN_SERIAL ON
${definitions}
) )
add_testsuite(FairMQ.Parts add_testsuite(FairMQ.Parts
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx parts/runner.cxx
parts/_iterator_interface.cxx parts/_iterator_interface.cxx
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/parts
${CMAKE_CURRENT_SOURCE_DIR}/parts
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 5 TIMEOUT 5
) )
add_testsuite(FairMQ.MessageResize add_testsuite(FairMQ.MessageResize
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx message_resize/runner.cxx
message_resize/_message_resize.cxx message_resize/_message_resize.cxx
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/message_resize
${CMAKE_CURRENT_SOURCE_DIR}/message_resize
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 5 TIMEOUT 5
${definitions}
) )
add_testsuite(FairMQ.Device add_testsuite(FairMQ.Device
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
device/TestSender.h device/TestSender.h
device/TestReceiver.h device/TestReceiver.h
device/TestVersion.h
device/runner.cxx
device/_multiple_devices.cxx device/_multiple_devices.cxx
device/_device_version.cxx device/_device_version.cxx
device/_device_config.cxx
device/_waitfor.cxx
LINKS FairMQ LINKS FairMQ
DEPENDS testhelper_runTestDevice INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}/device
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/device
${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 5 TIMEOUT 5
RUN_SERIAL ON RUN_SERIAL ON
@@ -139,81 +129,54 @@ add_testlib(FairMQPlugin_test_dummy2
add_testsuite(FairMQ.Plugins add_testsuite(FairMQ.Plugins
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx plugins/runner.cxx
plugins/_plugin.cxx plugins/_plugin.cxx
plugins/_plugin_manager.cxx plugins/_plugin_manager.cxx
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS FairMQPlugin_test_dummy FairMQPlugin_test_dummy2 DEPENDS FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
TIMEOUT 10 TIMEOUT 10
) )
add_testsuite(FairMQ.PluginsPrelinked add_testsuite(FairMQ.PluginsPrelinked
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx plugins/runner.cxx
plugins/_plugin_manager_prelink.cxx plugins/_plugin_manager_prelink.cxx
LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2 LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10 TIMEOUT 10
) )
add_testsuite(FairMQ.PluginServices add_testsuite(FairMQ.PluginServices
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx plugin_services/runner.cxx
plugin_services/_config.cxx plugin_services/_config.cxx
plugin_services/_control.cxx plugin_services/_control.cxx
plugin_services/Fixture.h plugin_services/Fixture.h
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10 TIMEOUT 10
) )
add_testsuite(FairMQ.EventManager add_testsuite(FairMQ.EventManager
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx event_manager/runner.cxx
event_manager/_event_manager.cxx event_manager/_event_manager.cxx
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10 TIMEOUT 10
) )
add_testsuite(FairMQ.StateMachine add_testsuite(FairMQ.StateMachine
SOURCES SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx state_machine/runner.cxx
state_machine/_state_machine.cxx state_machine/_state_machine.cxx
LINKS FairMQ LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR} INCLUDES ${CMAKE_CURRENT_BINARY_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10
)
add_testsuite(FairMQ.Transport
SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
transport/_transfer_timeout.cxx
LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10
)
add_testsuite(FairMQ.Poller
SOURCES
${CMAKE_CURRENT_BINARY_DIR}/runner.cxx
poller/_poller.cxx
LINKS FairMQ
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_BINARY_DIR}
TIMEOUT 10 TIMEOUT 10
) )

View File

@@ -8,8 +8,7 @@
#include <FairMQDevice.h> #include <FairMQDevice.h>
#include <FairMQLogger.h> #include <FairMQLogger.h>
#include <options/FairMQProgOptions.h>
#include <iostream>
namespace fair namespace fair
{ {
@@ -18,14 +17,12 @@ namespace mq
namespace test namespace test
{ {
class TestWaitFor : public FairMQDevice class TestVersion : public FairMQDevice
{ {
public: public:
void Run() TestVersion(fair::mq::tools::Version version)
{ : FairMQDevice(version)
std::cout << "hello" << std::endl; {}
WaitFor(std::chrono::seconds(60));
}
}; };
} // namespace test } // namespace test

View File

@@ -1,122 +0,0 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <FairMQDevice.h>
#include <options/FairMQProgOptions.h>
#include <fairmq/Tools.h>
#include <gtest/gtest.h>
#include <sstream> // std::stringstream
#include <thread>
namespace
{
using namespace std;
void control(FairMQDevice& device)
{
device.ChangeState("INIT_DEVICE");
device.WaitForEndOfState("INIT_DEVICE");
device.ChangeState("INIT_TASK");
device.WaitForEndOfState("INIT_TASK");
device.ChangeState("RUN");
device.WaitForEndOfState("RUN");
device.ChangeState("RESET_TASK");
device.WaitForEndOfState("RESET_TASK");
device.ChangeState("RESET_DEVICE");
device.WaitForEndOfState("RESET_DEVICE");
device.ChangeState("END");
}
class DeviceConfig : public ::testing::Test
{
public:
DeviceConfig()
{}
string TestDeviceSetConfig(const string& transport)
{
FairMQProgOptions config;
vector<string> emptyArgs = {"dummy", "--id", "test", "--color", "false"};
if (config.ParseAll(emptyArgs, true))
{
return 0;
}
config.SetValue<string>("transport", transport);
FairMQDevice device;
device.SetConfig(config);
FairMQChannel channel;
channel.UpdateType("pub");
channel.UpdateMethod("connect");
channel.UpdateAddress("tcp://localhost:5558");
device.AddChannel("data", channel);
thread t(control, ref(device));
device.RunStateMachine();
if (t.joinable())
{
t.join();
}
return device.GetTransportName();
}
string TestDeviceSetTransport(const string& transport)
{
FairMQDevice device;
device.SetTransport(transport);
FairMQChannel channel;
channel.UpdateType("pub");
channel.UpdateMethod("connect");
channel.UpdateAddress("tcp://localhost:5558");
device.AddChannel("data", channel);
std::thread t(control, std::ref(device));
device.RunStateMachine();
if (t.joinable())
{
t.join();
}
return device.GetTransportName();
}
};
TEST_F(DeviceConfig, SetConfig)
{
string transport = "zeromq";
string returnedTransport = TestDeviceSetConfig(transport);
EXPECT_EQ(transport, returnedTransport);
}
TEST_F(DeviceConfig, SetTransport)
{
string transport = "zeromq";
string returnedTransport = TestDeviceSetTransport(transport);
EXPECT_EQ(transport, returnedTransport);
}
} // namespace

View File

@@ -1,12 +1,12 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include <FairMQDevice.h> #include "TestVersion.h"
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
@@ -19,24 +19,16 @@ namespace
{ {
using namespace std; using namespace std;
using namespace fair::mq::test;
class TestVersion : public FairMQDevice class DeviceVersion : public ::testing::Test {
{
public:
TestVersion(fair::mq::tools::Version version)
: FairMQDevice(version)
{}
};
class DeviceVersion : public ::testing::Test
{
public: public:
DeviceVersion() DeviceVersion()
{} {}
fair::mq::tools::Version TestDeviceVersion() fair::mq::tools::Version TestDeviceVersion()
{ {
TestVersion versionDevice({1, 2, 3}); fair::mq::test::TestVersion versionDevice({1, 2, 3});
versionDevice.ChangeState("END"); versionDevice.ChangeState("END");
return versionDevice.GetVersion(); return versionDevice.GetVersion();

View File

@@ -1,5 +1,5 @@
/******************************************************************************** /********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* * * *
* This software is distributed under the terms of the * * This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, * * GNU Lesser General Public Licence (LGPL) version 3, *
@@ -12,7 +12,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
#include <thread>
#include <future> // std::async, std::future #include <future> // std::async, std::future
namespace namespace
@@ -20,24 +19,6 @@ namespace
using namespace std; using namespace std;
void control(FairMQDevice& device)
{
device.ChangeState("INIT_DEVICE");
device.WaitForEndOfState("INIT_DEVICE");
device.ChangeState("INIT_TASK");
device.WaitForEndOfState("INIT_TASK");
device.ChangeState("RUN");
device.WaitForEndOfState("RUN");
device.ChangeState("RESET_TASK");
device.WaitForEndOfState("RESET_TASK");
device.ChangeState("RESET_DEVICE");
device.WaitForEndOfState("RESET_DEVICE");
device.ChangeState("END");
}
class MultipleDevices : public ::testing::Test { class MultipleDevices : public ::testing::Test {
public: public:
MultipleDevices() MultipleDevices()
@@ -51,16 +32,22 @@ class MultipleDevices : public ::testing::Test {
FairMQChannel channel("push", "connect", "ipc://multiple-devices-test"); FairMQChannel channel("push", "connect", "ipc://multiple-devices-test");
channel.UpdateRateLogging(0); channel.UpdateRateLogging(0);
sender.AddChannel("data", channel); sender.fChannels["data"].push_back(channel);
thread t(control, std::ref(sender)); sender.ChangeState("INIT_DEVICE");
sender.WaitForEndOfState("INIT_DEVICE");
sender.ChangeState("INIT_TASK");
sender.WaitForEndOfState("INIT_TASK");
sender.RunStateMachine(); sender.ChangeState("RUN");
sender.WaitForEndOfState("RUN");
if (t.joinable()) sender.ChangeState("RESET_TASK");
{ sender.WaitForEndOfState("RESET_TASK");
t.join(); sender.ChangeState("RESET_DEVICE");
} sender.WaitForEndOfState("RESET_DEVICE");
sender.ChangeState("END");
return true; return true;
} }
@@ -73,16 +60,22 @@ class MultipleDevices : public ::testing::Test {
FairMQChannel channel("pull", "bind", "ipc://multiple-devices-test"); FairMQChannel channel("pull", "bind", "ipc://multiple-devices-test");
channel.UpdateRateLogging(0); channel.UpdateRateLogging(0);
receiver.AddChannel("data", channel); receiver.fChannels["data"].push_back(channel);
thread t(control, std::ref(receiver)); receiver.ChangeState("INIT_DEVICE");
receiver.WaitForEndOfState("INIT_DEVICE");
receiver.ChangeState("INIT_TASK");
receiver.WaitForEndOfState("INIT_TASK");
receiver.RunStateMachine(); receiver.ChangeState("RUN");
receiver.WaitForEndOfState("RUN");
if (t.joinable()) receiver.ChangeState("RESET_TASK");
{ receiver.WaitForEndOfState("RESET_TASK");
t.join(); receiver.ChangeState("RESET_DEVICE");
} receiver.WaitForEndOfState("RESET_DEVICE");
receiver.ChangeState("END");
return true; return true;
} }

View File

@@ -1,74 +0,0 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "runner.h"
#include <gtest/gtest.h>
#include <boost/process.hpp>
#include <sys/types.h>
#include <signal.h>
#include <string>
#include <thread>
#include <chrono>
#include <iostream>
#include <future> // std::async, std::future
namespace
{
using namespace std;
using namespace fair::mq::test;
void RunWaitFor()
{
std::mutex mtx;
std::condition_variable cv;
int pid = 0;
int exit_code = 0;
thread deviceThread([&]() {
stringstream cmd;
cmd << runTestDevice << " --id waitfor_" << " --control static " << " --severity nolog";
boost::process::ipstream stdout;
boost::process::child c(cmd.str(), boost::process::std_out > stdout);
string line;
getline(stdout, line);
{
std::lock_guard<std::mutex> lock(mtx);
pid = c.id();
}
cv.notify_one();
c.wait();
exit_code = c.exit_code();
});
{
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, [&pid]{ return pid != 0; });
}
kill(pid, SIGINT);
deviceThread.join();
exit(exit_code);
}
TEST(Device, WaitFor)
{
EXPECT_EXIT(RunWaitFor(), ::testing::ExitedWithCode(0), "");
}
} // namespace

20
test/device/runner.cxx Normal file
View File

@@ -0,0 +1,20 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
#include <stdlib.h>
auto main(int argc, char** argv) -> int
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}

View File

@@ -0,0 +1,19 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
auto main(int argc, char** argv) -> int
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}

View File

@@ -21,88 +21,33 @@ class TransferTimeout : public FairMQDevice
protected: protected:
auto Run() -> void override auto Run() -> void override
{ {
bool sendMsgCanceling = false; auto sendCanceling = false;
bool receiveMsgCanceling = false; auto receiveCanceling = false;
FairMQMessagePtr msg1(NewMessage()); auto msg1 = FairMQMessagePtr{NewMessage()};
FairMQMessagePtr msg2(NewMessage()); auto msg2 = FairMQMessagePtr{NewMessage()};
if (Send(msg1, "data-out", 0, 100) == -2) if (Send(msg1, "data-out", 0, 100) == -2)
{ {
LOG(info) << "send msg canceled"; LOG(info) << "send canceled";
sendMsgCanceling = true; sendCanceling = true;
} }
else else
{ {
LOG(error) << "send msg did not cancel"; LOG(error) << "send did not cancel";
} }
if (Receive(msg2, "data-in", 0, 100) == -2) if (Receive(msg2, "data-in", 0, 100) == -2)
{ {
LOG(info) << "receive msg canceled"; LOG(info) << "receive canceled";
receiveMsgCanceling = true; receiveCanceling = true;
} }
else else
{ {
LOG(error) << "receive msg did not cancel"; LOG(error) << "receive did not cancel";
} }
bool send1PartCanceling = false; if (sendCanceling && receiveCanceling)
bool receive1PartCanceling = false;
FairMQParts parts1;
parts1.AddPart(NewMessage(10));
FairMQParts parts2;
if (Send(parts1, "data-out", 0, 100) == -2)
{
LOG(info) << "send 1 part canceled";
send1PartCanceling = true;
}
else
{
LOG(error) << "send 1 part did not cancel";
}
if (Receive(parts2, "data-in", 0, 100) == -2)
{
LOG(info) << "receive 1 part canceled";
receive1PartCanceling = true;
}
else
{
LOG(error) << "receive 1 part did not cancel";
}
bool send2PartsCanceling = false;
bool receive2PartsCanceling = false;
FairMQParts parts3;
parts3.AddPart(NewMessage(10));
parts3.AddPart(NewMessage(10));
FairMQParts parts4;
if (Send(parts3, "data-out", 0, 100) == -2)
{
LOG(info) << "send 2 parts canceled";
send2PartsCanceling = true;
}
else
{
LOG(error) << "send 2 parts did not cancel";
}
if (Receive(parts4, "data-in", 0, 100) == -2)
{
LOG(info) << "receive 2 parts canceled";
receive2PartsCanceling = true;
}
else
{
LOG(error) << "receive 2 parts did not cancel";
}
if (sendMsgCanceling && receiveMsgCanceling && send1PartCanceling && receive1PartCanceling && send2PartsCanceling && receive2PartsCanceling)
{ {
LOG(info) << "Transfer timeout test successfull"; LOG(info) << "Transfer timeout test successfull";
} }

View File

@@ -17,12 +17,9 @@
#include "devices/TestReq.cxx" #include "devices/TestReq.cxx"
#include "devices/TestSub.cxx" #include "devices/TestSub.cxx"
#include "devices/TestTransferTimeout.cxx" #include "devices/TestTransferTimeout.cxx"
#include "devices/TestWaitFor.cxx"
#include <runFairMQDevice.h>
#include <boost/program_options.hpp> #include <boost/program_options.hpp>
#include <iostream> #include <iostream>
#include <runFairMQDevice.h>
#include <string> #include <string>
namespace bpo = boost::program_options; namespace bpo = boost::program_options;
@@ -83,10 +80,6 @@ auto getDevice(const FairMQProgOptions& config) -> FairMQDevicePtr
{ {
return new PairRight; return new PairRight;
} }
else if (0 == id.find("waitfor_"))
{
return new TestWaitFor;
}
else else
{ {
cerr << "Don't know id '" << id << "'" << endl; cerr << "Don't know id '" << id << "'" << endl;

View File

@@ -0,0 +1,19 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
auto main(int argc, char** argv) -> int
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}

16
test/parts/runner.cxx Normal file
View File

@@ -0,0 +1,16 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <gtest/gtest.h>
auto main(int argc, char** argv) -> int
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
return RUN_ALL_TESTS();
}

View File

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

View File

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

View File

@@ -0,0 +1,19 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}

View File

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

View File

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

View File

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

19
test/plugins/runner.cxx Normal file
View File

@@ -0,0 +1,19 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
int main(int argc, char** argv)
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}

View File

@@ -6,12 +6,13 @@
* copied verbatim in the file "LICENSE" * * copied verbatim in the file "LICENSE" *
********************************************************************************/ ********************************************************************************/
#include <runner.h> #include "runner.h"
#include <TestEnvironment.h> #include <TestEnvironment.h>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <string> #include <string>
#include <iostream>
namespace fair namespace fair
{ {
@@ -29,7 +30,7 @@ string mqConfig = "@MQ_CONFIG@";
} /* namespace mq */ } /* namespace mq */
} /* namespace fair */ } /* namespace fair */
int main(int argc, char** argv) auto main(int argc, char** argv) -> int
{ {
::testing::InitGoogleTest(&argc, argv); ::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe"; ::testing::FLAGS_gtest_death_test_style = "threadsafe";

View File

@@ -0,0 +1,19 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <TestEnvironment.h>
#include <gtest/gtest.h>
auto main(int argc, char** argv) -> int
{
::testing::InitGoogleTest(&argc, argv);
::testing::FLAGS_gtest_death_test_style = "threadsafe";
setenv("FAIRMQ_PATH", FAIRMQ_TEST_ENVIRONMENT, 0);
return RUN_ALL_TESTS();
}