mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-15 17:41:45 +00:00
Compare commits
112 Commits
v1.3.4
...
ofi_dev_st
Author | SHA1 | Date | |
---|---|---|---|
|
92632a022c | ||
|
bd5105d609 | ||
|
080dd0a9df | ||
|
a9dfe39bf7 | ||
|
e1b1e5e21b | ||
|
763c21ffdd | ||
|
95ec56dcf0 | ||
|
4c2785dfc1 | ||
|
c09757a09c | ||
|
0f1e39ee7a | ||
|
5af604c0a9 | ||
|
f191c5099c | ||
|
3bf5f3bf45 | ||
|
11a3a41a0f | ||
|
53a5456d8c | ||
|
2eb09df1f7 | ||
|
1752e116e3 | ||
|
5eae5ccd31 | ||
|
7df278818c | ||
|
f85663bfe8 | ||
|
a262d4684a | ||
|
ad198edd59 | ||
|
9ffaa55181 | ||
|
b3005ecbdc | ||
|
ee890a7a46 | ||
|
241bf08337 | ||
|
02e1511667 | ||
|
a08a34acd5 | ||
|
b31ab1cc48 | ||
|
672e12f45b | ||
|
8e7cfacd78 | ||
|
46e2420547 | ||
|
9ae48c21f5 | ||
|
da070a407e | ||
|
35dd9578aa | ||
|
c8b7059ff7 | ||
|
60f1f1000f | ||
|
b394feca18 | ||
|
91025cbc88 | ||
|
ba4e6f72c9 | ||
|
1c5d7ca46a | ||
|
0ff8eaf84d | ||
|
7a5da93d1f | ||
|
03912e86f8 | ||
|
fc778ab3b8 | ||
|
a670b4bbf5 | ||
|
4d7a1c81c6 | ||
|
d9edcad845 | ||
|
7dcd84dd93 | ||
|
8375faf835 | ||
|
b7125b746e | ||
|
ec519cb318 | ||
|
fc94342db8 | ||
|
5e71d09e4d | ||
|
36f409dc72 | ||
|
62781389d4 | ||
|
dfc6b5c4a3 | ||
|
2047dbef59 | ||
|
61a3da8697 | ||
|
0a98fa4bac | ||
|
2358d7b03a | ||
|
0c54aab19d | ||
|
1191c3cda5 | ||
|
c0771c81d6 | ||
|
e2e476ba19 | ||
|
8ee989dbc1 | ||
|
291d00c73f | ||
|
4dc37efc12 | ||
|
5e24fdba8b | ||
|
0cb8f6166a | ||
|
ee24144d61 | ||
|
a9619a06d0 | ||
|
c605cbc3f6 | ||
|
ffd31aa09a | ||
|
a3fdfcad9e | ||
|
44c0fe5abf | ||
|
66d6d0e07b | ||
|
ffbe90b638 | ||
|
dc1d7a23c1 | ||
|
33f5590626 | ||
|
489bea5a51 | ||
|
cc0c525e0d | ||
|
25fcf13985 | ||
|
3ca0d7236a | ||
|
227a302903 | ||
|
bd899a2806 | ||
|
0b199e779a | ||
|
5e4876c947 | ||
|
3b5b2b501f | ||
|
3561255cf9 | ||
|
cbab7649be | ||
|
6ac94b7bc7 | ||
|
f9658f69a4 | ||
|
34286ef75e | ||
|
1a07137dda | ||
|
1f42f49ae5 | ||
|
d40bbfe208 | ||
|
310b9647b5 | ||
|
919193a1ad | ||
|
0cfa9192d7 | ||
|
c40bd7d6a9 | ||
|
4951433330 | ||
|
1b53538d8c | ||
|
d4a4ea14d2 | ||
|
ffab4ac78c | ||
|
ce4062f3a0 | ||
|
f8824335a5 | ||
|
2e7005225e | ||
|
dfa1b68867 | ||
|
00800f16f1 | ||
|
44acd4997d | ||
|
cfb727181f |
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,6 @@
|
||||
Describe your proposal.
|
||||
|
||||
Mention any issue this PR is resolves or is related to.
|
||||
Mention any issue this PR resolves or is related to.
|
||||
|
||||
---
|
||||
|
||||
|
@@ -6,7 +6,7 @@
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
cmake_minimum_required(VERSION 3.9.4 FATAL_ERROR)
|
||||
cmake_minimum_required(VERSION 3.10 FATAL_ERROR)
|
||||
|
||||
|
||||
# Project ######################################################################
|
||||
@@ -19,6 +19,12 @@ get_git_version()
|
||||
project(FairMQ VERSION ${PROJECT_VERSION} LANGUAGES CXX)
|
||||
message(STATUS "${BWhite}${PROJECT_NAME}${CR} ${PROJECT_GIT_VERSION} from ${PROJECT_DATE}")
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(PROJECT_MIN_CXX_STANDARD 14)
|
||||
else()
|
||||
set(PROJECT_MIN_CXX_STANDARD 11)
|
||||
endif()
|
||||
|
||||
set_fairmq_defaults()
|
||||
|
||||
include(CTest)
|
||||
@@ -32,6 +38,7 @@ cmake_dependent_option(BUILD_TESTING "Build tests." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_NANOMSG_TRANSPORT "Build nanomsg transport." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_DDS_PLUGIN "Build DDS plugin." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_PMIX_PLUGIN "Build PMIx plugin." OFF "BUILD_FAIRMQ" OFF)
|
||||
cmake_dependent_option(BUILD_EXAMPLES "Build FairMQ examples." ON "BUILD_FAIRMQ" OFF)
|
||||
option(BUILD_DOCS "Build FairMQ documentation." OFF)
|
||||
option(FAST_BUILD "Fast production build. Not recommended for development." OFF)
|
||||
@@ -47,35 +54,69 @@ set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
||||
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PUBLIC Boost VERSION 1.64 REQUIRED
|
||||
COMPONENTS program_options thread system filesystem regex date_time signals
|
||||
)
|
||||
find_package2(PUBLIC FairLogger VERSION 1.2.0 REQUIRED)
|
||||
find_package2(PRIVATE ZeroMQ VERSION 4.1.5 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE nanomsg REQUIRED)
|
||||
set(PROJECT_nanomsg_VERSION 1.1.3) # Once upstream releases 1.1.5, we should bump again and use version check
|
||||
find_package2(PRIVATE msgpack VERSION 3.1.0 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
find_package2(PRIVATE OFI VERSION 1.6.0 REQUIRED COMPONENTS fi_sockets fi_verbs)
|
||||
find_package2(PRIVATE Protobuf VERSION 3.4.0 REQUIRED)
|
||||
find_package2(PRIVATE asiofi REQUIRED
|
||||
VERSION 0.2.0
|
||||
)
|
||||
find_package2(PRIVATE OFI REQUIRED
|
||||
VERSION ${asiofi_OFI_VERSION}
|
||||
COMPONENTS ${asiofi_OFI_COMPONENTS}
|
||||
)
|
||||
find_package2(PRIVATE AZMQ REQUIRED)
|
||||
set(PROJECT_AZMQ_VERSION 1.0.2)
|
||||
endif()
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
find_package2(PRIVATE msgpack REQUIRED
|
||||
VERSION 3.1.0
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_FAIRMQ)
|
||||
find_package2(PUBLIC Boost REQUIRED
|
||||
VERSION 1.64 ${asiofi_Boost_VERSION}
|
||||
|
||||
COMPONENTS
|
||||
container
|
||||
program_options
|
||||
filesystem
|
||||
date_time
|
||||
regex
|
||||
${asiofi_Boost_COMPONENTS}
|
||||
)
|
||||
find_package2(PUBLIC FairLogger REQUIRED
|
||||
VERSION 1.2.0
|
||||
)
|
||||
find_package2(PRIVATE ZeroMQ REQUIRED
|
||||
VERSION 4.1.5
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
find_package2(PRIVATE DDS VERSION 2.0 REQUIRED)
|
||||
find_package2(PRIVATE DDS VERSION 2.2 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
find_package2(PRIVATE PMIx VERSION 2.1.4 REQUIRED)
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
find_package2(PRIVATE GTest VERSION 1.7.0 REQUIRED)
|
||||
find_package2(PRIVATE GTest REQUIRED
|
||||
VERSION 1.7.0
|
||||
)
|
||||
endif()
|
||||
|
||||
if(BUILD_DOCS)
|
||||
find_package2(PRIVATE Doxygen VERSION 1.8.8 REQUIRED COMPONENTS dot OPTIONAL_COMPONENTS mscgen dia)
|
||||
find_package2(PRIVATE Doxygen REQUIRED
|
||||
VERSION 1.8.8
|
||||
COMPONENTS dot
|
||||
OPTIONAL_COMPONENTS mscgen dia
|
||||
)
|
||||
endif()
|
||||
################################################################################
|
||||
|
||||
@@ -101,7 +142,7 @@ endif()
|
||||
if(BUILD_DOCS)
|
||||
set(DOXYGEN_OUTPUT_DIRECTORY doxygen)
|
||||
set(DOXYGEN_PROJECT_NUMBER ${PROJECT_GIT_VERSION})
|
||||
set(DOXYGEN_PROJECT_BRIEF "C++ Message Passing Framework")
|
||||
set(DOXYGEN_PROJECT_BRIEF "C++ Message Queuing Library and Framework")
|
||||
set(DOXYGEN_USE_MDFILE_AS_MAINPAGE README.md)
|
||||
set(DOXYGEN_HTML_FOOTER docs/footer.html)
|
||||
doxygen_add_docs(doxygen README.md fairmq)
|
||||
@@ -120,6 +161,9 @@ endif()
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS dds_plugin)
|
||||
endif()
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
|
||||
endif()
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
list(APPEND PROJECT_PACKAGE_COMPONENTS nanomsg_transport)
|
||||
endif()
|
||||
@@ -151,7 +195,7 @@ if(BUILD_DDS_PLUGIN)
|
||||
)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
install(FILES cmake/FindOFI.cmake
|
||||
install(FILES cmake/FindAZMQ.cmake
|
||||
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
|
||||
)
|
||||
endif()
|
||||
@@ -166,6 +210,8 @@ install_cmake_package()
|
||||
|
||||
|
||||
# Summary ######################################################################
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}CXX STANDARD${CR} ${BGreen}C++${CMAKE_CXX_STANDARD}${CR} (>= C++${PROJECT_MIN_CXX_STANDARD}, change with ${BMagenta}-DCMAKE_CXX_STANDARD=17${CR})")
|
||||
if(CMAKE_CXX_FLAGS)
|
||||
message(STATUS " ")
|
||||
message(STATUS " ${Cyan}GLOBAL CXX FLAGS${CR} ${BGreen}${CMAKE_CXX_FLAGS}${CR}")
|
||||
@@ -218,6 +264,8 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
|
||||
elseif(${dep} STREQUAL msgpack)
|
||||
get_target_property(msgpack_include msgpackc-cxx INTERFACE_INCLUDE_DIRECTORIES)
|
||||
get_filename_component(prefix ${msgpack_include}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL asiofi)
|
||||
set(prefix ${asiofi_ROOT})
|
||||
elseif(${dep} STREQUAL OFI)
|
||||
get_filename_component(prefix ${${dep}_INCLUDE_DIRS}/.. ABSOLUTE)
|
||||
elseif(${dep} STREQUAL nanomsg)
|
||||
@@ -257,9 +305,9 @@ else()
|
||||
endif()
|
||||
message(STATUS " ${BWhite}nanomsg_transport${CR} ${nn_summary}")
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
|
||||
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (requires C++14) (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
|
||||
else()
|
||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (requires C++14) (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
@@ -268,6 +316,12 @@ else()
|
||||
set(dds_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DDS_PLUGIN=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
set(pmix_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
|
||||
else()
|
||||
set(pmix_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_PMIX_PLUGIN=ON${CR})")
|
||||
endif()
|
||||
message(STATUS " ${BWhite}pmix_plugin${CR} ${pmix_summary}")
|
||||
if(BUILD_EXAMPLES)
|
||||
set(examples_summary "${BGreen}YES${CR} (default, disable with ${BMagenta}-DBUILD_EXAMPLES=OFF${CR})")
|
||||
else()
|
||||
|
@@ -4,6 +4,7 @@ Eulisse, Giulio
|
||||
Karabowicz, Radoslaw
|
||||
Kretz, Matthias <kretz@kde.org>
|
||||
Krzewicki, Mikolaj
|
||||
Mrnjavac, Teo <teo.m@cern.ch>
|
||||
Neskovic, Gvozden
|
||||
Richter, Matthias
|
||||
Uhlig, Florian
|
||||
|
@@ -27,6 +27,7 @@ Set(configure_options "${configure_options};-DCTEST_USE_LAUNCHERS=${CTEST_USE_LA
|
||||
Set(configure_options "${configure_options};-DDISABLE_COLOR=ON")
|
||||
Set(configure_options "${configure_options};-DCMAKE_PREFIX_PATH=$ENV{SIMPATH}")
|
||||
Set(configure_options "${configure_options};-DBUILD_NANOMSG_TRANSPORT=ON")
|
||||
# Set(configure_options "${configure_options};-DBUILD_OFI_TRANSPORT=ON")
|
||||
Set(configure_options "${configure_options};-DBUILD_DDS_PLUGIN=ON")
|
||||
Set(configure_options "${configure_options};-DFAST_BUILD=ON")
|
||||
Set(configure_options "${configure_options};-DCOTIRE_MAXIMUM_NUMBER_OF_UNITY_INCLUDES=-j$ENV{number_of_processors}")
|
||||
@@ -57,7 +58,8 @@ Ctest_Configure(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
Ctest_Build(BUILD "${CTEST_BINARY_DIRECTORY}")
|
||||
|
||||
Ctest_Test(BUILD "${CTEST_BINARY_DIRECTORY}"
|
||||
PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
# PARALLEL_LEVEL $ENV{number_of_processors}
|
||||
PARALLEL_LEVEL 1
|
||||
RETURN_VALUE _ctest_test_ret_val
|
||||
)
|
||||
If("$ENV{do_codecov_upload}")
|
||||
|
31
Jenkinsfile
vendored
31
Jenkinsfile
vendored
@@ -8,6 +8,9 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def fairsoft = spec.fairsoft
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes["${prefix}/${label}"] = {
|
||||
node(label) {
|
||||
githubNotify(context: "${prefix}/${label}", description: 'Building ...', status: 'PENDING')
|
||||
@@ -15,12 +18,31 @@ def jobMatrix(String prefix, List specs, Closure callback) {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
}
|
||||
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=$JOB_BASE_NAME" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
@@ -44,14 +66,15 @@ pipeline{
|
||||
steps{
|
||||
script {
|
||||
def build_jobs = jobMatrix('alfa-ci/build', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
sh './Dart.sh alfa_ci Dart.cfg'
|
||||
}
|
||||
|
||||
def profile_jobs = jobMatrix('alfa-ci/codecov', [
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
withCredentials([string(credentialsId: 'fairmq_codecov_token', variable: 'CODECOV_TOKEN')]) {
|
||||
sh './Dart.sh codecov Dart.cfg'
|
||||
|
@@ -8,12 +8,40 @@ def buildMatrix(List specs, Closure callback) {
|
||||
def nodes = [:]
|
||||
for (spec in specs) {
|
||||
def label = specToLabel(spec)
|
||||
def fairsoft = spec.fairsoft
|
||||
def os = spec.os
|
||||
def compiler = spec.compiler
|
||||
nodes[label] = {
|
||||
node(label) {
|
||||
try {
|
||||
deleteDir()
|
||||
checkout scm
|
||||
|
||||
sh """\
|
||||
echo "export SIMPATH=\${SIMPATH_PREFIX}${fairsoft}" >> Dart.cfg
|
||||
echo "export FAIRSOFT_VERSION=${fairsoft}" >> Dart.cfg
|
||||
"""
|
||||
if (os =~ /Debian/ && compiler =~ /gcc8/) {
|
||||
sh '''\
|
||||
echo "source /etc/profile.d/modules.sh" >> Dart.cfg
|
||||
echo "module use /cvmfs/it.gsi.de/modulefiles" >> Dart.cfg
|
||||
echo "module load compiler/gcc/8" >> Dart.cfg
|
||||
'''
|
||||
}
|
||||
if (os =~ /MacOS/) {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=clang++'\" >> Dart.cfg"
|
||||
} else {
|
||||
sh "echo \"export EXTRA_FLAGS='-DCMAKE_CXX_COMPILER=g++'\" >> Dart.cfg"
|
||||
}
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=\\\$SIMPATH/bin:\\\$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=dev" >> Dart.cfg
|
||||
echo "echo \\\$PATH" >> Dart.cfg
|
||||
'''
|
||||
sh 'cat Dart.cfg'
|
||||
|
||||
callback.call(spec, label)
|
||||
|
||||
deleteDir()
|
||||
@@ -35,16 +63,10 @@ pipeline{
|
||||
steps{
|
||||
script {
|
||||
parallel(buildMatrix([
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc4.9', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.11', arch: 'x86_64', compiler: 'AppleLLVM8.0.0', fairsoft: 'may18'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM9.0.0', fairsoft: 'may18'],
|
||||
[os: 'Debian8', arch: 'x86_64', compiler: 'gcc8.1.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.13', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
[os: 'MacOS10.14', arch: 'x86_64', compiler: 'AppleLLVM10.0.0', fairsoft: 'fairmq_dev'],
|
||||
]) { spec, label ->
|
||||
sh '''\
|
||||
echo "export BUILDDIR=$PWD/build" >> Dart.cfg
|
||||
echo "export SOURCEDIR=$PWD" >> Dart.cfg
|
||||
echo "export PATH=$SIMPATH/bin:$PATH" >> Dart.cfg
|
||||
echo "export GIT_BRANCH=dev" >> Dart.cfg
|
||||
'''
|
||||
sh './Dart.sh Nightly Dart.cfg'
|
||||
sh './Dart.sh Profile Dart.cfg'
|
||||
})
|
||||
|
@@ -1,5 +1,5 @@
|
||||
<!-- {#mainpage} -->
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) [](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&utm_medium=referral&utm_content=FairRootGroup/FairMQ&utm_campaign=Badge_Grade)
|
||||
# FairMQ [](COPYRIGHT) [](https://alfa-ci.gsi.de/blue/organizations/jenkins/FairRootGroup%2FFairMQ/branches) [](https://codecov.io/gh/FairRootGroup/FairMQ/branch/master) [](https://scan.coverity.com/projects/fairrootgroup-fairmq) [](https://www.codacy.com/app/dennisklein/FairMQ?utm_source=github.com&utm_medium=referral&utm_content=FairRootGroup/FairMQ&utm_campaign=Badge_Grade)
|
||||
|
||||
C++ Message Queuing Library and Framework
|
||||
|
||||
@@ -38,7 +38,7 @@ a simulation, reconstruction and analysis framework.
|
||||
* PUBLIC: [**Boost**](https://www.boost.org/), [**FairLogger**](https://github.com/FairRootGroup/FairLogger)
|
||||
* BUILD: [CMake](https://cmake.org/), [GTest](https://github.com/google/googletest), [Doxygen](http://www.doxygen.org/)
|
||||
* PRIVATE: [ZeroMQ](http://zeromq.org/), [Msgpack](https://msgpack.org/index.html), [nanomsg](http://nanomsg.org/),
|
||||
[OFI](https://ofiwg.github.io/libfabric/), [Protobuf](https://developers.google.com/protocol-buffers/), [DDS](http://dds.gsi.de)
|
||||
[asiofi](https://github.com/FairRootGroup/asiofi), [DDS](http://dds.gsi.de), [PMIx](https://pmix.org/), [AZMQ](https://github.com/zeromq/azmq), [asiofi](https://github.com/FairRootGroup/asiofi)
|
||||
|
||||
Supported platforms: Linux and MacOS.
|
||||
|
||||
@@ -51,7 +51,7 @@ cmake -DCMAKE_INSTALL_PREFIX=./fairmq_install ../fairmq
|
||||
cmake --build . --target install
|
||||
```
|
||||
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PROTOBUF`, or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
If dependencies are not installed in standard system directories, you can hint the installation location via `-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...`. `{DEPENDENCY}` can be `GTEST`, `BOOST`, `FAIRLOGGER`, `ZEROMQ`, `MSGPACK`, `NANOMSG`, `OFI`, `PMIX`, `ASIOFI`, `AZMQ` or `DDS` (`*_ROOT` variables can also be environment variables).
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -104,6 +104,7 @@ On command line:
|
||||
* `-DBUILD_NANOMSG_TRANSPORT=ON` enables building of nanomsg transport.
|
||||
* `-DBUILD_OFI_TRANSPORT=ON` enables building of the experimental OFI transport.
|
||||
* `-DBUILD_DDS_PLUGIN=ON` enables building of the DDS plugin.
|
||||
* `-DBUILD_PMIX_PLUGIN=ON` enables building of the PMIx plugin.
|
||||
* `-DBUILD_DOCS=ON` enables building of API docs.
|
||||
* You can hint non-system installations for dependent packages, see the #Installation section above
|
||||
|
||||
@@ -119,7 +120,7 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
|
||||
| `${FairMQ_#COMPONENT#_FOUND}` | `TRUE` if this component was built |
|
||||
| `${FairMQ_VERSION}` | the version in format `MAJOR.MINOR.PATCH` |
|
||||
| `${FairMQ_GIT_VERSION}` | the version in the format returned by `git describe --tags --dirty --match "v*"` |
|
||||
| `${FairMQ_ROOT}` | the actual installation prefix, notice the difference to the hint variable `FAIRMQ_ROOT` |
|
||||
| `${FairMQ_PREFIX}` | the actual installation prefix |
|
||||
| `${FairMQ_BINDIR}` | the installation bin directory |
|
||||
| `${FairMQ_INCDIR}` | the installation include directory |
|
||||
| `${FairMQ_LIBDIR}` | the installation lib directory |
|
||||
|
@@ -13,7 +13,7 @@ set(@PROJECT_NAME@_VERSION @PROJECT_VERSION@)
|
||||
set(@PROJECT_NAME@_GIT_VERSION @PROJECT_GIT_VERSION@)
|
||||
set(@PROJECT_NAME@_GIT_DATE @PROJECT_GIT_DATE@)
|
||||
|
||||
set_and_check(@PROJECT_NAME@_ROOT @PACKAGE_CMAKE_INSTALL_PREFIX@)
|
||||
set_and_check(@PROJECT_NAME@_PREFIX @PACKAGE_CMAKE_INSTALL_PREFIX@)
|
||||
set_and_check(@PROJECT_NAME@_BINDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_BINDIR@)
|
||||
set_and_check(@PROJECT_NAME@_INCDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@CMAKE_INSTALL_INCLUDEDIR@)
|
||||
set_and_check(@PROJECT_NAME@_LIBDIR @PACKAGE_CMAKE_INSTALL_PREFIX@/@PROJECT_INSTALL_LIBDIR@)
|
||||
|
@@ -40,6 +40,7 @@ macro(set_fairmq_cmake_policies)
|
||||
CMP0042 # MACOSX_RPATH is enabled by default.
|
||||
CMP0048 # The ``project()`` command manages VERSION variables.
|
||||
CMP0054 # Only interpret ``if()`` arguments as variables or keywords when unquoted.
|
||||
CMP0074 # ``find_package()`` uses ``<PackageName>_ROOT`` variables.
|
||||
)
|
||||
if(POLICY ${policy})
|
||||
cmake_policy(SET ${policy} NEW)
|
||||
@@ -115,11 +116,9 @@ macro(set_fairmq_defaults)
|
||||
# Handle C++ standard level
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
if(NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
elseif(${CMAKE_CXX_STANDARD} LESS 11)
|
||||
message(FATAL_ERROR "A minimum CMAKE_CXX_STANDARD of 11 is required.")
|
||||
elseif(${CMAKE_CXX_STANDARD} GREATER 11)
|
||||
message(WARNING "A CMAKE_CXX_STANDARD of ${CMAKE_CXX_STANDARD} (greater than 11) is not tested. Use on your own risk.")
|
||||
set(CMAKE_CXX_STANDARD ${PROJECT_MIN_CXX_STANDARD})
|
||||
elseif(${CMAKE_CXX_STANDARD} LESS ${PROJECT_MIN_CXX_STANDARD})
|
||||
message(FATAL_ERROR "A minimum CMAKE_CXX_STANDARD of ${PROJECT_MIN_CXX_STANDARD} is required.")
|
||||
endif()
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
@@ -261,6 +260,8 @@ endfunction()
|
||||
|
||||
# Configure/Install CMake package
|
||||
macro(install_cmake_package)
|
||||
list(SORT PROJECT_PACKAGE_DEPENDENCIES)
|
||||
list(SORT PROJECT_INTERFACE_PACKAGE_DEPENDENCIES)
|
||||
include(CMakePackageConfigHelpers)
|
||||
set(PACKAGE_INSTALL_DESTINATION
|
||||
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_GIT_VERSION}
|
||||
@@ -293,35 +294,48 @@ macro(install_cmake_package)
|
||||
endmacro()
|
||||
|
||||
macro(find_package2 qualifier pkgname)
|
||||
cmake_parse_arguments(ARGS "" "VERSION" "COMPONENTS" ${ARGN})
|
||||
cmake_parse_arguments(ARGS "" "" "VERSION;COMPONENTS" ${ARGN})
|
||||
|
||||
string(TOUPPER ${pkgname} pkgname_upper)
|
||||
set(old_CPP ${CMAKE_PREFIX_PATH})
|
||||
set(CMAKE_PREFIX_PATH ${${pkgname_upper}_ROOT} $ENV{${pkgname_upper}_ROOT} ${CMAKE_PREFIX_PATH})
|
||||
unset(__version__)
|
||||
if(ARGS_VERSION)
|
||||
list(GET ARGS_VERSION 0 __version__)
|
||||
list(LENGTH ARGS_VERSION __length__)
|
||||
foreach(v IN LISTS ARGS_VERSION)
|
||||
if(${v} VERSION_GREATER ${__version__})
|
||||
set(__version__ ${v})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
if(ARGS_COMPONENTS)
|
||||
find_package(${pkgname} ${ARGS_VERSION} QUIET COMPONENTS ${ARGS_COMPONENTS} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
list(REMOVE_DUPLICATES ARGS_COMPONENTS)
|
||||
find_package(${pkgname} ${__version__} QUIET COMPONENTS ${ARGS_COMPONENTS} ${ARGS_UNPARSED_ARGUMENTS})
|
||||
else()
|
||||
find_package(${pkgname} ${ARGS_VERSION} QUIET ${ARGS_UNPARSED_ARGUMENTS})
|
||||
find_package(${pkgname} ${__version__} QUIET ${ARGS_UNPARSED_ARGUMENTS})
|
||||
endif()
|
||||
set(CMAKE_PREFIX_PATH ${old_CPP})
|
||||
unset(old_CPP)
|
||||
|
||||
if(${pkgname}_FOUND)
|
||||
if(${qualifier} STREQUAL PRIVATE)
|
||||
set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
elseif(${qualifier} STREQUAL PUBLIC)
|
||||
set(PROJECT_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_PACKAGE_DEPENDENCIES ${PROJECT_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
elseif(${qualifier} STREQUAL INTERFACE)
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${ARGS_VERSION})
|
||||
set(PROJECT_INTERFACE_${pkgname}_VERSION ${__version__})
|
||||
set(PROJECT_INTERFACE_${pkgname}_COMPONENTS ${ARGS_COMPONENTS})
|
||||
set(PROJECT_INTERFACE_PACKAGE_DEPENDENCIES ${PROJECT_INTERFACE_PACKAGE_DEPENDENCIES} ${pkgname})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(__version__)
|
||||
endmacro()
|
||||
|
57
cmake/FindAZMQ.cmake
Normal file
57
cmake/FindAZMQ.cmake
Normal file
@@ -0,0 +1,57 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
#
|
||||
# ###########################
|
||||
# # Locate the AZMQ library #
|
||||
# ###########################
|
||||
#
|
||||
#
|
||||
# Usage:
|
||||
#
|
||||
# find_package(AZMQ [version] [QUIET] [REQUIRED])
|
||||
#
|
||||
#
|
||||
# Defines the following variables:
|
||||
#
|
||||
# AZMQ_FOUND - Found the ZeroMQ library
|
||||
# AZMQ_INCLUDE_DIR (CMake cache) - Include directory
|
||||
#
|
||||
#
|
||||
# Accepts the following variables as hints for installation directories:
|
||||
#
|
||||
# AZMQ_ROOT (CMake var, ENV var)
|
||||
#
|
||||
#
|
||||
# If the above variables are not defined, or if ZeroMQ could not be found there,
|
||||
# it will look for it in the system directories. Custom ZeroMQ installations
|
||||
# will always have priority over system ones.
|
||||
#
|
||||
|
||||
if(NOT AZMQ_ROOT)
|
||||
set(AZMQ_ROOT $ENV{AZMQ_ROOT})
|
||||
endif()
|
||||
|
||||
find_path(AZMQ_INCLUDE_DIR
|
||||
NAMES azmq/socket.hpp
|
||||
HINTS ${AZMQ_ROOT} $ENV{AZMQ_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
DOC "AZMQ include directory"
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(AZMQ
|
||||
REQUIRED_VARS AZMQ_INCLUDE_DIR
|
||||
)
|
||||
|
||||
if(AZMQ_FOUND AND NOT TARGET AZMQ::AZMQ)
|
||||
add_library(AZMQ::AZMQ INTERFACE IMPORTED)
|
||||
set_target_properties(AZMQ::AZMQ PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${AZMQ_INCLUDE_DIR}
|
||||
INTERFACE_LINK_LIBRARIES "libzmq;Boost::boost;Boost::container;Boost::system"
|
||||
)
|
||||
endif()
|
@@ -1,67 +0,0 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
find_path(FLATBUFFERS_INCLUDE_DIR
|
||||
NAMES flatbuffers/flatbuffers.h
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_path(FLATBUFFERS_LIBRARY_DIR
|
||||
NAMES libflatbuffers.a
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_library(FLATBUFFERS_STATIC_LIBRARY
|
||||
NAMES libflatbuffers.a
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
find_path(FLATBUFFERS_BINARY_DIR
|
||||
NAMES flatc
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
find_program(FLATBUFFERS_BINARY_FLATC
|
||||
NAMES flatc
|
||||
HINTS ${FLATBUFFERS_ROOT} $ENV{FLATBUFFERS_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(FlatBuffers
|
||||
REQUIRED_VARS
|
||||
FLATBUFFERS_INCLUDE_DIR
|
||||
FLATBUFFERS_LIBRARY_DIR
|
||||
FLATBUFFERS_BINARY_DIR
|
||||
)
|
||||
|
||||
# idempotently import targets
|
||||
if(NOT TARGET FlatBuffers)
|
||||
if(FLATBUFFERS_FOUND)
|
||||
# import target
|
||||
add_library(FlatBuffers STATIC IMPORTED)
|
||||
set_target_properties(FlatBuffers PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${FLATBUFFERS_INCLUDE_DIR}
|
||||
IMPORTED_LOCATION ${FLATBUFFERS_STATIC_LIBRARY}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(NOT TARGET FlatBuffers::flatc)
|
||||
if(FLATBUFFERS_FOUND)
|
||||
# import target
|
||||
add_executable(FlatBuffers::flatc IMPORTED)
|
||||
set_target_properties(FlatBuffers::flatc PROPERTIES
|
||||
IMPORTED_LOCATION ${FLATBUFFERS_BINARY_FLATC}
|
||||
)
|
||||
endif()
|
||||
endif()
|
@@ -1,89 +0,0 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
# According to the docs the modification of the PKG_CONFIG_PATH environment should
|
||||
# not be necessary, but it does not work otherwise.
|
||||
if(OFI_ROOT)
|
||||
list(APPEND CMAKE_PREFIX_PATH "${OFI_ROOT}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "${OFI_ROOT}/lib/pkgconfig:" $ENV{PKG_CONFIG_PATH})
|
||||
endif()
|
||||
|
||||
if(ENV{OFI_ROOT})
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{OFI_ROOT}/lib/pkgconfig")
|
||||
set(ENV{PKG_CONFIG_PATH} "$ENV{OFI_ROOT}/lib/pkgconfig:" $ENV{PKG_CONFIG_PATH})
|
||||
endif()
|
||||
|
||||
# This should be the default as of CMake 3.1, but it is not set. BUG? Also, it does not work
|
||||
set(PKG_CONFIG_USE_CMAKE_PREFIX_PATH 1)
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
if(PKG_CONFIG_FOUND)
|
||||
# Find include dir and dependencies from pkgconfig
|
||||
pkg_check_modules(_OFI libfabric QUIET)
|
||||
|
||||
# Retrieve version from pkgconfig
|
||||
execute_process(
|
||||
COMMAND ${PKG_CONFIG_EXECUTABLE} libfabric --modversion
|
||||
OUTPUT_VARIABLE OFI_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
# The IMPORTED_TARGET option of the pkg_check_modules() function is useless,
|
||||
# so let's build it ourselves
|
||||
find_library(OFI_LIBFABRIC
|
||||
NAMES libfabric.so libfabric.dylib
|
||||
HINTS ${OFI_ROOT} $ENV{OFI_ROOT}
|
||||
PATH_SUFFIXES lib
|
||||
)
|
||||
|
||||
# Just take the include dirs found by the PkgConfig module
|
||||
set(OFI_INCLUDE_DIRS ${_OFI_INCLUDE_DIRS})
|
||||
|
||||
# Find fi_info command to be able to check required features of the OFI installation
|
||||
find_program(OFI_INFO_EXECUTABLE
|
||||
NAMES fi_info
|
||||
HINTS ${OFI_ROOT} $ENV{OFI_ROOT}
|
||||
PATH_SUFFIXES bin
|
||||
)
|
||||
|
||||
# Detect ofi providers, they can be required via the COMPONENTS argument of find_package
|
||||
if(OFI_INFO_EXECUTABLE)
|
||||
execute_process(
|
||||
COMMAND ${OFI_INFO_EXECUTABLE} -l
|
||||
OUTPUT_VARIABLE output
|
||||
)
|
||||
string(REPLACE "\n" ";" lines ${output})
|
||||
foreach(line IN LISTS lines)
|
||||
string(REGEX
|
||||
MATCH "^([a-zA-Z0-9_]+):"
|
||||
found "${line}"
|
||||
)
|
||||
if(found)
|
||||
string(TOLOWER "${CMAKE_MATCH_1}" provider)
|
||||
set(OFI_fi_${provider}_FOUND TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
# Check search result, check version constraints and print status
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(OFI
|
||||
REQUIRED_VARS OFI_LIBFABRIC OFI_INCLUDE_DIRS OFI_INFO_EXECUTABLE
|
||||
VERSION_VAR OFI_VERSION
|
||||
HANDLE_COMPONENTS
|
||||
)
|
||||
endif()
|
||||
|
||||
if(NOT TARGET OFI::libfabric AND OFI_FOUND)
|
||||
# Define an imported target
|
||||
add_library(OFI::libfabric SHARED IMPORTED GLOBAL)
|
||||
set_target_properties(OFI::libfabric PROPERTIES
|
||||
IMPORTED_LOCATION ${OFI_LIBFABRIC}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${OFI_INCLUDE_DIRS}
|
||||
)
|
||||
endif()
|
67
cmake/FindPMIx.cmake
Normal file
67
cmake/FindPMIx.cmake
Normal file
@@ -0,0 +1,67 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
find_path(PMIx_INCLUDE_DIR
|
||||
NAMES pmix.h
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
find_path(PMIx_LIBRARY_DIR
|
||||
NAMES libpmix.dylib libpmix.so
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES lib lib64
|
||||
)
|
||||
|
||||
find_library(PMIx_LIBRARY_SHARED
|
||||
NAMES libpmix.dylib libpmix.so
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES lib lib64
|
||||
)
|
||||
|
||||
find_file(PMIx_VERSION_FILE
|
||||
NAMES pmix_version.h
|
||||
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
|
||||
PATH_SUFFIXES include
|
||||
)
|
||||
|
||||
file(READ "${PMIx_VERSION_FILE}" __version_raw)
|
||||
string(REGEX MATCH "#define PMIX_VERSION_MAJOR ([0-9]?)L?"
|
||||
__version_major_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define PMIX_VERSION_MINOR ([0-9]?)L?"
|
||||
__version_minor_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define PMIX_VERSION_RELEASE ([0-9]?)L?"
|
||||
__version_patch_raw "${__version_raw}"
|
||||
)
|
||||
set(PMIx_VERSION_PATCH "${CMAKE_MATCH_1}")
|
||||
|
||||
set(PMIx_VERSION "${PMIx_VERSION_MAJOR}.${PMIx_VERSION_MINOR}.${PMIx_VERSION_PATCH}")
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PMIx
|
||||
REQUIRED_VARS
|
||||
PMIx_INCLUDE_DIR
|
||||
PMIx_LIBRARY_DIR
|
||||
PMIx_LIBRARY_SHARED
|
||||
|
||||
VERSION_VAR PMIx_VERSION
|
||||
)
|
||||
|
||||
if(NOT TARGET PMIx::libpmix AND PMIx_FOUND)
|
||||
add_library(PMIx::libpmix SHARED IMPORTED)
|
||||
set_target_properties(PMIx::libpmix PROPERTIES
|
||||
IMPORTED_LOCATION ${PMIx_LIBRARY_SHARED}
|
||||
INTERFACE_INCLUDE_DIRECTORIES ${PMIx_INCLUDE_DIR}
|
||||
)
|
||||
endif()
|
@@ -47,6 +47,8 @@
|
||||
#
|
||||
#
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
function(add_testsuite suitename)
|
||||
cmake_parse_arguments(testsuite
|
||||
""
|
||||
@@ -73,13 +75,23 @@ function(add_testsuite suitename)
|
||||
target_compile_definitions("${target}" PUBLIC ${testsuite_DEFINITIONS})
|
||||
endif()
|
||||
|
||||
add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
|
||||
# add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
|
||||
if(testsuite_TIMEOUT)
|
||||
set_tests_properties("${suitename}" PROPERTIES TIMEOUT ${testsuite_TIMEOUT})
|
||||
# set_tests_properties("${suitename}" PROPERTIES TIMEOUT ${testsuite_TIMEOUT})
|
||||
else()
|
||||
set(testsuite_TIMEOUT 10)
|
||||
endif()
|
||||
if(testsuite_RUN_SERIAL)
|
||||
set_tests_properties("${suitename}" PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL})
|
||||
# set_tests_properties("${suitename}" PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL})
|
||||
else()
|
||||
set(testsuite_RUN_SERIAL OFF)
|
||||
endif()
|
||||
gtest_discover_tests(${target}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
TEST_PREFIX ${suitename}.
|
||||
PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL}
|
||||
TIMEOUT ${testsuite_TIMEOUT}
|
||||
)
|
||||
|
||||
list(APPEND ALL_TEST_TARGETS ${target})
|
||||
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
|
||||
|
@@ -31,14 +31,15 @@ The state machine can be querried and controlled via `GetCurrentStateName()` and
|
||||
If the device is running in interactive mode (default), states can be changed via keyboard input:
|
||||
|
||||
- `'h'` - help
|
||||
- `'p'` - pause
|
||||
- `'r'` - run
|
||||
- `'s'` - stop
|
||||
- `'t'` - reset task
|
||||
- `'d'` - reset device
|
||||
- `'q'` - end
|
||||
- `'j'` - init task
|
||||
- `'i'` - init device
|
||||
- `'i'` - initialize
|
||||
- `'b'` - bind
|
||||
- `'x'` - connect
|
||||
|
||||
Without the interactive mode, for example for a run in background, two other control mechanisms are available:
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 175 KiB |
@@ -31,16 +31,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-1.sh.in ${CMAKE_CUR
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh)
|
||||
|
||||
add_test(NAME Example-1-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
|
||||
set_tests_properties(Example-1-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
|
||||
set_tests_properties(Example.1-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-1-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
|
||||
set_tests_properties(Example-1-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-1-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
|
||||
set_tests_properties(Example-1-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
|
||||
set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -39,16 +39,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-1-n-1.json ${CMAKE_CURRENT_BINARY_
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh)
|
||||
|
||||
add_test(NAME Example-1-n-1-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
|
||||
set_tests_properties(Example-1-n-1-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-n-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
|
||||
set_tests_properties(Example.1-n-1.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-1-n-1-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
|
||||
set_tests_properties(Example-1-n-1-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-n-1.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh nanomsg)
|
||||
set_tests_properties(Example.1-n-1.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-1-n-1-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
|
||||
set_tests_properties(Example-1-n-1-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
add_test(NAME Example.1-n-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
|
||||
set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -8,6 +8,7 @@
|
||||
|
||||
add_subdirectory(1-1)
|
||||
add_subdirectory(1-n-1)
|
||||
add_subdirectory(builtin-devices)
|
||||
add_subdirectory(copypush)
|
||||
add_subdirectory(dds)
|
||||
add_subdirectory(multipart)
|
||||
@@ -15,5 +16,6 @@ add_subdirectory(multiple-channels)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_subdirectory(multiple-transports)
|
||||
endif()
|
||||
add_subdirectory(readout)
|
||||
add_subdirectory(region)
|
||||
add_subdirectory(req-rep)
|
||||
|
50
examples/builtin-devices/CMakeLists.txt
Normal file
50
examples/builtin-devices/CMakeLists.txt
Normal file
@@ -0,0 +1,50 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh)
|
||||
|
||||
# test
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh)
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq)
|
||||
set_tests_properties(Example.BuiltinDevices.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg)
|
||||
set_tests_properties(Example.BuiltinDevices.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem)
|
||||
set_tests_properties(Example.BuiltinDevices.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example.BuiltinDevices.multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh nanomsg true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example.BuiltinDevices.multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem true 2)
|
||||
set_tests_properties(Example.BuiltinDevices.multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
|
||||
|
||||
# install
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-builtin-devices.sh
|
||||
)
|
4
examples/builtin-devices/README.md
Normal file
4
examples/builtin-devices/README.md
Normal file
@@ -0,0 +1,4 @@
|
||||
Built-in devices
|
||||
==========================
|
||||
|
||||
This example demonstrates use of generic devices that are provided with FairMQ - BenchmarkSampler, Merger, Multiplier, Proxy, Sink, Splitter. They are all connected in one topology and transfer some dummy buffers generated by the BenchmarkSampler.
|
93
examples/builtin-devices/fairmq-start-ex-builtin-devices.sh.in
Executable file
93
examples/builtin-devices/fairmq-start-ex-builtin-devices.sh.in
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
transport="zeromq"
|
||||
multipart="false"
|
||||
numParts="1"
|
||||
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
if [[ $2 =~ ^[a-z]+$ ]]; then
|
||||
multipart=$2
|
||||
fi
|
||||
|
||||
if [[ $3 =~ ^[0-9]+$ ]]; then
|
||||
numParts=$3
|
||||
fi
|
||||
|
||||
SAMPLER="fairmq-bsampler"
|
||||
SAMPLER+=" --id bsampler1"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --control interactive"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size 100000"
|
||||
SAMPLER+=" --multipart $multipart"
|
||||
SAMPLER+=" --num-parts $numParts"
|
||||
SAMPLER+=" --msg-rate 100"
|
||||
SAMPLER+=" --max-iterations 0"
|
||||
SAMPLER+=" --out-channel data1"
|
||||
SAMPLER+=" --channel-config name=data1,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
xterm -geometry 90x20+0+175 -hold -e @FAIRMQ_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SPLITTER="fairmq-splitter"
|
||||
SPLITTER+=" --id splitter"
|
||||
SPLITTER+=" --transport $transport"
|
||||
SPLITTER+=" --multipart $multipart"
|
||||
SPLITTER+=" --in-channel data1"
|
||||
SPLITTER+=" --out-channel data2"
|
||||
SPLITTER+=" --channel-config name=data1,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
SPLITTER+=" name=data2,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556,address=tcp://localhost:5557"
|
||||
xterm -geometry 90x20+0+475 -hold -e @FAIRMQ_BIN_DIR@/$SPLITTER &
|
||||
|
||||
PROXY1="fairmq-proxy"
|
||||
PROXY1+=" --id proxy1"
|
||||
PROXY1+=" --transport $transport"
|
||||
PROXY1+=" --multipart $multipart"
|
||||
PROXY1+=" --in-channel data2"
|
||||
PROXY1+=" --out-channel data3"
|
||||
PROXY1+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556"
|
||||
PROXY1+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558"
|
||||
xterm -geometry 90x20+550+175 -hold -e @FAIRMQ_BIN_DIR@/$PROXY1 &
|
||||
|
||||
PROXY2="fairmq-proxy"
|
||||
PROXY2+=" --id proxy2"
|
||||
PROXY2+=" --transport $transport"
|
||||
PROXY2+=" --multipart $multipart"
|
||||
PROXY2+=" --in-channel data2"
|
||||
PROXY2+=" --out-channel data3"
|
||||
PROXY2+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5557"
|
||||
PROXY2+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5559"
|
||||
xterm -geometry 90x20+550+475 -hold -e @FAIRMQ_BIN_DIR@/$PROXY2 &
|
||||
|
||||
MERGER="fairmq-merger"
|
||||
MERGER+=" --id merger"
|
||||
MERGER+=" --transport $transport"
|
||||
MERGER+=" --multipart $multipart"
|
||||
MERGER+=" --in-channel data3"
|
||||
MERGER+=" --out-channel data4"
|
||||
MERGER+=" --channel-config name=data3,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558,address=tcp://localhost:5559"
|
||||
MERGER+=" name=data4,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
xterm -geometry 90x20+1100+50 -hold -e @FAIRMQ_BIN_DIR@/$MERGER &
|
||||
|
||||
MULTIPLIER="fairmq-multiplier"
|
||||
MULTIPLIER+=" --id multiplier"
|
||||
MULTIPLIER+=" --transport $transport"
|
||||
MULTIPLIER+=" --multipart $multipart"
|
||||
MULTIPLIER+=" --in-channel data4"
|
||||
MULTIPLIER+=" --out-channel data5"
|
||||
MULTIPLIER+=" --channel-config name=data4,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
MULTIPLIER+=" name=data5,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561,address=tcp://localhost:5561"
|
||||
xterm -geometry 90x20+1100+350 -hold -e @FAIRMQ_BIN_DIR@/$MULTIPLIER &
|
||||
|
||||
SINK="fairmq-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --multipart $multipart"
|
||||
SINK+=" --max-iterations 0"
|
||||
SINK+=" --in-channel data5"
|
||||
SINK+=" --channel-config name=data5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561"
|
||||
xterm -geometry 90x20+1100+650 -hold -e @FAIRMQ_BIN_DIR@/$SINK &
|
148
examples/builtin-devices/test-ex-builtin-devices.sh.in
Executable file
148
examples/builtin-devices/test-ex-builtin-devices.sh.in
Executable file
@@ -0,0 +1,148 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
|
||||
|
||||
transport="zeromq"
|
||||
multipart="false"
|
||||
numParts="1"
|
||||
|
||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
||||
transport=$1
|
||||
fi
|
||||
|
||||
if [[ $2 =~ ^[a-z]+$ ]]; then
|
||||
multipart=$2
|
||||
fi
|
||||
|
||||
if [[ $3 =~ ^[0-9]+$ ]]; then
|
||||
numParts=$3
|
||||
fi
|
||||
|
||||
# setup a trap to kill everything if the test fails/timeouts
|
||||
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SPLITTER_PID; kill -TERM $PROXY1_PID; kill -TERM $PROXY2_PID; kill -TERM $MERGER_PID; kill -TERM $MULTIPLIER_PID; kill -TERM $SINK_PID;' TERM
|
||||
|
||||
SAMPLER="fairmq-bsampler"
|
||||
SAMPLER+=" --id bsampler1"
|
||||
SAMPLER+=" --session $SESSION"
|
||||
SAMPLER+=" --transport $transport"
|
||||
SAMPLER+=" --color false"
|
||||
SAMPLER+=" --control static"
|
||||
SAMPLER+=" --verbosity veryhigh"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size 100000"
|
||||
SAMPLER+=" --multipart $multipart"
|
||||
SAMPLER+=" --num-parts $numParts"
|
||||
SAMPLER+=" --msg-rate 1"
|
||||
SAMPLER+=" --max-iterations 0"
|
||||
SAMPLER+=" --out-channel data1"
|
||||
SAMPLER+=" --channel-config name=data1,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
@FAIRMQ_BIN_DIR@/$SAMPLER &
|
||||
SAMPLER_PID=$!
|
||||
|
||||
SPLITTER="fairmq-splitter"
|
||||
SPLITTER+=" --id splitter"
|
||||
SPLITTER+=" --session $SESSION"
|
||||
SPLITTER+=" --transport $transport"
|
||||
SPLITTER+=" --color false"
|
||||
SPLITTER+=" --control static"
|
||||
SPLITTER+=" --verbosity veryhigh"
|
||||
SPLITTER+=" --multipart $multipart"
|
||||
SPLITTER+=" --in-channel data1"
|
||||
SPLITTER+=" --out-channel data2"
|
||||
SPLITTER+=" --channel-config name=data1,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5555"
|
||||
SPLITTER+=" name=data2,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556,address=tcp://localhost:5557"
|
||||
@FAIRMQ_BIN_DIR@/$SPLITTER &
|
||||
SPLITTER_PID=$!
|
||||
|
||||
PROXY1="fairmq-proxy"
|
||||
PROXY1+=" --id proxy1"
|
||||
PROXY1+=" --session $SESSION"
|
||||
PROXY1+=" --transport $transport"
|
||||
PROXY1+=" --color false"
|
||||
PROXY1+=" --control static"
|
||||
PROXY1+=" --verbosity veryhigh"
|
||||
PROXY1+=" --multipart $multipart"
|
||||
PROXY1+=" --in-channel data2"
|
||||
PROXY1+=" --out-channel data3"
|
||||
PROXY1+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5556"
|
||||
PROXY1+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558"
|
||||
@FAIRMQ_BIN_DIR@/$PROXY1 &
|
||||
PROXY1_PID=$!
|
||||
|
||||
PROXY2="fairmq-proxy"
|
||||
PROXY2+=" --id proxy2"
|
||||
PROXY2+=" --session $SESSION"
|
||||
PROXY2+=" --transport $transport"
|
||||
PROXY2+=" --color false"
|
||||
PROXY2+=" --control static"
|
||||
PROXY2+=" --verbosity veryhigh"
|
||||
PROXY2+=" --multipart $multipart"
|
||||
PROXY2+=" --in-channel data2"
|
||||
PROXY2+=" --out-channel data3"
|
||||
PROXY2+=" --channel-config name=data2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5557"
|
||||
PROXY2+=" name=data3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5559"
|
||||
@FAIRMQ_BIN_DIR@/$PROXY2 &
|
||||
PROXY2_PID=$!
|
||||
|
||||
MERGER="fairmq-merger"
|
||||
MERGER+=" --id merger"
|
||||
MERGER+=" --session $SESSION"
|
||||
MERGER+=" --transport $transport"
|
||||
MERGER+=" --color false"
|
||||
MERGER+=" --control static"
|
||||
MERGER+=" --verbosity veryhigh"
|
||||
MERGER+=" --multipart $multipart"
|
||||
MERGER+=" --in-channel data3"
|
||||
MERGER+=" --out-channel data4"
|
||||
MERGER+=" --channel-config name=data3,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5558,address=tcp://localhost:5559"
|
||||
MERGER+=" name=data4,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
@FAIRMQ_BIN_DIR@/$MERGER &
|
||||
MERGER_PID=$!
|
||||
|
||||
MULTIPLIER="fairmq-multiplier"
|
||||
MULTIPLIER+=" --id multiplier"
|
||||
MULTIPLIER+=" --session $SESSION"
|
||||
MULTIPLIER+=" --transport $transport"
|
||||
MULTIPLIER+=" --color false"
|
||||
MULTIPLIER+=" --control static"
|
||||
MULTIPLIER+=" --verbosity veryhigh"
|
||||
MULTIPLIER+=" --multipart $multipart"
|
||||
MULTIPLIER+=" --in-channel data4"
|
||||
MULTIPLIER+=" --out-channel data5"
|
||||
MULTIPLIER+=" --channel-config name=data4,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5560"
|
||||
MULTIPLIER+=" name=data5,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561,address=tcp://localhost:5561"
|
||||
@FAIRMQ_BIN_DIR@/$MULTIPLIER &
|
||||
MULTIPLIER_PID=$!
|
||||
|
||||
SINK="fairmq-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --session $SESSION"
|
||||
SINK+=" --transport $transport"
|
||||
SINK+=" --color false"
|
||||
SINK+=" --control static"
|
||||
SINK+=" --verbosity veryhigh"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --multipart $multipart"
|
||||
SINK+=" --max-iterations 2"
|
||||
SINK+=" --in-channel data5"
|
||||
SINK+=" --channel-config name=data5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=tcp://localhost:5561"
|
||||
@FAIRMQ_BIN_DIR@/$SINK &
|
||||
SINK_PID=$!
|
||||
|
||||
wait $SINK_PID
|
||||
|
||||
kill -SIGINT $SAMPLER_PID
|
||||
kill -SIGINT $SPLITTER_PID
|
||||
kill -SIGINT $PROXY1_PID
|
||||
kill -SIGINT $PROXY2_PID
|
||||
kill -SIGINT $MERGER_PID
|
||||
kill -SIGINT $MULTIPLIER_PID
|
||||
|
||||
wait $SAMPLER_PID
|
||||
wait $SPLITTER_PID
|
||||
wait $PROXY1_PID
|
||||
wait $PROXY2_PID
|
||||
wait $MERGER_PID
|
||||
wait $MULTIPLIER_PID
|
@@ -32,16 +32,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-copypush.sh.in ${CMAK
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh)
|
||||
|
||||
add_test(NAME Example-CopyPush-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
|
||||
set_tests_properties(Example-CopyPush-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example.CopyPush.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
|
||||
set_tests_properties(Example.CopyPush.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-CopyPush-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
|
||||
set_tests_properties(Example-CopyPush-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example.CopyPush.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh nanomsg)
|
||||
set_tests_properties(Example.CopyPush.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-CopyPush-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
|
||||
set_tests_properties(Example-CopyPush-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
add_test(NAME Example.CopyPush.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
|
||||
set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
|
@@ -47,7 +47,7 @@ The configuration of the channel connection addresses is done by the DDS plugin
|
||||
|
||||
Note that the attributes `value` contain a different value.
|
||||
|
||||
##### 4. Start DDS server.
|
||||
##### 4. Start DDS session.
|
||||
|
||||
First you need to initialize DDS environment:
|
||||
|
||||
@@ -55,10 +55,10 @@ First you need to initialize DDS environment:
|
||||
source DDS_env.sh # this script is located in the DDS installation directory
|
||||
```
|
||||
|
||||
The DDS server is started with:
|
||||
The DDS session is started with:
|
||||
|
||||
```bash
|
||||
dds-server start -s
|
||||
dds-session start
|
||||
```
|
||||
|
||||
##### 5. Submit DDS Agents (configured in the hosts file).
|
||||
@@ -91,7 +91,7 @@ A simple utility (fairmq-dds-command-ui) is included with FairMQ to send command
|
||||
|
||||
To see it in action, start the fairmq-dds-command-ui while the topology is running. Run the utility with `-h` to see everything that it can do.
|
||||
|
||||
The utility requires a session parameter to connect to appropriate DDS session. The session value is given when starting dds-server.
|
||||
The utility requires a session parameter to connect to appropriate DDS session. The session value is given when starting dds-session.
|
||||
|
||||
By default the command UI sends commands to all tasks. This can be further refined by giving a specific topology path via `-p` argument.
|
||||
Given our topology file, here are some examples of valid paths:
|
||||
@@ -108,15 +108,15 @@ Given our topology file, here are some examples of valid paths:
|
||||
./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 session/topology.
|
||||
|
||||
The execution of tasks can be stopped with:
|
||||
```bash
|
||||
dds-topology --stop
|
||||
```
|
||||
Or by stopping the DDS server:
|
||||
Or by stopping the DDS session:
|
||||
```bash
|
||||
dds-server stop
|
||||
dds-session stop
|
||||
```
|
||||
|
||||
For general DDS documentation please refer to [DDS Website](http://dds.gsi.de/).
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -2,6 +2,6 @@
|
||||
# source setup.sh
|
||||
@bash_end@
|
||||
|
||||
sampler, username@localhost, , /path/to/dds-work-dir/, 1
|
||||
processor, username@localhost, , /path/to/dds-work-dir/, 10
|
||||
sink, username@localhost, , /path/to/dds-work-dir/, 1
|
||||
sampler, username@localhost, , /path/to/dds-work/, 1
|
||||
processor, username@localhost, , /path/to/dds-work/, 10
|
||||
sink, username@localhost, , /path/to/dds-work/, 1
|
||||
|
@@ -31,16 +31,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMA
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh)
|
||||
|
||||
add_test(NAME Example-Multipart-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example-Multipart-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
add_test(NAME Example.Multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
|
||||
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-Multipart-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example-Multipart-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
add_test(NAME Example.Multipart.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh nanomsg)
|
||||
set_tests_properties(Example.Multipart.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-Multipart-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example-Multipart-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
add_test(NAME Example.Multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
|
||||
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 2 parts")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -36,12 +36,12 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-channels.sh.
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh)
|
||||
|
||||
add_test(NAME Example-Multiple-Channels-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
|
||||
set_tests_properties(Example-Multiple-Channels-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example.MultipleChannels.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
|
||||
set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-Multiple-Channels-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
|
||||
set_tests_properties(Example-Multiple-Channels-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example.MultipleChannels.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh nanomsg)
|
||||
set_tests_properties(Example.MultipleChannels.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
endif()
|
||||
|
||||
# install
|
||||
|
@@ -41,7 +41,7 @@ void Sampler::Run()
|
||||
{
|
||||
FairMQPollerPtr poller(NewPoller("data", "broadcast"));
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
poller->Poll(100);
|
||||
|
||||
|
@@ -35,8 +35,8 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.s
|
||||
# test
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
add_test(NAME Example-Multiple-Transports COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
set_tests_properties(Example-Multiple-Transports PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
add_test(NAME Example.MultipleTransports COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
|
||||
set_tests_properties(Example.MultipleTransports PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received messages from both sources.")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -60,7 +60,7 @@ void Sampler1::ListenForAcks()
|
||||
{
|
||||
uint64_t numAcks = 0;
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
FairMQMessagePtr ack(NewMessageFor("ack", 0));
|
||||
if (Receive(ack, "ack") < 0)
|
||||
|
40
examples/readout/Builder.h
Normal file
40
examples/readout/Builder.h
Normal file
@@ -0,0 +1,40 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIRMQEXAMPLEREGIONBUILDER_H
|
||||
#define FAIRMQEXAMPLEREGIONBUILDER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_region
|
||||
{
|
||||
|
||||
class Builder : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Builder() {
|
||||
OnData("data1", &Builder::HandleData);
|
||||
}
|
||||
virtual ~Builder() {}
|
||||
|
||||
protected:
|
||||
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
|
||||
{
|
||||
if (Send(msg, "data2") < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace example_region
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONBUILDER_H */
|
55
examples/readout/CMakeLists.txt
Normal file
55
examples/readout/CMakeLists.txt
Normal file
@@ -0,0 +1,55 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
add_library(ExampleReadoutLib STATIC
|
||||
"Sampler.cxx"
|
||||
"Sampler.h"
|
||||
"Builder.h"
|
||||
"Sink.cxx"
|
||||
"Sink.h"
|
||||
)
|
||||
|
||||
target_link_libraries(ExampleReadoutLib PUBLIC FairMQ)
|
||||
|
||||
add_executable(fairmq-ex-readout-sampler runSampler.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-sampler PRIVATE ExampleReadoutLib)
|
||||
|
||||
add_executable(fairmq-ex-readout-builder runBuilder.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-builder PRIVATE ExampleReadoutLib)
|
||||
|
||||
add_executable(fairmq-ex-readout-sink runSink.cxx)
|
||||
target_link_libraries(fairmq-ex-readout-sink PRIVATE ExampleReadoutLib)
|
||||
|
||||
add_custom_target(ExampleReadout DEPENDS fairmq-ex-readout-sampler fairmq-ex-readout-builder fairmq-ex-readout-sink)
|
||||
|
||||
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh)
|
||||
|
||||
# install
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
fairmq-ex-readout-sampler
|
||||
fairmq-ex-readout-builder
|
||||
fairmq-ex-readout-sink
|
||||
|
||||
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
)
|
||||
|
||||
# configure run script with different executable paths for build and for install directories
|
||||
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
|
||||
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install)
|
||||
|
||||
install(
|
||||
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
|
||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||
RENAME fairmq-start-ex-readout.sh
|
||||
)
|
86
examples/readout/Sampler.cxx
Normal file
86
examples/readout/Sampler.cxx
Normal file
@@ -0,0 +1,86 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sampler.cpp
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "Sampler.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace example_region
|
||||
{
|
||||
|
||||
Sampler::Sampler()
|
||||
: fMsgSize(10000)
|
||||
, fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
, fRegion(nullptr)
|
||||
, fNumUnackedMsgs(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Sampler::InitTask()
|
||||
{
|
||||
fMsgSize = fConfig->GetValue<int>("msg-size");
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
|
||||
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegion(10000000,
|
||||
[this](void* /*data*/, size_t /*size*/, void* /*hint*/) { // callback to be called when message buffers no longer needed by transport
|
||||
--fNumUnackedMsgs;
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
LOG(debug) << "Received ack";
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
bool Sampler::ConditionalRun()
|
||||
{
|
||||
FairMQMessagePtr msg(NewMessage(fRegion, // region
|
||||
fRegion->GetData(), // ptr within region
|
||||
fMsgSize, // offset from ptr
|
||||
nullptr // hint
|
||||
));
|
||||
|
||||
if (Send(msg, "data1", 0) > 0)
|
||||
{
|
||||
++fNumUnackedMsgs;
|
||||
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
|
||||
{
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sampler::ResetTask()
|
||||
{
|
||||
// if not all messages acknowledged, wait for a bit. But only once, since receiver could be already dead.
|
||||
if (fNumUnackedMsgs != 0)
|
||||
{
|
||||
LOG(debug) << "waiting for all acknowledgements... (" << fNumUnackedMsgs << ")";
|
||||
this_thread::sleep_for(chrono::milliseconds(500));
|
||||
LOG(debug) << "done, still unacked: " << fNumUnackedMsgs;
|
||||
}
|
||||
fRegion.reset();
|
||||
}
|
||||
|
||||
Sampler::~Sampler()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace example_region
|
46
examples/readout/Sampler.h
Normal file
46
examples/readout/Sampler.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sampler.h
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQEXAMPLEREGIONSAMPLER_H
|
||||
#define FAIRMQEXAMPLEREGIONSAMPLER_H
|
||||
|
||||
#include <atomic>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_region
|
||||
{
|
||||
|
||||
class Sampler : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sampler();
|
||||
virtual ~Sampler();
|
||||
|
||||
protected:
|
||||
virtual void InitTask();
|
||||
virtual bool ConditionalRun();
|
||||
virtual void ResetTask();
|
||||
|
||||
private:
|
||||
int fMsgSize;
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
FairMQUnmanagedRegionPtr fRegion;
|
||||
std::atomic<uint64_t> fNumUnackedMsgs;
|
||||
};
|
||||
|
||||
} // namespace example_region
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONSAMPLER_H */
|
56
examples/readout/Sink.cxx
Normal file
56
examples/readout/Sink.cxx
Normal file
@@ -0,0 +1,56 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sink.cxx
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "Sink.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
namespace example_region
|
||||
{
|
||||
|
||||
Sink::Sink()
|
||||
: fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
{
|
||||
}
|
||||
|
||||
void Sink::InitTask()
|
||||
{
|
||||
// Get the fMaxIterations value from the command line options (via fConfig)
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
}
|
||||
|
||||
void Sink::Run()
|
||||
{
|
||||
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
|
||||
|
||||
while (!NewStatePending())
|
||||
{
|
||||
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
|
||||
dataInChannel.Receive(msg);
|
||||
// void* ptr = msg->GetData();
|
||||
|
||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations)
|
||||
{
|
||||
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Sink::~Sink()
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace example_region
|
42
examples/readout/Sink.h
Normal file
42
examples/readout/Sink.h
Normal file
@@ -0,0 +1,42 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* Sink.h
|
||||
*
|
||||
* @since 2014-10-10
|
||||
* @author A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQEXAMPLEREGIONSINK_H
|
||||
#define FAIRMQEXAMPLEREGIONSINK_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "FairMQDevice.h"
|
||||
|
||||
namespace example_region
|
||||
{
|
||||
|
||||
class Sink : public FairMQDevice
|
||||
{
|
||||
public:
|
||||
Sink();
|
||||
virtual ~Sink();
|
||||
|
||||
protected:
|
||||
virtual void Run();
|
||||
virtual void InitTask();
|
||||
|
||||
private:
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
};
|
||||
|
||||
} // namespace example_region
|
||||
|
||||
#endif /* FAIRMQEXAMPLEREGIONSINK_H */
|
32
examples/readout/fairmq-start-ex-readout.sh.in
Executable file
32
examples/readout/fairmq-start-ex-readout.sh.in
Executable file
@@ -0,0 +1,32 @@
|
||||
#!/bin/bash
|
||||
|
||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||
|
||||
msgSize="2000000"
|
||||
|
||||
if [[ $1 =~ ^[0-9]+$ ]]; then
|
||||
msgSize=$1
|
||||
fi
|
||||
|
||||
SAMPLER="fairmq-ex-readout-sampler"
|
||||
SAMPLER+=" --id sampler1"
|
||||
SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --transport shmem"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --rate 10"
|
||||
SAMPLER+=" --channel-config name=data1,type=pair,method=bind,address=tcp://127.0.0.1:7777,transport=shmem"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
BUILDER="fairmq-ex-readout-builder"
|
||||
BUILDER+=" --id builder1"
|
||||
BUILDER+=" --severity debug"
|
||||
BUILDER+=" --channel-config name=data1,type=pair,method=connect,address=tcp://127.0.0.1:7777,transport=shmem"
|
||||
BUILDER+=" name=data2,type=pair,method=connect,address=tcp://127.0.0.1:7778,transport=ofi"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$BUILDER &
|
||||
|
||||
SINK="fairmq-ex-readout-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --ofi-size-hint $msgSize"
|
||||
SINK+=" --channel-config name=data,type=pair,method=bind,address=tcp://127.0.0.1:7778,transport=ofi"
|
||||
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SINK &
|
20
examples/readout/runBuilder.cxx
Normal file
20
examples/readout/runBuilder.cxx
Normal file
@@ -0,0 +1,20 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "Builder.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& /* options */)
|
||||
{}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new example_region::Builder();
|
||||
}
|
24
examples/readout/runSampler.cxx
Normal file
24
examples/readout/runSampler.cxx
Normal file
@@ -0,0 +1,24 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "Sampler.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new example_region::Sampler();
|
||||
}
|
23
examples/readout/runSink.cxx
Normal file
23
examples/readout/runSink.cxx
Normal file
@@ -0,0 +1,23 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#include "runFairMQDevice.h"
|
||||
#include "Sink.h"
|
||||
|
||||
namespace bpo = boost::program_options;
|
||||
|
||||
void addCustomOptions(bpo::options_description& options)
|
||||
{
|
||||
options.add_options()
|
||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
||||
}
|
||||
|
||||
FairMQDevicePtr getDevice(const FairMQProgOptions& /*config*/)
|
||||
{
|
||||
return new example_region::Sink();
|
||||
}
|
@@ -18,7 +18,6 @@ target_link_libraries(ExampleRegionLib PUBLIC FairMQ)
|
||||
add_executable(fairmq-ex-region-sampler runSampler.cxx)
|
||||
target_link_libraries(fairmq-ex-region-sampler PRIVATE ExampleRegionLib)
|
||||
|
||||
|
||||
add_executable(fairmq-ex-region-sink runSink.cxx)
|
||||
target_link_libraries(fairmq-ex-region-sink PRIVATE ExampleRegionLib)
|
||||
|
||||
@@ -32,16 +31,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh)
|
||||
|
||||
add_test(NAME Example-Region-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
|
||||
set_tests_properties(Example-Region-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example.Region.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
|
||||
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-Region-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
|
||||
set_tests_properties(Example-Region-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example.Region.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh nanomsg)
|
||||
set_tests_properties(Example.Region.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-Region-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
|
||||
set_tests_properties(Example-Region-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
add_test(NAME Example.Region.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
|
||||
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received ack")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -35,7 +35,7 @@ void Sink::Run()
|
||||
{
|
||||
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
|
||||
dataInChannel.Receive(msg);
|
||||
|
@@ -14,12 +14,12 @@ SAMPLER+=" --severity debug"
|
||||
SAMPLER+=" --msg-size $msgSize"
|
||||
# SAMPLER+=" --rate 10"
|
||||
SAMPLER+=" --transport shmem"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777"
|
||||
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777,sndKernelSize=212992"
|
||||
xterm -geometry 80x23+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||
|
||||
SINK="fairmq-ex-region-sink"
|
||||
SINK+=" --id sink1"
|
||||
SINK+=" --severity debug"
|
||||
SINK+=" --transport shmem"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777,rcvKernelSize=212992"
|
||||
xterm -geometry 80x23+500+0 -hold -e @EX_BIN_DIR@/$SINK &
|
||||
|
@@ -32,16 +32,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-req-rep.sh.in ${CMAKE
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh)
|
||||
|
||||
add_test(NAME Example-ReqRep-zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
|
||||
set_tests_properties(Example-ReqRep-zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example.ReqRep.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
|
||||
set_tests_properties(Example.ReqRep.zeromq PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_test(NAME Example-ReqRep-nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
|
||||
set_tests_properties(Example-ReqRep-nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example.ReqRep.nanomsg COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh nanomsg)
|
||||
set_tests_properties(Example.ReqRep.nanomsg PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
endif()
|
||||
|
||||
add_test(NAME Example-ReqRep-shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
|
||||
set_tests_properties(Example-ReqRep-shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
add_test(NAME Example.ReqRep.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
|
||||
set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received reply from server: ")
|
||||
|
||||
# install
|
||||
|
||||
|
@@ -12,24 +12,8 @@
|
||||
if(BUILD_DDS_PLUGIN)
|
||||
add_subdirectory(plugins/DDS)
|
||||
endif()
|
||||
|
||||
|
||||
############################
|
||||
# preprocessor definitions #
|
||||
############################
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
add_definitions(-DBUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_definitions(-DBUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
|
||||
|
||||
##################
|
||||
# subdirectories #
|
||||
##################
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
add_subdirectory(ofi)
|
||||
if(BUILD_PMIX_PLUGIN)
|
||||
add_subdirectory(plugins/PMIx)
|
||||
endif()
|
||||
|
||||
|
||||
@@ -47,8 +31,10 @@ set(FAIRMQ_PUBLIC_HEADER_FILES
|
||||
FairMQPoller.h
|
||||
FairMQUnmanagedRegion.h
|
||||
FairMQSocket.h
|
||||
FairMQStateMachine.h
|
||||
StateMachine.h
|
||||
FairMQTransportFactory.h
|
||||
MemoryResources.h
|
||||
MemoryResourceTools.h
|
||||
Tools.h
|
||||
Transports.h
|
||||
options/FairMQProgOptions.h
|
||||
@@ -78,7 +64,6 @@ set(FAIRMQ_PRIVATE_HEADER_FILES
|
||||
options/FairProgOptionsHelper.h
|
||||
plugins/Builtin.h
|
||||
plugins/Control.h
|
||||
StateMachine.h
|
||||
shmem/FairMQMessageSHM.h
|
||||
shmem/FairMQPollerSHM.h
|
||||
shmem/FairMQUnmanagedRegionSHM.h
|
||||
@@ -125,7 +110,7 @@ set(FAIRMQ_SOURCE_FILES
|
||||
FairMQMessage.cxx
|
||||
FairMQPoller.cxx
|
||||
FairMQSocket.cxx
|
||||
FairMQStateMachine.cxx
|
||||
StateMachine.cxx
|
||||
FairMQTransportFactory.cxx
|
||||
devices/FairMQBenchmarkSampler.cxx
|
||||
devices/FairMQMerger.cxx
|
||||
@@ -139,7 +124,6 @@ set(FAIRMQ_SOURCE_FILES
|
||||
PluginManager.cxx
|
||||
PluginServices.cxx
|
||||
plugins/Control.cxx
|
||||
StateMachine.cxx
|
||||
shmem/FairMQMessageSHM.cxx
|
||||
shmem/FairMQPollerSHM.cxx
|
||||
shmem/FairMQUnmanagedRegionSHM.cxx
|
||||
@@ -155,6 +139,7 @@ set(FAIRMQ_SOURCE_FILES
|
||||
zeromq/FairMQUnmanagedRegionZMQ.cxx
|
||||
zeromq/FairMQSocketZMQ.cxx
|
||||
zeromq/FairMQTransportFactoryZMQ.cxx
|
||||
MemoryResources.cxx
|
||||
)
|
||||
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
@@ -204,6 +189,19 @@ if(FAST_BUILD)
|
||||
set_target_properties(${_target} PROPERTIES OUTPUT_NAME FairMQ)
|
||||
endif()
|
||||
|
||||
|
||||
############################
|
||||
# preprocessor definitions #
|
||||
############################
|
||||
target_compile_definitions(${_target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
|
||||
if(BUILD_NANOMSG_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_NANOMSG_TRANSPORT)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
target_compile_definitions(${_target} PRIVATE BUILD_OFI_TRANSPORT)
|
||||
endif()
|
||||
|
||||
|
||||
#######################
|
||||
# include directories #
|
||||
#######################
|
||||
@@ -223,7 +221,11 @@ if(BUILD_NANOMSG_TRANSPORT)
|
||||
set(NANOMSG_DEPS nanomsg msgpackc-cxx)
|
||||
endif()
|
||||
if(BUILD_OFI_TRANSPORT)
|
||||
set(OFI_DEPS OFI::libfabric protobuf::libprotobuf $<TARGET_OBJECTS:OfiTransport>)
|
||||
set(OFI_DEPS
|
||||
asiofi::asiofi
|
||||
Boost::container
|
||||
AZMQ::AZMQ
|
||||
)
|
||||
endif()
|
||||
set(optional_deps ${NANOMSG_DEPS} ${OFI_DEPS})
|
||||
if(optional_deps)
|
||||
@@ -232,6 +234,7 @@ endif()
|
||||
|
||||
target_link_libraries(${_target}
|
||||
INTERFACE # only consumers link against interface dependencies
|
||||
Boost::container
|
||||
|
||||
PUBLIC # libFairMQ AND consumers of libFairMQ link aginst public dependencies
|
||||
Threads::Threads
|
||||
@@ -239,12 +242,8 @@ target_link_libraries(${_target}
|
||||
$<$<PLATFORM_ID:Linux>:rt>
|
||||
Boost::boost
|
||||
Boost::program_options
|
||||
Boost::thread
|
||||
Boost::system
|
||||
Boost::filesystem
|
||||
Boost::regex
|
||||
Boost::date_time
|
||||
Boost::signals
|
||||
FairLogger::FairLogger
|
||||
|
||||
PRIVATE # only libFairMQ links against private dependencies
|
||||
|
@@ -74,15 +74,14 @@ auto DeviceRunner::Run() -> int
|
||||
fDevice->RegisterChannelEndpoints();
|
||||
if (fConfig.Count("print-channels")) {
|
||||
fDevice->PrintRegisteredChannels();
|
||||
fDevice->ChangeState(FairMQDevice::END);
|
||||
fDevice->ChangeState(fair::mq::Transition::End);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Handle --version
|
||||
if (fConfig.Count("version")) {
|
||||
std::cout << "User device version: " << fDevice->GetVersion() << std::endl;
|
||||
std::cout << "FAIRMQ_INTERFACE_VERSION: " << FAIRMQ_INTERFACE_VERSION << std::endl;
|
||||
fDevice->ChangeState(FairMQDevice::END);
|
||||
fDevice->ChangeState(fair::mq::Transition::End);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -10,10 +10,12 @@
|
||||
#define FAIRMQCHANNEL_H_
|
||||
|
||||
#include <string>
|
||||
#include <memory> // unique_ptr
|
||||
#include <memory> // unique_ptr, shared_ptr
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
#include <utility> // std::move
|
||||
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <FairMQSocket.h>
|
||||
@@ -42,6 +44,14 @@ class FairMQChannel
|
||||
/// @param factory TransportFactory
|
||||
FairMQChannel(const std::string& name, const std::string& type, std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
/// Constructor
|
||||
/// @param name Channel name
|
||||
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
/// @param method Socket method (bind/connect)
|
||||
/// @param address Network address to bind/connect to (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
|
||||
/// @param factory TransportFactory
|
||||
FairMQChannel(const std::string& name, const std::string& type, const std::string& method, const std::string& address, std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
/// Copy Constructor
|
||||
FairMQChannel(const FairMQChannel&);
|
||||
|
||||
@@ -49,18 +59,20 @@ class FairMQChannel
|
||||
FairMQChannel& operator=(const FairMQChannel&);
|
||||
|
||||
/// Default destructor
|
||||
virtual ~FairMQChannel();
|
||||
virtual ~FairMQChannel() {}
|
||||
|
||||
FairMQSocket const & GetSocket() const;
|
||||
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
auto Bind(const std::string& address) -> bool
|
||||
FairMQSocket& GetSocket() const;
|
||||
|
||||
bool Bind(const std::string& address)
|
||||
{
|
||||
fMethod = "bind";
|
||||
fAddress = address;
|
||||
return fSocket->Bind(address);
|
||||
}
|
||||
|
||||
auto Connect(const std::string& address) -> void
|
||||
bool Connect(const std::string& address)
|
||||
{
|
||||
fMethod = "connect";
|
||||
fAddress = address;
|
||||
@@ -69,15 +81,18 @@ class FairMQChannel
|
||||
|
||||
/// Get channel name
|
||||
/// @return Returns full channel name (e.g. "data[0]")
|
||||
std::string GetChannelName() const;
|
||||
std::string GetChannelName() const { return GetName(); } // TODO: deprecate this in favor of following
|
||||
std::string GetName() const;
|
||||
|
||||
/// Get channel prefix
|
||||
/// @return Returns channel prefix (e.g. "data" in "data[0]")
|
||||
std::string GetChannelPrefix() const;
|
||||
std::string GetChannelPrefix() const { return GetPrefix(); } // TODO: deprecate this in favor of following
|
||||
std::string GetPrefix() const;
|
||||
|
||||
/// Get channel index
|
||||
/// @return Returns channel index (e.g. 0 in "data[0]")
|
||||
std::string GetChannelIndex() const;
|
||||
std::string GetChannelIndex() const { return GetIndex(); } // TODO: deprecate this in favor of following
|
||||
std::string GetIndex() const;
|
||||
|
||||
/// Get socket type
|
||||
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
@@ -111,10 +126,26 @@ class FairMQChannel
|
||||
/// @return Returns socket kernel transmit receive buffer size (in bytes)
|
||||
int GetRcvKernelSize() const;
|
||||
|
||||
/// Get linger duration (in milliseconds)
|
||||
/// @return Returns linger duration (in milliseconds)
|
||||
int GetLinger() const;
|
||||
|
||||
/// Get socket rate logging interval (in seconds)
|
||||
/// @return Returns socket rate logging interval (in seconds)
|
||||
int GetRateLogging() const;
|
||||
|
||||
/// Get start of the port range for automatic binding
|
||||
/// @return start of the port range
|
||||
int GetPortRangeMin() const;
|
||||
|
||||
/// Get end of the port range for automatic binding
|
||||
/// @return end of the port range
|
||||
int GetPortRangeMax() const;
|
||||
|
||||
/// Set automatic binding (pick random port if bind fails)
|
||||
/// @return true/false, true if automatic binding is enabled
|
||||
bool GetAutoBind() const;
|
||||
|
||||
/// Set socket type
|
||||
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
|
||||
void UpdateType(const std::string& type);
|
||||
@@ -147,13 +178,30 @@ class FairMQChannel
|
||||
/// @param rcvKernelSize Socket receive buffer size (in bytes)
|
||||
void UpdateRcvKernelSize(const int rcvKernelSize);
|
||||
|
||||
/// Set linger duration (in milliseconds)
|
||||
/// @param duration linger duration (in milliseconds)
|
||||
void UpdateLinger(const int duration);
|
||||
|
||||
/// Set socket rate logging interval (in seconds)
|
||||
/// @param rateLogging Socket rate logging interval (in seconds)
|
||||
void UpdateRateLogging(const int rateLogging);
|
||||
|
||||
/// Set start of the port range for automatic binding
|
||||
/// @param minPort start of the port range
|
||||
void UpdatePortRangeMin(const int minPort);
|
||||
|
||||
/// Set end of the port range for automatic binding
|
||||
/// @param maxPort end of the port range
|
||||
void UpdatePortRangeMax(const int maxPort);
|
||||
|
||||
/// Set automatic binding (pick random port if bind fails)
|
||||
/// @param autobind true/false, true to enable automatic binding
|
||||
void UpdateAutoBind(const bool autobind);
|
||||
|
||||
/// Set channel name
|
||||
/// @param name Arbitrary channel name
|
||||
void UpdateChannelName(const std::string& name);
|
||||
void UpdateChannelName(const std::string& name) { UpdateName(name); } // TODO: deprecate this in favor of following
|
||||
void UpdateName(const std::string& name);
|
||||
|
||||
/// Checks if the configured channel settings are valid (checks the validity parameter, without running full validation (as oposed to ValidateChannel()))
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
@@ -161,166 +209,163 @@ class FairMQChannel
|
||||
|
||||
/// Validates channel configuration
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
bool ValidateChannel();
|
||||
bool ValidateChannel() // TODO: deprecate this
|
||||
{
|
||||
return Validate();
|
||||
}
|
||||
|
||||
/// Validates channel configuration
|
||||
/// @return true if channel settings are valid, false otherwise.
|
||||
bool Validate();
|
||||
|
||||
void Init();
|
||||
|
||||
bool ConnectEndpoint(const std::string& endpoint);
|
||||
|
||||
bool BindEndpoint(std::string& endpoint);
|
||||
|
||||
/// Resets the channel (requires validation to be used again).
|
||||
void ResetChannel();
|
||||
|
||||
int Send(FairMQMessagePtr& msg) const;
|
||||
int Receive(FairMQMessagePtr& msg) const;
|
||||
|
||||
/// Sends a message to the socket queue.
|
||||
/// @details Send method attempts to send a message by
|
||||
/// putting it in the output queue. If the queue is full or queueing is not possible
|
||||
/// for some other reason (e.g. no peers connected for a binding socket), the method blocks.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Send(FairMQMessagePtr& msg, int sndTimeoutInMs) const;
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int Send(FairMQMessagePtr& msg, int sndTimeoutInMs = -1)
|
||||
{
|
||||
CheckSendCompatibility(msg);
|
||||
return fSocket->Send(msg, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Receives a message from the socket queue.
|
||||
/// @details Receive method attempts to receive a message from the input queue.
|
||||
/// If the queue is empty the method blocks.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs) const;
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
CheckReceiveCompatibility(msg);
|
||||
return fSocket->Receive(msg, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Sends a message in non-blocking mode.
|
||||
/// @details SendAsync method attempts to send a message without blocking by
|
||||
/// putting it in the queue.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been queued. If queueing failed due to
|
||||
/// full queue or no connected peers (when binding), returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int SendAsync(FairMQMessagePtr& msg) const;
|
||||
|
||||
/// Receives a message in non-blocking mode.
|
||||
///
|
||||
/// @param msg Constant reference of unique_ptr to a FairMQMessage
|
||||
/// @return Number of bytes that have been received. If queue is empty, returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int ReceiveAsync(FairMQMessagePtr& msg) const;
|
||||
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
int SendAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, timeout);")))
|
||||
{
|
||||
CheckSendCompatibility(msg);
|
||||
return fSocket->Send(msg, 0);
|
||||
}
|
||||
int ReceiveAsync(FairMQMessagePtr& msg) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, timeout);")))
|
||||
{
|
||||
CheckReceiveCompatibility(msg);
|
||||
return fSocket->Receive(msg, 0);
|
||||
}
|
||||
|
||||
/// Send a vector of messages
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs) const;
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(std::vector<FairMQMessagePtr>& msgVec, int sndTimeoutInMs = -1)
|
||||
{
|
||||
CheckSendCompatibility(msgVec);
|
||||
return fSocket->Send(msgVec, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Receive a vector of messages
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs) const;
|
||||
|
||||
/// Sends a vector of message in non-blocking mode.
|
||||
/// @details SendAsync method attempts to send a vector of messages without blocking by
|
||||
/// putting it them the queue.
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been queued. If queueing failed due to
|
||||
/// full queue or no connected peers (when binding), returns -2. In case of errors, returns -1.
|
||||
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
/// Receives a vector of messages in non-blocking mode.
|
||||
///
|
||||
/// @param msgVec message vector reference
|
||||
/// @return Number of bytes that have been received. If queue is empty, returns -2.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
int64_t Send(FairMQParts& parts) const
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
return Send(parts.fParts);
|
||||
CheckReceiveCompatibility(msgVec);
|
||||
return fSocket->Receive(msgVec, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t Receive(FairMQParts& parts) const
|
||||
int64_t SendAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msgVec, timeout);")))
|
||||
{
|
||||
return Receive(parts.fParts);
|
||||
CheckSendCompatibility(msgVec);
|
||||
return fSocket->Send(msgVec, 0);
|
||||
}
|
||||
int64_t ReceiveAsync(std::vector<FairMQMessagePtr>& msgVec) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msgVec, timeout);")))
|
||||
{
|
||||
CheckReceiveCompatibility(msgVec);
|
||||
return fSocket->Receive(msgVec, 0);
|
||||
}
|
||||
|
||||
int64_t Send(FairMQParts& parts, int sndTimeoutInMs) const
|
||||
/// Send FairMQParts
|
||||
/// @param parts FairMQParts reference
|
||||
/// @param sndTimeoutInMs send timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(FairMQParts& parts, int sndTimeoutInMs = -1)
|
||||
{
|
||||
return Send(parts.fParts, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs) const
|
||||
/// Receive FairMQParts
|
||||
/// @param parts FairMQParts reference
|
||||
/// @param rcvTimeoutInMs receive timeout in ms. -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
return Receive(parts.fParts, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
int64_t SendAsync(FairMQParts& parts) const
|
||||
int64_t SendAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, timeout);")))
|
||||
{
|
||||
return SendAsync(parts.fParts);
|
||||
return Send(parts.fParts, 0);
|
||||
}
|
||||
|
||||
int64_t ReceiveAsync(FairMQParts& parts) const
|
||||
int64_t ReceiveAsync(FairMQParts& parts) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, timeout);")))
|
||||
{
|
||||
return ReceiveAsync(parts.fParts);
|
||||
return Receive(parts.fParts, 0);
|
||||
}
|
||||
|
||||
unsigned long GetBytesTx() const;
|
||||
unsigned long GetBytesRx() const;
|
||||
unsigned long GetMessagesTx() const;
|
||||
unsigned long GetMessagesRx() const;
|
||||
unsigned long GetBytesTx() const { return fSocket->GetBytesTx(); }
|
||||
unsigned long GetBytesRx() const { return fSocket->GetBytesRx(); }
|
||||
unsigned long GetMessagesTx() const { return fSocket->GetMessagesTx(); }
|
||||
unsigned long GetMessagesRx() const { return fSocket->GetMessagesRx(); }
|
||||
|
||||
auto Transport() const -> const FairMQTransportFactory*
|
||||
auto Transport() -> FairMQTransportFactory*
|
||||
{
|
||||
return fTransportFactory.get();
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessage(Args&&... args) const
|
||||
FairMQMessagePtr NewMessage(Args&&... args)
|
||||
{
|
||||
return Transport()->CreateMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
{
|
||||
return Transport()->NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
{
|
||||
return Transport()->NewStaticMessage(data);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
|
||||
fair::mq::Transport fTransportType;
|
||||
std::unique_ptr<FairMQSocket> fSocket;
|
||||
|
||||
std::string fType;
|
||||
std::string fMethod;
|
||||
std::string fAddress;
|
||||
fair::mq::Transport fTransportType;
|
||||
int fSndBufSize;
|
||||
int fRcvBufSize;
|
||||
int fSndKernelSize;
|
||||
int fRcvKernelSize;
|
||||
int fLinger;
|
||||
int fRateLogging;
|
||||
int fPortRangeMin;
|
||||
int fPortRangeMax;
|
||||
bool fAutoBind;
|
||||
|
||||
std::string fName;
|
||||
std::atomic<bool> fIsValid;
|
||||
|
||||
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
|
||||
|
||||
void CheckSendCompatibility(FairMQMessagePtr& msg) const;
|
||||
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
void CheckReceiveCompatibility(FairMQMessagePtr& msg) const;
|
||||
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec) const;
|
||||
|
||||
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory);
|
||||
|
||||
// use static mutex to make the class easily copyable
|
||||
// implication: same mutex is used for all instances of the class
|
||||
// this does not hurt much, because mutex is used only during initialization with very low contention
|
||||
@@ -329,8 +374,66 @@ class FairMQChannel
|
||||
|
||||
bool fMultipart;
|
||||
bool fModified;
|
||||
auto SetModified(const bool modified) -> void;
|
||||
bool fReset;
|
||||
|
||||
void CheckSendCompatibility(FairMQMessagePtr& msg)
|
||||
{
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr msgWrapper(NewMessage(
|
||||
msg->GetData(),
|
||||
msg->GetSize(),
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
msg = move(msgWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr msgWrapper(NewMessage(
|
||||
msg->GetData(),
|
||||
msg->GetSize(),
|
||||
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
|
||||
msg.get()
|
||||
));
|
||||
msg.release();
|
||||
msg = move(msgWrapper);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckReceiveCompatibility(FairMQMessagePtr& msg)
|
||||
{
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr newMsg(NewMessage());
|
||||
msg = move(newMsg);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec)
|
||||
{
|
||||
for (auto& msg : msgVec) {
|
||||
if (fTransportType != msg->GetType()) {
|
||||
// LOG(debug) << "Channel type does not match message type. Creating wrapper";
|
||||
FairMQMessagePtr newMsg(NewMessage());
|
||||
msg = move(newMsg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory)
|
||||
{
|
||||
fTransportFactory = factory;
|
||||
fTransportType = factory->GetType();
|
||||
}
|
||||
auto SetModified(const bool modified) -> void;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQCHANNEL_H_ */
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -9,7 +9,7 @@
|
||||
#ifndef FAIRMQDEVICE_H_
|
||||
#define FAIRMQDEVICE_H_
|
||||
|
||||
#include <FairMQStateMachine.h>
|
||||
#include <StateMachine.h>
|
||||
#include <FairMQTransportFactory.h>
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <functional>
|
||||
#include <assert.h> // static_assert
|
||||
#include <type_traits> // is_trivially_copyable
|
||||
#include <stdexcept>
|
||||
#include <queue>
|
||||
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
@@ -42,11 +44,43 @@ using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChann
|
||||
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
|
||||
using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
|
||||
|
||||
class FairMQDevice : public FairMQStateMachine
|
||||
class FairMQDevice
|
||||
{
|
||||
friend class FairMQChannel;
|
||||
|
||||
public:
|
||||
// backwards-compatibility enum for old state machine interface, todo: delete this
|
||||
enum Event
|
||||
{
|
||||
INIT_DEVICE,
|
||||
internal_DEVICE_READY,
|
||||
INIT_TASK,
|
||||
internal_READY,
|
||||
RUN,
|
||||
STOP,
|
||||
RESET_TASK,
|
||||
RESET_DEVICE,
|
||||
internal_IDLE,
|
||||
END,
|
||||
ERROR_FOUND
|
||||
};
|
||||
|
||||
// backwards-compatibility enum for old state machine interface, todo: delete this
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
Error,
|
||||
IDLE,
|
||||
INITIALIZING_DEVICE,
|
||||
DEVICE_READY,
|
||||
INITIALIZING_TASK,
|
||||
READY,
|
||||
RUNNING,
|
||||
RESETTING_TASK,
|
||||
RESETTING_DEVICE,
|
||||
EXITING
|
||||
};
|
||||
|
||||
/// Default constructor
|
||||
FairMQDevice();
|
||||
/// Constructor with external FairMQProgOptions
|
||||
@@ -69,9 +103,6 @@ class FairMQDevice : public FairMQStateMachine
|
||||
/// Default destructor
|
||||
virtual ~FairMQDevice();
|
||||
|
||||
/// Catches interrupt signals (SIGINT, SIGTERM)
|
||||
void CatchSignals();
|
||||
|
||||
/// Outputs the socket transfer rates
|
||||
virtual void LogSocketRates();
|
||||
|
||||
@@ -80,10 +111,6 @@ class FairMQDevice : public FairMQStateMachine
|
||||
/// @param reindex Should reindexing be done
|
||||
void SortChannel(const std::string& name, const bool reindex = true);
|
||||
|
||||
/// Prints channel configuration
|
||||
/// @param name Name of the channel
|
||||
void PrintChannel(const std::string& name);
|
||||
|
||||
template<typename Serializer, typename DataType, typename... Args>
|
||||
void Serialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
|
||||
{
|
||||
@@ -96,164 +123,118 @@ class FairMQDevice : public FairMQStateMachine
|
||||
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
int Send(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(msg);
|
||||
}
|
||||
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(msg);
|
||||
}
|
||||
|
||||
/// Shorthand method to send `msg` on `chan` at index `i`
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Send(FairMQMessagePtr& msg, const std::string& chan, const int i, int sndTimeoutInMs) const
|
||||
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int Send(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(msg, sndTimeoutInMs);
|
||||
return GetChannel(channel, index).Send(msg, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive `msg` on `chan` at index `i`
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& chan, const int i, int rcvTimeoutInMs) const
|
||||
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int Receive(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(msg, rcvTimeoutInMs);
|
||||
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to send `msg` on `chan` at index `i` without blocking
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int SendAsync(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
int SendAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return fChannels.at(chan).at(i).SendAsync(msg);
|
||||
return GetChannel(channel, index).Send(msg, 0);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive `msg` on `chan` at index `i` without blocking
|
||||
/// @param msg message reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int ReceiveAsync(FairMQMessagePtr& msg, const std::string& chan, const int i = 0) const
|
||||
int ReceiveAsync(FairMQMessagePtr& msg, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(msg, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return fChannels.at(chan).at(i).ReceiveAsync(msg);
|
||||
}
|
||||
|
||||
int64_t Send(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(parts.fParts);
|
||||
}
|
||||
|
||||
int64_t Receive(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(parts.fParts);
|
||||
return GetChannel(channel, index).Receive(msg, 0);
|
||||
}
|
||||
|
||||
/// Shorthand method to send FairMQParts on `chan` at index `i`
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Send(FairMQParts& parts, const std::string& chan, const int i, int sndTimeoutInMs) const
|
||||
/// @param sndTimeoutInMs send timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot send)
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out. -1 if there was an error.
|
||||
int64_t Send(FairMQParts& parts, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
|
||||
{
|
||||
return fChannels.at(chan).at(i).Send(parts.fParts, sndTimeoutInMs);
|
||||
return GetChannel(channel, index).Send(parts.fParts, sndTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive FairMQParts on `chan` at index `i`
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t Receive(FairMQParts& parts, const std::string& chan, const int i, int rcvTimeoutInMs) const
|
||||
/// @param rcvTimeoutInMs receive timeout in ms, -1 will wait forever (or until interrupt (e.g. via state change)), 0 will not wait (return immediately if cannot receive)
|
||||
/// @return Number of bytes that have been received. -2 if reading from the queue was not possible or timed out. -1 if there was an error.
|
||||
int64_t Receive(FairMQParts& parts, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
|
||||
{
|
||||
return fChannels.at(chan).at(i).Receive(parts.fParts, rcvTimeoutInMs);
|
||||
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
|
||||
}
|
||||
|
||||
/// Shorthand method to send FairMQParts on `chan` at index `i` without blocking
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been queued. -2 If queueing was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t SendAsync(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
int64_t SendAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Send, use timeout version with timeout of 0: Send(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return fChannels.at(chan).at(i).SendAsync(parts.fParts);
|
||||
return GetChannel(channel, index).Send(parts.fParts, 0);
|
||||
}
|
||||
|
||||
/// Shorthand method to receive FairMQParts on `chan` at index `i` without blocking
|
||||
/// @param parts parts reference
|
||||
/// @param chan channel name
|
||||
/// @param i channel index
|
||||
/// @return Number of bytes that have been received. -2 If reading from the queue was not possible or timed out.
|
||||
/// In case of errors, returns -1.
|
||||
int64_t ReceiveAsync(FairMQParts& parts, const std::string& chan, const int i = 0) const
|
||||
int64_t ReceiveAsync(FairMQParts& parts, const std::string& channel, const int index = 0) __attribute__((deprecated("For non-blocking Receive, use timeout version with timeout of 0: Receive(parts, \"channelA\", subchannelIndex, timeout);")))
|
||||
{
|
||||
return fChannels.at(chan).at(i).ReceiveAsync(parts.fParts);
|
||||
return GetChannel(channel, index).Receive(parts.fParts, 0);
|
||||
}
|
||||
|
||||
/// @brief Getter for default transport factory
|
||||
auto Transport() const -> const FairMQTransportFactory*
|
||||
auto Transport() const -> FairMQTransportFactory*
|
||||
{
|
||||
return fTransportFactory.get();
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessage(Args&&... args) const
|
||||
FairMQMessagePtr NewMessage(Args&&... args)
|
||||
{
|
||||
return Transport()->CreateMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args) const
|
||||
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
|
||||
{
|
||||
return fChannels.at(channel).at(index).NewMessage(std::forward<Args>(args)...);
|
||||
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
{
|
||||
return Transport()->NewStaticMessage(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data) const
|
||||
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
|
||||
{
|
||||
return fChannels.at(channel).at(index).NewStaticMessage(data);
|
||||
return GetChannel(channel, index).NewStaticMessage(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
{
|
||||
return Transport()->NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data) const
|
||||
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
|
||||
{
|
||||
return fChannels.at(channel).at(index).NewSimpleMessage(data);
|
||||
return GetChannel(channel, index).NewSimpleMessage(data);
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size)
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr)
|
||||
{
|
||||
return Transport()->CreateUnmanagedRegion(size);
|
||||
return Transport()->CreateUnmanagedRegion(size, callback);
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, const size_t size, FairMQRegionCallback callback = nullptr)
|
||||
{
|
||||
return fChannels.at(channel).at(index).Transport()->CreateUnmanagedRegion(size, callback);
|
||||
return GetChannel(channel, index).Transport()->CreateUnmanagedRegion(size, callback);
|
||||
}
|
||||
|
||||
template<typename ...Ts>
|
||||
@@ -264,22 +245,22 @@ class FairMQDevice : public FairMQStateMachine
|
||||
// if more than one channel provided, check compatibility
|
||||
if (chans.size() > 1)
|
||||
{
|
||||
fair::mq::Transport type = fChannels.at(chans.at(0)).at(0).Transport()->GetType();
|
||||
fair::mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
|
||||
|
||||
for (unsigned int i = 1; i < chans.size(); ++i)
|
||||
{
|
||||
if (type != fChannels.at(chans.at(i)).at(0).Transport()->GetType())
|
||||
if (type != GetChannel(chans.at(i), 0).Transport()->GetType())
|
||||
{
|
||||
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
|
||||
ChangeState(ERROR_FOUND);
|
||||
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fChannels.at(chans.at(0)).at(0).Transport()->CreatePoller(fChannels, chans);
|
||||
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
|
||||
}
|
||||
|
||||
FairMQPollerPtr NewPoller(const std::vector<const FairMQChannel*>& channels)
|
||||
FairMQPollerPtr NewPoller(const std::vector<FairMQChannel*>& channels)
|
||||
{
|
||||
// if more than one channel provided, check compatibility
|
||||
if (channels.size() > 1)
|
||||
@@ -291,7 +272,7 @@ class FairMQDevice : public FairMQStateMachine
|
||||
if (type != channels.at(i)->Transport()->GetType())
|
||||
{
|
||||
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
|
||||
ChangeState(ERROR_FOUND);
|
||||
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -300,7 +281,7 @@ class FairMQDevice : public FairMQStateMachine
|
||||
}
|
||||
|
||||
/// Waits for the first initialization run to finish
|
||||
void WaitForInitialValidation();
|
||||
void WaitForInitialValidation() __attribute__((deprecated("This method will have no effect in future versions and will be removed. Instead subscribe for state changes and inspect configuration values."))) {}
|
||||
|
||||
/// Adds a transport to the device if it doesn't exist
|
||||
/// @param transport Transport string ("zeromq"/"nanomsg"/"shmem")
|
||||
@@ -319,6 +300,7 @@ class FairMQDevice : public FairMQStateMachine
|
||||
/// @param rhs Left hand side value for comparison
|
||||
static bool SortSocketsByAddress(const FairMQChannel &lhs, const FairMQChannel &rhs);
|
||||
|
||||
// overload to easily bind member functions
|
||||
template<typename T>
|
||||
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQMessagePtr& msg, int index))
|
||||
{
|
||||
@@ -345,6 +327,7 @@ class FairMQDevice : public FairMQStateMachine
|
||||
}
|
||||
}
|
||||
|
||||
// overload to easily bind member functions
|
||||
template<typename T>
|
||||
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
|
||||
{
|
||||
@@ -371,15 +354,21 @@ class FairMQDevice : public FairMQStateMachine
|
||||
}
|
||||
}
|
||||
|
||||
const FairMQChannel& GetChannel(const std::string& channelName, const int index = 0) const;
|
||||
FairMQChannel& GetChannel(const std::string& channelName, const int index = 0)
|
||||
try {
|
||||
return fChannels.at(channelName).at(index);
|
||||
} catch (const std::out_of_range& oor) {
|
||||
LOG(error) << "out of range: " << oor.what();
|
||||
LOG(error) << "requested channel has not been configured? check channel names/configuration.";
|
||||
throw;
|
||||
}
|
||||
|
||||
virtual void RegisterChannelEndpoints() {}
|
||||
|
||||
bool RegisterChannelEndpoint(const std::string& channelName, uint16_t minNumSubChannels = 1, uint16_t maxNumSubChannels = 1)
|
||||
{
|
||||
bool ok = fChannelRegistry.insert(std::make_pair(channelName, std::make_pair(minNumSubChannels, maxNumSubChannels))).second;
|
||||
if (!ok)
|
||||
{
|
||||
if (!ok) {
|
||||
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
|
||||
}
|
||||
return ok;
|
||||
@@ -387,14 +376,10 @@ class FairMQDevice : public FairMQStateMachine
|
||||
|
||||
void PrintRegisteredChannels()
|
||||
{
|
||||
if (fChannelRegistry.size() < 1)
|
||||
{
|
||||
if (fChannelRegistry.size() < 1) {
|
||||
std::cout << "no channels registered." << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (const auto& c : fChannelRegistry)
|
||||
{
|
||||
} else {
|
||||
for (const auto& c : fChannelRegistry) {
|
||||
std::cout << c.first << ":" << c.second.first << ":" << c.second.second << std::endl;
|
||||
}
|
||||
}
|
||||
@@ -408,12 +393,6 @@ class FairMQDevice : public FairMQStateMachine
|
||||
void SetNumIoThreads(int numIoThreads) { fConfig->SetValue<int>("io-threads", numIoThreads);}
|
||||
int GetNumIoThreads() const { return fConfig->GetValue<int>("io-threads"); }
|
||||
|
||||
void SetPortRangeMin(int portRangeMin) { fConfig->SetValue<int>("port-range-min", portRangeMin); }
|
||||
int GetPortRangeMin() const { return fConfig->GetValue<int>("port-range-min"); }
|
||||
|
||||
void SetPortRangeMax(int portRangeMax) { fConfig->SetValue<int>("port-range-max", portRangeMax); }
|
||||
int GetPortRangeMax() const { return fConfig->GetValue<int>("port-range-max"); }
|
||||
|
||||
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetValue<std::string>("network-interface", networkInterface); }
|
||||
std::string GetNetworkInterface() const { return fConfig->GetValue<std::string>("network-interface"); }
|
||||
|
||||
@@ -432,7 +411,10 @@ class FairMQDevice : public FairMQStateMachine
|
||||
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
|
||||
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
|
||||
|
||||
void RunStateMachine() { ProcessWork(); };
|
||||
void RunStateMachine()
|
||||
{
|
||||
fStateMachine.ProcessWork();
|
||||
};
|
||||
|
||||
/// Wait for the supplied amount of time or for interruption.
|
||||
/// If interrupted, returns false, otherwise true.
|
||||
@@ -440,8 +422,7 @@ class FairMQDevice : public FairMQStateMachine
|
||||
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
|
||||
return fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -462,73 +443,95 @@ class FairMQDevice : public FairMQStateMachine
|
||||
std::string fId; ///< Device ID
|
||||
|
||||
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
|
||||
virtual void Init();
|
||||
virtual void Init() {}
|
||||
|
||||
virtual void Bind() {}
|
||||
|
||||
virtual void Connect() {}
|
||||
|
||||
/// Task initialization (can be overloaded in child classes)
|
||||
virtual void InitTask();
|
||||
virtual void InitTask() {}
|
||||
|
||||
/// Runs the device (to be overloaded in child classes)
|
||||
virtual void Run();
|
||||
virtual void Run() {}
|
||||
|
||||
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
|
||||
virtual void PreRun();
|
||||
virtual void PreRun() {}
|
||||
|
||||
/// Called during RUNNING state repeatedly until it returns false or device state changes
|
||||
virtual bool ConditionalRun();
|
||||
virtual bool ConditionalRun() { return false; }
|
||||
|
||||
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
|
||||
virtual void PostRun();
|
||||
virtual void PostRun() {}
|
||||
|
||||
/// Handles the PAUSE state
|
||||
virtual void Pause();
|
||||
virtual void Pause() __attribute__((deprecated("PAUSE state is removed. This method is never called. To pause Run, go to READY with STOP transition and back to RUNNING with RUN to resume."))) {}
|
||||
|
||||
/// Resets the user task (to be overloaded in child classes)
|
||||
virtual void ResetTask();
|
||||
virtual void ResetTask() {}
|
||||
|
||||
/// Resets the device (can be overloaded in child classes)
|
||||
virtual void Reset();
|
||||
virtual void Reset() {}
|
||||
|
||||
public:
|
||||
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
|
||||
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::StateMachine::GetTransition(transition)); }
|
||||
|
||||
bool ChangeState(const int transition) __attribute__((deprecated("Use ChangeState(const fair::mq::Transition transition).")));
|
||||
|
||||
void WaitForEndOfState(const fair::mq::Transition transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState).")));
|
||||
void WaitForEndOfState(const std::string& transition) __attribute__((deprecated("Use WaitForState(fair::mq::State expectedState)."))) { WaitForState(transition); }
|
||||
|
||||
fair::mq::State WaitForNextState();
|
||||
void WaitForState(fair::mq::State state);
|
||||
void WaitForState(const std::string& state) { fair::mq::StateMachine::GetState(state); }
|
||||
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
|
||||
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
|
||||
|
||||
void SubscribeToNewTransition(const std::string& key, std::function<void(const fair::mq::Transition)> callback) { fStateMachine.SubscribeToNewTransition(key, callback); }
|
||||
void UnsubscribeFromNewTransition(const std::string& key) { fStateMachine.UnsubscribeFromNewTransition(key); }
|
||||
|
||||
bool CheckCurrentState(const int /* state */) const __attribute__((deprecated("Use NewStatePending()."))) { return !fStateMachine.NewStatePending(); }
|
||||
bool CheckCurrentState(const std::string& /* state */) const __attribute__((deprecated("Use NewStatePending()."))) { return !fStateMachine.NewStatePending(); }
|
||||
|
||||
/// Returns true is a new state has been requested, signaling the current handler to stop.
|
||||
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
|
||||
|
||||
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
|
||||
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
|
||||
|
||||
static std::string GetStateName(const fair::mq::State state) { return fair::mq::StateMachine::GetStateName(state); }
|
||||
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::StateMachine::GetTransitionName(transition); }
|
||||
|
||||
struct DeviceStateError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
|
||||
private:
|
||||
// condition variable to notify parent thread about end of initial validation.
|
||||
bool fInitialValidationFinished;
|
||||
std::condition_variable fInitialValidationCondition;
|
||||
std::mutex fInitialValidationMutex;
|
||||
|
||||
int fPortRangeMin; ///< Minimum value for the port range (if dynamic)
|
||||
int fPortRangeMax; ///< Maximum value for the port range (if dynamic)
|
||||
|
||||
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
|
||||
fair::mq::StateMachine fStateMachine;
|
||||
|
||||
/// Handles the initialization and the Init() method
|
||||
/// Handles the initialization
|
||||
void InitWrapper();
|
||||
/// Initializes binding channels
|
||||
void BindWrapper();
|
||||
/// Initializes connecting channels
|
||||
void ConnectWrapper();
|
||||
/// Handles the InitTask() method
|
||||
void InitTaskWrapper();
|
||||
/// Handles the Run() method
|
||||
void RunWrapper();
|
||||
/// Handles the Pause() method
|
||||
void PauseWrapper();
|
||||
/// Handles the ResetTask() method
|
||||
void ResetTaskWrapper();
|
||||
/// Handles the Reset() method
|
||||
void ResetWrapper();
|
||||
|
||||
/// Unblocks blocking channel send/receive calls
|
||||
void Unblock();
|
||||
/// Notifies transports to cease any blocking activity
|
||||
void UnblockTransports();
|
||||
|
||||
/// Shuts down the transports and the device
|
||||
void Exit();
|
||||
void Exit() {}
|
||||
|
||||
/// Attach (bind/connect) channels in the list
|
||||
void AttachChannels(std::vector<FairMQChannel*>& chans);
|
||||
|
||||
/// Sets up and connects/binds a socket to an endpoint
|
||||
/// return a string with the actual endpoint if it happens
|
||||
/// to stray from default.
|
||||
bool ConnectEndpoint(FairMQSocket& socket, std::string& endpoint);
|
||||
bool BindEndpoint(FairMQSocket& socket, std::string& endpoint);
|
||||
/// Attaches the channel to all listed endpoints
|
||||
/// the list is comma separated; the default method (bind/connect) is used.
|
||||
/// to override default: prepend "@" to bind, "+" or ">" to connect endpoint.
|
||||
bool AttachChannel(FairMQChannel& ch);
|
||||
|
||||
void HandleSingleChannelInput();
|
||||
@@ -536,10 +539,11 @@ class FairMQDevice : public FairMQStateMachine
|
||||
void HandleMultipleTransportInput();
|
||||
void PollForTransport(const FairMQTransportFactory* factory, const std::vector<std::string>& channelKeys);
|
||||
|
||||
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i) const;
|
||||
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i) const;
|
||||
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
|
||||
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i);
|
||||
|
||||
void CreateOwnConfig();
|
||||
std::vector<FairMQChannel*> fUninitializedBindingChannels;
|
||||
std::vector<FairMQChannel*> fUninitializedConnectingChannels;
|
||||
|
||||
bool fDataCallbacks;
|
||||
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
|
||||
@@ -552,11 +556,12 @@ class FairMQDevice : public FairMQStateMachine
|
||||
|
||||
const fair::mq::tools::Version fVersion;
|
||||
float fRate; ///< Rate limiting for ConditionalRun
|
||||
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which state will change to Ready (in seconds, 0 for no limit).
|
||||
std::vector<std::string> fRawCmdLineArgs;
|
||||
|
||||
std::atomic<bool> fInterrupted;
|
||||
std::condition_variable fInterruptedCV;
|
||||
std::mutex fInterruptedMtx;
|
||||
std::queue<fair::mq::State> fStates;
|
||||
std::mutex fStatesMtx;
|
||||
std::condition_variable fStatesCV;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQDEVICE_H_ */
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -15,10 +15,13 @@
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
using fairmq_free_fn = void(void* data, void* hint);
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQMessage
|
||||
{
|
||||
public:
|
||||
FairMQMessage() = default;
|
||||
FairMQMessage(FairMQTransportFactory* factory):fTransport{factory} {}
|
||||
virtual void Rebuild() = 0;
|
||||
virtual void Rebuild(const size_t size) = 0;
|
||||
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||
@@ -29,11 +32,15 @@ class FairMQMessage
|
||||
virtual bool SetUsedSize(const size_t size) = 0;
|
||||
|
||||
virtual fair::mq::Transport GetType() const = 0;
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
//void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
|
||||
|
||||
virtual void Copy(const std::unique_ptr<FairMQMessage>& msg) __attribute__((deprecated("Use 'Copy(const FairMQMessage& msg)'"))) = 0;
|
||||
virtual void Copy(const FairMQMessage& msg) = 0;
|
||||
|
||||
virtual ~FairMQMessage() {};
|
||||
|
||||
private:
|
||||
FairMQTransportFactory* fTransport{nullptr};
|
||||
};
|
||||
|
||||
using FairMQMessagePtr = std::unique_ptr<FairMQMessage>;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -14,46 +14,52 @@
|
||||
#include <memory>
|
||||
|
||||
#include "FairMQMessage.h"
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQSocket
|
||||
{
|
||||
public:
|
||||
FairMQSocket() {}
|
||||
FairMQSocket(FairMQTransportFactory* fac): fTransport(fac) {}
|
||||
|
||||
virtual std::string GetId() = 0;
|
||||
|
||||
virtual bool Bind(const std::string& address) = 0;
|
||||
virtual void Connect(const std::string& address) = 0;
|
||||
virtual bool Connect(const std::string& address) = 0;
|
||||
|
||||
virtual int Send(FairMQMessagePtr& msg, int timeout = 0) = 0;
|
||||
virtual int Receive(FairMQMessagePtr& msg, int timeout = 0) = 0;
|
||||
virtual int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = 0) = 0;
|
||||
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = 0) = 0;
|
||||
|
||||
virtual int TrySend(FairMQMessagePtr& msg) = 0;
|
||||
virtual int TryReceive(FairMQMessagePtr& msg) = 0;
|
||||
virtual int64_t TrySend(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) = 0;
|
||||
virtual int64_t TryReceive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) = 0;
|
||||
|
||||
virtual void* GetSocket() const = 0;
|
||||
virtual int GetSocket(int nothing) const = 0;
|
||||
virtual int Send(FairMQMessagePtr& msg, int timeout = -1) = 0;
|
||||
virtual int Receive(FairMQMessagePtr& msg, int timeout = -1) = 0;
|
||||
virtual int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
|
||||
virtual int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, int timeout = -1) = 0;
|
||||
|
||||
virtual void Close() = 0;
|
||||
|
||||
virtual void SetOption(const std::string& option, const void* value, size_t valueSize) = 0;
|
||||
virtual void GetOption(const std::string& option, void* value, size_t* valueSize) = 0;
|
||||
|
||||
virtual void SetLinger(const int value) = 0;
|
||||
virtual int GetLinger() const = 0;
|
||||
virtual void SetSndBufSize(const int value) = 0;
|
||||
virtual int GetSndBufSize() const = 0;
|
||||
virtual void SetRcvBufSize(const int value) = 0;
|
||||
virtual int GetRcvBufSize() const = 0;
|
||||
virtual void SetSndKernelSize(const int value) = 0;
|
||||
virtual int GetSndKernelSize() const = 0;
|
||||
virtual void SetRcvKernelSize(const int value) = 0;
|
||||
virtual int GetRcvKernelSize() const = 0;
|
||||
|
||||
virtual unsigned long GetBytesTx() const = 0;
|
||||
virtual unsigned long GetBytesRx() const = 0;
|
||||
virtual unsigned long GetMessagesTx() const = 0;
|
||||
virtual unsigned long GetMessagesRx() const = 0;
|
||||
|
||||
virtual bool SetSendTimeout(const int timeout, const std::string& address, const std::string& method) = 0;
|
||||
virtual int GetSendTimeout() const = 0;
|
||||
virtual bool SetReceiveTimeout(const int timeout, const std::string& address, const std::string& method) = 0;
|
||||
virtual int GetReceiveTimeout() const = 0;
|
||||
FairMQTransportFactory* GetTransport() { return fTransport; }
|
||||
void SetTransport(FairMQTransportFactory* transport) { fTransport=transport; }
|
||||
|
||||
virtual ~FairMQSocket() {};
|
||||
|
||||
private:
|
||||
FairMQTransportFactory* fTransport{nullptr};
|
||||
};
|
||||
|
||||
using FairMQSocketPtr = std::unique_ptr<FairMQSocket>;
|
||||
|
@@ -1,671 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQStateMachine.cxx
|
||||
*
|
||||
* @since 2012-10-25
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#include "FairMQStateMachine.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
// Increase maximum number of boost::msm states (default is 10)
|
||||
// This #define has to be before any msm header includes
|
||||
#define FUSION_MAX_VECTOR_SIZE 20
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/msm/back/state_machine.hpp>
|
||||
#include <boost/msm/back/tools.hpp>
|
||||
#include <boost/msm/back/metafunctions.hpp>
|
||||
#include <boost/msm/front/state_machine_def.hpp>
|
||||
#include <boost/msm/front/functor_row.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/signals2.hpp> // signal/slot for onStateChange callbacks
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
|
||||
using namespace std;
|
||||
using namespace boost::msm::front;
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<>
|
||||
struct hash<FairMQStateMachine::Event> : fair::mq::tools::HashEnum<FairMQStateMachine::Event> {};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace fsm
|
||||
{
|
||||
|
||||
// list of FSM states
|
||||
struct OK_FSM_STATE : public state<> { static string Name() { return "OK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::OK; } };
|
||||
struct ERROR_FSM_STATE : public terminate_state<> { static string Name() { return "ERROR"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::Error; } };
|
||||
|
||||
struct IDLE_FSM_STATE : public state<> { static string Name() { return "IDLE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::IDLE; } };
|
||||
struct INITIALIZING_DEVICE_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_DEVICE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_DEVICE; } };
|
||||
struct DEVICE_READY_FSM_STATE : public state<> { static string Name() { return "DEVICE_READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::DEVICE_READY; } };
|
||||
struct INITIALIZING_TASK_FSM_STATE : public state<> { static string Name() { return "INITIALIZING_TASK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::INITIALIZING_TASK; } };
|
||||
struct READY_FSM_STATE : public state<> { static string Name() { return "READY"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::READY; } };
|
||||
struct RUNNING_FSM_STATE : public state<> { static string Name() { return "RUNNING"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RUNNING; } };
|
||||
struct PAUSED_FSM_STATE : public state<> { static string Name() { return "PAUSED"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::PAUSED; } };
|
||||
struct RESETTING_TASK_FSM_STATE : public state<> { static string Name() { return "RESETTING_TASK"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RESETTING_TASK; } };
|
||||
struct RESETTING_DEVICE_FSM_STATE : public state<> { static string Name() { return "RESETTING_DEVICE"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::RESETTING_DEVICE; } };
|
||||
struct EXITING_FSM_STATE : public state<> { static string Name() { return "EXITING"; } static FairMQStateMachine::State Type() { return FairMQStateMachine::State::EXITING; } };
|
||||
|
||||
// list of FSM events
|
||||
struct INIT_DEVICE_FSM_EVENT { static string Name() { return "INIT_DEVICE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::INIT_DEVICE; } };
|
||||
struct internal_DEVICE_READY_FSM_EVENT { static string Name() { return "internal_DEVICE_READY"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_DEVICE_READY; } };
|
||||
struct INIT_TASK_FSM_EVENT { static string Name() { return "INIT_TASK"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::INIT_TASK; } };
|
||||
struct internal_READY_FSM_EVENT { static string Name() { return "internal_READY"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_READY; } };
|
||||
struct RUN_FSM_EVENT { static string Name() { return "RUN"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RUN; } };
|
||||
struct PAUSE_FSM_EVENT { static string Name() { return "PAUSE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::PAUSE; } };
|
||||
struct STOP_FSM_EVENT { static string Name() { return "STOP"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::STOP; } };
|
||||
struct RESET_TASK_FSM_EVENT { static string Name() { return "RESET_TASK"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RESET_TASK; } };
|
||||
struct RESET_DEVICE_FSM_EVENT { static string Name() { return "RESET_DEVICE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::RESET_DEVICE; } };
|
||||
struct internal_IDLE_FSM_EVENT { static string Name() { return "internal_IDLE"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::internal_IDLE; } };
|
||||
struct END_FSM_EVENT { static string Name() { return "END"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::END; } };
|
||||
struct ERROR_FOUND_FSM_EVENT { static string Name() { return "ERROR_FOUND"; } static FairMQStateMachine::Event Type() { return FairMQStateMachine::Event::ERROR_FOUND; } };
|
||||
|
||||
static array<string, 12> stateNames =
|
||||
{
|
||||
{
|
||||
"OK",
|
||||
"Error",
|
||||
"IDLE",
|
||||
"INITIALIZING_DEVICE",
|
||||
"DEVICE_READY",
|
||||
"INITIALIZING_TASK",
|
||||
"READY",
|
||||
"RUNNING",
|
||||
"PAUSED",
|
||||
"RESETTING_TASK",
|
||||
"RESETTING_DEVICE",
|
||||
"EXITING"
|
||||
}
|
||||
};
|
||||
|
||||
static array<string, 12> eventNames =
|
||||
{
|
||||
{
|
||||
"INIT_DEVICE",
|
||||
"internal_DEVICE_READY",
|
||||
"INIT_TASK",
|
||||
"internal_READY",
|
||||
"RUN",
|
||||
"PAUSE",
|
||||
"STOP",
|
||||
"RESET_TASK",
|
||||
"RESET_DEVICE",
|
||||
"internal_IDLE",
|
||||
"END",
|
||||
"ERROR_FOUND"
|
||||
}
|
||||
};
|
||||
|
||||
static map<string, int> stateNumbers =
|
||||
{
|
||||
{ "OK", FairMQStateMachine::State::OK },
|
||||
{ "Error", FairMQStateMachine::State::Error },
|
||||
{ "IDLE", FairMQStateMachine::State::IDLE },
|
||||
{ "INITIALIZING_DEVICE", FairMQStateMachine::State::INITIALIZING_DEVICE },
|
||||
{ "DEVICE_READY", FairMQStateMachine::State::DEVICE_READY },
|
||||
{ "INITIALIZING_TASK", FairMQStateMachine::State::INITIALIZING_TASK },
|
||||
{ "READY", FairMQStateMachine::State::READY },
|
||||
{ "RUNNING", FairMQStateMachine::State::RUNNING },
|
||||
{ "PAUSED", FairMQStateMachine::State::PAUSED },
|
||||
{ "RESETTING_TASK", FairMQStateMachine::State::RESETTING_TASK },
|
||||
{ "RESETTING_DEVICE", FairMQStateMachine::State::RESETTING_DEVICE },
|
||||
{ "EXITING", FairMQStateMachine::State::EXITING }
|
||||
};
|
||||
|
||||
static map<string, int> eventNumbers =
|
||||
{
|
||||
{ "INIT_DEVICE", FairMQStateMachine::Event::INIT_DEVICE },
|
||||
{ "internal_DEVICE_READY", FairMQStateMachine::Event::internal_DEVICE_READY },
|
||||
{ "INIT_TASK", FairMQStateMachine::Event::INIT_TASK },
|
||||
{ "internal_READY", FairMQStateMachine::Event::internal_READY },
|
||||
{ "RUN", FairMQStateMachine::Event::RUN },
|
||||
{ "PAUSE", FairMQStateMachine::Event::PAUSE },
|
||||
{ "STOP", FairMQStateMachine::Event::STOP },
|
||||
{ "RESET_TASK", FairMQStateMachine::Event::RESET_TASK },
|
||||
{ "RESET_DEVICE", FairMQStateMachine::Event::RESET_DEVICE },
|
||||
{ "internal_IDLE", FairMQStateMachine::Event::internal_IDLE },
|
||||
{ "END", FairMQStateMachine::Event::END },
|
||||
{ "ERROR_FOUND", FairMQStateMachine::Event::ERROR_FOUND }
|
||||
};
|
||||
|
||||
// defining the boost MSM state machine
|
||||
struct Machine_ : public state_machine_def<Machine_>
|
||||
{
|
||||
public:
|
||||
Machine_()
|
||||
: fUnblockHandler()
|
||||
, fStateHandlers()
|
||||
, fWork()
|
||||
, fWorkAvailableCondition()
|
||||
, fWorkDoneCondition()
|
||||
, fWorkMutex()
|
||||
, fWorkerTerminated(false)
|
||||
, fWorkActive(false)
|
||||
, fWorkAvailable(false)
|
||||
, fStateChangeSignal()
|
||||
, fStateChangeSignalsMap()
|
||||
, fState()
|
||||
{}
|
||||
|
||||
virtual ~Machine_()
|
||||
{}
|
||||
|
||||
// initial states
|
||||
using initial_state = boost::mpl::vector<IDLE_FSM_STATE, OK_FSM_STATE>;
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
void on_entry(Event const&, FSM& fsm)
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine";
|
||||
fState = FairMQStateMachine::IDLE;
|
||||
LOG(state) << "Entering IDLE state";
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::IDLE);
|
||||
}
|
||||
|
||||
template<typename Event, typename FSM>
|
||||
void on_exit(Event const&, FSM& /*fsm*/)
|
||||
{
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
// actions
|
||||
struct AutomaticFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct DefaultFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.fWork = fsm.fStateHandlers.at(e.Type());
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct PauseFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
fsm.fWorkAvailable = true;
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.fWork = fsm.fPauseWrapperHandler;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
};
|
||||
|
||||
struct StopFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
|
||||
fsm.fUnblockHandler();
|
||||
unique_lock<mutex> lock(fsm.fWorkMutex);
|
||||
while (fsm.fWorkActive)
|
||||
{
|
||||
fsm.fWorkDoneCondition.wait(lock);
|
||||
}
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct InternalStopFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
fsm.fUnblockHandler();
|
||||
LOG(state) << "RUNNING state finished without an external event, entering " << ts.Name() << " state";
|
||||
}
|
||||
};
|
||||
|
||||
struct ExitingFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.fState = ts.Type();
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::EXITING);
|
||||
|
||||
// Stop ProcessWork()
|
||||
{
|
||||
lock_guard<mutex> lock(fsm.fWorkMutex);
|
||||
fsm.fWorkerTerminated = true;
|
||||
fsm.fWorkAvailableCondition.notify_one();
|
||||
}
|
||||
|
||||
fsm.fStateHandlers.at(e.Type())();
|
||||
}
|
||||
};
|
||||
|
||||
struct ErrorFoundFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const&, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fsm.fState = ts.Type();
|
||||
LOG(state) << "Entering " << ts.Name() << " state";
|
||||
fsm.CallStateChangeCallbacks(FairMQStateMachine::Error);
|
||||
}
|
||||
};
|
||||
|
||||
// Transition table for Machine_
|
||||
struct transition_table : boost::mpl::vector<
|
||||
// Start Event Next Action Guard
|
||||
Row<IDLE_FSM_STATE, INIT_DEVICE_FSM_EVENT, INITIALIZING_DEVICE_FSM_STATE, DefaultFct, none>,
|
||||
Row<IDLE_FSM_STATE, END_FSM_EVENT, EXITING_FSM_STATE, ExitingFct, none>,
|
||||
Row<INITIALIZING_DEVICE_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<DEVICE_READY_FSM_STATE, INIT_TASK_FSM_EVENT, INITIALIZING_TASK_FSM_STATE, DefaultFct, none>,
|
||||
Row<DEVICE_READY_FSM_STATE, RESET_DEVICE_FSM_EVENT, RESETTING_DEVICE_FSM_STATE, DefaultFct, none>,
|
||||
Row<INITIALIZING_TASK_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<READY_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
|
||||
Row<READY_FSM_STATE, RESET_TASK_FSM_EVENT, RESETTING_TASK_FSM_STATE, DefaultFct, none>,
|
||||
Row<RUNNING_FSM_STATE, PAUSE_FSM_EVENT, PAUSED_FSM_STATE, DefaultFct, none>,
|
||||
Row<RUNNING_FSM_STATE, STOP_FSM_EVENT, READY_FSM_STATE, StopFct, none>,
|
||||
Row<RUNNING_FSM_STATE, internal_READY_FSM_EVENT, READY_FSM_STATE, InternalStopFct, none>,
|
||||
Row<PAUSED_FSM_STATE, RUN_FSM_EVENT, RUNNING_FSM_STATE, DefaultFct, none>,
|
||||
Row<RESETTING_TASK_FSM_STATE, internal_DEVICE_READY_FSM_EVENT, DEVICE_READY_FSM_STATE, AutomaticFct, none>,
|
||||
Row<RESETTING_DEVICE_FSM_STATE, internal_IDLE_FSM_EVENT, IDLE_FSM_STATE, AutomaticFct, none>,
|
||||
Row<OK_FSM_STATE, ERROR_FOUND_FSM_EVENT, ERROR_FSM_STATE, ErrorFoundFct, none>>
|
||||
{};
|
||||
|
||||
// replaces the default no-transition response.
|
||||
template<typename FSM, typename Event>
|
||||
void no_transition(Event const& e, FSM&, int state)
|
||||
{
|
||||
using recursive_stt = typename boost::msm::back::recursive_get_transition_table<FSM>::type;
|
||||
using all_states = typename boost::msm::back::generate_state_set<recursive_stt>::type;
|
||||
|
||||
string stateName;
|
||||
|
||||
boost::mpl::for_each<all_states, boost::msm::wrap<boost::mpl::placeholders::_1>>(boost::msm::back::get_state_name<recursive_stt>(stateName, state));
|
||||
|
||||
stateName = boost::core::demangle(stateName.c_str());
|
||||
size_t pos = stateName.rfind(":");
|
||||
if (pos != string::npos)
|
||||
{
|
||||
stateName = stateName.substr(pos + 1);
|
||||
stateName = stateName.substr(0, stateName.size() - 10);
|
||||
}
|
||||
|
||||
if (stateName != "OK")
|
||||
{
|
||||
LOG(state) << "No transition from state " << stateName << " on event " << e.Name();
|
||||
}
|
||||
}
|
||||
|
||||
void CallStateChangeCallbacks(const FairMQStateMachine::State state) const
|
||||
{
|
||||
if (!fStateChangeSignal.empty())
|
||||
{
|
||||
fStateChangeSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
function<void(void)> fUnblockHandler;
|
||||
unordered_map<FairMQStateMachine::Event, function<void(void)>> fStateHandlers;
|
||||
|
||||
// function to execute user states in a worker thread
|
||||
function<void(void)> fWork;
|
||||
condition_variable fWorkAvailableCondition;
|
||||
condition_variable fWorkDoneCondition;
|
||||
mutex fWorkMutex;
|
||||
bool fWorkerTerminated;
|
||||
bool fWorkActive;
|
||||
bool fWorkAvailable;
|
||||
|
||||
boost::signals2::signal<void(const FairMQStateMachine::State)> fStateChangeSignal;
|
||||
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
|
||||
|
||||
atomic<FairMQStateMachine::State> fState;
|
||||
|
||||
void ProcessWork()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
{
|
||||
unique_lock<mutex> lock(fWorkMutex);
|
||||
// Wait for work to be done.
|
||||
while (!fWorkAvailable && !fWorkerTerminated)
|
||||
{
|
||||
fWorkAvailableCondition.wait_for(lock, chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
if (fWorkerTerminated)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
fWorkActive = true;
|
||||
}
|
||||
|
||||
fWork();
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(fWorkMutex);
|
||||
fWorkActive = false;
|
||||
fWorkAvailable = false;
|
||||
fWorkDoneCondition.notify_one();
|
||||
}
|
||||
CallStateChangeCallbacks(fState);
|
||||
}
|
||||
}
|
||||
}; // Machine_
|
||||
|
||||
using FairMQFSM = boost::msm::back::state_machine<Machine_>;
|
||||
|
||||
} // namespace fsm
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
using namespace fair::mq::fsm;
|
||||
|
||||
FairMQStateMachine::FairMQStateMachine()
|
||||
: fChangeStateMutex()
|
||||
, fFsm(new FairMQFSM)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(INIT_DEVICE, bind(&FairMQStateMachine::InitWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(INIT_TASK, bind(&FairMQStateMachine::InitTaskWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RUN, bind(&FairMQStateMachine::RunWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(PAUSE, bind(&FairMQStateMachine::PauseWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_TASK, bind(&FairMQStateMachine::ResetTaskWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(RESET_DEVICE, bind(&FairMQStateMachine::ResetWrapper, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateHandlers.emplace(END, bind(&FairMQStateMachine::Exit, this));
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fUnblockHandler = bind(&FairMQStateMachine::Unblock, this);
|
||||
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->start();
|
||||
}
|
||||
|
||||
FairMQStateMachine::~FairMQStateMachine()
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->stop();
|
||||
}
|
||||
|
||||
int FairMQStateMachine::GetInterfaceVersion() const
|
||||
{
|
||||
return FAIRMQ_INTERFACE_VERSION;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::ChangeState(int event)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_DEVICE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_DEVICE_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_DEVICE_READY_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case INIT_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(INIT_TASK_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_READY:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_READY_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RUN:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RUN_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case PAUSE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(PAUSE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case STOP:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(STOP_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_DEVICE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case RESET_TASK:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(RESET_TASK_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case internal_IDLE:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(internal_IDLE_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case END:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(END_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
case ERROR_FOUND:
|
||||
{
|
||||
lock_guard<mutex> lock(fChangeStateMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->process_event(ERROR_FOUND_FSM_EVENT());
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
{
|
||||
LOG(error) << "Requested state transition with an unsupported event: " << event << endl
|
||||
<< "Supported are: INIT_DEVICE, INIT_TASK, RUN, PAUSE, STOP, RESET_TASK, RESET_DEVICE, END, ERROR_FOUND";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::ChangeState(): " << e.what();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::ChangeState(const string& event)
|
||||
{
|
||||
return ChangeState(GetEventNumber(event));
|
||||
}
|
||||
|
||||
void FairMQStateMachine::WaitForEndOfState(int event)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
case INIT_TASK:
|
||||
case RUN:
|
||||
case RESET_TASK:
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
unique_lock<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
while (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive || static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.wait_for(lock, chrono::seconds(1));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
LOG(error) << "Requested state is either synchronous or does not exist.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::WaitForEndOfState(): " << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQStateMachine::WaitForEndOfState(const string& event)
|
||||
{
|
||||
return WaitForEndOfState(GetEventNumber(event));
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::WaitForEndOfStateForMs(int event, int durationInMs)
|
||||
{
|
||||
try
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case INIT_DEVICE:
|
||||
case INIT_TASK:
|
||||
case RUN:
|
||||
case RESET_TASK:
|
||||
case RESET_DEVICE:
|
||||
{
|
||||
unique_lock<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
while (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive || static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.wait_for(lock, chrono::milliseconds(durationInMs));
|
||||
if (static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
LOG(error) << "Requested state is either synchronous or does not exist.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (exception& e)
|
||||
{
|
||||
LOG(error) << "Exception in FairMQStateMachine::WaitForEndOfStateForMs(): " << e.what();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FairMQStateMachine::WaitForEndOfStateForMs(const string& event, int durationInMs)
|
||||
{
|
||||
return WaitForEndOfStateForMs(GetEventNumber(event), durationInMs);
|
||||
}
|
||||
|
||||
void FairMQStateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignal.connect(callback)});
|
||||
}
|
||||
void FairMQStateMachine::UnsubscribeFromStateChange(const string& key)
|
||||
{
|
||||
if (static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.count(key))
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.at(key).disconnect();
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQStateMachine::CallStateChangeCallbacks(const State state) const
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->CallStateChangeCallbacks(state);
|
||||
}
|
||||
|
||||
string FairMQStateMachine::GetCurrentStateName() const
|
||||
{
|
||||
return GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState);
|
||||
}
|
||||
string FairMQStateMachine::GetStateName(const State state)
|
||||
{
|
||||
return stateNames.at(state);
|
||||
}
|
||||
int FairMQStateMachine::GetCurrentState() const
|
||||
{
|
||||
return static_pointer_cast<FairMQFSM>(fFsm)->fState;
|
||||
}
|
||||
bool FairMQStateMachine::CheckCurrentState(int state) const
|
||||
{
|
||||
return state == static_pointer_cast<FairMQFSM>(fFsm)->fState;
|
||||
}
|
||||
bool FairMQStateMachine::CheckCurrentState(const string& state) const
|
||||
{
|
||||
return state == GetCurrentStateName();
|
||||
}
|
||||
|
||||
void FairMQStateMachine::ProcessWork()
|
||||
try
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->ProcessWork();
|
||||
} catch(...) {
|
||||
{
|
||||
lock_guard<mutex> lock(static_pointer_cast<FairMQFSM>(fFsm)->fWorkMutex);
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkActive = false;
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkAvailable = false;
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fWorkDoneCondition.notify_one();
|
||||
}
|
||||
ChangeState(ERROR_FOUND);
|
||||
throw;
|
||||
}
|
||||
|
||||
|
||||
int FairMQStateMachine::GetEventNumber(const string& event)
|
||||
{
|
||||
return eventNumbers.at(event);
|
||||
}
|
@@ -1,107 +0,0 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
* FairMQStateMachine.h
|
||||
*
|
||||
* @since 2012-10-25
|
||||
* @author D. Klein, A. Rybalchenko
|
||||
*/
|
||||
|
||||
#ifndef FAIRMQSTATEMACHINE_H_
|
||||
#define FAIRMQSTATEMACHINE_H_
|
||||
|
||||
#define FAIRMQ_INTERFACE_VERSION 3
|
||||
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
|
||||
class FairMQStateMachine
|
||||
{
|
||||
public:
|
||||
enum Event
|
||||
{
|
||||
INIT_DEVICE,
|
||||
internal_DEVICE_READY,
|
||||
INIT_TASK,
|
||||
internal_READY,
|
||||
RUN,
|
||||
PAUSE,
|
||||
STOP,
|
||||
RESET_TASK,
|
||||
RESET_DEVICE,
|
||||
internal_IDLE,
|
||||
END,
|
||||
ERROR_FOUND
|
||||
};
|
||||
|
||||
enum State
|
||||
{
|
||||
OK,
|
||||
Error,
|
||||
IDLE,
|
||||
INITIALIZING_DEVICE,
|
||||
DEVICE_READY,
|
||||
INITIALIZING_TASK,
|
||||
READY,
|
||||
RUNNING,
|
||||
PAUSED,
|
||||
RESETTING_TASK,
|
||||
RESETTING_DEVICE,
|
||||
EXITING
|
||||
};
|
||||
|
||||
FairMQStateMachine();
|
||||
virtual ~FairMQStateMachine();
|
||||
|
||||
int GetInterfaceVersion() const;
|
||||
|
||||
bool ChangeState(int event);
|
||||
bool ChangeState(const std::string& event);
|
||||
|
||||
void WaitForEndOfState(int event);
|
||||
void WaitForEndOfState(const std::string& event);
|
||||
|
||||
bool WaitForEndOfStateForMs(int event, int durationInMs);
|
||||
bool WaitForEndOfStateForMs(const std::string& event, int durationInMs);
|
||||
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback);
|
||||
void UnsubscribeFromStateChange(const std::string& key);
|
||||
|
||||
void CallStateChangeCallbacks(const State state) const;
|
||||
|
||||
std::string GetCurrentStateName() const;
|
||||
static std::string GetStateName(const State);
|
||||
int GetCurrentState() const;
|
||||
bool CheckCurrentState(int state) const;
|
||||
bool CheckCurrentState(const std::string& state) const;
|
||||
|
||||
// actions to be overwritten by derived classes
|
||||
virtual void InitWrapper() {}
|
||||
virtual void InitTaskWrapper() {}
|
||||
virtual void RunWrapper() {}
|
||||
virtual void PauseWrapper() {}
|
||||
virtual void ResetWrapper() {}
|
||||
virtual void ResetTaskWrapper() {}
|
||||
virtual void Exit() {}
|
||||
virtual void Unblock() {}
|
||||
|
||||
void ProcessWork();
|
||||
|
||||
private:
|
||||
static int GetEventNumber(const std::string& event);
|
||||
|
||||
std::mutex fChangeStateMutex;
|
||||
|
||||
std::shared_ptr<void> fFsm;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSTATEMACHINE_H_ */
|
@@ -9,11 +9,12 @@
|
||||
#ifndef FAIRMQTRANSPORTFACTORY_H_
|
||||
#define FAIRMQTRANSPORTFACTORY_H_
|
||||
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQPoller.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <FairMQLogger.h>
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQPoller.h>
|
||||
#include <FairMQSocket.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
#include <fairmq/Transports.h>
|
||||
|
||||
#include <string>
|
||||
@@ -30,6 +31,9 @@ class FairMQTransportFactory
|
||||
/// Topology wide unique id
|
||||
const std::string fkId;
|
||||
|
||||
/// The polymorphic memory resource associated with the transport
|
||||
fair::mq::ChannelResource fMemoryResource{this};
|
||||
|
||||
public:
|
||||
/// ctor
|
||||
/// @param id Topology wide unique id, usually the device id.
|
||||
@@ -37,34 +41,36 @@ class FairMQTransportFactory
|
||||
|
||||
auto GetId() const -> const std::string { return fkId; };
|
||||
|
||||
/// Get a pointer to the associated polymorphic memory resource
|
||||
fair::mq::ChannelResource* GetMemoryResource() { return &fMemoryResource; }
|
||||
operator fair::mq::ChannelResource*() { return &fMemoryResource; }
|
||||
|
||||
/// @brief Create empty FairMQMessage
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage() const = 0;
|
||||
virtual FairMQMessagePtr CreateMessage() = 0;
|
||||
/// @brief Create new FairMQMessage of specified size
|
||||
/// @param size message size
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size) const = 0;
|
||||
virtual FairMQMessagePtr CreateMessage(const size_t size) = 0;
|
||||
/// @brief Create new FairMQMessage with user provided buffer and size
|
||||
/// @param data pointer to user provided buffer
|
||||
/// @param size size of the user provided buffer
|
||||
/// @param ffn callback, called when the message is transfered (and can be deleted)
|
||||
/// @param obj optional helper pointer that can be used in the callback
|
||||
/// @return pointer to FairMQMessage
|
||||
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) const = 0;
|
||||
virtual FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
|
||||
|
||||
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) const = 0;
|
||||
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
|
||||
|
||||
/// Create a socket
|
||||
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) const = 0;
|
||||
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
|
||||
|
||||
/// Create a poller for a single channel (all subchannels)
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
|
||||
/// Create a poller for specific channels
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<const FairMQChannel*>& channels) const = 0;
|
||||
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
|
||||
/// Create a poller for specific channels (all subchannels)
|
||||
virtual FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const = 0;
|
||||
/// Create a poller for two sockets
|
||||
virtual FairMQPollerPtr CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const = 0;
|
||||
|
||||
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr) const = 0;
|
||||
|
||||
@@ -73,6 +79,7 @@ class FairMQTransportFactory
|
||||
|
||||
virtual void Interrupt() = 0;
|
||||
virtual void Resume() = 0;
|
||||
virtual void Reset() = 0;
|
||||
|
||||
virtual ~FairMQTransportFactory() {};
|
||||
|
||||
@@ -89,7 +96,7 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data) const
|
||||
FairMQMessagePtr NewSimpleMessage(const T& data)
|
||||
{
|
||||
// todo: is_trivially_copyable not available on gcc < 5, workaround?
|
||||
// static_assert(std::is_trivially_copyable<T>::value, "The argument type for NewSimpleMessage has to be trivially copyable!");
|
||||
@@ -98,13 +105,13 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<std::size_t N>
|
||||
FairMQMessagePtr NewSimpleMessage(const char(&data)[N]) const
|
||||
FairMQMessagePtr NewSimpleMessage(const char(&data)[N])
|
||||
{
|
||||
std::string* msgStr = new std::string(data);
|
||||
return CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
|
||||
}
|
||||
|
||||
FairMQMessagePtr NewSimpleMessage(const std::string& str) const
|
||||
FairMQMessagePtr NewSimpleMessage(const std::string& str)
|
||||
{
|
||||
|
||||
std::string* msgStr = new std::string(str);
|
||||
@@ -112,12 +119,12 @@ class FairMQTransportFactory
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
FairMQMessagePtr NewStaticMessage(const T& data) const
|
||||
FairMQMessagePtr NewStaticMessage(const T& data)
|
||||
{
|
||||
return CreateMessage(data, sizeof(T), FairMQNoCleanup, nullptr);
|
||||
}
|
||||
|
||||
FairMQMessagePtr NewStaticMessage(const std::string& str) const
|
||||
FairMQMessagePtr NewStaticMessage(const std::string& str)
|
||||
{
|
||||
return CreateMessage(const_cast<char*>(str.c_str()), str.length(), FairMQNoCleanup, nullptr);
|
||||
}
|
||||
|
66
fairmq/MemoryResourceTools.h
Normal file
66
fairmq/MemoryResourceTools.h
Normal file
@@ -0,0 +1,66 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Tools for interfacing containers to the transport via polymorphic
|
||||
/// allocators
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#include <fairmq/FairMQTransportFactory.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
||||
using BytePmrAllocator = pmr::polymorphic_allocator<fair::mq::byte>;
|
||||
|
||||
//_________________________________________________________________________________________________
|
||||
// return the message associated with the container or throw if it is not possible
|
||||
template<typename ContainerT>
|
||||
// typename std::enable_if<
|
||||
// std::is_base_of<
|
||||
// pmr::polymorphic_allocator<typename
|
||||
// ContainerT::value_type>,
|
||||
// typename ContainerT::allocator_type>::value == true,
|
||||
// FairMQMessagePtr>::type
|
||||
FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targetResource = nullptr)
|
||||
{
|
||||
auto container = std::move(container_);
|
||||
auto alloc = container.get_allocator();
|
||||
|
||||
auto resource = dynamic_cast<FairMQMemoryResource *>(alloc.resource());
|
||||
if (!resource && !targetResource) {
|
||||
throw std::runtime_error("Neither the container or target resource specified");
|
||||
}
|
||||
size_t containerSizeBytes = container.size() * sizeof(typename ContainerT::value_type);
|
||||
if ((!targetResource && resource)
|
||||
|| (resource && targetResource && resource->is_equal(*targetResource))) {
|
||||
auto message = resource->getMessage(static_cast<void *>(
|
||||
const_cast<typename std::remove_const<typename ContainerT::value_type>::type *>(
|
||||
container.data())));
|
||||
if (message)
|
||||
{
|
||||
message->SetUsedSize(containerSizeBytes);
|
||||
return message;
|
||||
} else {
|
||||
//container is not required to allocate (like in std::string small string optimization)
|
||||
//in case we get no message we fall back to default (copy) behaviour)
|
||||
targetResource = resource;
|
||||
}
|
||||
}
|
||||
|
||||
auto message = targetResource->getTransportFactory()->CreateMessage(containerSizeBytes);
|
||||
std::memcpy(static_cast<fair::mq::byte *>(message->GetData()),
|
||||
container.data(),
|
||||
containerSizeBytes);
|
||||
return message;
|
||||
};
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
22
fairmq/MemoryResources.cxx
Normal file
22
fairmq/MemoryResources.cxx
Normal file
@@ -0,0 +1,22 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Memory allocators and interfaces related to managing memory via the
|
||||
/// trasport layer
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#include <fairmq/FairMQTransportFactory.h>
|
||||
#include <fairmq/MemoryResources.h>
|
||||
|
||||
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t /*alignment*/)
|
||||
{
|
||||
return setMessage(factory->CreateMessage(bytes));
|
||||
};
|
||||
|
116
fairmq/MemoryResources.h
Normal file
116
fairmq/MemoryResources.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
/// @brief Memory allocators and interfaces related to managing memory via the
|
||||
/// trasport layer
|
||||
///
|
||||
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
|
||||
|
||||
#ifndef FAIR_MQ_MEMORY_RESOURCES_H
|
||||
#define FAIR_MQ_MEMORY_RESOURCES_H
|
||||
|
||||
#include <fairmq/FairMQMessage.h>
|
||||
class FairMQTransportFactory;
|
||||
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include <boost/container/pmr/memory_resource.hpp>
|
||||
#include <boost/container/pmr/monotonic_buffer_resource.hpp>
|
||||
#include <boost/container/pmr/polymorphic_allocator.hpp>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
|
||||
using byte = unsigned char;
|
||||
namespace pmr = boost::container::pmr;
|
||||
|
||||
/// All FairMQ related memory resources need to inherit from this interface
|
||||
/// class for the
|
||||
/// getMessage() api.
|
||||
class FairMQMemoryResource : public pmr::memory_resource
|
||||
{
|
||||
public:
|
||||
/// return the message containing data associated with the pointer (to start
|
||||
/// of
|
||||
/// buffer), e.g. pointer returned by std::vector::data() return nullptr if
|
||||
/// returning
|
||||
/// a message does not make sense!
|
||||
virtual FairMQMessagePtr getMessage(void *p) = 0;
|
||||
virtual void *setMessage(FairMQMessagePtr) = 0;
|
||||
virtual FairMQTransportFactory *getTransportFactory() noexcept = 0;
|
||||
virtual size_t getNumberOfMessages() const noexcept = 0;
|
||||
};
|
||||
|
||||
/// This is the allocator that interfaces to FairMQ memory management. All
|
||||
/// allocations are
|
||||
/// delegated to FairMQ so standard (e.g. STL) containers can construct their
|
||||
/// stuff in
|
||||
/// memory regions appropriate for the data channel configuration.
|
||||
class ChannelResource : public FairMQMemoryResource
|
||||
{
|
||||
protected:
|
||||
FairMQTransportFactory *factory{nullptr};
|
||||
// TODO: for now a map to keep track of allocations, something else would
|
||||
// probably be
|
||||
// faster, but for now this does not need to be fast.
|
||||
boost::container::flat_map<void *, FairMQMessagePtr> messageMap;
|
||||
|
||||
public:
|
||||
ChannelResource() = delete;
|
||||
|
||||
ChannelResource(FairMQTransportFactory *_factory)
|
||||
: FairMQMemoryResource()
|
||||
, factory(_factory)
|
||||
, messageMap()
|
||||
{
|
||||
if (!_factory) {
|
||||
throw std::runtime_error("Tried to construct from a nullptr FairMQTransportFactory");
|
||||
}
|
||||
};
|
||||
|
||||
FairMQMessagePtr getMessage(void *p) override
|
||||
{
|
||||
auto mes = std::move(messageMap[p]);
|
||||
messageMap.erase(p);
|
||||
return mes;
|
||||
}
|
||||
|
||||
void *setMessage(FairMQMessagePtr message) override
|
||||
{
|
||||
void *addr = message->GetData();
|
||||
messageMap[addr] = std::move(message);
|
||||
return addr;
|
||||
}
|
||||
|
||||
FairMQTransportFactory *getTransportFactory() noexcept override { return factory; }
|
||||
|
||||
size_t getNumberOfMessages() const noexcept override { return messageMap.size(); }
|
||||
|
||||
protected:
|
||||
void *do_allocate(std::size_t bytes, std::size_t alignment) override;
|
||||
void do_deallocate(void *p, std::size_t /*bytes*/, std::size_t /*alignment*/) override
|
||||
{
|
||||
messageMap.erase(p);
|
||||
};
|
||||
|
||||
bool do_is_equal(const pmr::memory_resource &other) const noexcept override
|
||||
{
|
||||
return this == &other;
|
||||
};
|
||||
};
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif /* FAIR_MQ_MEMORY_RESOURCES_H */
|
@@ -78,7 +78,7 @@ class Plugin
|
||||
auto TakeDeviceControl() -> void { fPluginServices->TakeDeviceControl(fkName); };
|
||||
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
|
||||
auto ReleaseDeviceControl() -> void { fPluginServices->ReleaseDeviceControl(fkName); };
|
||||
auto ChangeDeviceState(const DeviceStateTransition next) -> void { fPluginServices->ChangeDeviceState(fkName, next); }
|
||||
auto ChangeDeviceState(const DeviceStateTransition next) -> bool { return fPluginServices->ChangeDeviceState(fkName, next); }
|
||||
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
|
||||
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
|
||||
|
||||
|
@@ -29,7 +29,7 @@ using boost::optional;
|
||||
const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
|
||||
|
||||
fair::mq::PluginManager::PluginManager()
|
||||
: fSearchPaths{{"."}}
|
||||
: fSearchPaths{}
|
||||
, fPluginFactories()
|
||||
, fPluginServices()
|
||||
, fPlugins()
|
||||
@@ -39,7 +39,7 @@ fair::mq::PluginManager::PluginManager()
|
||||
}
|
||||
|
||||
fair::mq::PluginManager::PluginManager(const vector<string> args)
|
||||
: fSearchPaths{{"."}}
|
||||
: fSearchPaths{}
|
||||
, fPluginFactories()
|
||||
, fPluginServices()
|
||||
, fPlugins()
|
||||
@@ -115,7 +115,8 @@ auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
|
||||
"* Append(>) or prepend(<) to default search path, e.g.\n"
|
||||
" -S >/lib </home/user/lib\n"
|
||||
"* If you mix the overriding and appending/prepending syntaxes, the overriding paths act as default search path, e.g.\n"
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib")
|
||||
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
|
||||
"If nothing is found, the default dynamic library lookup is performed, see man ld.so(8) for details.")
|
||||
("plugin,P", po::value<vector<string>>(), "List of plugin names to load in order,"
|
||||
"e.g. if the file is called 'libFairMQPlugin_example.so', just list 'example' or 'd:example' here."
|
||||
"To load a prelinked plugin, list 'p:example' here.");
|
||||
@@ -170,29 +171,42 @@ auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> voi
|
||||
if (fPluginFactories.find(pluginName) == fPluginFactories.end())
|
||||
{
|
||||
auto success = false;
|
||||
for(const auto& searchPath : SearchPaths())
|
||||
{
|
||||
try
|
||||
{
|
||||
LoadSymbols(
|
||||
pluginName,
|
||||
searchPath / ToString(LibPrefix(), pluginName),
|
||||
dll::load_mode::append_decorations
|
||||
);
|
||||
|
||||
for (const auto& searchPath : SearchPaths()) {
|
||||
try {
|
||||
LoadSymbols(pluginName,
|
||||
searchPath / ToString(LibPrefix(), pluginName),
|
||||
dll::load_mode::append_decorations | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
success = true;
|
||||
break;
|
||||
}
|
||||
catch (boost::system::system_error& e)
|
||||
{
|
||||
if(string{e.what()}.find("No such file or directory") == string::npos)
|
||||
{
|
||||
throw PluginLoadError(ToString("An error occurred while loading dynamic plugin ", pluginName, ": ", e.what()));
|
||||
} catch (boost::system::system_error& e) {
|
||||
if (string{e.what()}.find("No such file or directory") == string::npos) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!success) { throw PluginLoadError(ToString("The plugin ", pluginName, " could not be found in the plugin search paths.")); }
|
||||
|
||||
if (!success) {
|
||||
try {
|
||||
// LoadSymbols(pluginName,
|
||||
// ToString(LibPrefix(), pluginName),
|
||||
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
|
||||
// Not sure, why the above does not work. Workaround for now:
|
||||
LoadSymbols(pluginName,
|
||||
ToString("lib",
|
||||
LibPrefix(),
|
||||
pluginName,
|
||||
boost::dll::detail::shared_library_impl::suffix().native()),
|
||||
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
|
||||
fPluginOrder.push_back(pluginName);
|
||||
} catch (boost::system::system_error& e) {
|
||||
throw PluginLoadError(
|
||||
ToString("An error occurred while loading dynamic plugin ",
|
||||
pluginName, ": ", e.what()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,11 +16,14 @@ const std::unordered_map<std::string, PluginServices::DeviceState> PluginService
|
||||
{"ERROR", DeviceState::Error},
|
||||
{"IDLE", DeviceState::Idle},
|
||||
{"INITIALIZING DEVICE", DeviceState::InitializingDevice},
|
||||
{"INITIALIZED", DeviceState::Initialized},
|
||||
{"BINDING", DeviceState::Binding},
|
||||
{"BOUND", DeviceState::Bound},
|
||||
{"CONNECTING", DeviceState::Connecting},
|
||||
{"DEVICE READY", DeviceState::DeviceReady},
|
||||
{"INITIALIZING TASK", DeviceState::InitializingTask},
|
||||
{"READY", DeviceState::Ready},
|
||||
{"RUNNING", DeviceState::Running},
|
||||
{"PAUSED", DeviceState::Paused},
|
||||
{"RESETTING TASK", DeviceState::ResettingTask},
|
||||
{"RESETTING DEVICE", DeviceState::ResettingDevice},
|
||||
{"EXITING", DeviceState::Exiting}
|
||||
@@ -30,83 +33,96 @@ const std::unordered_map<PluginServices::DeviceState, std::string, tools::HashEn
|
||||
{DeviceState::Error, "ERROR"},
|
||||
{DeviceState::Idle, "IDLE"},
|
||||
{DeviceState::InitializingDevice, "INITIALIZING DEVICE"},
|
||||
{DeviceState::Initialized, "INITIALIZED"},
|
||||
{DeviceState::Binding, "BINDING"},
|
||||
{DeviceState::Bound, "BOUND"},
|
||||
{DeviceState::Connecting, "CONNECTING"},
|
||||
{DeviceState::DeviceReady, "DEVICE READY"},
|
||||
{DeviceState::InitializingTask, "INITIALIZING TASK"},
|
||||
{DeviceState::Ready, "READY"},
|
||||
{DeviceState::Running, "RUNNING"},
|
||||
{DeviceState::Paused, "PAUSED"},
|
||||
{DeviceState::ResettingTask, "RESETTING TASK"},
|
||||
{DeviceState::ResettingDevice, "RESETTING DEVICE"},
|
||||
{DeviceState::Exiting, "EXITING"}
|
||||
};
|
||||
const std::unordered_map<std::string, PluginServices::DeviceStateTransition> PluginServices::fkDeviceStateTransitionStrMap = {
|
||||
{"INIT DEVICE", DeviceStateTransition::InitDevice},
|
||||
{"INIT TASK", DeviceStateTransition::InitTask},
|
||||
{"RUN", DeviceStateTransition::Run},
|
||||
{"PAUSE", DeviceStateTransition::Pause},
|
||||
{"RESUME", DeviceStateTransition::Resume},
|
||||
{"STOP", DeviceStateTransition::Stop},
|
||||
{"RESET TASK", DeviceStateTransition::ResetTask},
|
||||
{"RESET DEVICE", DeviceStateTransition::ResetDevice},
|
||||
{"END", DeviceStateTransition::End},
|
||||
{"ERROR FOUND", DeviceStateTransition::ErrorFound},
|
||||
{"AUTO", DeviceStateTransition::Auto},
|
||||
{"INIT DEVICE", DeviceStateTransition::InitDevice},
|
||||
{"COMPLETE INIT", DeviceStateTransition::CompleteInit},
|
||||
{"BIND", DeviceStateTransition::Bind},
|
||||
{"CONNECT", DeviceStateTransition::Connect},
|
||||
{"INIT TASK", DeviceStateTransition::InitTask},
|
||||
{"RUN", DeviceStateTransition::Run},
|
||||
{"STOP", DeviceStateTransition::Stop},
|
||||
{"RESET TASK", DeviceStateTransition::ResetTask},
|
||||
{"RESET DEVICE", DeviceStateTransition::ResetDevice},
|
||||
{"END", DeviceStateTransition::End},
|
||||
{"ERROR FOUND", DeviceStateTransition::ErrorFound},
|
||||
};
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, std::string, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkStrDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::InitDevice, "INIT DEVICE"},
|
||||
{DeviceStateTransition::InitTask, "INIT TASK"},
|
||||
{DeviceStateTransition::Run, "RUN"},
|
||||
{DeviceStateTransition::Pause, "PAUSE"},
|
||||
{DeviceStateTransition::Resume, "RESUME"},
|
||||
{DeviceStateTransition::Stop, "STOP"},
|
||||
{DeviceStateTransition::ResetTask, "RESET TASK"},
|
||||
{DeviceStateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{DeviceStateTransition::End, "END"},
|
||||
{DeviceStateTransition::ErrorFound, "ERROR FOUND"},
|
||||
{DeviceStateTransition::Auto, "Auto"},
|
||||
{DeviceStateTransition::InitDevice, "INIT DEVICE"},
|
||||
{DeviceStateTransition::CompleteInit, "COMPLETE INIT"},
|
||||
{DeviceStateTransition::Bind, "BIND"},
|
||||
{DeviceStateTransition::Connect, "CONNECT"},
|
||||
{DeviceStateTransition::InitTask, "INIT TASK"},
|
||||
{DeviceStateTransition::Run, "RUN"},
|
||||
{DeviceStateTransition::Stop, "STOP"},
|
||||
{DeviceStateTransition::ResetTask, "RESET TASK"},
|
||||
{DeviceStateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{DeviceStateTransition::End, "END"},
|
||||
{DeviceStateTransition::ErrorFound, "ERROR FOUND"},
|
||||
};
|
||||
const std::unordered_map<FairMQDevice::State, PluginServices::DeviceState, fair::mq::tools::HashEnum<FairMQDevice::State>> PluginServices::fkDeviceStateMap = {
|
||||
{FairMQDevice::OK, DeviceState::Ok},
|
||||
{FairMQDevice::Error, DeviceState::Error},
|
||||
{FairMQDevice::IDLE, DeviceState::Idle},
|
||||
{FairMQDevice::INITIALIZING_DEVICE, DeviceState::InitializingDevice},
|
||||
{FairMQDevice::DEVICE_READY, DeviceState::DeviceReady},
|
||||
{FairMQDevice::INITIALIZING_TASK, DeviceState::InitializingTask},
|
||||
{FairMQDevice::READY, DeviceState::Ready},
|
||||
{FairMQDevice::RUNNING, DeviceState::Running},
|
||||
{FairMQDevice::PAUSED, DeviceState::Paused},
|
||||
{FairMQDevice::RESETTING_TASK, DeviceState::ResettingTask},
|
||||
{FairMQDevice::RESETTING_DEVICE, DeviceState::ResettingDevice},
|
||||
{FairMQDevice::EXITING, DeviceState::Exiting}
|
||||
const std::unordered_map<fair::mq::State, PluginServices::DeviceState, fair::mq::tools::HashEnum<fair::mq::State>> PluginServices::fkDeviceStateMap = {
|
||||
{fair::mq::State::Ok, DeviceState::Ok},
|
||||
{fair::mq::State::Error, DeviceState::Error},
|
||||
{fair::mq::State::Idle, DeviceState::Idle},
|
||||
{fair::mq::State::InitializingDevice, DeviceState::InitializingDevice},
|
||||
{fair::mq::State::Initialized, DeviceState::Initialized},
|
||||
{fair::mq::State::Binding, DeviceState::Binding},
|
||||
{fair::mq::State::Bound, DeviceState::Bound},
|
||||
{fair::mq::State::Connecting, DeviceState::Connecting},
|
||||
{fair::mq::State::DeviceReady, DeviceState::DeviceReady},
|
||||
{fair::mq::State::InitializingTask, DeviceState::InitializingTask},
|
||||
{fair::mq::State::Ready, DeviceState::Ready},
|
||||
{fair::mq::State::Running, DeviceState::Running},
|
||||
{fair::mq::State::ResettingTask, DeviceState::ResettingTask},
|
||||
{fair::mq::State::ResettingDevice, DeviceState::ResettingDevice},
|
||||
{fair::mq::State::Exiting, DeviceState::Exiting}
|
||||
};
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::InitDevice, FairMQDevice::INIT_DEVICE},
|
||||
{DeviceStateTransition::InitTask, FairMQDevice::INIT_TASK},
|
||||
{DeviceStateTransition::Run, FairMQDevice::RUN},
|
||||
{DeviceStateTransition::Pause, FairMQDevice::PAUSE},
|
||||
{DeviceStateTransition::Resume, FairMQDevice::RUN},
|
||||
{DeviceStateTransition::Stop, FairMQDevice::STOP},
|
||||
{DeviceStateTransition::ResetTask, FairMQDevice::RESET_TASK},
|
||||
{DeviceStateTransition::ResetDevice, FairMQDevice::RESET_DEVICE},
|
||||
{DeviceStateTransition::End, FairMQDevice::END},
|
||||
{DeviceStateTransition::ErrorFound, FairMQDevice::ERROR_FOUND}
|
||||
const std::unordered_map<PluginServices::DeviceStateTransition, fair::mq::Transition, tools::HashEnum<PluginServices::DeviceStateTransition>> PluginServices::fkDeviceStateTransitionMap = {
|
||||
{DeviceStateTransition::Auto, fair::mq::Transition::Auto},
|
||||
{DeviceStateTransition::InitDevice, fair::mq::Transition::InitDevice},
|
||||
{DeviceStateTransition::CompleteInit, fair::mq::Transition::CompleteInit},
|
||||
{DeviceStateTransition::Bind, fair::mq::Transition::Bind},
|
||||
{DeviceStateTransition::Connect, fair::mq::Transition::Connect},
|
||||
{DeviceStateTransition::InitTask, fair::mq::Transition::InitTask},
|
||||
{DeviceStateTransition::Run, fair::mq::Transition::Run},
|
||||
{DeviceStateTransition::Stop, fair::mq::Transition::Stop},
|
||||
{DeviceStateTransition::ResetTask, fair::mq::Transition::ResetTask},
|
||||
{DeviceStateTransition::ResetDevice, fair::mq::Transition::ResetDevice},
|
||||
{DeviceStateTransition::End, fair::mq::Transition::End},
|
||||
{DeviceStateTransition::ErrorFound, fair::mq::Transition::ErrorFound}
|
||||
};
|
||||
|
||||
auto PluginServices::ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> void
|
||||
auto PluginServices::ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool
|
||||
{
|
||||
lock_guard<mutex> lock{fDeviceControllerMutex};
|
||||
|
||||
if (!fDeviceController) fDeviceController = controller;
|
||||
|
||||
if (fDeviceController == controller)
|
||||
{
|
||||
fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
}
|
||||
else
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
if (fDeviceController == controller) {
|
||||
result = fDevice.ChangeState(fkDeviceStateTransitionMap.at(next));
|
||||
} else {
|
||||
throw DeviceControlError{tools::ToString(
|
||||
"Plugin '", controller, "' is not allowed to change device states. ",
|
||||
"Currently, plugin '", *fDeviceController, "' has taken control."
|
||||
)};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
auto PluginServices::TakeDeviceControl(const std::string& controller) -> void
|
||||
|
@@ -63,11 +63,14 @@ class PluginServices
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
Paused,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
@@ -75,11 +78,13 @@ class PluginServices
|
||||
|
||||
enum class DeviceStateTransition : int // transition event between DeviceStates
|
||||
{
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Pause,
|
||||
Resume,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
@@ -115,7 +120,7 @@ class PluginServices
|
||||
friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
|
||||
|
||||
/// @return current device state
|
||||
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<FairMQDevice::State>(fDevice.GetCurrentState())); }
|
||||
auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast<fair::mq::State>(fDevice.GetCurrentState())); }
|
||||
|
||||
/// @brief Become device controller
|
||||
/// @param controller id
|
||||
@@ -151,7 +156,7 @@ class PluginServices
|
||||
/// The state transition may not happen immediately, but when the current state evaluates the
|
||||
/// pending transition event and terminates. In other words, the device states are scheduled cooperatively.
|
||||
/// If the device control role has not been taken yet, calling this function will take over control implicitely.
|
||||
auto ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> void;
|
||||
auto ChangeDeviceState(const std::string& controller, const DeviceStateTransition next) -> bool;
|
||||
|
||||
/// @brief Subscribe with a callback to device state changes
|
||||
/// @param subscriber id
|
||||
@@ -161,7 +166,7 @@ class PluginServices
|
||||
/// the state is running in.
|
||||
auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function<void(DeviceState /*newState*/)> callback) -> void
|
||||
{
|
||||
fDevice.SubscribeToStateChange(subscriber, [&,callback](FairMQDevice::State newState){
|
||||
fDevice.SubscribeToStateChange(subscriber, [&,callback](fair::mq::State newState){
|
||||
callback(fkDeviceStateMap.at(newState));
|
||||
});
|
||||
}
|
||||
@@ -186,13 +191,17 @@ class PluginServices
|
||||
auto SetProperty(const std::string& key, T val) -> void
|
||||
{
|
||||
auto currentState = GetCurrentDeviceState();
|
||||
if (currentState == DeviceState::InitializingDevice)
|
||||
{
|
||||
if ( (currentState == DeviceState::InitializingDevice)
|
||||
|| (currentState == DeviceState::Initialized)
|
||||
|| (currentState == DeviceState::Binding)
|
||||
|| (currentState == DeviceState::Bound)
|
||||
|| (currentState == DeviceState::Connecting)
|
||||
|| (currentState == DeviceState::Idle && key == "channel-config")) {
|
||||
fConfig.SetValue(key, val);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw InvalidStateError{tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". Supported state is ", DeviceState::InitializingDevice, ".")};
|
||||
} else {
|
||||
throw InvalidStateError{
|
||||
tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". ",
|
||||
"Supported state is ", DeviceState::InitializingDevice, ".")};
|
||||
}
|
||||
}
|
||||
struct InvalidStateError : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
@@ -268,8 +277,8 @@ class PluginServices
|
||||
static const std::unordered_map<DeviceState, std::string, tools::HashEnum<DeviceState>> fkStrDeviceStateMap;
|
||||
static const std::unordered_map<std::string, DeviceStateTransition> fkDeviceStateTransitionStrMap;
|
||||
static const std::unordered_map<DeviceStateTransition, std::string, tools::HashEnum<DeviceStateTransition>> fkStrDeviceStateTransitionMap;
|
||||
static const std::unordered_map<FairMQDevice::State, DeviceState, tools::HashEnum<FairMQDevice::State>> fkDeviceStateMap;
|
||||
static const std::unordered_map<DeviceStateTransition, FairMQDevice::Event, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
|
||||
static const std::unordered_map<fair::mq::State, DeviceState, tools::HashEnum<fair::mq::State>> fkDeviceStateMap;
|
||||
static const std::unordered_map<DeviceStateTransition, fair::mq::Transition, tools::HashEnum<DeviceStateTransition>> fkDeviceStateTransitionMap;
|
||||
|
||||
private:
|
||||
FairMQProgOptions& fConfig;
|
||||
|
@@ -1,5 +1,5 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
@@ -7,189 +7,476 @@
|
||||
********************************************************************************/
|
||||
|
||||
#include "StateMachine.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
// Increase maximum number of boost::msm states (default is 10)
|
||||
// This #define has to be before any msm header includes
|
||||
#define FUSION_MAX_VECTOR_SIZE 20
|
||||
|
||||
#include <boost/mpl/for_each.hpp>
|
||||
#include <boost/msm/back/state_machine.hpp>
|
||||
#include <boost/msm/back/tools.hpp>
|
||||
#include <boost/msm/back/metafunctions.hpp>
|
||||
#include <boost/msm/front/state_machine_def.hpp>
|
||||
#include <boost/msm/front/functor_row.hpp>
|
||||
#include <boost/core/demangle.hpp>
|
||||
#include <boost/signals2.hpp> // signal/slot for onStateChange callbacks
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
#include <chrono>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
|
||||
using namespace fair::mq;
|
||||
using namespace std;
|
||||
using namespace boost::msm;
|
||||
using namespace boost::msm::front;
|
||||
using namespace boost::msm::back;
|
||||
namespace bmpl = boost::mpl;
|
||||
|
||||
const std::unordered_map<std::string, StateMachine::State> StateMachine::fkStateStrMap = {
|
||||
{"OK", State::Ok},
|
||||
{"ERROR", State::Error},
|
||||
{"IDLE", State::Idle},
|
||||
{"INITIALIZING DEVICE", State::InitializingDevice},
|
||||
{"DEVICE READY", State::DeviceReady},
|
||||
{"INITIALIZING TASK", State::InitializingTask},
|
||||
{"READY", State::Ready},
|
||||
{"RUNNING", State::Running},
|
||||
{"RESETTING TASK", State::ResettingTask},
|
||||
{"RESETTING DEVICE", State::ResettingDevice},
|
||||
{"EXITING", State::Exiting}
|
||||
};
|
||||
const std::unordered_map<StateMachine::State, std::string, tools::HashEnum<StateMachine::State>> StateMachine::fkStrStateMap = {
|
||||
{State::Ok, "OK"},
|
||||
{State::Error, "ERROR"},
|
||||
{State::Idle, "IDLE"},
|
||||
{State::InitializingDevice, "INITIALIZING DEVICE"},
|
||||
{State::DeviceReady, "DEVICE READY"},
|
||||
{State::InitializingTask, "INITIALIZING TASK"},
|
||||
{State::Ready, "READY"},
|
||||
{State::Running, "RUNNING"},
|
||||
{State::ResettingTask, "RESETTING TASK"},
|
||||
{State::ResettingDevice, "RESETTING DEVICE"},
|
||||
{State::Exiting, "EXITING"}
|
||||
};
|
||||
const std::unordered_map<std::string, StateMachine::StateTransition> StateMachine::fkStateTransitionStrMap = {
|
||||
{"INIT DEVICE", StateTransition::InitDevice},
|
||||
{"INIT TASK", StateTransition::InitTask},
|
||||
{"RUN", StateTransition::Run},
|
||||
{"STOP", StateTransition::Stop},
|
||||
{"RESET TASK", StateTransition::ResetTask},
|
||||
{"RESET DEVICE", StateTransition::ResetDevice},
|
||||
{"END", StateTransition::End},
|
||||
{"ERROR FOUND", StateTransition::ErrorFound},
|
||||
{"AUTOMATIC", StateTransition::Automatic},
|
||||
};
|
||||
const std::unordered_map<StateMachine::StateTransition, std::string, tools::HashEnum<StateMachine::StateTransition>> StateMachine::fkStrStateTransitionMap = {
|
||||
{StateTransition::InitDevice, "INIT DEVICE"},
|
||||
{StateTransition::InitTask, "INIT TASK"},
|
||||
{StateTransition::Run, "RUN"},
|
||||
{StateTransition::Stop, "STOP"},
|
||||
{StateTransition::ResetTask, "RESET TASK"},
|
||||
{StateTransition::ResetDevice, "RESET DEVICE"},
|
||||
{StateTransition::End, "END"},
|
||||
{StateTransition::ErrorFound, "ERROR FOUND"},
|
||||
{StateTransition::Automatic, "AUTOMATIC"},
|
||||
};
|
||||
|
||||
auto StateMachine::Run() -> void
|
||||
namespace std
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine";
|
||||
|
||||
LOG(debug) << "Entering initial " << fErrorState << " state (orthogonal error state machine)";
|
||||
LOG(state) << "Entering initial " << fState << " state";
|
||||
template<>
|
||||
struct hash<fair::mq::Transition> : fair::mq::tools::HashEnum<fair::mq::Transition> {};
|
||||
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
while (true)
|
||||
template<>
|
||||
struct hash<fair::mq::State> : fair::mq::tools::HashEnum<fair::mq::State> {};
|
||||
|
||||
} /* namespace std */
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
namespace fsm
|
||||
{
|
||||
|
||||
// list of FSM states
|
||||
struct OK_S : public state<> { static string Name() { return "OK"; } static State Type() { return State::Ok; } };
|
||||
|
||||
struct IDLE_S : public state<> { static string Name() { return "IDLE"; } static State Type() { return State::Idle; } };
|
||||
struct INITIALIZING_DEVICE_S : public state<> { static string Name() { return "INITIALIZING_DEVICE"; } static State Type() { return State::InitializingDevice; } };
|
||||
struct INITIALIZED_S : public state<> { static string Name() { return "INITIALIZED"; } static State Type() { return State::Initialized; } };
|
||||
struct BINDING_S : public state<> { static string Name() { return "BINDING"; } static State Type() { return State::Binding; } };
|
||||
struct BOUND_S : public state<> { static string Name() { return "BOUND"; } static State Type() { return State::Bound; } };
|
||||
struct CONNECTING_S : public state<> { static string Name() { return "CONNECTING"; } static State Type() { return State::Connecting; } };
|
||||
struct DEVICE_READY_S : public state<> { static string Name() { return "DEVICE_READY"; } static State Type() { return State::DeviceReady; } };
|
||||
struct INITIALIZING_TASK_S : public state<> { static string Name() { return "INITIALIZING_TASK"; } static State Type() { return State::InitializingTask; } };
|
||||
struct READY_S : public state<> { static string Name() { return "READY"; } static State Type() { return State::Ready; } };
|
||||
struct RUNNING_S : public state<> { static string Name() { return "RUNNING"; } static State Type() { return State::Running; } };
|
||||
struct RESETTING_TASK_S : public state<> { static string Name() { return "RESETTING_TASK"; } static State Type() { return State::ResettingTask; } };
|
||||
struct RESETTING_DEVICE_S : public state<> { static string Name() { return "RESETTING_DEVICE"; } static State Type() { return State::ResettingDevice; } };
|
||||
struct EXITING_S : public state<> { static string Name() { return "EXITING"; } static State Type() { return State::Exiting; } };
|
||||
|
||||
struct ERROR_S : public terminate_state<> { static string Name() { return "ERROR"; } static State Type() { return State::Error; } };
|
||||
|
||||
// list of FSM transitions (events)
|
||||
struct AUTO_E { static string Name() { return "AUTO"; } static Transition Type() { return Transition::Auto; } };
|
||||
struct INIT_DEVICE_E { static string Name() { return "INIT_DEVICE"; } static Transition Type() { return Transition::InitDevice; } };
|
||||
struct COMPLETE_INIT_E { static string Name() { return "COMPLETE_INIT"; } static Transition Type() { return Transition::CompleteInit; } };
|
||||
struct BIND_E { static string Name() { return "BIND"; } static Transition Type() { return Transition::Bind; } };
|
||||
struct CONNECT_E { static string Name() { return "CONNECT"; } static Transition Type() { return Transition::Connect; } };
|
||||
struct INIT_TASK_E { static string Name() { return "INIT_TASK"; } static Transition Type() { return Transition::InitTask; } };
|
||||
struct RUN_E { static string Name() { return "RUN"; } static Transition Type() { return Transition::Run; } };
|
||||
struct STOP_E { static string Name() { return "STOP"; } static Transition Type() { return Transition::Stop; } };
|
||||
struct RESET_TASK_E { static string Name() { return "RESET_TASK"; } static Transition Type() { return Transition::ResetTask; } };
|
||||
struct RESET_DEVICE_E { static string Name() { return "RESET_DEVICE"; } static Transition Type() { return Transition::ResetDevice; } };
|
||||
struct END_E { static string Name() { return "END"; } static Transition Type() { return Transition::End; } };
|
||||
struct ERROR_FOUND_E { static string Name() { return "ERROR_FOUND"; } static Transition Type() { return Transition::ErrorFound; } };
|
||||
|
||||
static array<string, 15> stateNames =
|
||||
{
|
||||
{
|
||||
while (fNextStates.empty())
|
||||
"OK",
|
||||
"Error",
|
||||
"IDLE",
|
||||
"INITIALIZING_DEVICE",
|
||||
"INITIALIZED",
|
||||
"BINDING",
|
||||
"BOUND",
|
||||
"CONNECTING",
|
||||
"DEVICE_READY",
|
||||
"INITIALIZING_TASK",
|
||||
"READY",
|
||||
"RUNNING",
|
||||
"RESETTING_TASK",
|
||||
"RESETTING_DEVICE",
|
||||
"EXITING"
|
||||
}
|
||||
};
|
||||
|
||||
static array<string, 12> transitionNames =
|
||||
{
|
||||
{
|
||||
"AUTO",
|
||||
"INIT_DEVICE",
|
||||
"COMPLETE_INIT",
|
||||
"BIND",
|
||||
"CONNECT",
|
||||
"INIT_TASK",
|
||||
"RUN",
|
||||
"STOP",
|
||||
"RESET_TASK",
|
||||
"RESET_DEVICE",
|
||||
"END",
|
||||
"ERROR_FOUND"
|
||||
}
|
||||
};
|
||||
|
||||
static map<string, State> stateNumbers =
|
||||
{
|
||||
{ "OK", State::Ok },
|
||||
{ "Error", State::Error },
|
||||
{ "IDLE", State::Idle },
|
||||
{ "INITIALIZING_DEVICE", State::InitializingDevice },
|
||||
{ "INITIALIZED", State::Initialized },
|
||||
{ "BINDING", State::Binding },
|
||||
{ "BOUND", State::Bound },
|
||||
{ "CONNECTING", State::Connecting },
|
||||
{ "DEVICE_READY", State::DeviceReady },
|
||||
{ "INITIALIZING_TASK", State::InitializingTask },
|
||||
{ "READY", State::Ready },
|
||||
{ "RUNNING", State::Running },
|
||||
{ "RESETTING_TASK", State::ResettingTask },
|
||||
{ "RESETTING_DEVICE", State::ResettingDevice },
|
||||
{ "EXITING", State::Exiting }
|
||||
};
|
||||
|
||||
static map<string, Transition> transitionNumbers =
|
||||
{
|
||||
{ "AUTO", Transition::Auto },
|
||||
{ "INIT_DEVICE", Transition::InitDevice },
|
||||
{ "COMPLETE_INIT", Transition::CompleteInit },
|
||||
{ "BIND", Transition::Bind },
|
||||
{ "CONNECT", Transition::Connect },
|
||||
{ "INIT_TASK", Transition::InitTask },
|
||||
{ "RUN", Transition::Run },
|
||||
{ "STOP", Transition::Stop },
|
||||
{ "RESET_TASK", Transition::ResetTask },
|
||||
{ "RESET_DEVICE", Transition::ResetDevice },
|
||||
{ "END", Transition::End },
|
||||
{ "ERROR_FOUND", Transition::ErrorFound }
|
||||
};
|
||||
|
||||
// defining the boost MSM state machine
|
||||
struct Machine_ : public state_machine_def<Machine_>
|
||||
{
|
||||
public:
|
||||
Machine_()
|
||||
: fLastTransitionResult(true)
|
||||
, fNewStatePending(false)
|
||||
, fWorkOngoing(false)
|
||||
{}
|
||||
|
||||
virtual ~Machine_() {}
|
||||
|
||||
// initial states
|
||||
using initial_state = bmpl::vector<IDLE_S, OK_S>;
|
||||
|
||||
template<typename Transition, typename FSM>
|
||||
void on_entry(Transition const&, FSM& /* fsm */)
|
||||
{
|
||||
LOG(state) << "Starting FairMQ state machine --> IDLE";
|
||||
fState = State::Idle;
|
||||
}
|
||||
|
||||
template<typename Transition, typename FSM>
|
||||
void on_exit(Transition const&, FSM& /*fsm*/)
|
||||
{
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
struct DefaultFct
|
||||
{
|
||||
template<typename EVT, typename FSM, typename SourceState, typename TargetState>
|
||||
void operator()(EVT const& e, FSM& fsm, SourceState& /* ss */, TargetState& ts)
|
||||
{
|
||||
fNewState.wait(lock);
|
||||
fsm.fNewState = ts.Type();
|
||||
fsm.fLastTransitionResult = true;
|
||||
fsm.CallNewTransitionCallbacks(e.Type());
|
||||
fsm.fNewStatePending = true;
|
||||
fsm.fNewStatePendingCV.notify_all();
|
||||
}
|
||||
};
|
||||
|
||||
State lastState;
|
||||
struct transition_table : bmpl::vector<
|
||||
// Start Transition Next Action Guard
|
||||
Row<IDLE_S, END_E, EXITING_S, DefaultFct, none>,
|
||||
Row<IDLE_S, INIT_DEVICE_E, INITIALIZING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
if (fNextStates.front() == State::Error)
|
||||
Row<INITIALIZING_DEVICE_S, COMPLETE_INIT_E, INITIALIZED_S, DefaultFct, none>,
|
||||
Row<INITIALIZED_S, BIND_E, BINDING_S, DefaultFct, none>,
|
||||
Row<INITIALIZED_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<BINDING_S, AUTO_E, BOUND_S, DefaultFct, none>,
|
||||
Row<BOUND_S, CONNECT_E, CONNECTING_S, DefaultFct, none>,
|
||||
Row<BOUND_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<CONNECTING_S, AUTO_E, DEVICE_READY_S, DefaultFct, none>,
|
||||
Row<DEVICE_READY_S, INIT_TASK_E, INITIALIZING_TASK_S, DefaultFct, none>,
|
||||
Row<DEVICE_READY_S, RESET_DEVICE_E, RESETTING_DEVICE_S, DefaultFct, none>,
|
||||
|
||||
Row<INITIALIZING_TASK_S, AUTO_E, READY_S, DefaultFct, none>,
|
||||
|
||||
Row<READY_S, RUN_E, RUNNING_S, DefaultFct, none>,
|
||||
Row<READY_S, RESET_TASK_E, RESETTING_TASK_S, DefaultFct, none>,
|
||||
|
||||
Row<RUNNING_S, STOP_E, READY_S, DefaultFct, none>,
|
||||
|
||||
Row<RESETTING_TASK_S, AUTO_E, DEVICE_READY_S, DefaultFct, none>,
|
||||
Row<RESETTING_DEVICE_S, AUTO_E, IDLE_S, DefaultFct, none>,
|
||||
|
||||
Row<OK_S, ERROR_FOUND_E, ERROR_S, DefaultFct, none>> {};
|
||||
|
||||
void CallStateChangeCallbacks(const State state) const
|
||||
{
|
||||
if (!fStateChangeSignal.empty()) {
|
||||
fStateChangeSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
void CallStateHandler(const State state) const
|
||||
{
|
||||
if (!fStateHandleSignal.empty()) {
|
||||
fStateHandleSignal(state);
|
||||
}
|
||||
}
|
||||
|
||||
void CallNewTransitionCallbacks(const Transition transition) const
|
||||
{
|
||||
if (!fNewTransitionSignal.empty()) {
|
||||
fNewTransitionSignal(transition);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
atomic<State> fState;
|
||||
atomic<State> fNewState;
|
||||
atomic<bool> fLastTransitionResult;
|
||||
|
||||
mutex fStateMtx;
|
||||
atomic<bool> fNewStatePending;
|
||||
atomic<bool> fWorkOngoing;
|
||||
condition_variable fNewStatePendingCV;
|
||||
condition_variable fWorkDoneCV;
|
||||
|
||||
boost::signals2::signal<void(const State)> fStateChangeSignal;
|
||||
boost::signals2::signal<void(const State)> fStateHandleSignal;
|
||||
boost::signals2::signal<void(const Transition)> fNewTransitionSignal;
|
||||
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
|
||||
unordered_map<string, boost::signals2::connection> fNewTransitionSignalsMap;
|
||||
|
||||
void ProcessWork()
|
||||
{
|
||||
bool stop = false;
|
||||
|
||||
while (!stop) {
|
||||
{
|
||||
unique_lock<mutex> lock(fStateMtx);
|
||||
|
||||
while (!fNewStatePending) {
|
||||
fNewStatePendingCV.wait_for(lock, chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
LOG(state) << fState << " ---> " << fNewState;
|
||||
fState = static_cast<State>(fNewState);
|
||||
fNewStatePending = false;
|
||||
fWorkOngoing = true;
|
||||
|
||||
if (fState == State::Exiting || fState == State::Error) {
|
||||
stop = true;
|
||||
}
|
||||
}
|
||||
|
||||
CallStateChangeCallbacks(fState);
|
||||
CallStateHandler(fState);
|
||||
|
||||
{
|
||||
lock_guard<mutex> lock(fStateMtx);
|
||||
fWorkOngoing = false;
|
||||
fWorkDoneCV.notify_one();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replaces the default no-transition response.
|
||||
template<typename FSM, typename Transition>
|
||||
void no_transition(Transition const& t, FSM& fsm, int state)
|
||||
{
|
||||
using RecursiveStt = typename recursive_get_transition_table<FSM>::type;
|
||||
using AllStates = typename generate_state_set<RecursiveStt>::type;
|
||||
|
||||
string stateName;
|
||||
|
||||
bmpl::for_each<AllStates, wrap<bmpl::placeholders::_1>>(get_state_name<RecursiveStt>(stateName, state));
|
||||
|
||||
stateName = boost::core::demangle(stateName.c_str());
|
||||
size_t pos = stateName.rfind(":");
|
||||
stateName = stateName.substr(pos + 1);
|
||||
size_t pos2 = stateName.rfind("_");
|
||||
stateName = stateName.substr(0, pos2);
|
||||
|
||||
if (stateName != "OK") {
|
||||
LOG(state) << "No transition from state " << stateName << " on transition " << t.Name();
|
||||
}
|
||||
fsm.fLastTransitionResult = false;
|
||||
}
|
||||
}; // Machine_
|
||||
|
||||
using FairMQFSM = state_machine<Machine_>;
|
||||
|
||||
} // namespace fsm
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
using namespace fair::mq::fsm;
|
||||
using namespace fair::mq;
|
||||
|
||||
StateMachine::StateMachine() : fFsm(new FairMQFSM) {}
|
||||
void StateMachine::Start() { static_pointer_cast<FairMQFSM>(fFsm)->start(); }
|
||||
StateMachine::~StateMachine() { static_pointer_cast<FairMQFSM>(fFsm)->stop(); }
|
||||
|
||||
bool StateMachine::ChangeState(const Transition transition)
|
||||
try {
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
lock_guard<mutex> lock(fsm->fStateMtx);
|
||||
if (!static_cast<bool>(fsm->fNewStatePending) || transition == Transition::ErrorFound) {
|
||||
switch (transition) {
|
||||
case Transition::Auto:
|
||||
fsm->process_event(AUTO_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::InitDevice:
|
||||
fsm->process_event(INIT_DEVICE_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::CompleteInit:
|
||||
fsm->process_event(COMPLETE_INIT_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Bind:
|
||||
fsm->process_event(BIND_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Connect:
|
||||
fsm->process_event(CONNECT_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::InitTask:
|
||||
fsm->process_event(INIT_TASK_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Run:
|
||||
fsm->process_event(RUN_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::Stop:
|
||||
fsm->process_event(STOP_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ResetDevice:
|
||||
fsm->process_event(RESET_DEVICE_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ResetTask:
|
||||
fsm->process_event(RESET_TASK_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::End:
|
||||
fsm->process_event(END_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
case Transition::ErrorFound:
|
||||
fsm->process_event(ERROR_FOUND_E());
|
||||
return fsm->fLastTransitionResult;
|
||||
default:
|
||||
LOG(error) << "Requested unsupported state transition: " << transition << endl;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
LOG(state) << "Transition " << transitionNames.at(static_cast<int>(transition)) << " incoming, but another state transition is already ongoing.";
|
||||
return false;
|
||||
}
|
||||
} catch (exception& e) {
|
||||
LOG(error) << "Exception in StateMachine::ChangeState(): " << e.what();
|
||||
return false;
|
||||
}
|
||||
|
||||
void StateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignal.connect(callback)});
|
||||
}
|
||||
|
||||
void StateMachine::UnsubscribeFromStateChange(const string& key)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fStateChangeSignalsMap.count(key)) {
|
||||
fsm->fStateChangeSignalsMap.at(key).disconnect();
|
||||
fsm->fStateChangeSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::HandleStates(function<void(const State)> callback)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fStateHandleSignal.empty()) {
|
||||
fsm->fStateHandleSignal.connect(callback);
|
||||
} else {
|
||||
LOG(error) << "state handler is already set";
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::StopHandlingStates()
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (!fsm->fStateHandleSignal.empty()) {
|
||||
fsm->fStateHandleSignal.disconnect_all_slots();
|
||||
}
|
||||
}
|
||||
|
||||
void StateMachine::SubscribeToNewTransition(const string& key, function<void(const Transition)> callback)
|
||||
{
|
||||
static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignal.connect(callback)});
|
||||
}
|
||||
|
||||
void StateMachine::UnsubscribeFromNewTransition(const string& key)
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
if (fsm->fNewTransitionSignalsMap.count(key)) {
|
||||
fsm->fNewTransitionSignalsMap.at(key).disconnect();
|
||||
fsm->fNewTransitionSignalsMap.erase(key);
|
||||
}
|
||||
}
|
||||
|
||||
State StateMachine::GetCurrentState() const { return static_pointer_cast<FairMQFSM>(fFsm)->fState; }
|
||||
string StateMachine::GetCurrentStateName() const { return GetStateName(static_pointer_cast<FairMQFSM>(fFsm)->fState); }
|
||||
|
||||
bool StateMachine::NewStatePending() const { return static_cast<bool>(static_pointer_cast<FairMQFSM>(fFsm)->fNewStatePending); }
|
||||
void StateMachine::WaitForPendingState() const
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
unique_lock<mutex> lock(fsm->fStateMtx);
|
||||
fsm->fNewStatePendingCV.wait(lock, [&]{ return static_cast<bool>(fsm->fNewStatePending); });
|
||||
}
|
||||
bool StateMachine::WaitForPendingStateFor(const int durationInMs) const
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
unique_lock<mutex> lock(fsm->fStateMtx);
|
||||
return fsm->fNewStatePendingCV.wait_for(lock, std::chrono::milliseconds(durationInMs), [&]{ return static_cast<bool>(fsm->fNewStatePending); });
|
||||
}
|
||||
|
||||
void StateMachine::ProcessWork()
|
||||
{
|
||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||
|
||||
try {
|
||||
fsm->CallStateChangeCallbacks(State::Idle);
|
||||
fsm->ProcessWork();
|
||||
} catch(...) {
|
||||
{
|
||||
// advance error FSM
|
||||
lastState = fErrorState;
|
||||
fErrorState = fNextStates.front();
|
||||
fNextStates.pop_front();
|
||||
LOG(error) << "Entering " << fErrorState << " state (orthogonal error state machine)";
|
||||
lock_guard<mutex> lock(fsm->fStateMtx);
|
||||
fsm->fState = State::Error;
|
||||
fsm->CallStateChangeCallbacks(State::Error);
|
||||
fsm->fWorkOngoing = false;
|
||||
fsm->fWorkDoneCV.notify_one();
|
||||
}
|
||||
else
|
||||
{
|
||||
// advance regular FSM
|
||||
lastState = fState;
|
||||
fState = fNextStates.front();
|
||||
fNextStates.pop_front();
|
||||
LOG(state) << "Entering " << fState << " state";
|
||||
}
|
||||
lock.unlock();
|
||||
|
||||
fCallbacks.Emit<StateChange, State>(fState, lastState);
|
||||
|
||||
lock.lock();
|
||||
if (fState == State::Exiting || fErrorState == State::Error) break;
|
||||
ChangeState(Transition::ErrorFound);
|
||||
throw;
|
||||
}
|
||||
|
||||
LOG(state) << "Exiting FairMQ state machine";
|
||||
}
|
||||
|
||||
auto StateMachine::ChangeState(StateTransition transition) -> void
|
||||
{
|
||||
State lastState;
|
||||
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
if (transition == StateTransition::ErrorFound)
|
||||
{
|
||||
lastState = fErrorState;
|
||||
}
|
||||
else if (fNextStates.empty())
|
||||
{
|
||||
lastState = fState;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastState = fNextStates.back();
|
||||
}
|
||||
|
||||
const State nextState{Transition(lastState, transition)};
|
||||
fNextStates.push_back(nextState);
|
||||
lock.unlock();
|
||||
|
||||
fCallbacks.Emit<StateQueued, State>(nextState, lastState);
|
||||
fNewState.notify_one();
|
||||
}
|
||||
|
||||
auto StateMachine::Transition(const State currentState, const StateTransition transition) -> State
|
||||
{
|
||||
switch (currentState) {
|
||||
case State::Idle:
|
||||
if (transition == StateTransition::InitDevice ) return State::InitializingDevice;
|
||||
if (transition == StateTransition::End ) return State::Exiting;
|
||||
break;
|
||||
case State::InitializingDevice:
|
||||
if (transition == StateTransition::Automatic ) return State::DeviceReady;
|
||||
break;
|
||||
case State::DeviceReady:
|
||||
if (transition == StateTransition::InitTask ) return State::InitializingTask;
|
||||
if (transition == StateTransition::ResetDevice) return State::ResettingDevice;
|
||||
break;
|
||||
case State::InitializingTask:
|
||||
if (transition == StateTransition::Automatic ) return State::Ready;
|
||||
break;
|
||||
case State::Ready:
|
||||
if (transition == StateTransition::Run ) return State::Running;
|
||||
if (transition == StateTransition::ResetTask ) return State::ResettingTask;
|
||||
break;
|
||||
case State::Running:
|
||||
if (transition == StateTransition::Stop ) return State::Ready;
|
||||
break;
|
||||
case State::ResettingTask:
|
||||
if (transition == StateTransition::Automatic ) return State::DeviceReady;
|
||||
break;
|
||||
case State::ResettingDevice:
|
||||
if (transition == StateTransition::Automatic ) return State::Idle;
|
||||
break;
|
||||
case State::Exiting:
|
||||
break;
|
||||
case State::Ok:
|
||||
if (transition == StateTransition::ErrorFound ) return State::Error;
|
||||
break;
|
||||
case State::Error:
|
||||
break;
|
||||
}
|
||||
throw IllegalTransition{tools::ToString("No transition ", transition, " from state ", currentState, ".")};
|
||||
}
|
||||
|
||||
StateMachine::StateMachine()
|
||||
: fState{State::Idle}
|
||||
, fErrorState{State::Ok}
|
||||
{
|
||||
}
|
||||
|
||||
auto StateMachine::Reset() -> void
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
fState = State::Idle;
|
||||
fErrorState = State::Ok;
|
||||
fNextStates.clear();
|
||||
}
|
||||
|
||||
auto StateMachine::NextStatePending() -> bool
|
||||
{
|
||||
std::unique_lock<std::mutex> lock{fMutex};
|
||||
|
||||
return fNextStates.size() > 0;
|
||||
}
|
||||
string StateMachine::GetStateName(const State state) { return stateNames.at(static_cast<int>(state)); }
|
||||
string StateMachine::GetTransitionName(const Transition transition) { return transitionNames.at(static_cast<int>(transition)); }
|
||||
State StateMachine::GetState(const string& state) { return stateNumbers.at(state); }
|
||||
Transition StateMachine::GetTransition(const string& transition) { return transitionNumbers.at(transition); }
|
||||
|
@@ -1,132 +1,107 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_STATEMACHINE_H
|
||||
#define FAIR_MQ_STATEMACHINE_H
|
||||
#ifndef FAIRMQSTATEMACHINE_H_
|
||||
#define FAIRMQSTATEMACHINE_H_
|
||||
|
||||
#include <utility>
|
||||
#include <FairMQLogger.h>
|
||||
#include <fairmq/Tools.h>
|
||||
#include <fairmq/EventManager.h>
|
||||
#include <deque>
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <ostream>
|
||||
#include <queue>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
namespace mq
|
||||
{
|
||||
|
||||
/**
|
||||
* @class StateMachine StateMachine.h <fairmq/StateMachine.h>
|
||||
* @brief Implements the state machine for FairMQ devices
|
||||
*
|
||||
* See https://github.com/FairRootGroup/FairRoot/blob/dev/fairmq/docs/Device.md#13-state-machine
|
||||
*/
|
||||
enum class State : int
|
||||
{
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
Initialized,
|
||||
Binding,
|
||||
Bound,
|
||||
Connecting,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
};
|
||||
|
||||
enum class Transition : int
|
||||
{
|
||||
Auto,
|
||||
InitDevice,
|
||||
CompleteInit,
|
||||
Bind,
|
||||
Connect,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound
|
||||
};
|
||||
|
||||
class StateMachine
|
||||
{
|
||||
public:
|
||||
enum class State : int
|
||||
{
|
||||
Ok,
|
||||
Error,
|
||||
Idle,
|
||||
InitializingDevice,
|
||||
DeviceReady,
|
||||
InitializingTask,
|
||||
Ready,
|
||||
Running,
|
||||
ResettingTask,
|
||||
ResettingDevice,
|
||||
Exiting
|
||||
};
|
||||
|
||||
enum class StateTransition : int // transition event between States
|
||||
{
|
||||
InitDevice,
|
||||
InitTask,
|
||||
Run,
|
||||
Stop,
|
||||
ResetTask,
|
||||
ResetDevice,
|
||||
End,
|
||||
ErrorFound,
|
||||
Automatic
|
||||
};
|
||||
|
||||
/// @brief Convert string to State
|
||||
/// @param state to convert
|
||||
/// @return State enum entry
|
||||
/// @throw std::out_of_range if a string cannot be resolved to a State
|
||||
static auto ToState(const std::string& state) -> State { return fkStateStrMap.at(state); }
|
||||
|
||||
/// @brief Convert string to StateTransition
|
||||
/// @param transition to convert
|
||||
/// @return StateTransition enum entry
|
||||
/// @throw std::out_of_range if a string cannot be resolved to a StateTransition
|
||||
static auto ToStateTransition(const std::string& transition) -> StateTransition { return fkStateTransitionStrMap.at(transition); }
|
||||
|
||||
/// @brief Convert State to string
|
||||
/// @param state to convert
|
||||
/// @return string representation of State enum entry
|
||||
static auto ToStr(State state) -> std::string { return fkStrStateMap.at(state); }
|
||||
|
||||
/// @brief Convert StateTransition to string
|
||||
/// @param transition to convert
|
||||
/// @return string representation of StateTransition enum entry
|
||||
static auto ToStr(StateTransition transition) -> std::string { return fkStrStateTransitionMap.at(transition); }
|
||||
|
||||
friend auto operator<<(std::ostream& os, const State& state) -> std::ostream& { return os << ToStr(state); }
|
||||
friend auto operator<<(std::ostream& os, const StateTransition& transition) -> std::ostream& { return os << ToStr(transition); }
|
||||
|
||||
StateMachine();
|
||||
virtual ~StateMachine();
|
||||
|
||||
struct IllegalTransition : std::runtime_error { using std::runtime_error::runtime_error; };
|
||||
bool ChangeState(const Transition transition);
|
||||
bool ChangeState(const std::string& transition) { return ChangeState(GetTransition(transition)); }
|
||||
|
||||
struct StateChange : Event<State> {};
|
||||
struct StateQueued : Event<State> {};
|
||||
auto SubscribeToStateChange(const std::string& subscriber, std::function<void(typename StateChange::KeyType newState, State lastState)> callback) -> void { fCallbacks.Subscribe<StateChange, State>(subscriber, callback); }
|
||||
auto UnsubscribeFromStateChange(const std::string& subscriber) -> void { fCallbacks.Unsubscribe<StateChange, State>(subscriber); }
|
||||
auto SubscribeToStateQueued(const std::string& subscriber, std::function<void(typename StateQueued::KeyType newState, State lastState)> callback) -> void { fCallbacks.Subscribe<StateQueued, State>(subscriber, callback); }
|
||||
auto UnsubscribeFromStateQueued(const std::string& subscriber) -> void { fCallbacks.Unsubscribe<StateQueued, State>(subscriber); }
|
||||
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback);
|
||||
void UnsubscribeFromStateChange(const std::string& key);
|
||||
|
||||
auto GetCurrentState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fState; }
|
||||
auto GetCurrentErrorState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fErrorState; }
|
||||
auto GetLastQueuedState() const -> State { std::lock_guard<std::mutex> lock{fMutex}; return fNextStates.back(); }
|
||||
void HandleStates(std::function<void(const State)> callback);
|
||||
void StopHandlingStates();
|
||||
|
||||
auto ChangeState(StateTransition transition) -> void;
|
||||
void SubscribeToNewTransition(const std::string& key, std::function<void(const Transition)> callback);
|
||||
void UnsubscribeFromNewTransition(const std::string& key);
|
||||
|
||||
auto Run() -> void;
|
||||
auto Reset() -> void;
|
||||
bool NewStatePending() const;
|
||||
void WaitForPendingState() const;
|
||||
bool WaitForPendingStateFor(const int durationInMs) const;
|
||||
|
||||
auto NextStatePending() -> bool;
|
||||
State GetCurrentState() const;
|
||||
std::string GetCurrentStateName() const;
|
||||
|
||||
void Start();
|
||||
|
||||
void ProcessWork();
|
||||
|
||||
static std::string GetStateName(const State);
|
||||
static std::string GetTransitionName(const Transition);
|
||||
static State GetState(const std::string& state);
|
||||
static Transition GetTransition(const std::string& transition);
|
||||
|
||||
private:
|
||||
State fState;
|
||||
State fErrorState;
|
||||
std::deque<State> fNextStates;
|
||||
EventManager fCallbacks;
|
||||
std::shared_ptr<void> fFsm;
|
||||
};
|
||||
|
||||
static const std::unordered_map<std::string, State> fkStateStrMap;
|
||||
static const std::unordered_map<State, std::string, tools::HashEnum<State>> fkStrStateMap;
|
||||
static const std::unordered_map<std::string, StateTransition> fkStateTransitionStrMap;
|
||||
static const std::unordered_map<StateTransition, std::string, tools::HashEnum<StateTransition>> fkStrStateTransitionMap;
|
||||
inline std::ostream& operator<<(std::ostream& os, const State& state) { return os << StateMachine::GetStateName(state); }
|
||||
inline std::ostream& operator<<(std::ostream& os, const Transition& transition) { return os << StateMachine::GetTransitionName(transition); }
|
||||
|
||||
mutable std::mutex fMutex;
|
||||
std::condition_variable fNewState;
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
static auto Transition(const State currentState, const StateTransition transition) -> State;
|
||||
}; /* class StateMachine */
|
||||
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
||||
#endif /* FAIR_MQ_STATEMACHINE_H */
|
||||
#endif /* FAIRMQSTATEMACHINE_H_ */
|
||||
|
@@ -1,3 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
find . -type f \( -iname "*.h" ! -iname "*.pb.h" ! -iname "*LinkDef.h" -o -iname "*.cxx" -o -iname "*.tpl" \) -execdir clang-format -i {} \;
|
@@ -18,7 +18,8 @@
|
||||
using namespace std;
|
||||
|
||||
FairMQBenchmarkSampler::FairMQBenchmarkSampler()
|
||||
: fSameMessage(true)
|
||||
: fMultipart(false)
|
||||
, fNumParts(1)
|
||||
, fMsgSize(10000)
|
||||
, fMsgRate(0)
|
||||
, fNumIterations(0)
|
||||
@@ -33,8 +34,9 @@ FairMQBenchmarkSampler::~FairMQBenchmarkSampler()
|
||||
|
||||
void FairMQBenchmarkSampler::InitTask()
|
||||
{
|
||||
fSameMessage = fConfig->GetValue<bool>("same-msg");
|
||||
fMsgSize = fConfig->GetValue<int>("msg-size");
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fNumParts = fConfig->GetValue<size_t>("num-parts");
|
||||
fMsgSize = fConfig->GetValue<size_t>("msg-size");
|
||||
fMsgRate = fConfig->GetValue<float>("msg-rate");
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
fOutChannelName = fConfig->GetValue<string>("out-channel");
|
||||
@@ -52,14 +54,18 @@ void FairMQBenchmarkSampler::Run()
|
||||
|
||||
fair::mq::tools::RateLimiter rateLimiter(fMsgRate);
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
if (fSameMessage)
|
||||
if (fMultipart)
|
||||
{
|
||||
FairMQMessagePtr msg(dataOutChannel.NewMessage());
|
||||
msg->Copy(*baseMsg);
|
||||
FairMQParts parts;
|
||||
|
||||
if (dataOutChannel.Send(msg) >= 0)
|
||||
for (size_t i = 0; i < fNumParts; ++i)
|
||||
{
|
||||
parts.AddPart(dataOutChannel.NewMessage(fMsgSize));
|
||||
}
|
||||
|
||||
if (dataOutChannel.Send(parts) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
|
@@ -26,8 +26,9 @@ class FairMQBenchmarkSampler : public FairMQDevice
|
||||
virtual ~FairMQBenchmarkSampler();
|
||||
|
||||
protected:
|
||||
bool fSameMessage;
|
||||
int fMsgSize;
|
||||
bool fMultipart;
|
||||
size_t fNumParts;
|
||||
size_t fMsgSize;
|
||||
std::atomic<int> fMsgCounter;
|
||||
float fMsgRate;
|
||||
uint64_t fNumIterations;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -20,7 +20,7 @@
|
||||
using namespace std;
|
||||
|
||||
FairMQMerger::FairMQMerger()
|
||||
: fMultipart(1)
|
||||
: fMultipart(true)
|
||||
, fInChannelName("data-in")
|
||||
, fOutChannelName("data-out")
|
||||
{
|
||||
@@ -30,6 +30,8 @@ void FairMQMerger::RegisterChannelEndpoints()
|
||||
{
|
||||
RegisterChannelEndpoint(fInChannelName, 1, 10000);
|
||||
RegisterChannelEndpoint(fOutChannelName, 1, 1);
|
||||
|
||||
PrintRegisteredChannels();
|
||||
}
|
||||
|
||||
FairMQMerger::~FairMQMerger()
|
||||
@@ -38,7 +40,7 @@ FairMQMerger::~FairMQMerger()
|
||||
|
||||
void FairMQMerger::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetValue<int>("multipart");
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fInChannelName = fConfig->GetValue<string>("in-channel");
|
||||
fOutChannelName = fConfig->GetValue<string>("out-channel");
|
||||
}
|
||||
@@ -47,7 +49,7 @@ void FairMQMerger::Run()
|
||||
{
|
||||
int numInputs = fChannels.at(fInChannelName).size();
|
||||
|
||||
vector<const FairMQChannel*> chans;
|
||||
vector<FairMQChannel*> chans;
|
||||
|
||||
for (auto& chan : fChannels.at(fInChannelName))
|
||||
{
|
||||
@@ -58,7 +60,7 @@ void FairMQMerger::Run()
|
||||
|
||||
if (fMultipart)
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
poller->Poll(100);
|
||||
|
||||
@@ -89,7 +91,7 @@ void FairMQMerger::Run()
|
||||
}
|
||||
else
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
poller->Poll(100);
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class FairMQMerger : public FairMQDevice
|
||||
virtual ~FairMQMerger();
|
||||
|
||||
protected:
|
||||
int fMultipart;
|
||||
bool fMultipart;
|
||||
std::string fInChannelName;
|
||||
std::string fOutChannelName;
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
using namespace std;
|
||||
|
||||
FairMQMultiplier::FairMQMultiplier()
|
||||
: fMultipart(1)
|
||||
: fMultipart(true)
|
||||
, fNumOutputs(0)
|
||||
, fInChannelName()
|
||||
, fOutChannelNames()
|
||||
@@ -27,7 +27,7 @@ FairMQMultiplier::~FairMQMultiplier()
|
||||
|
||||
void FairMQMultiplier::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetValue<int>("multipart");
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fInChannelName = fConfig->GetValue<string>("in-channel");
|
||||
fOutChannelNames = fConfig->GetValue<vector<string>>("out-channel");
|
||||
fNumOutputs = fChannels.at(fOutChannelNames.at(0)).size();
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -20,7 +20,7 @@ class FairMQMultiplier : public FairMQDevice
|
||||
virtual ~FairMQMultiplier();
|
||||
|
||||
protected:
|
||||
int fMultipart;
|
||||
bool fMultipart;
|
||||
int fNumOutputs;
|
||||
std::string fInChannelName;
|
||||
std::vector<std::string> fOutChannelNames;
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -20,7 +20,7 @@
|
||||
using namespace std;
|
||||
|
||||
FairMQProxy::FairMQProxy()
|
||||
: fMultipart(1)
|
||||
: fMultipart(true)
|
||||
, fInChannelName()
|
||||
, fOutChannelName()
|
||||
{
|
||||
@@ -32,7 +32,7 @@ FairMQProxy::~FairMQProxy()
|
||||
|
||||
void FairMQProxy::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetValue<int>("multipart");
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fInChannelName = fConfig->GetValue<string>("in-channel");
|
||||
fOutChannelName = fConfig->GetValue<string>("out-channel");
|
||||
}
|
||||
@@ -41,7 +41,7 @@ void FairMQProxy::Run()
|
||||
{
|
||||
if (fMultipart)
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
FairMQParts payload;
|
||||
if (Receive(payload, fInChannelName) >= 0)
|
||||
@@ -61,7 +61,7 @@ void FairMQProxy::Run()
|
||||
}
|
||||
else
|
||||
{
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
unique_ptr<FairMQMessage> payload(fTransportFactory->CreateMessage());
|
||||
if (Receive(payload, fInChannelName) >= 0)
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class FairMQProxy : public FairMQDevice
|
||||
virtual ~FairMQProxy();
|
||||
|
||||
protected:
|
||||
int fMultipart;
|
||||
bool fMultipart;
|
||||
std::string fInChannelName;
|
||||
std::string fOutChannelName;
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -27,7 +27,8 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
{
|
||||
public:
|
||||
FairMQSink()
|
||||
: fMaxIterations(0)
|
||||
: fMultipart(false)
|
||||
, fMaxIterations(0)
|
||||
, fNumIterations(0)
|
||||
, fInChannelName()
|
||||
{}
|
||||
@@ -36,12 +37,14 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
{}
|
||||
|
||||
protected:
|
||||
bool fMultipart;
|
||||
uint64_t fMaxIterations;
|
||||
uint64_t fNumIterations;
|
||||
std::string fInChannelName;
|
||||
|
||||
virtual void InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fMaxIterations = fConfig->GetValue<uint64_t>("max-iterations");
|
||||
fInChannelName = fConfig->GetValue<std::string>("in-channel");
|
||||
}
|
||||
@@ -54,20 +57,41 @@ class FairMQSink : public FairMQDevice//, public OutputPolicy
|
||||
LOG(info) << "Starting the benchmark and expecting to receive " << fMaxIterations << " messages.";
|
||||
auto tStart = std::chrono::high_resolution_clock::now();
|
||||
|
||||
while (CheckCurrentState(RUNNING))
|
||||
while (!NewStatePending())
|
||||
{
|
||||
FairMQMessagePtr msg(dataInChannel.NewMessage());
|
||||
|
||||
if (dataInChannel.Receive(msg) >= 0)
|
||||
if (fMultipart)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
FairMQParts parts;
|
||||
|
||||
if (dataInChannel.Receive(parts) >= 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
break;
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
FairMQMessagePtr msg(dataInChannel.NewMessage());
|
||||
|
||||
if (dataInChannel.Receive(msg) >= 0)
|
||||
{
|
||||
if (fMaxIterations > 0)
|
||||
{
|
||||
if (fNumIterations >= fMaxIterations)
|
||||
{
|
||||
LOG(info) << "Configured maximum number of iterations reached.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
fNumIterations++;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -20,7 +20,7 @@
|
||||
using namespace std;
|
||||
|
||||
FairMQSplitter::FairMQSplitter()
|
||||
: fMultipart(1)
|
||||
: fMultipart(true)
|
||||
, fNumOutputs(0)
|
||||
, fDirection(0)
|
||||
, fInChannelName()
|
||||
@@ -34,7 +34,7 @@ FairMQSplitter::~FairMQSplitter()
|
||||
|
||||
void FairMQSplitter::InitTask()
|
||||
{
|
||||
fMultipart = fConfig->GetValue<int>("multipart");
|
||||
fMultipart = fConfig->GetValue<bool>("multipart");
|
||||
fInChannelName = fConfig->GetValue<string>("in-channel");
|
||||
fOutChannelName = fConfig->GetValue<string>("out-channel");
|
||||
fNumOutputs = fChannels.at(fOutChannelName).size();
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -26,7 +26,7 @@ class FairMQSplitter : public FairMQDevice
|
||||
virtual ~FairMQSplitter();
|
||||
|
||||
protected:
|
||||
int fMultipart;
|
||||
bool fMultipart;
|
||||
int fNumOutputs;
|
||||
int fDirection;
|
||||
std::string fInChannelName;
|
||||
|
@@ -24,8 +24,9 @@ using namespace std;
|
||||
|
||||
fair::mq::Transport FairMQMessageNN::fTransportType = fair::mq::Transport::NN;
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN()
|
||||
: fMessage(nullptr)
|
||||
FairMQMessageNN::FairMQMessageNN(FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
@@ -38,8 +39,9 @@ FairMQMessageNN::FairMQMessageNN()
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN(const size_t size)
|
||||
: fMessage(nullptr)
|
||||
FairMQMessageNN::FairMQMessageNN(const size_t size, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
@@ -59,8 +61,9 @@ FairMQMessageNN::FairMQMessageNN(const size_t size)
|
||||
* create FairMQMessage object only with size parameter and fill it with data.
|
||||
* possible TODO: make this zero copy (will should then be as efficient as ZeroMQ).
|
||||
*/
|
||||
FairMQMessageNN::FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
: fMessage(nullptr)
|
||||
FairMQMessageNN::FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(nullptr)
|
||||
, fSize(0)
|
||||
, fHint(0)
|
||||
, fReceiving(false)
|
||||
@@ -86,8 +89,9 @@ FairMQMessageNN::FairMQMessageNN(void* data, const size_t size, fairmq_free_fn*
|
||||
}
|
||||
}
|
||||
|
||||
FairMQMessageNN::FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint)
|
||||
: fMessage(data)
|
||||
FairMQMessageNN::FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint, FairMQTransportFactory* factory)
|
||||
: FairMQMessage{factory}
|
||||
, fMessage(data)
|
||||
, fSize(size)
|
||||
, fHint(reinterpret_cast<size_t>(hint))
|
||||
, fReceiving(false)
|
||||
@@ -201,30 +205,6 @@ void FairMQMessageNN::Copy(const FairMQMessage& msg)
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQMessageNN::Copy(const FairMQMessagePtr& msg)
|
||||
{
|
||||
if (fMessage)
|
||||
{
|
||||
if (nn_freemsg(fMessage) < 0)
|
||||
{
|
||||
LOG(error) << "failed freeing message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
size_t size = msg->GetSize();
|
||||
|
||||
fMessage = nn_allocmsg(size, 0);
|
||||
if (!fMessage)
|
||||
{
|
||||
LOG(error) << "failed allocating message, reason: " << nn_strerror(errno);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(fMessage, static_cast<FairMQMessageNN*>(msg.get())->GetMessage(), size);
|
||||
fSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQMessageNN::CloseMessage()
|
||||
{
|
||||
if (nn_freemsg(fMessage) < 0)
|
||||
|
@@ -24,15 +24,15 @@
|
||||
|
||||
class FairMQSocketNN;
|
||||
|
||||
class FairMQMessageNN : public FairMQMessage
|
||||
class FairMQMessageNN final : public FairMQMessage
|
||||
{
|
||||
friend class FairMQSocketNN;
|
||||
|
||||
public:
|
||||
FairMQMessageNN();
|
||||
FairMQMessageNN(const size_t size);
|
||||
FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr);
|
||||
FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0);
|
||||
FairMQMessageNN(FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(const size_t size, FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr, FairMQTransportFactory* factory = nullptr);
|
||||
FairMQMessageNN(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, FairMQTransportFactory* factory = nullptr);
|
||||
|
||||
FairMQMessageNN(const FairMQMessageNN&) = delete;
|
||||
FairMQMessageNN operator=(const FairMQMessageNN&) = delete;
|
||||
@@ -49,7 +49,6 @@ class FairMQMessageNN : public FairMQMessage
|
||||
fair::mq::Transport GetType() const override;
|
||||
|
||||
void Copy(const FairMQMessage& msg) override;
|
||||
void Copy(const FairMQMessagePtr& msg) override;
|
||||
|
||||
~FairMQMessageNN() override;
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <nanomsg/pair.h>
|
||||
|
||||
#include "FairMQPollerNN.h"
|
||||
#include "FairMQSocketNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -33,17 +34,17 @@ FairMQPollerNN::FairMQPollerNN(const vector<FairMQChannel>& channels)
|
||||
|
||||
for (int i = 0; i < fNumItems; ++i)
|
||||
{
|
||||
fItems[i].fd = channels.at(i).GetSocket().GetSocket(1);
|
||||
fItems[i].fd = static_cast<const FairMQSocketNN*>(&(channels.at(i).GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(channels.at(i).GetSocket().GetSocket(1), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channels.at(i).GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[i], type);
|
||||
}
|
||||
}
|
||||
|
||||
FairMQPollerNN::FairMQPollerNN(const vector<const FairMQChannel*>& channels)
|
||||
FairMQPollerNN::FairMQPollerNN(const vector<FairMQChannel*>& channels)
|
||||
: fItems()
|
||||
, fNumItems(0)
|
||||
, fOffsetMap()
|
||||
@@ -53,11 +54,11 @@ FairMQPollerNN::FairMQPollerNN(const vector<const FairMQChannel*>& channels)
|
||||
|
||||
for (int i = 0; i < fNumItems; ++i)
|
||||
{
|
||||
fItems[i].fd = channels.at(i)->GetSocket().GetSocket(1);
|
||||
fItems[i].fd = static_cast<const FairMQSocketNN*>(&(channels.at(i)->GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(channels.at(i)->GetSocket().GetSocket(1), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channels.at(i)->GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[i], type);
|
||||
}
|
||||
@@ -87,11 +88,11 @@ FairMQPollerNN::FairMQPollerNN(const unordered_map<string, vector<FairMQChannel>
|
||||
for (unsigned int i = 0; i < channelsMap.at(channel).size(); ++i)
|
||||
{
|
||||
index = fOffsetMap[channel] + i;
|
||||
fItems[index].fd = channelsMap.at(channel).at(i).GetSocket().GetSocket(1);
|
||||
fItems[index].fd = static_cast<const FairMQSocketNN*>(&(channelsMap.at(channel).at(i).GetSocket()))->GetSocket();
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(channelsMap.at(channel).at(i).GetSocket().GetSocket(1), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
nn_getsockopt(static_cast<const FairMQSocketNN*>(&(channelsMap.at(channel).at(i).GetSocket()))->GetSocket(), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[index], type);
|
||||
}
|
||||
@@ -105,27 +106,6 @@ FairMQPollerNN::FairMQPollerNN(const unordered_map<string, vector<FairMQChannel>
|
||||
}
|
||||
}
|
||||
|
||||
FairMQPollerNN::FairMQPollerNN(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket)
|
||||
: fItems()
|
||||
, fNumItems(2)
|
||||
, fOffsetMap()
|
||||
{
|
||||
fItems = new nn_pollfd[fNumItems];
|
||||
|
||||
fItems[0].fd = cmdSocket.GetSocket(1);
|
||||
fItems[0].events = NN_POLLIN;
|
||||
fItems[0].revents = 0;
|
||||
|
||||
fItems[1].fd = dataSocket.GetSocket(1);
|
||||
fItems[1].revents = 0;
|
||||
|
||||
int type = 0;
|
||||
size_t sz = sizeof(type);
|
||||
nn_getsockopt(dataSocket.GetSocket(1), NN_SOL_SOCKET, NN_PROTOCOL, &type, &sz);
|
||||
|
||||
SetItemEvents(fItems[1], type);
|
||||
}
|
||||
|
||||
void FairMQPollerNN::SetItemEvents(nn_pollfd& item, const int type)
|
||||
{
|
||||
if (type == NN_REQ || type == NN_REP || type == NN_PAIR)
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -26,14 +26,14 @@
|
||||
class FairMQChannel;
|
||||
struct nn_pollfd;
|
||||
|
||||
class FairMQPollerNN : public FairMQPoller
|
||||
class FairMQPollerNN final : public FairMQPoller
|
||||
{
|
||||
friend class FairMQChannel;
|
||||
friend class FairMQTransportFactoryNN;
|
||||
|
||||
public:
|
||||
FairMQPollerNN(const std::vector<FairMQChannel>& channels);
|
||||
FairMQPollerNN(const std::vector<const FairMQChannel*>& channels);
|
||||
FairMQPollerNN(const std::vector<FairMQChannel*>& channels);
|
||||
FairMQPollerNN(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList);
|
||||
|
||||
FairMQPollerNN(const FairMQPollerNN&) = delete;
|
||||
@@ -41,21 +41,19 @@ class FairMQPollerNN : public FairMQPoller
|
||||
|
||||
void SetItemEvents(nn_pollfd& item, const int type);
|
||||
|
||||
virtual void Poll(const int timeout);
|
||||
virtual bool CheckInput(const int index);
|
||||
virtual bool CheckOutput(const int index);
|
||||
virtual bool CheckInput(const std::string& channelKey, const int index);
|
||||
virtual bool CheckOutput(const std::string& channelKey, const int index);
|
||||
void Poll(const int timeout) override;
|
||||
bool CheckInput(const int index) override;
|
||||
bool CheckOutput(const int index) override;
|
||||
bool CheckInput(const std::string& channelKey, const int index) override;
|
||||
bool CheckOutput(const std::string& channelKey, const int index) override;
|
||||
|
||||
virtual ~FairMQPollerNN();
|
||||
~FairMQPollerNN() override;
|
||||
|
||||
private:
|
||||
FairMQPollerNN(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket);
|
||||
|
||||
nn_pollfd* fItems;
|
||||
int fNumItems;
|
||||
|
||||
std::unordered_map<std::string, int> fOffsetMap;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQPOLLERNN_H_ */
|
||||
#endif /* FAIRMQPOLLERNN_H_ */
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
/**
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "FairMQMessageNN.h"
|
||||
#include "FairMQLogger.h"
|
||||
#include "FairMQUnmanagedRegionNN.h"
|
||||
#include <fairmq/Tools.h>
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
#include <nanomsg/pipeline.h>
|
||||
@@ -27,11 +28,13 @@
|
||||
#include <msgpack.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace fair::mq;
|
||||
|
||||
atomic<bool> FairMQSocketNN::fInterrupted(false);
|
||||
|
||||
FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const string& id /*= ""*/)
|
||||
: fSocket(-1)
|
||||
FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const string& id /*= ""*/, FairMQTransportFactory* fac /*=nullptr*/)
|
||||
: FairMQSocket{fac}
|
||||
, fSocket(-1)
|
||||
, fId(id + "." + name + "." + type)
|
||||
, fBytesTx(0)
|
||||
, fBytesRx(0)
|
||||
@@ -39,6 +42,7 @@ FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const str
|
||||
, fMessagesRx(0)
|
||||
, fSndTimeout(100)
|
||||
, fRcvTimeout(100)
|
||||
, fLinger(500)
|
||||
{
|
||||
if (type == "router" || type == "dealer")
|
||||
{
|
||||
@@ -84,7 +88,7 @@ FairMQSocketNN::FairMQSocketNN(const string& type, const string& name, const str
|
||||
}
|
||||
#endif
|
||||
|
||||
// LOG(info) << "created socket " << fId;
|
||||
LOG(debug) << "Created socket " << GetId();
|
||||
}
|
||||
|
||||
string FairMQSocketNN::GetId()
|
||||
@@ -96,38 +100,35 @@ bool FairMQSocketNN::Bind(const string& address)
|
||||
{
|
||||
// LOG(info) << "bind socket " << fId << " on " << address;
|
||||
|
||||
int eid = nn_bind(fSocket, address.c_str());
|
||||
if (eid < 0)
|
||||
if (nn_bind(fSocket, address.c_str()) < 0)
|
||||
{
|
||||
LOG(error) << "failed binding socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::Connect(const string& address)
|
||||
bool FairMQSocketNN::Connect(const string& address)
|
||||
{
|
||||
// LOG(info) << "connect socket " << fId << " to " << address;
|
||||
|
||||
int eid = nn_connect(fSocket, address.c_str());
|
||||
if (eid < 0)
|
||||
if (nn_connect(fSocket, address.c_str()) < 0)
|
||||
{
|
||||
LOG(error) << "failed connecting socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::Send(FairMQMessagePtr& msg, const int timeout) { return SendImpl(msg, 0, timeout); }
|
||||
int FairMQSocketNN::Receive(FairMQMessagePtr& msg, const int timeout) { return ReceiveImpl(msg, 0, timeout); }
|
||||
int64_t FairMQSocketNN::Send(vector<unique_ptr<FairMQMessage>>& msgVec, const int timeout) { return SendImpl(msgVec, 0, timeout); }
|
||||
int64_t FairMQSocketNN::Receive(vector<unique_ptr<FairMQMessage>>& msgVec, const int timeout) { return ReceiveImpl(msgVec, 0, timeout); }
|
||||
|
||||
int FairMQSocketNN::TrySend(FairMQMessagePtr& msg) { return SendImpl(msg, NN_DONTWAIT, 0); }
|
||||
int FairMQSocketNN::TryReceive(FairMQMessagePtr& msg) { return ReceiveImpl(msg, NN_DONTWAIT, 0); }
|
||||
int64_t FairMQSocketNN::TrySend(vector<unique_ptr<FairMQMessage>>& msgVec) { return SendImpl(msgVec, NN_DONTWAIT, 0); }
|
||||
int64_t FairMQSocketNN::TryReceive(vector<unique_ptr<FairMQMessage>>& msgVec) { return ReceiveImpl(msgVec, NN_DONTWAIT, 0); }
|
||||
|
||||
int FairMQSocketNN::SendImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
int FairMQSocketNN::Send(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
int nbytes = -1;
|
||||
int elapsed = 0;
|
||||
|
||||
@@ -155,15 +156,11 @@ int FairMQSocketNN::SendImpl(FairMQMessagePtr& msg, const int flags, const int t
|
||||
|
||||
return nbytes;
|
||||
}
|
||||
#if NN_VERSION_CURRENT>2 // backwards-compatibility with nanomsg version<=0.6
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
#else
|
||||
else if (nn_errno() == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
@@ -195,8 +192,13 @@ int FairMQSocketNN::SendImpl(FairMQMessagePtr& msg, const int flags, const int t
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const int timeout)
|
||||
int FairMQSocketNN::Receive(FairMQMessagePtr& msg, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
int elapsed = 0;
|
||||
|
||||
FairMQMessageNN* msgPtr = static_cast<FairMQMessageNN*>(msg.get());
|
||||
@@ -213,15 +215,11 @@ int FairMQSocketNN::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const in
|
||||
msgPtr->fReceiving = true;
|
||||
return nbytes;
|
||||
}
|
||||
#if NN_VERSION_CURRENT>2 // backwards-compatibility with nanomsg version<=0.6
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
#else
|
||||
else if (nn_errno() == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
@@ -253,8 +251,13 @@ int FairMQSocketNN::ReceiveImpl(FairMQMessagePtr& msg, const int flags, const in
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FairMQSocketNN::SendImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
int64_t FairMQSocketNN::Send(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
const unsigned int vecSize = msgVec.size();
|
||||
int elapsed = 0;
|
||||
|
||||
@@ -287,15 +290,11 @@ int64_t FairMQSocketNN::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fla
|
||||
++fMessagesTx;
|
||||
return nbytes;
|
||||
}
|
||||
#if NN_VERSION_CURRENT>2 // backwards-compatibility with nanomsg version<=0.6
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
#else
|
||||
else if (nn_errno() == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fSndTimeout;
|
||||
if (elapsed >= timeout)
|
||||
@@ -327,8 +326,13 @@ int64_t FairMQSocketNN::SendImpl(vector<FairMQMessagePtr>& msgVec, const int fla
|
||||
}
|
||||
}
|
||||
|
||||
int64_t FairMQSocketNN::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int flags, const int timeout)
|
||||
int64_t FairMQSocketNN::Receive(vector<FairMQMessagePtr>& msgVec, const int timeout)
|
||||
{
|
||||
int flags = 0;
|
||||
if (timeout == 0)
|
||||
{
|
||||
flags = NN_DONTWAIT;
|
||||
}
|
||||
// Warn if the vector is filled before Receive() and empty it.
|
||||
// if (msgVec.size() > 0)
|
||||
// {
|
||||
@@ -365,7 +369,7 @@ int64_t FairMQSocketNN::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int
|
||||
object.convert(buf);
|
||||
// get the single message size
|
||||
size_t size = buf.size() * sizeof(char);
|
||||
FairMQMessagePtr part(new FairMQMessageNN(size));
|
||||
FairMQMessagePtr part(new FairMQMessageNN(size, GetTransport()));
|
||||
static_cast<FairMQMessageNN*>(part.get())->fReceiving = true;
|
||||
memcpy(part->GetData(), buf.data(), size);
|
||||
msgVec.push_back(move(part));
|
||||
@@ -374,15 +378,11 @@ int64_t FairMQSocketNN::ReceiveImpl(vector<FairMQMessagePtr>& msgVec, const int
|
||||
nn_freemsg(ptr);
|
||||
return nbytes;
|
||||
}
|
||||
#if NN_VERSION_CURRENT>2 // backwards-compatibility with nanomsg version<=0.6
|
||||
else if (nn_errno() == ETIMEDOUT)
|
||||
#else
|
||||
else if (nn_errno() == EAGAIN)
|
||||
#endif
|
||||
{
|
||||
if (!fInterrupted && ((flags & NN_DONTWAIT) == 0))
|
||||
{
|
||||
if (timeout)
|
||||
if (timeout > 0)
|
||||
{
|
||||
elapsed += fRcvTimeout;
|
||||
if (elapsed >= timeout)
|
||||
@@ -429,12 +429,7 @@ void FairMQSocketNN::Resume()
|
||||
fInterrupted = false;
|
||||
}
|
||||
|
||||
void* FairMQSocketNN::GetSocket() const
|
||||
{
|
||||
return nullptr; // dummy method to comply with the interface. functionality not possible in zeromq.
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSocket(int /*nothing*/) const
|
||||
int FairMQSocketNN::GetSocket() const
|
||||
{
|
||||
return fSocket;
|
||||
}
|
||||
@@ -446,7 +441,7 @@ void FairMQSocketNN::SetOption(const string& option, const void* value, size_t v
|
||||
int val = *(static_cast<int*>(const_cast<void*>(value)));
|
||||
if (val <= 0)
|
||||
{
|
||||
LOG(warn) << "value for sndKernelSize/rcvKernelSize should be greater than 0, using defaults (128kB).";
|
||||
LOG(warn) << "value for sndKernelSize/rcvKernelSize should be greater than 0, leaving unchanged.";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -456,6 +451,12 @@ void FairMQSocketNN::SetOption(const string& option, const void* value, size_t v
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == "linger")
|
||||
{
|
||||
fLinger = *static_cast<int*>(const_cast<void*>(value));
|
||||
return;
|
||||
}
|
||||
|
||||
int rc = nn_setsockopt(fSocket, NN_SOL_SOCKET, GetConstant(option), value, valueSize);
|
||||
if (rc < 0)
|
||||
{
|
||||
@@ -465,6 +466,19 @@ void FairMQSocketNN::SetOption(const string& option, const void* value, size_t v
|
||||
|
||||
void FairMQSocketNN::GetOption(const string& option, void* value, size_t* valueSize)
|
||||
{
|
||||
if (option == "linger")
|
||||
{
|
||||
*static_cast<int*>(value) = fLinger;
|
||||
return;
|
||||
}
|
||||
|
||||
if (option == "snd-hwm" || option == "rcv-hwm")
|
||||
{
|
||||
*static_cast<int*>(value) = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int rc = nn_getsockopt(fSocket, NN_SOL_SOCKET, GetConstant(option), value, valueSize);
|
||||
if (rc < 0)
|
||||
{
|
||||
@@ -472,6 +486,73 @@ void FairMQSocketNN::GetOption(const string& option, void* value, size_t* valueS
|
||||
}
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetLinger(const int value)
|
||||
{
|
||||
fLinger = value;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetLinger() const
|
||||
{
|
||||
return fLinger;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetSndBufSize(const int /* value */)
|
||||
{
|
||||
// not used in nanomsg
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSndBufSize() const
|
||||
{
|
||||
// not used in nanomsg
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetRcvBufSize(const int /* value */)
|
||||
{
|
||||
// not used in nanomsg
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetRcvBufSize() const
|
||||
{
|
||||
// not used in nanomsg
|
||||
return -1;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetSndKernelSize(const int value)
|
||||
{
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_SNDBUF, &value, sizeof(value)) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting NN_SNDBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSndKernelSize() const
|
||||
{
|
||||
int value = 0;
|
||||
size_t valueSize;
|
||||
if (nn_getsockopt(fSocket, NN_SOL_SOCKET, NN_SNDBUF, &value, &valueSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed getting NN_SNDBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
void FairMQSocketNN::SetRcvKernelSize(const int value)
|
||||
{
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_RCVBUF, &value, sizeof(value)) < 0) {
|
||||
throw SocketError(tools::ToString("failed setting NN_RCVBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetRcvKernelSize() const
|
||||
{
|
||||
int value = 0;
|
||||
size_t valueSize;
|
||||
if (nn_getsockopt(fSocket, NN_SOL_SOCKET, NN_RCVBUF, &value, &valueSize) < 0) {
|
||||
throw SocketError(tools::ToString("failed getting NN_RCVBUF, reason: ", nn_strerror(errno)));
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
unsigned long FairMQSocketNN::GetBytesTx() const
|
||||
{
|
||||
return fBytesTx;
|
||||
@@ -492,40 +573,6 @@ unsigned long FairMQSocketNN::GetMessagesRx() const
|
||||
return fMessagesRx;
|
||||
}
|
||||
|
||||
bool FairMQSocketNN::SetSendTimeout(const int timeout, const string& /*address*/, const string& /*method*/)
|
||||
{
|
||||
fSndTimeout = timeout;
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_SNDTIMEO, &fSndTimeout, sizeof(fSndTimeout)) != 0)
|
||||
{
|
||||
LOG(error) << "Failed setting option 'send timeout' on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetSendTimeout() const
|
||||
{
|
||||
return fSndTimeout;
|
||||
}
|
||||
|
||||
bool FairMQSocketNN::SetReceiveTimeout(const int timeout, const string& /*address*/, const string& /*method*/)
|
||||
{
|
||||
fRcvTimeout = timeout;
|
||||
if (nn_setsockopt(fSocket, NN_SOL_SOCKET, NN_RCVTIMEO, &fRcvTimeout, sizeof(fRcvTimeout)) != 0)
|
||||
{
|
||||
LOG(error) << "Failed setting option 'receive timeout' on socket " << fId << ", reason: " << nn_strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetReceiveTimeout() const
|
||||
{
|
||||
return fRcvTimeout;
|
||||
}
|
||||
|
||||
int FairMQSocketNN::GetConstant(const string& constant)
|
||||
{
|
||||
if (constant == "")
|
||||
|
@@ -1,8 +1,8 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
@@ -14,31 +14,26 @@
|
||||
|
||||
#include "FairMQSocket.h"
|
||||
#include "FairMQMessage.h"
|
||||
class FairMQTransportFactory;
|
||||
|
||||
class FairMQSocketNN : public FairMQSocket
|
||||
class FairMQSocketNN final : public FairMQSocket
|
||||
{
|
||||
public:
|
||||
FairMQSocketNN(const std::string& type, const std::string& name, const std::string& id = "");
|
||||
FairMQSocketNN(const std::string& type, const std::string& name, const std::string& id = "", FairMQTransportFactory* fac = nullptr);
|
||||
FairMQSocketNN(const FairMQSocketNN&) = delete;
|
||||
FairMQSocketNN operator=(const FairMQSocketNN&) = delete;
|
||||
|
||||
std::string GetId() override;
|
||||
|
||||
bool Bind(const std::string& address) override;
|
||||
void Connect(const std::string& address) override;
|
||||
bool Connect(const std::string& address) override;
|
||||
|
||||
int Send(FairMQMessagePtr& msg, const int timeout = 0) override;
|
||||
int Receive(FairMQMessagePtr& msg, const int timeout = 0) override;
|
||||
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = 0) override;
|
||||
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = 0) override;
|
||||
int Send(FairMQMessagePtr& msg, const int timeout = -1) override;
|
||||
int Receive(FairMQMessagePtr& msg, const int timeout = -1) override;
|
||||
int64_t Send(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
int64_t Receive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int timeout = -1) override;
|
||||
|
||||
int TrySend(FairMQMessagePtr& msg) override;
|
||||
int TryReceive(FairMQMessagePtr& msg) override;
|
||||
int64_t TrySend(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) override;
|
||||
int64_t TryReceive(std::vector<std::unique_ptr<FairMQMessage>>& msgVec) override;
|
||||
|
||||
void* GetSocket() const override;
|
||||
int GetSocket(int nothing) const override;
|
||||
int GetSocket() const;
|
||||
|
||||
void Close() override;
|
||||
|
||||
@@ -48,16 +43,22 @@ class FairMQSocketNN : public FairMQSocket
|
||||
void SetOption(const std::string& option, const void* value, size_t valueSize) override;
|
||||
void GetOption(const std::string& option, void* value, size_t* valueSize) override;
|
||||
|
||||
void SetLinger(const int value) override;
|
||||
int GetLinger() const override;
|
||||
void SetSndBufSize(const int value) override;
|
||||
int GetSndBufSize() const override;
|
||||
void SetRcvBufSize(const int value) override;
|
||||
int GetRcvBufSize() const override;
|
||||
void SetSndKernelSize(const int value) override;
|
||||
int GetSndKernelSize() const override;
|
||||
void SetRcvKernelSize(const int value) override;
|
||||
int GetRcvKernelSize() const override;
|
||||
|
||||
unsigned long GetBytesTx() const override;
|
||||
unsigned long GetBytesRx() const override;
|
||||
unsigned long GetMessagesTx() const override;
|
||||
unsigned long GetMessagesRx() const override;
|
||||
|
||||
bool SetSendTimeout(const int timeout, const std::string& address, const std::string& method) override;
|
||||
int GetSendTimeout() const override;
|
||||
bool SetReceiveTimeout(const int timeout, const std::string& address, const std::string& method) override;
|
||||
int GetReceiveTimeout() const override;
|
||||
|
||||
static int GetConstant(const std::string& constant);
|
||||
|
||||
~FairMQSocketNN() override;
|
||||
@@ -74,11 +75,7 @@ class FairMQSocketNN : public FairMQSocket
|
||||
|
||||
int fSndTimeout;
|
||||
int fRcvTimeout;
|
||||
|
||||
int SendImpl(FairMQMessagePtr& msg, const int flags, const int timeout);
|
||||
int ReceiveImpl(FairMQMessagePtr& msg, const int flags, const int timeout);
|
||||
int64_t SendImpl(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int flags, const int timeout);
|
||||
int64_t ReceiveImpl(std::vector<std::unique_ptr<FairMQMessage>>& msgVec, const int flags, const int timeout);
|
||||
int fLinger;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQSOCKETNN_H_ */
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#include "FairMQTransportFactoryNN.h"
|
||||
|
||||
#include <nanomsg/nn.h>
|
||||
#include <algorithm>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -20,29 +23,31 @@ FairMQTransportFactoryNN::FairMQTransportFactoryNN(const string& id, const FairM
|
||||
LOG(debug) << "Transport: Using nanomsg library";
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage() const
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage()
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN());
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(const size_t size) const
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(const size_t size)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(size));
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(size, this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint) const
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(data, size, ffn, hint));
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(data, size, ffn, hint, this));
|
||||
}
|
||||
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint) const
|
||||
FairMQMessagePtr FairMQTransportFactoryNN::CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint)
|
||||
{
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(region, data, size, hint));
|
||||
return unique_ptr<FairMQMessage>(new FairMQMessageNN(region, data, size, hint, this));
|
||||
}
|
||||
|
||||
FairMQSocketPtr FairMQTransportFactoryNN::CreateSocket(const string& type, const string& name) const
|
||||
FairMQSocketPtr FairMQTransportFactoryNN::CreateSocket(const string& type, const string& name)
|
||||
{
|
||||
return unique_ptr<FairMQSocket>(new FairMQSocketNN(type, name, GetId()));
|
||||
unique_ptr<FairMQSocket> socket(new FairMQSocketNN(type, name, GetId(), this));
|
||||
fSockets.push_back(socket.get());
|
||||
return socket;
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const vector<FairMQChannel>& channels) const
|
||||
@@ -50,7 +55,7 @@ FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const vector<FairMQChanne
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channels));
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const std::vector<const FairMQChannel*>& channels) const
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const std::vector<FairMQChannel*>& channels) const
|
||||
{
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channels));
|
||||
}
|
||||
@@ -60,11 +65,6 @@ FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const unordered_map<strin
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(channelsMap, channelList));
|
||||
}
|
||||
|
||||
FairMQPollerPtr FairMQTransportFactoryNN::CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const
|
||||
{
|
||||
return unique_ptr<FairMQPoller>(new FairMQPollerNN(cmdSocket, dataSocket));
|
||||
}
|
||||
|
||||
FairMQUnmanagedRegionPtr FairMQTransportFactoryNN::CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback) const
|
||||
{
|
||||
return unique_ptr<FairMQUnmanagedRegion>(new FairMQUnmanagedRegionNN(size, callback));
|
||||
@@ -75,6 +75,17 @@ fair::mq::Transport FairMQTransportFactoryNN::GetType() const
|
||||
return fTransportType;
|
||||
}
|
||||
|
||||
void FairMQTransportFactoryNN::Reset()
|
||||
{
|
||||
auto it = max_element(fSockets.begin(), fSockets.end(), [](FairMQSocket* s1, FairMQSocket* s2) {
|
||||
return static_cast<FairMQSocketNN*>(s1)->GetLinger() < static_cast<FairMQSocketNN*>(s2)->GetLinger();
|
||||
});
|
||||
if (it != fSockets.end()) {
|
||||
this_thread::sleep_for(chrono::milliseconds(static_cast<FairMQSocketNN*>(*it)->GetLinger()));
|
||||
}
|
||||
fSockets.clear();
|
||||
}
|
||||
|
||||
FairMQTransportFactoryNN::~FairMQTransportFactoryNN()
|
||||
{
|
||||
// nn_term();
|
||||
|
@@ -19,23 +19,22 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class FairMQTransportFactoryNN : public FairMQTransportFactory
|
||||
class FairMQTransportFactoryNN final : public FairMQTransportFactory
|
||||
{
|
||||
public:
|
||||
FairMQTransportFactoryNN(const std::string& id = "", const FairMQProgOptions* config = nullptr);
|
||||
~FairMQTransportFactoryNN() override;
|
||||
|
||||
FairMQMessagePtr CreateMessage() const override;
|
||||
FairMQMessagePtr CreateMessage(const size_t size) const override;
|
||||
FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) const override;
|
||||
FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0) const override;
|
||||
FairMQMessagePtr CreateMessage() override;
|
||||
FairMQMessagePtr CreateMessage(const size_t size) override;
|
||||
FairMQMessagePtr CreateMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) override;
|
||||
FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0) override;
|
||||
|
||||
FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) const override;
|
||||
FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) override;
|
||||
|
||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const override;
|
||||
FairMQPollerPtr CreatePoller(const std::vector<const FairMQChannel*>& channels) const override;
|
||||
FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const override;
|
||||
FairMQPollerPtr CreatePoller(const std::unordered_map<std::string, std::vector<FairMQChannel>>& channelsMap, const std::vector<std::string>& channelList) const override;
|
||||
FairMQPollerPtr CreatePoller(const FairMQSocket& cmdSocket, const FairMQSocket& dataSocket) const override;
|
||||
|
||||
FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback) const override;
|
||||
|
||||
@@ -43,9 +42,11 @@ class FairMQTransportFactoryNN : public FairMQTransportFactory
|
||||
|
||||
void Interrupt() override { FairMQSocketNN::Interrupt(); }
|
||||
void Resume() override { FairMQSocketNN::Resume(); }
|
||||
void Reset() override;
|
||||
|
||||
private:
|
||||
static fair::mq::Transport fTransportType;
|
||||
mutable std::vector<FairMQSocket*> fSockets;
|
||||
};
|
||||
|
||||
#endif /* FAIRMQTRANSPORTFACTORYNN_H_ */
|
||||
|
@@ -13,7 +13,7 @@
|
||||
|
||||
#include <cstddef> // size_t
|
||||
|
||||
class FairMQUnmanagedRegionNN : public FairMQUnmanagedRegion
|
||||
class FairMQUnmanagedRegionNN final : public FairMQUnmanagedRegion
|
||||
{
|
||||
friend class FairMQSocketNN;
|
||||
|
||||
|
@@ -1,12 +0,0 @@
|
||||
################################################################################
|
||||
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||
# #
|
||||
# This software is distributed under the terms of the #
|
||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||
# copied verbatim in the file "LICENSE" #
|
||||
################################################################################
|
||||
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS Control.proto)
|
||||
|
||||
add_library(OfiTransport OBJECT ${PROTO_SRCS} ${PROTO_HDRS})
|
||||
target_include_directories(OfiTransport PRIVATE $<TARGET_PROPERTY:protobuf::libprotobuf,INTERFACE_INCLUDE_DIRECTORIES>)
|
@@ -10,21 +10,17 @@
|
||||
#include <fairmq/Tools.h>
|
||||
#include <FairMQLogger.h>
|
||||
|
||||
#include <asiofi/version.hpp>
|
||||
#include <arpa/inet.h>
|
||||
#include <boost/version.hpp>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <google/protobuf/stubs/common.h>
|
||||
#include <memory>
|
||||
#include <netinet/in.h>
|
||||
#include <rdma/fabric.h>
|
||||
#include <rdma/fi_domain.h>
|
||||
#include <rdma/fi_endpoint.h>
|
||||
#include <rdma/fi_errno.h>
|
||||
#include <regex>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <sys/socket.h>
|
||||
#include <zmq.h>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -35,20 +31,14 @@ namespace ofi
|
||||
|
||||
using namespace std;
|
||||
|
||||
Context::Context(int numberIoThreads)
|
||||
: fOfiDomain(nullptr)
|
||||
, fOfiFabric(nullptr)
|
||||
, fOfiInfo(nullptr)
|
||||
, fOfiAddressVector(nullptr)
|
||||
, fOfiEventQueue(nullptr)
|
||||
, fZmqContext(zmq_ctx_new())
|
||||
, fIoWork(fIoContext)
|
||||
Context::Context(FairMQTransportFactory& sendFactory,
|
||||
FairMQTransportFactory& receiveFactory,
|
||||
int numberIoThreads)
|
||||
: fIoWork(fIoContext)
|
||||
, fReceiveFactory(receiveFactory)
|
||||
, fSendFactory(sendFactory)
|
||||
, fSizeHint(2000000) // temporary hack to provide expected message size for receive
|
||||
{
|
||||
if (!fZmqContext)
|
||||
throw ContextError{tools::ToString("Failed creating zmq context, reason: ", zmq_strerror(errno))};
|
||||
|
||||
GOOGLE_PROTOBUF_VERIFY_VERSION;
|
||||
|
||||
InitThreadPool(numberIoThreads);
|
||||
}
|
||||
|
||||
@@ -58,257 +48,27 @@ auto Context::InitThreadPool(int numberIoThreads) -> void
|
||||
|
||||
for (int i = 1; i <= numberIoThreads; ++i) {
|
||||
fThreadPool.emplace_back([&, i, numberIoThreads]{
|
||||
LOG(debug) << "I/O thread #" << i << "/" << numberIoThreads << " started";
|
||||
LOG(debug) << "OFI transport: I/O thread #" << i << " of " << numberIoThreads << " started";
|
||||
fIoContext.run();
|
||||
LOG(debug) << "I/O thread #" << i << "/" << numberIoThreads << " stopped";
|
||||
LOG(debug) << "OFI transport: I/O thread #" << i << " of " << numberIoThreads << " stopped";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
auto Context::Reset() -> void
|
||||
{
|
||||
fIoContext.stop();
|
||||
}
|
||||
|
||||
Context::~Context()
|
||||
{
|
||||
for (auto& thread : fThreadPool)
|
||||
thread.join();
|
||||
|
||||
if (zmq_ctx_term(fZmqContext) != 0)
|
||||
LOG(error) << "Failed closing zmq context, reason: " << zmq_strerror(errno);
|
||||
|
||||
if (fOfiEventQueue) {
|
||||
auto ret = fi_close(&fOfiEventQueue->fid);
|
||||
if (ret != FI_SUCCESS)
|
||||
LOG(error) << "Failed closing ofi event queue, reason: " << fi_strerror(ret);
|
||||
}
|
||||
|
||||
if (fOfiAddressVector) {
|
||||
auto ret = fi_close(&fOfiAddressVector->fid);
|
||||
if (ret != FI_SUCCESS)
|
||||
LOG(error) << "Failed closing ofi address vector, reason: " << fi_strerror(ret);
|
||||
}
|
||||
|
||||
if (fOfiDomain) {
|
||||
auto ret = fi_close(&fOfiDomain->fid);
|
||||
if (ret != FI_SUCCESS)
|
||||
LOG(error) << "Failed closing ofi domain, reason: " << fi_strerror(ret);
|
||||
}
|
||||
|
||||
if (fOfiFabric) {
|
||||
auto ret = fi_close(&fOfiFabric->fid);
|
||||
if (ret != FI_SUCCESS)
|
||||
LOG(error) << "Failed closing ofi fabric, reason: " << fi_strerror(ret);
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::GetZmqVersion() const -> string
|
||||
auto Context::GetAsiofiVersion() const -> string
|
||||
{
|
||||
int major, minor, patch;
|
||||
zmq_version(&major, &minor, &patch);
|
||||
return tools::ToString(major, ".", minor, ".", patch);
|
||||
}
|
||||
|
||||
auto Context::GetOfiApiVersion() const -> string
|
||||
{
|
||||
// Disable for now, does not compile with gcc 4.9.2 debian jessie
|
||||
//auto ofi_version{fi_version()};
|
||||
//return tools::ToString(FI_MAJOR(ofi_version), ".", FI_MINOR(ofi_version));
|
||||
return "unknown";
|
||||
}
|
||||
|
||||
auto Context::GetPbVersion() const -> string
|
||||
{
|
||||
return google::protobuf::internal::VersionString(GOOGLE_PROTOBUF_VERSION);
|
||||
}
|
||||
|
||||
auto Context::GetBoostVersion() const -> std::string
|
||||
{
|
||||
return tools::ToString(BOOST_VERSION / 100000, ".", BOOST_VERSION / 100 % 1000, ".", BOOST_VERSION % 100);
|
||||
}
|
||||
|
||||
auto Context::InitOfi(ConnectionType type, Address addr) -> void
|
||||
{
|
||||
if (!fOfiInfo) {
|
||||
sockaddr_in* sa = static_cast<sockaddr_in*>(malloc(sizeof(sockaddr_in)));
|
||||
addr.Port = 0;
|
||||
auto sa2 = ConvertAddress(addr);
|
||||
memcpy(sa, &sa2, sizeof(sockaddr_in));
|
||||
|
||||
// Prepare fi_getinfo query
|
||||
unique_ptr<fi_info, void(*)(fi_info*)> ofi_hints(fi_allocinfo(), fi_freeinfo);
|
||||
ofi_hints->caps = FI_MSG;
|
||||
//ofi_hints->mode = FI_CONTEXT;
|
||||
ofi_hints->addr_format = FI_SOCKADDR_IN;
|
||||
if (addr.Protocol == "tcp") {
|
||||
ofi_hints->fabric_attr->prov_name = strdup("sockets");
|
||||
} else if (addr.Protocol == "verbs") {
|
||||
ofi_hints->fabric_attr->prov_name = strdup("verbs;ofi_rxm");
|
||||
}
|
||||
ofi_hints->ep_attr->type = FI_EP_RDM;
|
||||
//ofi_hints->domain_attr->mr_mode = FI_MR_BASIC | FI_MR_SCALABLE;
|
||||
ofi_hints->domain_attr->threading = FI_THREAD_SAFE;
|
||||
ofi_hints->domain_attr->control_progress = FI_PROGRESS_AUTO;
|
||||
ofi_hints->domain_attr->data_progress = FI_PROGRESS_AUTO;
|
||||
ofi_hints->tx_attr->op_flags = FI_COMPLETION;
|
||||
ofi_hints->rx_attr->op_flags = FI_COMPLETION;
|
||||
if (type == ConnectionType::Bind) {
|
||||
ofi_hints->src_addr = sa;
|
||||
ofi_hints->src_addrlen = sizeof(sockaddr_in);
|
||||
ofi_hints->dest_addr = nullptr;
|
||||
ofi_hints->dest_addrlen = 0;
|
||||
} else {
|
||||
ofi_hints->src_addr = nullptr;
|
||||
ofi_hints->src_addrlen = 0;
|
||||
ofi_hints->dest_addr = sa;
|
||||
ofi_hints->dest_addrlen = sizeof(sockaddr_in);
|
||||
}
|
||||
|
||||
// Query fi_getinfo for fabric to use
|
||||
auto res = fi_getinfo(FI_VERSION(1, 5), nullptr, nullptr, 0, ofi_hints.get(), &fOfiInfo);
|
||||
if (res != 0) throw ContextError{tools::ToString("Failed querying fi_getinfo, reason: ", fi_strerror(res))};
|
||||
if (!fOfiInfo) throw ContextError{"Could not find any ofi compatible fabric."};
|
||||
|
||||
// for(auto cursor{ofi_info}; cursor->next != nullptr; cursor = cursor->next) {
|
||||
// LOG(debug) << fi_tostr(fOfiInfo, FI_TYPE_INFO);
|
||||
// }
|
||||
//
|
||||
} else {
|
||||
LOG(debug) << "Ofi info already queried. Skipping.";
|
||||
}
|
||||
|
||||
OpenOfiFabric();
|
||||
// OpenOfiEventQueue();
|
||||
OpenOfiDomain();
|
||||
OpenOfiAddressVector();
|
||||
}
|
||||
|
||||
auto Context::OpenOfiFabric() -> void
|
||||
{
|
||||
if (!fOfiFabric) {
|
||||
assert(fOfiInfo);
|
||||
fi_context ctx;
|
||||
auto ret = fi_fabric(fOfiInfo->fabric_attr, &fOfiFabric, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed opening ofi fabric, reason: ", fi_strerror(ret))};
|
||||
} else {
|
||||
// TODO Check, if requested fabric matches existing one.
|
||||
// TODO Decide, if we want to support more than one fabric simultaneously.
|
||||
LOG(debug) << "Ofi fabric already opened. Skipping.";
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::OpenOfiDomain() -> void
|
||||
{
|
||||
if (!fOfiDomain) {
|
||||
assert(fOfiInfo);
|
||||
assert(fOfiFabric);
|
||||
fi_context ctx;
|
||||
auto ret = fi_domain(fOfiFabric, fOfiInfo, &fOfiDomain, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed opening ofi domain, reason: ", fi_strerror(ret))};
|
||||
} else {
|
||||
LOG(debug) << "Ofi domain already opened. Skipping.";
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::OpenOfiEventQueue() -> void
|
||||
{
|
||||
fi_eq_attr eqAttr = {100, 0, FI_WAIT_UNSPEC, 0, nullptr};
|
||||
// size_t size; [> # entries for EQ <]
|
||||
// uint64_t flags; [> operation flags <]
|
||||
// enum fi_wait_obj wait_obj; [> requested wait object <]
|
||||
// int signaling_vector; [> interrupt affinity <]
|
||||
// struct fid_wait *wait_set; [> optional wait set <]
|
||||
fi_context ctx;
|
||||
auto ret = fi_eq_open(fOfiFabric, &eqAttr, &fOfiEventQueue, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed opening ofi event queue, reason: ", fi_strerror(ret))};
|
||||
}
|
||||
|
||||
auto Context::OpenOfiAddressVector() -> void
|
||||
{
|
||||
if (!fOfiAddressVector) {
|
||||
assert(fOfiDomain);
|
||||
fi_av_attr attr = {fOfiInfo->domain_attr->av_type, 0, 1000, 0, nullptr, nullptr, 0};
|
||||
// enum fi_av_type type; [> type of AV <]
|
||||
// int rx_ctx_bits; [> address bits to identify rx ctx <]
|
||||
// size_t count; [> # entries for AV <]
|
||||
// size_t ep_per_node; [> # endpoints per fabric address <]
|
||||
// const char *name; [> system name of AV <]
|
||||
// void *map_addr; [> base mmap address <]
|
||||
// uint64_t flags; [> operation flags <]
|
||||
fi_context ctx;
|
||||
auto ret = fi_av_open(fOfiDomain, &attr, &fOfiAddressVector, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed opening ofi address vector, reason: ", fi_strerror(ret))};
|
||||
|
||||
//assert(fOfiEventQueue);
|
||||
//ret = fi_av_bind(fOfiAddressVector, &fOfiEventQueue->fid, 0);
|
||||
//if (ret != FI_SUCCESS)
|
||||
// throw ContextError{tools::ToString("Failed binding ofi event queue to address vector, reason: ", fi_strerror(ret))};
|
||||
} else {
|
||||
LOG(debug) << "Ofi address vector already opened. Skipping.";
|
||||
}
|
||||
}
|
||||
|
||||
auto Context::CreateOfiEndpoint() -> fid_ep*
|
||||
{
|
||||
assert(fOfiDomain);
|
||||
assert(fOfiInfo);
|
||||
fid_ep* ep = nullptr;
|
||||
fi_context ctx;
|
||||
auto ret = fi_endpoint(fOfiDomain, fOfiInfo, &ep, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed creating ofi endpoint, reason: ", fi_strerror(ret))};
|
||||
|
||||
//assert(fOfiEventQueue);
|
||||
//ret = fi_ep_bind(ep, &fOfiEventQueue->fid, 0);
|
||||
//if (ret != FI_SUCCESS)
|
||||
// throw ContextError{tools::ToString("Failed binding ofi event queue to ofi endpoint, reason: ", fi_strerror(ret))};
|
||||
|
||||
assert(fOfiAddressVector);
|
||||
ret = fi_ep_bind(ep, &fOfiAddressVector->fid, 0);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed binding ofi address vector to ofi endpoint, reason: ", fi_strerror(ret))};
|
||||
|
||||
return ep;
|
||||
}
|
||||
|
||||
auto Context::CreateOfiCompletionQueue(Direction dir) -> fid_cq*
|
||||
{
|
||||
fid_cq* cq = nullptr;
|
||||
fi_cq_attr attr = {0, 0, FI_CQ_FORMAT_DATA, FI_WAIT_UNSPEC, 0, FI_CQ_COND_NONE, nullptr};
|
||||
if (dir == Direction::Receive) {
|
||||
attr.size = fOfiInfo->rx_attr->size;
|
||||
} else {
|
||||
attr.size = fOfiInfo->tx_attr->size;
|
||||
}
|
||||
// size_t size; [> # entries for CQ <]
|
||||
// uint64_t flags; [> operation flags <]
|
||||
// enum fi_cq_format format; [> completion format <]
|
||||
// enum fi_wait_obj wait_obj; [> requested wait object <]
|
||||
// int signaling_vector; [> interrupt affinity <]
|
||||
// enum fi_cq_wait_cond wait_cond; [> wait condition format <]
|
||||
// struct fid_wait *wait_set; [> optional wait set <]
|
||||
fi_context ctx;
|
||||
auto ret = fi_cq_open(fOfiDomain, &attr, &cq, &ctx);
|
||||
if (ret != FI_SUCCESS)
|
||||
throw ContextError{tools::ToString("Failed creating ofi completion queue, reason: ", fi_strerror(ret))};
|
||||
return cq;
|
||||
}
|
||||
|
||||
auto Context::InsertAddressVector(sockaddr_in address) -> fi_addr_t
|
||||
{
|
||||
fi_addr_t mappedAddress;
|
||||
fi_context ctx;
|
||||
auto ret = fi_av_insert(fOfiAddressVector, &address, 1, &mappedAddress, 0, &ctx);
|
||||
if (ret != 1)
|
||||
throw ContextError{tools::ToString("Failed to insert address into ofi address vector")};
|
||||
|
||||
return mappedAddress;
|
||||
}
|
||||
|
||||
auto Context::AddressVectorLookup(fi_addr_t address) -> sockaddr_in
|
||||
{
|
||||
throw ContextError("Not yet implemented");
|
||||
return ASIOFI_VERSION;
|
||||
}
|
||||
|
||||
auto Context::ConvertAddress(std::string address) -> Address
|
||||
@@ -355,6 +115,16 @@ auto Context::VerifyAddress(const std::string& address) -> Address
|
||||
return addr;
|
||||
}
|
||||
|
||||
auto Context::MakeReceiveMessage(size_t size) -> MessagePtr
|
||||
{
|
||||
return fReceiveFactory.CreateMessage(size);
|
||||
}
|
||||
|
||||
auto Context::MakeSendMessage(size_t size) -> MessagePtr
|
||||
{
|
||||
return fSendFactory.CreateMessage(size);
|
||||
}
|
||||
|
||||
} /* namespace ofi */
|
||||
} /* namespace mq */
|
||||
} /* namespace fair */
|
||||
|
@@ -9,11 +9,16 @@
|
||||
#ifndef FAIR_MQ_OFI_CONTEXT_H
|
||||
#define FAIR_MQ_OFI_CONTEXT_H
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <FairMQLogger.h>
|
||||
#include <FairMQTransportFactory.h>
|
||||
|
||||
#include <asiofi/domain.hpp>
|
||||
#include <asiofi/fabric.hpp>
|
||||
#include <asiofi/info.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <memory>
|
||||
#include <netinet/in.h>
|
||||
#include <ostream>
|
||||
#include <rdma/fabric.h>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
@@ -27,7 +32,20 @@ namespace ofi
|
||||
{
|
||||
|
||||
enum class ConnectionType : bool { Bind, Connect };
|
||||
enum class Direction : bool { Receive, Transmit };
|
||||
|
||||
struct Address {
|
||||
std::string Protocol;
|
||||
std::string Ip;
|
||||
unsigned int Port;
|
||||
friend auto operator<<(std::ostream& os, const Address& a) -> std::ostream&
|
||||
{
|
||||
return os << a.Protocol << "://" << a.Ip << ":" << a.Port;
|
||||
}
|
||||
friend auto operator==(const Address& lhs, const Address& rhs) -> bool
|
||||
{
|
||||
return (lhs.Protocol == rhs.Protocol) && (lhs.Ip == rhs.Ip) && (lhs.Port == rhs.Port);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @class Context Context.h <fairmq/ofi/Context.h>
|
||||
@@ -38,46 +56,34 @@ enum class Direction : bool { Receive, Transmit };
|
||||
class Context
|
||||
{
|
||||
public:
|
||||
Context(int numberIoThreads = 2);
|
||||
Context(FairMQTransportFactory& sendFactory,
|
||||
FairMQTransportFactory& receiveFactory,
|
||||
int numberIoThreads = 1);
|
||||
~Context();
|
||||
|
||||
auto CreateOfiEndpoint() -> fid_ep*;
|
||||
auto CreateOfiCompletionQueue(Direction dir) -> fid_cq*;
|
||||
auto GetZmqVersion() const -> std::string;
|
||||
auto GetOfiApiVersion() const -> std::string;
|
||||
auto GetPbVersion() const -> std::string;
|
||||
auto GetBoostVersion() const -> std::string;
|
||||
auto GetZmqContext() const -> void* { return fZmqContext; }
|
||||
auto GetIoContext() -> boost::asio::io_service& { return fIoContext; }
|
||||
auto InsertAddressVector(sockaddr_in address) -> fi_addr_t;
|
||||
auto AddressVectorLookup(fi_addr_t address) -> sockaddr_in;
|
||||
struct Address {
|
||||
std::string Protocol;
|
||||
std::string Ip;
|
||||
unsigned int Port;
|
||||
friend auto operator<<(std::ostream& os, const Address& a) -> std::ostream& { return os << a.Protocol << "://" << a.Ip << ":" << a.Port; }
|
||||
};
|
||||
auto InitOfi(ConnectionType type, Address address) -> void;
|
||||
auto GetAsiofiVersion() const -> std::string;
|
||||
auto GetIoContext() -> boost::asio::io_context& { return fIoContext; }
|
||||
static auto ConvertAddress(std::string address) -> Address;
|
||||
static auto ConvertAddress(Address address) -> sockaddr_in;
|
||||
static auto ConvertAddress(sockaddr_in address) -> Address;
|
||||
static auto VerifyAddress(const std::string& address) -> Address;
|
||||
auto Interrupt() -> void { LOG(debug) << "OFI transport: Interrupted (NOOP - not implemented)."; }
|
||||
auto Resume() -> void { LOG(debug) << "OFI transport: Resumed (NOOP - not implemented)."; }
|
||||
auto Reset() -> void;
|
||||
auto MakeReceiveMessage(size_t size) -> MessagePtr;
|
||||
auto MakeSendMessage(size_t size) -> MessagePtr;
|
||||
size_t GetSizeHint() { return fSizeHint; } // temporary hack to provide expected message size for receive
|
||||
void SetSizeHint(size_t size) { fSizeHint = size; } // temporary hack to provide expected message size for receive
|
||||
|
||||
private:
|
||||
void* fZmqContext;
|
||||
fi_info* fOfiInfo;
|
||||
fid_fabric* fOfiFabric;
|
||||
fid_domain* fOfiDomain;
|
||||
fid_av* fOfiAddressVector;
|
||||
fid_eq* fOfiEventQueue;
|
||||
boost::asio::io_service fIoContext;
|
||||
boost::asio::io_service::work fIoWork;
|
||||
boost::asio::io_context fIoContext;
|
||||
boost::asio::io_context::work fIoWork;
|
||||
std::vector<std::thread> fThreadPool;
|
||||
FairMQTransportFactory& fReceiveFactory;
|
||||
FairMQTransportFactory& fSendFactory;
|
||||
|
||||
size_t fSizeHint; // temporary hack to provide expected message size for receive
|
||||
|
||||
auto OpenOfiFabric() -> void;
|
||||
auto OpenOfiEventQueue() -> void;
|
||||
auto OpenOfiDomain() -> void;
|
||||
auto OpenOfiAddressVector() -> void;
|
||||
auto InitThreadPool(int numberIoThreads) -> void;
|
||||
}; /* class Context */
|
||||
|
||||
|
@@ -1,25 +0,0 @@
|
||||
syntax = "proto3";
|
||||
option optimize_for = SPEED;
|
||||
|
||||
package fair.mq.ofi;
|
||||
|
||||
message DataAddressAnnouncement {
|
||||
uint32 ipv4 = 1; // in_addr_t from <netinet/in.h>
|
||||
uint32 port = 2; // in_port_t from <netinet/in.h>
|
||||
}
|
||||
|
||||
message PostBuffer {
|
||||
uint64 size = 1; // buffer size (size_t)
|
||||
}
|
||||
|
||||
message PostBufferAcknowledgement {
|
||||
uint64 size = 1; // size_t
|
||||
}
|
||||
|
||||
message ControlMessage {
|
||||
oneof type {
|
||||
DataAddressAnnouncement data_address_announcement = 1;
|
||||
PostBuffer post_buffer = 2;
|
||||
PostBufferAcknowledgement post_buffer_acknowledgement = 3;
|
||||
}
|
||||
}
|
99
fairmq/ofi/ControlMessages.h
Normal file
99
fairmq/ofi/ControlMessages.h
Normal file
@@ -0,0 +1,99 @@
|
||||
/********************************************************************************
|
||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||
* *
|
||||
* This software is distributed under the terms of the *
|
||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||
* copied verbatim in the file "LICENSE" *
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef FAIR_MQ_OFI_CONTROLMESSAGES_H
|
||||
#define FAIR_MQ_OFI_CONTROLMESSAGES_H
|
||||
|
||||
#include <FairMQLogger.h>
|
||||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/container/pmr/memory_resource.hpp>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
|
||||
namespace boost {
|
||||
namespace asio {
|
||||
|
||||
template<typename PodType>
|
||||
auto buffer(const PodType& obj) -> boost::asio::const_buffer
|
||||
{
|
||||
return boost::asio::const_buffer(static_cast<const void*>(&obj), sizeof(PodType));
|
||||
}
|
||||
|
||||
} // namespace asio
|
||||
} // namespace boost
|
||||
|
||||
namespace fair {
|
||||
namespace mq {
|
||||
namespace ofi {
|
||||
|
||||
enum class ControlMessageType
|
||||
{
|
||||
DataAddressAnnouncement = 1,
|
||||
PostBuffer,
|
||||
PostBufferAcknowledgement
|
||||
};
|
||||
|
||||
struct ControlMessage
|
||||
{
|
||||
ControlMessageType type;
|
||||
};
|
||||
|
||||
struct DataAddressAnnouncement : ControlMessage
|
||||
{
|
||||
uint32_t ipv4; // in_addr_t from <netinet/in.h>
|
||||
uint32_t port; // in_port_t from <netinet/in.h>
|
||||
};
|
||||
|
||||
struct PostBuffer : ControlMessage
|
||||
{
|
||||
uint64_t size; // buffer size (size_t)
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
using unique_ptr = std::unique_ptr<T, std::function<void(T*)>>;
|
||||
|
||||
template<typename T, typename... Args>
|
||||
auto MakeControlMessageWithPmr(boost::container::pmr::memory_resource* pmr, Args&&... args)
|
||||
-> ofi::unique_ptr<T>
|
||||
{
|
||||
void* mem = pmr->allocate(sizeof(T));
|
||||
T* ctrl = new (mem) T(std::forward<Args>(args)...);
|
||||
|
||||
if (std::is_same<T, DataAddressAnnouncement>::value) {
|
||||
ctrl->type = ControlMessageType::DataAddressAnnouncement;
|
||||
} else if (std::is_same<T, PostBuffer>::value) {
|
||||
ctrl->type = ControlMessageType::PostBuffer;
|
||||
}
|
||||
|
||||
return ofi::unique_ptr<T>(ctrl, [=](T* p) {
|
||||
p->~T();
|
||||
pmr->deallocate(p, sizeof(T));
|
||||
});
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
auto MakeControlMessage(Args&&... args) -> T
|
||||
{
|
||||
T ctrl = T(std::forward<Args>(args)...);
|
||||
|
||||
if (std::is_same<T, DataAddressAnnouncement>::value) {
|
||||
ctrl.type = ControlMessageType::DataAddressAnnouncement;
|
||||
} else if (std::is_same<T, PostBuffer>::value) {
|
||||
ctrl.type = ControlMessageType::PostBuffer;
|
||||
}
|
||||
|
||||
return ctrl;
|
||||
}
|
||||
|
||||
} // namespace ofi
|
||||
} // namespace mq
|
||||
} // namespace fair
|
||||
|
||||
#endif /* FAIR_MQ_OFI_CONTROLMESSAGES_H */
|
@@ -10,6 +10,7 @@
|
||||
#include <fairmq/Tools.h>
|
||||
#include <FairMQLogger.h>
|
||||
|
||||
#include <asiofi.hpp>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <zmq.h>
|
||||
@@ -23,38 +24,50 @@ namespace ofi
|
||||
|
||||
using namespace std;
|
||||
|
||||
Message::Message()
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr)
|
||||
: fInitialSize(0)
|
||||
, fSize(0)
|
||||
, fData(nullptr)
|
||||
, fFreeFunction(nullptr)
|
||||
, fHint(nullptr)
|
||||
, fPmr(pmr)
|
||||
{
|
||||
}
|
||||
|
||||
Message::Message(const size_t size)
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr, const size_t size)
|
||||
: fInitialSize(size)
|
||||
, fSize(size)
|
||||
, fData(nullptr)
|
||||
, fFreeFunction(nullptr)
|
||||
, fHint(nullptr)
|
||||
, fPmr(pmr)
|
||||
{
|
||||
if (size) {
|
||||
fData = malloc(size);
|
||||
// static void* buffer = fPmr->allocate(size);
|
||||
// fData = buffer;
|
||||
fData = fPmr->allocate(size);
|
||||
assert(fData);
|
||||
}
|
||||
}
|
||||
|
||||
Message::Message(void* data, const size_t size, fairmq_free_fn* ffn, void* hint)
|
||||
Message::Message(boost::container::pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
const size_t size,
|
||||
fairmq_free_fn* ffn,
|
||||
void* hint)
|
||||
: fInitialSize(size)
|
||||
, fSize(size)
|
||||
, fData(data)
|
||||
, fFreeFunction(ffn)
|
||||
, fHint(hint)
|
||||
{
|
||||
}
|
||||
, fPmr(pmr)
|
||||
{}
|
||||
|
||||
Message::Message(FairMQUnmanagedRegionPtr& /*region*/, void* /*data*/, const size_t /*size*/, void* /*hint*/)
|
||||
Message::Message(boost::container::pmr::memory_resource* /*pmr*/,
|
||||
FairMQUnmanagedRegionPtr& /*region*/,
|
||||
void* /*data*/,
|
||||
const size_t /*size*/,
|
||||
void* /*hint*/)
|
||||
{
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
@@ -62,9 +75,11 @@ Message::Message(FairMQUnmanagedRegionPtr& /*region*/, void* /*data*/, const siz
|
||||
auto Message::Rebuild() -> void
|
||||
{
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
fFreeFunction(fData, fHint);
|
||||
} else {
|
||||
free(fData);
|
||||
if (fData) {
|
||||
fPmr->deallocate(fData, fSize);
|
||||
}
|
||||
}
|
||||
fData = nullptr;
|
||||
fInitialSize = 0;
|
||||
@@ -78,10 +93,12 @@ auto Message::Rebuild(const size_t size) -> void
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
} else {
|
||||
free(fData);
|
||||
if (fData) {
|
||||
fPmr->deallocate(fData, fSize);
|
||||
}
|
||||
}
|
||||
if (size) {
|
||||
fData = malloc(size);
|
||||
fData = fPmr->allocate(size);
|
||||
assert(fData);
|
||||
} else {
|
||||
fData = nullptr;
|
||||
@@ -97,10 +114,12 @@ auto Message::Rebuild(void* /*data*/, const size_t size, fairmq_free_fn* ffn, vo
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
} else {
|
||||
free(fData);
|
||||
if (fData) {
|
||||
fPmr->deallocate(fData, fSize);
|
||||
}
|
||||
}
|
||||
if (size) {
|
||||
fData = malloc(size);
|
||||
fData = fPmr->allocate(size);
|
||||
assert(fData);
|
||||
} else {
|
||||
fData = nullptr;
|
||||
@@ -138,17 +157,14 @@ auto Message::Copy(const fair::mq::Message& /*msg*/) -> void
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
|
||||
auto Message::Copy(const fair::mq::MessagePtr& /*msg*/) -> void
|
||||
{
|
||||
throw MessageError{"Not yet implemented."};
|
||||
}
|
||||
|
||||
Message::~Message()
|
||||
{
|
||||
if (fFreeFunction) {
|
||||
fFreeFunction(fData, fHint);
|
||||
fFreeFunction(fData, fHint);
|
||||
} else {
|
||||
free(fData);
|
||||
if (fData) {
|
||||
fPmr->deallocate(fData, fSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -12,10 +12,10 @@
|
||||
#include <FairMQMessage.h>
|
||||
#include <FairMQUnmanagedRegion.h>
|
||||
|
||||
#include <zmq.h>
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <asiofi.hpp>
|
||||
#include <atomic>
|
||||
#include <cstddef> // size_t
|
||||
#include <zmq.h>
|
||||
|
||||
namespace fair
|
||||
{
|
||||
@@ -30,13 +30,21 @@ namespace ofi
|
||||
*
|
||||
* @todo TODO insert long description
|
||||
*/
|
||||
class Message : public fair::mq::Message
|
||||
class Message final : public fair::mq::Message
|
||||
{
|
||||
public:
|
||||
Message();
|
||||
Message(const size_t size);
|
||||
Message(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr);
|
||||
Message(FairMQUnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0);
|
||||
Message(boost::container::pmr::memory_resource* pmr);
|
||||
Message(boost::container::pmr::memory_resource* pmr, const size_t size);
|
||||
Message(boost::container::pmr::memory_resource* pmr,
|
||||
void* data,
|
||||
const size_t size,
|
||||
fairmq_free_fn* ffn,
|
||||
void* hint = nullptr);
|
||||
Message(boost::container::pmr::memory_resource* pmr,
|
||||
FairMQUnmanagedRegionPtr& region,
|
||||
void* data,
|
||||
const size_t size,
|
||||
void* hint = 0);
|
||||
|
||||
Message(const Message&) = delete;
|
||||
Message operator=(const Message&) = delete;
|
||||
@@ -53,7 +61,6 @@ class Message : public fair::mq::Message
|
||||
auto GetType() const -> fair::mq::Transport override { return fair::mq::Transport::OFI; }
|
||||
|
||||
auto Copy(const fair::mq::Message& msg) -> void override;
|
||||
auto Copy(const fair::mq::MessagePtr& msg) -> void override;
|
||||
|
||||
~Message() override;
|
||||
|
||||
@@ -63,6 +70,7 @@ class Message : public fair::mq::Message
|
||||
void* fData;
|
||||
fairmq_free_fn* fFreeFunction;
|
||||
void* fHint;
|
||||
boost::container::pmr::memory_resource* fPmr;
|
||||
}; /* class Message */
|
||||
|
||||
} /* namespace ofi */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user