Compare commits

..

66 Commits

Author SHA1 Message Date
Alexey Rybalchenko
1a75141fc4 shm: allow monitor::ResetContent to cleanup after a crash 2022-02-02 10:49:00 +01:00
Alexey Rybalchenko
2f82eb4f09 shm: monitor: disable number of msgs in the ack queue output 2022-02-02 10:49:00 +01:00
Alexey Rybalchenko
92a56c26bc shm: remove UR queues on ResetContent 2022-02-02 10:49:00 +01:00
Alexey Rybalchenko
4f9aeda8ec shm: Add size to UnmanagedRegion debug output 2022-02-02 10:49:00 +01:00
Giulio Eulisse
ad894c79cf GUI Controller
provide a controller which can be used to control state
transitions from an external GUI.
2022-01-25 18:02:25 +01:00
Alexey Rybalchenko
5f33401d41 Parallelize more tests 2022-01-25 11:55:38 +01:00
Alexey Rybalchenko
f4d39d224b Avoid fixed ports in the test suites 2022-01-25 11:55:38 +01:00
Alexey Rybalchenko
bfd08bb33f Don't use to-be-deprecated names 2022-01-24 06:40:24 +01:00
Alexey Rybalchenko
f15f669853 use [[maybe_unused]] for values used in assertions 2022-01-24 06:40:24 +01:00
Alexey Rybalchenko
f6bade32bb modify keep-alive example executable a bit, make it configurable 2022-01-12 19:54:49 +01:00
Alexey Rybalchenko
ddf9bc7272 shm: keep mng segment around when skipping cleanup 2022-01-12 19:54:49 +01:00
Alexey Rybalchenko
f79a0714b4 shm: fix double unlock() 2022-01-12 19:54:49 +01:00
Alexey Rybalchenko
c04958e2a4 shm: reduce contention on region events 2022-01-10 19:42:08 +01:00
Alexey Rybalchenko
692576a5b1 shm: add APIs for implementing keep-alive process 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
eb4620b1ec shm: always open_or_create segment 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
9f9583eb55 shm: hide picosha2 from header 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
08ba068791 shm: remove unused member 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
1839f7e8c0 shm: integrate mtx and cv into management segment 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
80ed45df63 extend region config 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
eef42d2dea simplify region cleanup 2021-12-16 16:27:07 +01:00
Alexey Rybalchenko
d630fbb1e4 consolidate UnmanagedRegion options 2021-12-16 16:27:07 +01:00
Giulio Eulisse
acfb495411 Do not print logo, if not requested 2021-12-14 11:26:10 +01:00
Alexey Rybalchenko
953c4a75c8 refactor: deduplicate more zmq/shmem code 2021-12-06 09:45:39 +01:00
Alexey Rybalchenko
f24dee33c2 Add configurable default snd/rcv timeout 2021-12-06 09:45:39 +01:00
Alexey Rybalchenko
856780f88a fix: install tools/Exceptions.h 2021-11-12 13:20:48 +01:00
Alexey Rybalchenko
dbdf17c661 Avoid accessing Device.fChannels directly, use getters 2021-11-03 20:23:40 +01:00
Alexey Rybalchenko
a3bb5fb4b0 feat: Add Device::GetNumSubChannels(channel) 2021-11-03 20:23:40 +01:00
Alexey Rybalchenko
0eaea3c66f Do not catch and rethrow exception from state handlers 2021-11-03 20:23:40 +01:00
Alexey Rybalchenko
ebcbe2dde6 feat: Add interactive controller button to print connected peers 2021-10-19 10:22:19 +02:00
Dennis Klein
fda8126a43 feat: Add new GetNumberOfConnectedPeers() API 2021-10-19 10:22:19 +02:00
Dennis Klein
8796ce5b20 feat: Add new assertm macro
This allows to add a message to the assertion which can improve
readability of error diagnostics.
2021-10-19 10:22:19 +02:00
Dennis Klein
b8503bfbd5 fix: Deprecate Message::Close because it is really a dtor 2021-10-19 10:22:19 +02:00
Dennis Klein
7329cb4428 refactor: Deduplicate GetConstant()
* Deprecate its old name in the Socket classes
2021-10-19 10:22:19 +02:00
Dennis Klein
e84a16da88 fix: warning readability-braces-around-statements 2021-10-19 10:22:19 +02:00
Dennis Klein
1a5d0eddbe fix: Silence false positive cppcoreguidel-pro-bounds-array-to-pointer-decay 2021-10-19 10:22:19 +02:00
Alexey Rybalchenko
5fe2f53c7b feat: add tool for noncanonical input 2021-10-08 09:42:28 +02:00
Alexey Rybalchenko
d7fb01908c fix(shm): fix regression in debug mode data 2021-10-08 09:42:28 +02:00
Alexey Rybalchenko
1449166d44 feat: add options to control allocation attempts 2021-10-08 09:42:28 +02:00
Dennis Klein
55a2cfcc37 ci: Add macos-11-arm64 (apple-clang-13) build 2021-10-01 17:08:50 +02:00
Alexey Rybalchenko
36600dce2c Apply clang-diagnostic-unused-private-field 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
153dcfab94 Apply modernize-use-override 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
ad824b4de1 Define copy/move ctors and assignment ops
Delete special member functions where they are not used.
(as part of applying suggestions from cppcoreguidelines-special-member-functions)

These classes don't need to be copyable/movable:
  # copy/move not used:
  zmq:: TransportFactory, Socket, Message, UnmanagedRegion, Poller, Context
  shm:: TransportFactory, Socket, Message, UnmanagedRegion, Poller
  ofi:: TransportFactory, Socket, Message, Context
  shm:: ZMsg, Region, Monitor, TerminalConfig, Manager
  plugins:: Config, Control, TerminalConfig
  fairmq::StateQueue, StateMachine, ProgOptions, PluginServices, PluginManager, Plugin, Device, StateSubscription
  TestData, BadDevice, TestDevice (test suite heplers)

  # used via ptr interface:
  fairmq::UnmanagedRegion, TransportFactory, Socket, Poller, Message

These classes need to be movable/copyable:
 MyClass (test suite helper), fairmq::Channel, fairmq::Parts
2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
597d88277b Apply clang-analyzer-optin.performance.Padding 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
9590b5be40 Apply readability-static-accessed-through-instance 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
cf9b45cd75 Apply cppcoreguidelines-avoid-non-const-global-variables 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
1ee9d2d222 Apply misc-unused-alias-decls 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
310204a89d Apply performance-faster-string-find 2021-09-27 12:04:07 +02:00
Alexey Rybalchenko
f33c597f34 Apply readability-avoid-const-params-in-decls 2021-09-27 12:04:07 +02:00
Dennis Klein
42a7e298c0 ci: Update build environments 2021-09-24 14:16:44 +02:00
Alexey Rybalchenko
efca8e0ad4 fix(pmix): Avoid deprecated value 2021-09-24 13:36:58 +02:00
Alexey Rybalchenko
1ac30b51b1 fix(pmix): compiler warning infinite-recursion 2021-09-24 13:36:58 +02:00
Alexey Rybalchenko
2934016586 fix(pmix): ler warning string-plus-int 2021-09-24 13:36:58 +02:00
Alexey Rybalchenko
e484bf4578 Shm: Fix SetUsedSize() 2021-09-20 13:29:28 +02:00
Dennis Klein
b442483dc3 fix: Deprecate static string helper 2021-09-09 18:01:55 +02:00
Dennis Klein
727a709aff fix: -Winfinite-recursion 2021-09-09 18:01:55 +02:00
Alexey Rybalchenko
bce380d871 Implement shmem msg zero-copy 2021-09-07 20:53:16 +02:00
Alexey Rybalchenko
c57410b820 Extend test for empty messages 2021-09-07 20:53:16 +02:00
Alexey Rybalchenko
815b2f1d76 shm: reimplement alignment 2021-09-07 20:53:16 +02:00
Dennis Klein
4e8f247a0d fix: First round of using new non-namespaced typenames 2021-09-07 20:53:16 +02:00
Dennis Klein
0bf765e6ba build: Improve summary output 2021-09-07 20:53:16 +02:00
Dennis Klein
24fbf94946 build: Use fairmq-tidy on our own codebase when RUN_FAIRMQ_TIDY=ON 2021-09-07 20:53:16 +02:00
Dennis Klein
d392f60c09 build: Have color output depend on a common switch DISABLE_COLOR 2021-09-07 20:53:16 +02:00
Dennis Klein
dff2b4b7d1 feat(tidy): Add new FairMQTidy.cmake module 2021-09-07 20:53:16 +02:00
Dennis Klein
9cbaf7e0fd feat(tools): Move the error code to the Tools target 2021-09-07 20:53:16 +02:00
Dennis Klein
db727092c5 feat(tidy): Add new fairmq-tidy tool 2021-09-07 20:53:16 +02:00
Dennis Klein
8e6c50e7cc refactor: Prepare deprecation of non-namespaced types and headers 2021-09-07 20:53:16 +02:00
214 changed files with 6275 additions and 4374 deletions

5
.gitignore vendored
View File

@@ -1,5 +1,6 @@
build
install
.DS_Store
.vscode
/compile_commands.json
.cache

View File

@@ -39,6 +39,8 @@ fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN;BUILD_SDK_COMMANDS")
fairmq_build_option(BUILD_TIDY_TOOL "Build the fairmq-tidy tool."
DEFAULT OFF)
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
DEFAULT OFF)
fairmq_build_option(USE_EXTERNAL_GTEST "Do not use bundled GTest. Not recommended."
@@ -76,6 +78,10 @@ if(BUILD_DOCS)
doxygen_add_docs(doxygen README.md fairmq)
add_custom_target(docs ALL DEPENDS doxygen)
endif()
if(BUILD_TIDY_TOOL)
add_subdirectory(fairmq/tidy)
endif()
################################################################################
@@ -107,6 +113,9 @@ endif()
if(BUILD_SDK_COMMANDS)
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_commands)
endif()
if(BUILD_TIDY_TOOL)
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
endif()
################################################################################
@@ -126,6 +135,11 @@ if(BUILD_DOCS)
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
)
endif()
if(BUILD_TIDY_TOOL)
install(FILES cmake/FairMQTidy.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
include(FairMQPackage)
install_cmake_package()

6
Jenkinsfile vendored
View File

@@ -89,15 +89,15 @@ pipeline{
stage("CI") {
steps{
script {
def all = '-DHAS_ASIO=ON -DHAS_DDS=ON -DHAS_PMIX=ON'
def all = '-DHAS_ASIO=ON -DHAS_ASIOFI=ON -DHAS_PMIX=ON'
def builds = jobMatrix('build', [
[os: 'ubuntu', ver: '20.04', arch: 'x86_64', compiler: 'gcc-9', extra: all],
[os: 'fedora', ver: '32', arch: 'x86_64', compiler: 'gcc-10', extra: all],
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10', extra: all],
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11', extra: all],
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12',
extra: '-DHAS_ASIO=ON -DHAS_DDS=ON'],
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12', extra: '-DHAS_ASIO=ON'],
[os: 'macos', ver: '11', arch: 'arm64', compiler: 'apple-clang-13', extra: '-DHAS_ASIO=ON'],
])
def all_debug = "${all} -DCMAKE_BUILD_TYPE=Debug"

View File

@@ -147,6 +147,9 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
3. [Introspection](docs/Configuration.md#33-introspection)
4. [Development](docs/Development.md#4-development)
1. [Testing](docs/Development.md#41-testing)
2. [Static Analysis](docs/Development.md#42-static-analysis)
1. [CMake Integration](docs/Development.md#421-cmake-integration)
2. [Extra Compiler Arguments](docs/Development.md#422-extra-compiler-arguments)
5. [Logging](docs/Logging.md#5-logging)
1. [Log severity](docs/Logging.md#51-log-severity)
2. [Log verbosity](docs/Logging.md#52-log-verbosity)

View File

@@ -15,7 +15,7 @@ include(FairMQBundlePackageHelper)
if(BUILD_FAIRMQ OR BUILD_SDK)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package2(PUBLIC Threads REQUIRED)
set(Threads_PREFIX "<unknown system prefix>")
set(Threads_PREFIX "<system>")
endif()
if(BUILD_OFI_TRANSPORT)
@@ -37,7 +37,7 @@ if(BUILD_PMIX_PLUGIN)
find_package2(PRIVATE PMIx REQUIRED VERSION 2.1.4)
endif()
if(BUILD_FAIRMQ OR BUILD_SDK)
if(BUILD_FAIRMQ OR BUILD_SDK OR BUILD_TIDY_TOOL)
find_package2(PUBLIC FairLogger REQUIRED VERSION 1.6.0)
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
COMPONENTS container program_options filesystem date_time regex
@@ -59,6 +59,7 @@ if(BUILD_FAIRMQ)
endif()
find_package2(BUNDLED PicoSHA2 REQUIRED)
set(PicoSHA2_VERSION "1.0.0")
set(PicoSHA2_PREFIX "<bundled>")
endif()
if(BUILD_TESTING)
@@ -68,6 +69,7 @@ if(BUILD_TESTING)
find_package2(BUNDLED GTest REQUIRED)
if(GTest_BUNDLED)
set(GTest_VERSION "Apr 28 2021 @f5e592d8")
set(GTest_PREFIX "<bundled>")
endif()
endif()
@@ -77,6 +79,13 @@ if(BUILD_DOCS)
)
endif()
if(BUILD_TIDY_TOOL)
find_package2(PRIVATE LLVM REQUIRED)
find_package2(PRIVATE Clang REQUIRED)
set(Clang_VERSION ${LLVM_VERSION})
find_package2(PRIVATE CLI11 REQUIRED)
endif()
find_package2_implicit_dependencies() # Always call last after latest find_package2
if(PROJECT_PACKAGE_DEPENDENCIES)

View File

@@ -119,11 +119,11 @@ set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${_warnings} -DNDEBUG ${_sanitizers}"
unset(_warnings)
unset(_sanitizers)
if(CMAKE_GENERATOR STREQUAL "Ninja" AND
((CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) OR
(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.5)))
# Force colored warnings in Ninja's output, if the compiler has -fdiagnostics-color support.
# Rationale in https://github.com/ninja-build/ninja/issues/814
if(DISABLE_COLOR)
set(CMAKE_COLOR_MAKEFILE OFF)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=never")
else()
set(CMAKE_COLOR_MAKEFILE ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always")
endif()

View File

@@ -69,6 +69,12 @@ macro(fairmq_summary_components)
set(sdk_commands_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_SDK_COMMANDS=ON${CR})")
endif()
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
if(BUILD_TIDY_TOOL)
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
else()
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
endif()
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
endmacro()
macro(fairmq_summary_static_analysis)
@@ -91,9 +97,17 @@ macro(fairmq_summary_static_analysis)
endforeach()
set(static_ana_summary "${BWhite}(${CR}${analyser_list}${BWhite})${CR} (disable with ${BMagenta}-DRUN_STATIC_ANALYSIS=OFF${CR})")
else()
set(static_ana_summary "${BRed}OFF${CR} (default, enable with ${BMagenta}-DRUN_STATIC_ANALYSIS=ON${CR})")
set(static_ana_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DRUN_STATIC_ANALYSIS=ON${CR})")
endif()
message(STATUS " ${Cyan}RUN STATIC ANALYSIS ${static_ana_summary}")
if(BUILD_TIDY_TOOL)
if(RUN_FAIRMQ_TIDY)
set(tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DRUN_FAIRMQ_TIDY=OFF${CR})")
else()
set(tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DRUN_FAIRMQ_TIDY=ON${CR})")
endif()
message(STATUS " ${Cyan}RUN fairmq-tidy ${tidy_summary}")
endif()
endmacro()
macro(fairmq_summary_install_prefix)

103
cmake/FairMQTidy.cmake Normal file
View File

@@ -0,0 +1,103 @@
################################################################################
# Copyright (C) 2021 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_guard(GLOBAL)
#[=======================================================================[.rst:
``fairmq_target_tidy()``
========================
Runs the FairMQ static analyzer ``fairmq-tidy`` on source files in given
target.
.. code-block:: cmake
fairmq_target_tidy(TARGET <target> [EXTRA_ARGS <args>]
[CLANG_EXECUTABLE <clang>])
Registers a custom command that depends on ``<target>`` which runs ``fairmq-tidy``
on the source files that belong to ``<target>``. Optional extra arguments
``<args>`` are passed to the ``fairmq-tidy`` command-line.
Requires ``CMAKE_EXPORT_COMPILE_COMMANDS`` to be enabled.
#]=======================================================================]
function(fairmq_target_tidy)
cmake_parse_arguments(PARSE_ARGV 0 ARG "" "TARGET;EXTRA_ARGS;CLANG_EXECUTABLE" "")
if(NOT CMAKE_EXPORT_COMPILE_COMMANDS)
message(AUTHOR_WARNING "CMAKE_EXPORT_COMPILE_COMMANDS is not enabled. Skipping.")
return()
endif()
if(NOT ARG_TARGET)
message(AUTHOR_WARNING "TARGET argument is required. Skipping.")
return()
endif()
if(NOT TARGET ${ARG_TARGET})
message(AUTHOR_WARNING "Given TARGET argument `${ARG_TARGET}` is not a target. Skipping.")
return()
endif()
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
if(NOT fairmq_tidy_clang_resource_dir)
if(ARG_CLANG_EXECUTABLE)
set(clang_exe ${ARG_CLANG_EXECUTABLE})
else()
if(TARGET clang)
get_property(clang_exe TARGET clang PROPERTY LOCATION)
else()
set(clang_exe "clang")
endif()
endif()
execute_process(
COMMAND ${clang_exe} -print-resource-dir
OUTPUT_VARIABLE clang_resource_dir
OUTPUT_STRIP_TRAILING_WHITESPACE
)
set(fairmq_tidy_clang_resource_dir ${clang_resource_dir}
CACHE PATH "fairmq_target_tidy() internal state" FORCE)
endif()
list(APPEND ARG_EXTRA_ARGS
"--extra-arg-before=-I${fairmq_tidy_clang_resource_dir}/include")
endif()
if(ARG_EXTRA_ARGS)
set(extra 1)
else()
set(extra 0)
endif()
get_target_property(sources ${ARG_TARGET} SOURCES)
list(FILTER sources INCLUDE REGEX "\.(cpp|cxx)$")
string(REPLACE ":" "-" target_nocolon "${ARG_TARGET}")
set(src_deps)
foreach(source IN LISTS sources)
string(REPLACE "\/" "-" source_noslash "${source}")
set(src_stamp "${CMAKE_CURRENT_BINARY_DIR}/${target_nocolon}-${source_noslash}.fairmq-tidy")
add_custom_command(
OUTPUT ${src_stamp}
COMMAND $<TARGET_FILE:FairMQ::fairmq-tidy> -p=${CMAKE_BINARY_DIR}
$<${extra}:${ARG_EXTRA_ARGS}> ${source}
COMMAND ${CMAKE_COMMAND} -E touch ${src_stamp}
COMMENT "fairmq-tidy: Analyzing source file '${source}' of target '${ARG_TARGET}'"
DEPENDS ${ARG_TARGET}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND_EXPAND_LISTS VERBATIM
)
list(APPEND src_deps ${src_stamp})
endforeach()
if(src_deps)
add_custom_target("fairmq-tidy-${target_nocolon}" ALL DEPENDS ${src_deps})
endif()
endfunction()

View File

@@ -48,6 +48,9 @@
#
include(GoogleTest)
if(BUILD_TIDY_TOOL)
include(FairMQTidy)
endif()
function(add_testsuite suitename)
cmake_parse_arguments(testsuite
@@ -74,6 +77,9 @@ function(add_testsuite suitename)
if(testsuite_DEFINITIONS)
target_compile_definitions("${target}" PUBLIC ${testsuite_DEFINITIONS})
endif()
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
# add_test(NAME "${suitename}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} COMMAND ${target})
if(testsuite_TIMEOUT)
@@ -120,6 +126,9 @@ function(add_testhelper helpername)
if(testhelper_DEFINITIONS)
target_compile_definitions(${target} PUBLIC ${testhelper_DEFINITIONS})
endif()
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
list(APPEND ALL_TEST_TARGETS ${target})
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)
@@ -154,6 +163,9 @@ function(add_testlib libname)
if(testlib_DEFINITIONS)
target_compile_definitions(${target} PUBLIC ${testlib_DEFINITIONS})
endif()
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
list(APPEND ALL_TEST_TARGETS ${target})
set(ALL_TEST_TARGETS ${ALL_TEST_TARGETS} PARENT_SCOPE)

View File

@@ -8,6 +8,51 @@ For unit testing it is often not feasible to boot up a full-blown distributed sy
In some scenarios it is useful to not even instantiate a `FairMQDevice` at all. Please see [this example](../test/protocols/_push_pull_multipart.cxx) for single and multi threaded unit test without a device instance. If you store your transport factories and channels on the heap, pls make sure, you destroy the channels before you destroy the related transport factory for proper shutdown. Channels provide all the `Send/Receive` and `New*Message/New*Poller` APIs provided by the device too.
TODO Multiple devices in one process.
## 4.2 Static Analysis
With `-DBUILD_TIDY_TOOL=ON` you can build the `fairmq-tidy` tool that implements static checks on your source code. To use it, enable the generation of a [compilation database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) in your project via `-DCMAKE_EXPORT_COMPILE_COMMANDS=ON` (generates a file `<builddir>/compile_commands.json`):
```
fairmq-tidy -p <builddir> mysourcefile.cpp
```
If you find any issue (e.g. false positives) with this tool, please tell us by opening an issue on github.
### 4.2.1 CMake Integration
When discovering a FairMQ installation in your project, explicitely state, that you want one with the `fairmq-tidy` tool included:
```
find_package(FairMQ COMPONENTS tidy_tool)
```
Now the CMake module [`FairMQTidy.cmake`](../cmake/FairMQTidy.cmake) is available for inclusion:
```
include(FairMQTidy)
```
It provides the CMake function `fairmq_target_tidy()` which attaches appropriate `fairmq-tidy` build rules to each source file contained in the passed library or executable target, e.g. if you have an executable that uses FairMQ:
```
add_executable(myexe mysource1.cpp mysource2.cpp)
target_link_libraries(myexe PRIVATE FairMQ::FairMQ)
fairmq_target_tidy(TARGET myexe)
```
### 4.2.2 Extra Compiler Arguments
On most Linux distros you are likely to use GCC to compile your projects, so the resulting `compile_commands.json` contains the command-line tuned for GCC which might be missing options needed to successfully invoke the Clang frontend which is used internally by `fairmq-tidy`. In general, you can pass extra `clang` options via the following options:
```
--extra-arg=<string> - Additional argument to append to the compiler command line
--extra-arg-before=<string> - Additional argument to prepend to the compiler command line
```
E.g. if standard headers are not found, you can hint the location like this:
```
fairmq-top -p <builddir> --extra-arg-before=-I$(clang -print-resource-dir)/include mysourcefile.cpp
```
← [Back](../README.md)

View File

@@ -27,34 +27,34 @@ The next table shows the supported address types for each transport implementati
## 2.1 Message
Devices transport data between each other in form of `FairMQMessage`s. These can be filled with arbitrary content. Message can be initialized in three different ways by calling `NewMessage()`:
Devices transport data between each other in form of `fair::mq::Message`s. These can be filled with arbitrary content. Message can be initialized in three different ways by calling `NewMessage()`:
```cpp
FairMQMessagePtr NewMessage() const;
fair::mq::MessagePtr NewMessage() const;
```
**with no parameters**: Initializes an empty message (typically used for receiving).
```cpp
FairMQMessagePtr NewMessage(const size_t size) const;
fair::mq::MessagePtr NewMessage(const size_t size) const;
```
**given message size**: Initializes message body with a given size. Fill the created contents via buffer pointer.
```cpp
using fairmq_free_fn = void(void* data, void* hint);
FairMQMessagePtr NewMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) const;
fair::mq::MessagePtr NewMessage(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) const;
```
**given existing buffer and a size**: Initialize the message from an existing buffer. In case of ZeroMQ this is a zero-copy operation.
Additionally, FairMQ provides two more message factories for convenience:
```cpp
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data) const
fair::mq::MessagePtr NewSimpleMessage(const T& data) const
```
**copy and own**: Copy the `data` argument into the returned message and take ownership (free memory after message is sent). This interface is useful for small, [trivially copyable](http://en.cppreference.com/w/cpp/concept/TriviallyCopyable) data.
```cpp
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data) const
fair::mq::MessagePtr NewStaticMessage(const T& data) const
```
**point to existing memory**: The returned message will point to the `data` argument, but not take ownership (someone else must destruct this variable). Make sure that `data` lives long enough to be successfully sent. This interface is most useful for third party managed, contiguous memory (Be aware of shallow types with internal pointer references! These will not be sent.)
@@ -65,19 +65,19 @@ The component of a program, that is reponsible for the allocation or destruction
After queuing a message for sending in FairMQ, the transport takes ownership over the message body and will free it with `free()` after it is no longer used. A callback can be passed to the message object, to be called instead of the destruction with `free()` (for initialization via buffer+size).
```cpp
static void FairMQNoCleanup(void* /*data*/, void* /*obj*/) {}
static void fair::mq::NoCleanup(void* /*data*/, void* /*obj*/) {}
template<typename T>
static void FairMQSimpleMsgCleanup(void* /*data*/, void* obj) { delete static_cast<T*>(obj); }
static void fair::mq::SimpleMsgCleanup(void* /*data*/, void* obj) { delete static_cast<T*>(obj); }
```
For convenience, two common deleter callbacks are already defined in the `FairMQTransportFactory` class to aid the user in controlling ownership of the data.
For convenience, two common deleter callbacks are already defined in the `fair::mq::TransportFactory` class to aid the user in controlling ownership of the data.
## 2.2 Channel
A channel represents a communication endpoint in FairMQ. Usage is similar to a traditional Unix network socket. A device usually contains a number of channels that can either listen for incoming connections from channels of other devices or they can connect to other listening channels. Channels are organized by a channel name and a subchannel index.
```cpp
const FairMQChannel& GetChannel(const std::string& channelName, const int index = 0) const;
const fair::mq::Channel& GetChannel(const std::string& channelName, const int index = 0) const;
```
All subchannels with a common channel name need to be of the same transport type.
@@ -87,7 +87,7 @@ All subchannels with a common channel name need to be of the same transport type
A poller allows to wait on multiple channels either to receive or send a message.
```cpp
FairMQPollerPtr NewPoller(const std::vector<const FairMQChannel*>& channels)
fair::mq::PollerPtr NewPoller(const std::vector<const fair::mq::Channel*>& channels)
```
**list channels**: This poller waits on all supplied channels. Currently, it is limited to channels of the same transport type only.

View File

@@ -23,10 +23,10 @@ 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: ")
set_tests_properties(Example.1-1.zeromq PROPERTIES TIMEOUT "30" 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: ")
set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
# install

View File

@@ -30,7 +30,7 @@ struct Sampler : fair::mq::Device
// create message object with a pointer to the data buffer, its size,
// custom deletion function (called when transfer is done),
// and pointer to the object managing the data buffer
FairMQMessagePtr msg(NewMessage(
fair::mq::MessagePtr msg(NewMessage(
const_cast<char*>(text->c_str()),
text->length(),
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },

View File

@@ -27,7 +27,7 @@ struct Sink : fair::mq::Device
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";

View File

@@ -8,20 +8,23 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID;' TERM
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanAddr' TERM
SAMPLER="fairmq-ex-1-1-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --rate 1"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://*:5555,rateLogging=0"
SAMPLER+=" --channel-config name=$chan,type=push,method=bind,address=ipc://$chanAddr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -29,13 +32,16 @@ SINK="fairmq-ex-1-1-sink"
SINK+=" --id sink1"
SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $SESSION"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --control static --color false"
SINK+=" --max-iterations 1"
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://localhost:5555,rateLogging=0"
SINK+=" --channel-config name=$chan,type=pull,method=connect,address=ipc://$chanAddr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
# wait for sampler and sink to finish
wait $SAMPLER_PID
wait $SINK_PID
rm $chanAddr

View File

@@ -29,10 +29,10 @@ 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: ")
set_tests_properties(Example.1-n-1.zeromq PROPERTIES TIMEOUT "30" 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: ")
set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
# install

View File

@@ -20,7 +20,7 @@ struct Processor : fair::mq::Device
OnData("data1", &Processor::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received data, processing...";
@@ -32,7 +32,7 @@ struct Processor : fair::mq::Device
// its size,
// custom deletion function (called when transfer is done),
// and pointer to the object managing the data buffer
FairMQMessagePtr msg2(NewMessage(const_cast<char*>(text->c_str()),
fair::mq::MessagePtr msg2(NewMessage(const_cast<char*>(text->c_str()),
text->length(),
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
text));

View File

@@ -28,7 +28,7 @@ struct Sampler : fair::mq::Device
{
// Initializing message with NewStaticMessage will avoid copy
// but won't delete the data after the sending is completed.
FairMQMessagePtr msg(NewStaticMessage(fText));
fair::mq::MessagePtr msg(NewStaticMessage(fText));
LOG(info) << "Sending \"" << fText << "\"";

View File

@@ -27,7 +27,7 @@ struct Sink : fair::mq::Device
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";

View File

@@ -8,20 +8,25 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
ex2config="@CMAKE_CURRENT_BINARY_DIR@/ex-1-n-1.json"
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan1="data1"
chan2="data2"
chan1Addr="/tmp/fmq_$session""_""$chan1""_""$transport"
chan2Addr="/tmp/fmq_$session""_""$chan2""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $PROCESSOR1_PID; kill -TERM $PROCESSOR2_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $PROCESSOR1_PID; wait $PROCESSOR2_PID;' TERM
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $PROCESSOR1_PID; kill -TERM $PROCESSOR2_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $PROCESSOR1_PID; wait $PROCESSOR2_PID; rm $chan1Addr; rm $chan2Addr' TERM
SAMPLER="fairmq-ex-1-n-1-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --session $session"
SAMPLER+=" --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 2"
SAMPLER+=" --mq-config $ex2config"
SAMPLER+=" --channel-config name=$chan1,type=push,method=bind,address=ipc://$chan1Addr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -29,10 +34,12 @@ PROCESSOR1="fairmq-ex-1-n-1-processor"
PROCESSOR1+=" --id processor1"
PROCESSOR1+=" --transport $transport"
PROCESSOR1+=" --verbosity veryhigh"
PROCESSOR1+=" --session $SESSION"
PROCESSOR1+=" --session $session"
PROCESSOR1+=" --severity debug"
PROCESSOR1+=" --shm-segment-size 100000000"
PROCESSOR1+=" --control static --color false"
PROCESSOR1+=" --mq-config $ex2config"
PROCESSOR1+=" --config-key processor"
PROCESSOR1+=" --channel-config name=$chan1,type=pull,method=connect,address=ipc://$chan1Addr,rateLogging=0"
PROCESSOR1+=" name=$chan2,type=push,method=connect,address=ipc://$chan2Addr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$PROCESSOR1 &
PROCESSOR1_PID=$!
@@ -40,10 +47,12 @@ PROCESSOR2="fairmq-ex-1-n-1-processor"
PROCESSOR2+=" --id processor2"
PROCESSOR2+=" --transport $transport"
PROCESSOR2+=" --verbosity veryhigh"
PROCESSOR2+=" --session $SESSION"
PROCESSOR2+=" --session $session"
PROCESSOR2+=" --severity debug"
PROCESSOR2+=" --shm-segment-size 100000000"
PROCESSOR2+=" --control static --color false"
PROCESSOR2+=" --mq-config $ex2config"
PROCESSOR2+=" --config-key processor"
PROCESSOR2+=" --channel-config name=$chan1,type=pull,method=connect,address=ipc://$chan1Addr,rateLogging=0"
PROCESSOR2+=" name=$chan2,type=push,method=connect,address=ipc://$chan2Addr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$PROCESSOR2 &
PROCESSOR2_PID=$!
@@ -51,10 +60,12 @@ SINK="fairmq-ex-1-n-1-sink"
SINK+=" --id sink1"
SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $SESSION"
SINK+=" --session $session"
SINK+=" --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --control static --color false"
SINK+=" --max-iterations 2"
SINK+=" --mq-config $ex2config"
SINK+=" --channel-config name=$chan2,type=pull,method=bind,address=ipc://$chan2Addr,rateLogging=0"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
@@ -69,3 +80,5 @@ kill -SIGINT $PROCESSOR2_PID
# wait for everything to finish
wait $PROCESSOR1_PID
wait $PROCESSOR2_PID
rm $chan1Addr; rm $chan2Addr

View File

@@ -15,16 +15,16 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in
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")
set_tests_properties(Example.BuiltinDevices.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
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")
set_tests_properties(Example.BuiltinDevices.shmem PROPERTIES TIMEOUT "30" 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")
set_tests_properties(Example.BuiltinDevices.multipart.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
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")
set_tests_properties(Example.BuiltinDevices.multipart.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
# install

View File

@@ -2,8 +2,6 @@
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
transport="zeromq"
multipart="false"
numParts="1"
@@ -20,8 +18,22 @@ if [[ $3 =~ ^[0-9]+$ ]]; then
numParts=$3
fi
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan1="data1"
chan2="data2"
chan3="data3"
chan4="data4"
chan5="data5"
chan1Addr="/tmp/fmq_$session""_""$chan1""_""$transport"
chan2Addr1="/tmp/fmq_$session""_""$chan2""_1""_""$transport"
chan2Addr2="/tmp/fmq_$session""_""$chan2""_2""_""$transport"
chan3Addr1="/tmp/fmq_$session""_""$chan3""_1""_""$transport"
chan3Addr2="/tmp/fmq_$session""_""$chan3""_2""_""$transport"
chan4Addr="/tmp/fmq_$session""_""$chan4""_""$transport"
chan5Addr="/tmp/fmq_$session""_""$chan5""_""$transport"
# 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
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; rm $chan1Addr; rm $chan2Addr1; rm $chan2Addr2; rm $chan3Addr1; rm $chan3Addr2; rm $chan4Addr; rm $chan5Addr' TERM
SAMPLER="fairmq-bsampler"
SAMPLER+=" --id bsampler1"
@@ -30,14 +42,15 @@ SAMPLER+=" --transport $transport"
SAMPLER+=" --color false"
SAMPLER+=" --control static"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --shm-segment-size 100000000"
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"
SAMPLER+=" --out-channel $chan1"
SAMPLER+=" --channel-config name=$chan1,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan1Addr"
@FAIRMQ_BIN_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -48,11 +61,12 @@ SPLITTER+=" --transport $transport"
SPLITTER+=" --color false"
SPLITTER+=" --control static"
SPLITTER+=" --verbosity veryhigh"
SPLITTER+=" --shm-segment-size 100000000"
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"
SPLITTER+=" --in-channel $chan1"
SPLITTER+=" --out-channel $chan2"
SPLITTER+=" --channel-config name=$chan1,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan1Addr"
SPLITTER+=" name=$chan2,type=push,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan2Addr1,address=ipc://$chan2Addr2"
@FAIRMQ_BIN_DIR@/$SPLITTER &
SPLITTER_PID=$!
@@ -63,11 +77,12 @@ PROXY1+=" --transport $transport"
PROXY1+=" --color false"
PROXY1+=" --control static"
PROXY1+=" --verbosity veryhigh"
PROXY1+=" --shm-segment-size 100000000"
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"
PROXY1+=" --in-channel $chan2"
PROXY1+=" --out-channel $chan3"
PROXY1+=" --channel-config name=$chan2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan2Addr1"
PROXY1+=" name=$chan3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan3Addr1"
@FAIRMQ_BIN_DIR@/$PROXY1 &
PROXY1_PID=$!
@@ -78,11 +93,12 @@ PROXY2+=" --transport $transport"
PROXY2+=" --color false"
PROXY2+=" --control static"
PROXY2+=" --verbosity veryhigh"
PROXY2+=" --shm-segment-size 100000000"
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"
PROXY2+=" --in-channel $chan2"
PROXY2+=" --out-channel $chan3"
PROXY2+=" --channel-config name=$chan2,type=pull,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan2Addr2"
PROXY2+=" name=$chan3,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan3Addr2"
@FAIRMQ_BIN_DIR@/$PROXY2 &
PROXY2_PID=$!
@@ -93,11 +109,12 @@ MERGER+=" --transport $transport"
MERGER+=" --color false"
MERGER+=" --control static"
MERGER+=" --verbosity veryhigh"
MERGER+=" --shm-segment-size 100000000"
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"
MERGER+=" --in-channel $chan3"
MERGER+=" --out-channel $chan4"
MERGER+=" --channel-config name=$chan3,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan3Addr1,address=ipc://$chan3Addr2"
MERGER+=" name=$chan4,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan4Addr"
@FAIRMQ_BIN_DIR@/$MERGER &
MERGER_PID=$!
@@ -108,11 +125,12 @@ MULTIPLIER+=" --transport $transport"
MULTIPLIER+=" --color false"
MULTIPLIER+=" --control static"
MULTIPLIER+=" --verbosity veryhigh"
MULTIPLIER+=" --shm-segment-size 100000000"
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"
MULTIPLIER+=" --in-channel $chan4"
MULTIPLIER+=" --out-channel $chan5"
MULTIPLIER+=" --channel-config name=$chan4,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan4Addr"
MULTIPLIER+=" name=$chan5,type=push,method=connect,sndBufSize=50,rcvBufSize=50,address=ipc://$chan5Addr,address=ipc://$chan5Addr"
@FAIRMQ_BIN_DIR@/$MULTIPLIER &
MULTIPLIER_PID=$!
@@ -126,8 +144,8 @@ 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"
SINK+=" --in-channel $chan5"
SINK+=" --channel-config name=$chan5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan5Addr"
@FAIRMQ_BIN_DIR@/$SINK &
SINK_PID=$!
@@ -146,3 +164,5 @@ wait $PROXY1_PID
wait $PROXY2_PID
wait $MERGER_PID
wait $MULTIPLIER_PID
rm $chan1Addr; rm $chan2Addr1; rm $chan2Addr2; rm $chan3Addr1; rm $chan3Addr2; rm $chan4Addr; rm $chan5Addr

View File

@@ -24,10 +24,10 @@ 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: ")
set_tests_properties(Example.CopyPush.zeromq PROPERTIES TIMEOUT "30" 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: ")
set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message: ")
# install

View File

@@ -19,7 +19,7 @@ struct Sampler : fair::mq::Device
{
void InitTask() override
{
fNumDataChannels = fChannels.at("data").size();
fNumDataChannels = GetNumSubChannels("data");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
@@ -27,10 +27,10 @@ struct Sampler : fair::mq::Device
{
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
FairMQMessagePtr msg(NewSimpleMessage(fCounter++));
fair::mq::MessagePtr msg(NewSimpleMessage(fCounter++));
for (int i = 0; i < fNumDataChannels - 1; ++i) {
FairMQMessagePtr msgCopy(NewMessage());
fair::mq::MessagePtr msgCopy(NewMessage());
msgCopy->Copy(*msg);
Send(msgCopy, "data", i);
}

View File

@@ -27,7 +27,7 @@ struct Sink : fair::mq::Device
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received message: \"" << *(static_cast<uint64_t*>(msg->GetData())) << "\"";

View File

@@ -8,19 +8,24 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr1="/tmp/fmq_$session""_""$chan""_1""_""$transport"
chanAddr2="/tmp/fmq_$session""_""$chan""_2""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK1_PID; kill -TERM $SINK2_PID; wait $SAMPLER_PID; wait $SINK1_PID; wait $SINK2_PID;' TERM
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK1_PID; kill -TERM $SINK2_PID; wait $SAMPLER_PID; wait $SINK1_PID; wait $SINK2_PID; rm $chanAddr1; rm $chanAddr2' TERM
SAMPLER="fairmq-ex-copypush-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --session $session"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --channel-config name=data,type=push,method=bind,rateLogging=0,address=tcp://*:5555,address=tcp://*:5556"
SAMPLER+=" --channel-config name=$chan,type=push,method=bind,rateLogging=0,address=ipc://$chanAddr1,address=ipc://$chanAddr2"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -28,10 +33,12 @@ SINK1="fairmq-ex-copypush-sink"
SINK1+=" --id sink1"
SINK1+=" --transport $transport"
SINK1+=" --verbosity veryhigh"
SINK1+=" --session $SESSION"
SINK1+=" --severity debug"
SINK1+=" --shm-segment-size 100000000"
SINK1+=" --session $session"
SINK1+=" --control static --color false"
SINK1+=" --max-iterations 1"
SINK1+=" --channel-config name=data,type=pull,method=connect,rateLogging=0,address=tcp://localhost:5555"
SINK1+=" --channel-config name=$chan,type=pull,method=connect,rateLogging=0,address=ipc://$chanAddr1"
@CMAKE_CURRENT_BINARY_DIR@/$SINK1 &
SINK1_PID=$!
@@ -39,10 +46,12 @@ SINK2="fairmq-ex-copypush-sink"
SINK2+=" --id sink2"
SINK2+=" --transport $transport"
SINK2+=" --verbosity veryhigh"
SINK2+=" --session $SESSION"
SINK2+=" --severity debug"
SINK2+=" --shm-segment-size 100000000"
SINK2+=" --session $session"
SINK2+=" --control static --color false"
SINK2+=" --max-iterations 1"
SINK2+=" --channel-config name=data,type=pull,method=connect,rateLogging=0,address=tcp://localhost:5556"
SINK2+=" --channel-config name=$chan,type=pull,method=connect,rateLogging=0,address=ipc://$chanAddr2"
@CMAKE_CURRENT_BINARY_DIR@/$SINK2 &
SINK2_PID=$!
@@ -50,3 +59,5 @@ SINK2_PID=$!
wait $SAMPLER_PID
wait $SINK1_PID
wait $SINK2_PID
rm $chanAddr1; rm $chanAddr2

View File

@@ -20,7 +20,7 @@ struct Processor : fair::mq::Device
OnData("data1", &Processor::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received data, processing...";
@@ -32,7 +32,7 @@ struct Processor : fair::mq::Device
// its size,
// custom deletion function (called when transfer is done),
// and pointer to the object managing the data buffer
FairMQMessagePtr msg2(NewMessage(const_cast<char*>(text->c_str()),
fair::mq::MessagePtr msg2(NewMessage(const_cast<char*>(text->c_str()),
text->length(),
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); },
text));

View File

@@ -24,7 +24,7 @@ struct Sampler : fair::mq::Device
{
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
FairMQMessagePtr msg(NewSimpleMessage("Data"));
fair::mq::MessagePtr msg(NewSimpleMessage("Data"));
LOG(info) << "Sending \"Data\"";

View File

@@ -25,7 +25,7 @@ struct Sink : fair::mq::Device
fIterations = fConfig->GetValue<uint64_t>("iterations");
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
LOG(info) << "Received: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";

View File

@@ -23,14 +23,14 @@ 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 7 parts")
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 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 7 parts")
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 parts")
if(BUILD_OFI_TRANSPORT)
add_test(NAME Example.Multipart.ofi COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh ofi)
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" RUN_SERIAL true PASS_REGULAR_EXPRESSION "Received message with 7 parts")
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 parts")
endif()
# install

View File

@@ -5,7 +5,7 @@ A topology of two devices - Sampler and Sink, communicating with PUSH-PULL patte
The Sampler sends a multipart message to the Sink, consisting of two message parts - header and body.
Each message part is a regular FairMQMessage. To combine them into a multi-part message use `FairMQParts`. Add messages to `FairMQParts` with `AddPart` method.
Each message part is a regular fair::mq::Message. To combine them into a multi-part message use `fair::mq::Parts`. Add messages to `fair::mq::Parts` with `AddPart` method.
All parts are guaranteed to be delivered together. The Receive call in the sink will recive the entire parts structure.

View File

@@ -35,15 +35,15 @@ struct Sampler : fair::mq::Device
}
LOG(info) << "Sending header with stopFlag: " << header.stopFlag;
FairMQParts parts;
fair::mq::Parts parts;
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
parts.AddPart(NewSimpleMessage(header));
parts.AddPart(NewMessage(1000));
// create more data parts, testing the FairMQParts in-place constructor
FairMQParts auxData{ NewMessage(500), NewMessage(600), NewMessage(700) };
// create more data parts, testing the fair::mq::Parts in-place constructor
fair::mq::Parts auxData{ NewMessage(500), NewMessage(600), NewMessage(700) };
assert(auxData.Size() == 3);
parts.AddPart(std::move(auxData));
assert(auxData.Size() == 0);

View File

@@ -20,7 +20,7 @@ struct Sink : fair::mq::Device
OnData("data", &Sink::HandleData);
}
bool HandleData(FairMQParts& parts, int)
bool HandleData(fair::mq::Parts& parts, int)
{
LOG(info) << "Received message with " << parts.Size() << " parts";

View File

@@ -8,19 +8,28 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr=""
chanIpcFile="/tmp/fmq_$session""_""$chan""_""$transport"
if [ $transport = "ofi" ]; then
chanAddr="tcp://127.0.0.1:5656"
else
chanAddr="ipc://""$chanIpcFile"
fi
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID;' TERM
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanIpcFile' TERM
SAMPLER="fairmq-ex-multipart-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --control static --color false"
SAMPLER+=" --channel-config name=data,type=pair,method=connect,rateLogging=0,address=tcp://127.0.0.1:5555,linger=1000"
SAMPLER+=" --channel-config name=$chan,type=pair,method=connect,rateLogging=0,address=$chanAddr,linger=1000"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -28,11 +37,14 @@ SINK="fairmq-ex-multipart-sink"
SINK+=" --id sink1"
SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $SESSION"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --control static --color false"
SINK+=" --channel-config name=data,type=pair,method=bind,rateLogging=0,address=tcp://127.0.0.1:5555"
SINK+=" --channel-config name=$chan,type=pair,method=bind,rateLogging=0,address=$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
wait $SAMPLER_PID
wait $SINK_PID
rm $chanIpcFile

View File

@@ -26,7 +26,7 @@ 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.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.")
set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received messages from both sources.")
# install

View File

@@ -5,4 +5,4 @@ This example demonstrates how to work with multiple channels and multiplex betwe
A topology of three devices - **Sampler**, **Sink** and **Broadcaster**. The Sampler sends data to the Sink via the PUSH-PULL pattern. The Broadcaster device sends a message to both Sampler and Sink containing a string "OK" every second. The Broadcaster sends the message via PUB pattern. Both Sampler and Sink, besides doing their PUSH-PULL job, listen via SUB to the Broadcaster.
The multiplexing between their data channels and the broadcast channels happens with `FairMQPoller`.
The multiplexing between their data channels and the broadcast channels happens with `fair::mq::Poller`.

View File

@@ -22,7 +22,7 @@ struct Broadcaster : fair::mq::Device
// NewSimpleMessage creates a copy of the data and takes care of its destruction (after the transfer takes place).
// Should only be used for small data because of the cost of an additional copy
FairMQMessagePtr msg(NewSimpleMessage("OK"));
fair::mq::MessagePtr msg(NewSimpleMessage("OK"));
LOG(info) << "Sending OK";

View File

@@ -7,7 +7,7 @@
********************************************************************************/
#include <fairmq/Device.h>
#include <FairMQPoller.h>
#include <fairmq/Poller.h>
#include <fairmq/runDevice.h>
#include <chrono>
@@ -26,13 +26,13 @@ struct Sampler : fair::mq::Device
void Run() override
{
FairMQPollerPtr poller(NewPoller("data", "broadcast"));
fair::mq::PollerPtr poller(NewPoller("data", "broadcast"));
while (!NewStatePending()) {
poller->Poll(100);
if (poller->CheckInput("broadcast", 0)) {
FairMQMessagePtr msg(NewMessage());
fair::mq::MessagePtr msg(NewMessage());
if (Receive(msg, "broadcast") > 0) {
LOG(info) << "Received broadcast: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";
@@ -42,7 +42,7 @@ struct Sampler : fair::mq::Device
if (poller->CheckOutput("data", 0)) {
std::this_thread::sleep_for(std::chrono::seconds(1));
FairMQMessagePtr msg(NewSimpleMessage(fText));
fair::mq::MessagePtr msg(NewSimpleMessage(fText));
if (Send(msg, "data") > 0) {
LOG(info) << "Sent \"" << fText << "\"";

View File

@@ -27,7 +27,7 @@ struct Sink : fair::mq::Device
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool HandleBroadcast(FairMQMessagePtr& msg, int /*index*/)
bool HandleBroadcast(fair::mq::MessagePtr& msg, int /*index*/)
{
LOG(info) << "Received broadcast: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";
fReceivedBroadcast = true;
@@ -35,7 +35,7 @@ struct Sink : fair::mq::Device
return CheckIterations();
}
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
bool HandleData(fair::mq::MessagePtr& msg, int /*index*/)
{
LOG(info) << "Received message: \"" << std::string(static_cast<char*>(msg->GetData()), msg->GetSize()) << "\"";
fReceivedData = true;

View File

@@ -8,18 +8,25 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $BROADCASTER_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $BROADCASTER_PID;' TERM
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
dataChan="data"
broadcastChan="broadcast"
dataChanAddr="/tmp/fmq_$session""_""$dataChan""_""$transport"
broadcastChanAddr="/tmp/fmq_$session""_""$broadcastChan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $BROADCASTER_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $BROADCASTER_PID; rm $dataChanAddr; rm $broadcastChanAddr' TERM
SINK="fairmq-ex-multiple-channels-sink"
SINK+=" --id sink1"
SINK+=" --session $session"
SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --verbosity veryhigh --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --max-iterations 1"
SINK+=" --control static --color false"
SINK+=" --channel-config name=data,type=pull,method=connect,rateLogging=0,address=tcp://localhost:5555"
SINK+=" name=broadcast,type=sub,method=connect,rateLogging=0,address=tcp://localhost:5005"
SINK+=" --channel-config name=$dataChan,type=pull,method=connect,rateLogging=0,address=ipc://$dataChanAddr"
SINK+=" name=$broadcastChan,type=sub,method=connect,rateLogging=0,address=ipc://$broadcastChanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
@@ -27,21 +34,25 @@ sleep 1
SAMPLER="fairmq-ex-multiple-channels-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --session $session"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --verbosity veryhigh --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --control static --color false"
SAMPLER+=" --channel-config name=data,type=push,method=bind,rateLogging=0,address=tcp://*:5555"
SAMPLER+=" name=broadcast,type=sub,method=connect,rateLogging=0,address=tcp://localhost:5005"
SAMPLER+=" --channel-config name=$dataChan,type=push,method=bind,rateLogging=0,address=ipc://$dataChanAddr"
SAMPLER+=" name=$broadcastChan,type=sub,method=connect,rateLogging=0,address=ipc://$broadcastChanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
BROADCASTER="fairmq-ex-multiple-channels-broadcaster"
BROADCASTER+=" --id broadcaster1"
BROADCASTER+=" --session $session"
BROADCASTER+=" --transport $transport"
BROADCASTER+=" --verbosity veryhigh"
BROADCASTER+=" --verbosity veryhigh --severity debug"
BROADCASTER+=" --shm-segment-size 100000000"
BROADCASTER+=" --control static --color false"
BROADCASTER+=" --channel-config name=broadcast,type=pub,method=bind,rateLogging=0,address=tcp://*:5005"
BROADCASTER+=" --channel-config name=$broadcastChan,type=pub,method=bind,rateLogging=0,address=ipc://$broadcastChanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$BROADCASTER &
BROADCASTER_PID=$!
@@ -53,3 +64,5 @@ kill -SIGINT $BROADCASTER_PID
# wait for broadcaster to finish
wait $BROADCASTER_PID
rm $dataChanAddr; rm $broadcastChanAddr

View File

@@ -25,7 +25,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.s
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.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.")
set_tests_properties(Example.MultipleTransports PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received messages from both sources.")
# install

View File

@@ -28,7 +28,7 @@ struct Sampler1 : fair::mq::Device
bool ConditionalRun() override
{
// Creates a message using the transport of channel data1
FairMQMessagePtr msg(NewMessageFor("data1", 0, 1000000));
fair::mq::MessagePtr msg(NewMessageFor("data1", 0, 1000000));
// in case of error or transfer interruption, return false to go to IDLE state
// successfull transfer will return number of bytes transfered (can be 0 if sending an empty message).
@@ -54,7 +54,7 @@ struct Sampler1 : fair::mq::Device
uint64_t numAcks = 0;
while (!NewStatePending()) {
FairMQMessagePtr ack(NewMessageFor("ack", 0));
fair::mq::MessagePtr ack(NewMessageFor("ack", 0));
if (Receive(ack, "ack") < 0) {
break;
}

View File

@@ -22,7 +22,7 @@ struct Sampler2 : fair::mq::Device
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewMessage(1000));
fair::mq::MessagePtr msg(NewMessage(1000));
// in case of error or transfer interruption, return false to go to IDLE state
// successfull transfer will return number of bytes transfered (can be 0 if sending an empty message).

View File

@@ -26,11 +26,11 @@ struct Sink : fair::mq::Device
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool HandleData1(FairMQMessagePtr& /*msg*/, int /*index*/)
bool HandleData1(fair::mq::MessagePtr& /*msg*/, int /*index*/)
{
fNumIterations1++;
// Creates a message using the transport of channel ack
FairMQMessagePtr ack(NewMessageFor("ack", 0));
fair::mq::MessagePtr ack(NewMessageFor("ack", 0));
if (Send(ack, "ack") < 0) {
return false;
}
@@ -40,7 +40,7 @@ struct Sink : fair::mq::Device
}
// handler is called whenever a message arrives on "data", with a reference to the message and a sub-channel index (here 0)
bool HandleData2(FairMQMessagePtr& /*msg*/, int /*index*/)
bool HandleData2(fair::mq::MessagePtr& /*msg*/, int /*index*/)
{
fNumIterations2++;
// return true if want to be called again (otherwise go to IDLE state)

View File

@@ -2,46 +2,57 @@
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan1="data1"
chan2="data2"
ackChan="ack"
chan1Addr="/tmp/fmq_$session""_""$chan1"
chan2Addr="/tmp/fmq_$session""_""$chan2"
ackChanAddr="/tmp/fmq_$session""_""$ackChan"
trap 'kill -TERM $SAMPLER1_PID; kill -TERM $SAMPLER2_PID; kill -TERM $SINK_PID; wait $SAMPLER1_PID; wait $SAMPLER2_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION;' TERM
trap 'kill -TERM $SAMPLER1_PID; kill -TERM $SAMPLER2_PID; kill -TERM $SINK_PID; wait $SAMPLER1_PID; wait $SAMPLER2_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chan1Addr; rm $chan2Addr; rm $ackChanAddr' TERM
SINK="fairmq-ex-multiple-transports-sink"
SINK+=" --id sink1"
SINK+=" --verbosity veryhigh"
SINK+=" --session $SESSION"
SINK+=" --verbosity veryhigh --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --session $session"
SINK+=" --max-iterations 1"
SINK+=" --control static --color false"
SINK+=" --transport shmem"
SINK+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:5555"
SINK+=" name=data2,type=pull,method=connect,address=tcp://127.0.0.1:5556,transport=zeromq"
SINK+=" name=ack,type=pub,method=connect,address=tcp://127.0.0.1:5557,transport=zeromq"
SINK+=" --channel-config name=$chan1,type=pull,method=connect,address=ipc://$chan1Addr"
SINK+=" name=$chan2,type=pull,method=connect,address=ipc://$chan2Addr,transport=zeromq"
SINK+=" name=$ackChan,type=pub,method=connect,address=ipc://$ackChanAddr,transport=zeromq"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
SAMPLER1="fairmq-ex-multiple-transports-sampler1"
SAMPLER1+=" --id sampler1"
SAMPLER1+=" --session $SESSION"
SAMPLER1+=" --verbosity veryhigh"
SAMPLER1+=" --session $session"
SAMPLER1+=" --verbosity veryhigh --severity debug"
SAMPLER1+=" --shm-segment-size 100000000"
SAMPLER1+=" --max-iterations 1"
SAMPLER1+=" --control static --color false"
SAMPLER1+=" --transport shmem"
SAMPLER1+=" --channel-config name=data1,type=push,method=bind,address=tcp://127.0.0.1:5555"
SAMPLER1+=" name=ack,type=sub,method=bind,address=tcp://127.0.0.1:5557,transport=zeromq"
SAMPLER1+=" --channel-config name=$chan1,type=push,method=bind,address=ipc://$chan1Addr"
SAMPLER1+=" name=$ackChan,type=sub,method=bind,address=ipc://$ackChanAddr,transport=zeromq"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER1 &
SAMPLER1_PID=$!
SAMPLER2="fairmq-ex-multiple-transports-sampler2"
SAMPLER2+=" --id sampler2"
SAMPLER2+=" --session $SESSION"
SAMPLER2+=" --verbosity veryhigh"
SAMPLER2+=" --session $session"
SAMPLER2+=" --verbosity veryhigh --severity debug"
SAMPLER2+=" --shm-segment-size 100000000"
SAMPLER2+=" --max-iterations 1"
SAMPLER2+=" --control static --color false"
SAMPLER2+=" --transport zeromq"
SAMPLER2+=" --channel-config name=data2,type=push,method=bind,address=tcp://127.0.0.1:5556"
SAMPLER2+=" --channel-config name=$chan2,type=push,method=bind,address=ipc://$chan2Addr"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER2 &
SAMPLER2_PID=$!
wait $SAMPLER1_PID
wait $SAMPLER2_PID
wait $SINK_PID
rm $chan1Addr; rm $chan2Addr; rm $ackChanAddr

View File

@@ -24,7 +24,7 @@ namespace bpo = boost::program_options;
struct TFBuffer
{
FairMQParts parts;
fair::mq::Parts parts;
chrono::steady_clock::time_point start;
chrono::steady_clock::time_point end;
};
@@ -43,7 +43,7 @@ struct Receiver : fair::mq::Device
fMaxTimeframes = GetConfig()->GetValue<int>("max-timeframes");
}
bool HandleData(FairMQParts& parts, int /* index */)
bool HandleData(fair::mq::Parts& parts, int /* index */)
{
Header& h = *(static_cast<Header*>(parts.At(0)->GetData()));
// LOG(info) << "Received sub-time frame #" << h.id << " from Sender" << h.senderIndex;
@@ -107,7 +107,7 @@ void addCustomOptions(bpo::options_description& options)
("max-timeframes", bpo::value<int>()->default_value(0), "Maximum number of timeframes to receive (0 - unlimited)");
}
std::unique_ptr<fair::mq::Device> getDevice(FairMQProgOptions& /* config */)
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /* config */)
{
return std::make_unique<Receiver>();
}

View File

@@ -28,11 +28,11 @@ struct Sender : fair::mq::Device
void Run() override
{
FairMQChannel& dataInChannel = fChannels.at("sync").at(0);
fair::mq::Channel& dataInChannel = GetChannel("sync", 0);
while (!NewStatePending()) {
Header h;
FairMQMessagePtr id(NewMessage());
fair::mq::MessagePtr id(NewMessage());
if (dataInChannel.Receive(id) > 0) {
h.id = *(static_cast<uint16_t*>(id->GetData()));
h.senderIndex = fIndex;
@@ -40,7 +40,7 @@ struct Sender : fair::mq::Device
continue;
}
FairMQParts parts;
fair::mq::Parts parts;
parts.AddPart(NewSimpleMessage(h));
parts.AddPart(NewMessage(fSubtimeframeSize));
@@ -66,7 +66,7 @@ void addCustomOptions(bpo::options_description& options)
("subtimeframe-size", bpo::value<int>()->default_value(1000), "Subtimeframe size in bytes")
("num-receivers", bpo::value<int>()->required(), "Number of EPNs");
}
std::unique_ptr<fair::mq::Device> getDevice(FairMQProgOptions& /* config */)
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /* config */)
{
return std::make_unique<Sender>();
}

View File

@@ -19,7 +19,7 @@ struct Synchronizer : fair::mq::Device
{
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewSimpleMessage(fTimeframeId));
fair::mq::MessagePtr msg(NewSimpleMessage(fTimeframeId));
if (Send(msg, "sync") > 0) {
if (++fTimeframeId == UINT16_MAX - 1) {
@@ -37,7 +37,7 @@ struct Synchronizer : fair::mq::Device
};
void addCustomOptions(bpo::options_description& /* options */) {}
std::unique_ptr<fair::mq::Device> getDevice(FairMQProgOptions& /* config */)
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /* config */)
{
return std::make_unique<Synchronizer>();
}

View File

@@ -30,10 +30,10 @@ struct QCDispatcher : fair::mq::Device
});
}
bool HandleData(FairMQMessagePtr& msg, int)
bool HandleData(fair::mq::MessagePtr& msg, int)
{
if (fDoQC.load() == true) {
FairMQMessagePtr msgCopy(NewMessage());
fair::mq::MessagePtr msgCopy(NewMessage());
msgCopy->Copy(*msg);
if (Send(msg, "qc") < 0) {
return false;

View File

@@ -9,12 +9,12 @@
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
class QCTask : public FairMQDevice
class QCTask : public fair::mq::Device
{
public:
QCTask()
{
OnData("qc", [](FairMQMessagePtr& /*msg*/, int) {
OnData("qc", [](fair::mq::MessagePtr& /*msg*/, int) {
LOG(info) << "received data";
return false;
});

View File

@@ -16,7 +16,7 @@ struct Sampler : fair::mq::Device
{
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewMessage(1000));
fair::mq::MessagePtr msg(NewMessage(1000));
if (Send(msg, "data1") < 0) {
return false;

View File

@@ -14,7 +14,7 @@
struct Sink : fair::mq::Device
{
Sink() { OnData("data2", &Sink::HandleData); }
bool HandleData(FairMQMessagePtr& /*msg*/, int /*index*/) { return true; }
bool HandleData(fair::mq::MessagePtr& /*msg*/, int /*index*/) { return true; }
};
namespace bpo = boost::program_options;

View File

@@ -13,7 +13,7 @@
namespace bpo = boost::program_options;
class Builder : public FairMQDevice
class Builder : public fair::mq::Device
{
public:
Builder() = default;
@@ -24,7 +24,7 @@ class Builder : public FairMQDevice
OnData("rb", &Builder::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
bool HandleData(fair::mq::MessagePtr& msg, int /*index*/)
{
if (Send(msg, fOutputChannelName) < 0) {
return false;

View File

@@ -18,9 +18,9 @@ struct Processor : fair::mq::Device
OnData("bp", &Processor::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
bool HandleData(fair::mq::MessagePtr& msg, int /*index*/)
{
FairMQMessagePtr msg2(NewMessageFor("ps", 0, msg->GetSize()));
fair::mq::MessagePtr msg2(NewMessageFor("ps", 0, msg->GetSize()));
if (Send(msg2, "ps") < 0) {
return false;
}

View File

@@ -22,7 +22,7 @@ struct Readout : fair::mq::Device
fMsgSize = fConfig->GetProperty<int>("msg-size");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("rb",
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor("rb",
0,
10000000,
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
@@ -36,7 +36,7 @@ struct Readout : fair::mq::Device
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewMessageFor("rb", // channel
fair::mq::MessagePtr msg(NewMessageFor("rb", // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
@@ -71,7 +71,7 @@ struct Readout : fair::mq::Device
int fMsgSize = 10000;
uint64_t fMaxIterations = 0;
uint64_t fNumIterations = 0;
FairMQUnmanagedRegionPtr fRegion = nullptr;
fair::mq::UnmanagedRegionPtr fRegion = nullptr;
std::atomic<uint64_t> fNumUnackedMsgs = 0;
};

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -8,10 +8,15 @@
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
#include <memory>
using namespace std;
using namespace fair::mq;
namespace bpo = boost::program_options;
struct Receiver : fair::mq::Device
namespace {
struct Receiver : Device
{
void InitTask() override
{
@@ -21,15 +26,14 @@ struct Receiver : fair::mq::Device
void Run() override
{
FairMQChannel& dataInChannel = fChannels.at("sr").at(0);
Channel& dataInChannel = GetChannel("sr", 0);
while (!NewStatePending()) {
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
auto msg(dataInChannel.NewMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
break;
}
}
@@ -40,13 +44,14 @@ struct Receiver : fair::mq::Device
uint64_t fNumIterations = 0;
};
} // namespace
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)");
options.add_options()(
"max-iterations",
bpo::value<uint64_t>()->default_value(0),
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /*config*/)
{
return std::make_unique<Receiver>();
}
unique_ptr<Device> getDevice(ProgOptions& /*config*/) { return make_unique<Receiver>(); }

View File

@@ -21,7 +21,7 @@ struct Sender : fair::mq::Device
OnData(fInputChannelName, &Sender::HandleData);
}
bool HandleData(FairMQMessagePtr& msg, int /*index*/)
bool HandleData(fair::mq::MessagePtr& msg, int /*index*/)
{
if (Send(msg, "sr") < 0) {
return false;

View File

@@ -12,7 +12,10 @@ target_link_libraries(fairmq-ex-region-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-region-sink sink.cxx)
target_link_libraries(fairmq-ex-region-sink PRIVATE FairMQ)
add_custom_target(ExampleRegion DEPENDS fairmq-ex-region-sampler fairmq-ex-region-sink)
add_executable(fairmq-ex-region-keep-alive keep-alive.cxx)
target_link_libraries(fairmq-ex-region-keep-alive PRIVATE FairMQ)
add_custom_target(ExampleRegion DEPENDS fairmq-ex-region-sampler fairmq-ex-region-sink fairmq-ex-region-keep-alive)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
@@ -23,10 +26,10 @@ 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 [0-9*] acks")
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
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 [0-9*] acks")
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
# install

View File

@@ -0,0 +1,144 @@
/********************************************************************************
* Copyright (C) 2021 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 <fairmq/shmem/Common.h>
#include <fairmq/shmem/UnmanagedRegion.h>
#include <fairmq/shmem/Segment.h>
#include <fairmq/shmem/Monitor.h>
#include <fairmq/tools/Unique.h>
#include <fairlogger/Logger.h>
#include <boost/algorithm/string.hpp>
#include <boost/program_options.hpp>
#include <csignal>
#include <chrono>
#include <map>
#include <string>
#include <thread>
using namespace std;
using namespace boost::program_options;
namespace
{
volatile sig_atomic_t gStopping = 0;
}
void signalHandler(int /* signal */)
{
gStopping = 1;
}
struct ShmManager
{
ShmManager(uint64_t _shmId, const vector<string>& _segments, const vector<string>& _regions)
: shmId(fair::mq::shmem::makeShmIdStr(_shmId))
{
for (const auto& s : _segments) {
vector<string> segmentConf;
boost::algorithm::split(segmentConf, s, boost::algorithm::is_any_of(","));
if (segmentConf.size() != 2) {
LOG(error) << "incorrect format for --segments. Expecting pairs of <id>,<size>.";
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
throw runtime_error("incorrect format for --segments. Expecting pairs of <id>,<size>.");
}
uint16_t id = stoi(segmentConf.at(0));
uint64_t size = stoull(segmentConf.at(1));
auto ret = segments.emplace(id, fair::mq::shmem::Segment(shmId, id, size, fair::mq::shmem::rbTreeBestFit));
fair::mq::shmem::Segment& segment = ret.first->second;
LOG(info) << "Created segment " << id << " of size " << segment.GetSize() << ", starting at " << segment.GetData() << ". Locking...";
segment.Lock();
LOG(info) << "Done.";
LOG(info) << "Zeroing...";
segment.Zero();
LOG(info) << "Done.";
}
for (const auto& r : _regions) {
vector<string> regionConf;
boost::algorithm::split(regionConf, r, boost::algorithm::is_any_of(","));
if (regionConf.size() != 2) {
LOG(error) << "incorrect format for --regions. Expecting pairs of <id>,<size>.";
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
throw runtime_error("incorrect format for --regions. Expecting pairs of <id>,<size>.");
}
uint16_t id = stoi(regionConf.at(0));
uint64_t size = stoull(regionConf.at(1));
auto ret = regions.emplace(id, make_unique<fair::mq::shmem::UnmanagedRegion>(shmId, id, size));
fair::mq::shmem::UnmanagedRegion& region = *(ret.first->second);
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize() << ", starting at " << region.GetData() << ". Locking...";
region.Lock();
LOG(info) << "Done.";
LOG(info) << "Zeroing...";
region.Zero();
LOG(info) << "Done.";
}
}
void ResetContent()
{
fair::mq::shmem::Monitor::ResetContent(fair::mq::shmem::ShmId{shmId});
}
~ShmManager()
{
// clean all segments, regions and any other shmem objects belonging to this shmId
fair::mq::shmem::Monitor::Cleanup(fair::mq::shmem::ShmId{shmId});
}
std::string shmId;
map<uint16_t, fair::mq::shmem::Segment> segments;
map<uint16_t, unique_ptr<fair::mq::shmem::UnmanagedRegion>> regions;
};
int main(int argc, char** argv)
{
fair::Logger::SetConsoleColor(true);
signal(SIGINT, signalHandler);
signal(SIGTERM, signalHandler);
try {
uint64_t shmId = 0;
vector<string> segments;
vector<string> regions;
options_description desc("Options");
desc.add_options()
("shmid", value<uint64_t>(&shmId)->required(), "Shm id")
("segments", value<vector<string>>(&segments)->multitoken()->composing(), "Segments, as <id>,<size> <id>,<size> <id>,<size> ...")
("regions", value<vector<string>>(&regions)->multitoken()->composing(), "Regions, as <id>,<size> <id>,<size> <id>,<size> ...")
("help,h", "Print help");
variables_map vm;
store(parse_command_line(argc, argv, desc), vm);
if (vm.count("help")) {
LOG(info) << "ShmManager" << "\n" << desc;
return 0;
}
notify(vm);
ShmManager shmManager(shmId, segments, regions);
while (!gStopping) {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
}
LOG(info) << "stopping.";
} catch (exception& e) {
LOG(error) << "Unhandled Exception reached the top of main: " << e.what() << ", application will now exit";
return 2;
}
return 0;
}

View File

@@ -23,7 +23,7 @@ struct Sampler : fair::mq::Device
fLinger = fConfig->GetProperty<uint32_t>("region-linger");
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
GetChannel("data", 0).Transport()->SubscribeToRegionEvents([](fair::mq::RegionInfo info) {
LOG(info) << "Region event: " << info.event << ": "
<< (info.managed ? "managed" : "unmanaged")
<< ", id: " << info.id
@@ -32,27 +32,25 @@ struct Sampler : fair::mq::Device
<< ", flags: " << info.flags;
});
fRegion = FairMQUnmanagedRegionPtr(NewUnmanagedRegionFor("data", // region is created using the transport of this channel...
fair::mq::RegionConfig regionCfg;
regionCfg.linger = fLinger; // delay in ms before region destruction to collect outstanding events
regionCfg.lock = true; // mlock region after creation
regionCfg.zero = true; // zero region content after creation
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor("data", // region is created using the transport of this channel...
0, // ... and this sub-channel
10000000, // region size
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
std::lock_guard<std::mutex> lock(fMtx);
fNumUnackedMsgs -= blocks.size();
if (fMaxIterations > 0) {
LOG(info) << "Received " << blocks.size() << " acks";
}
},
"", // path, if a region is backed by a file
0, // flags that are passed for region creation
fair::mq::RegionConfig{true, true} // additional config: { call mlock on the region, zero the region memory }
));
fRegion->SetLinger(fLinger);
}, regionCfg));
}
bool ConditionalRun() override
{
FairMQMessagePtr msg(NewMessageFor("data", // channel
fair::mq::MessagePtr msg(NewMessageFor("data", // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
@@ -87,7 +85,7 @@ struct Sampler : fair::mq::Device
LOG(info) << "All acknowledgements received.";
}
}
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
}
private:
@@ -95,7 +93,7 @@ struct Sampler : fair::mq::Device
uint32_t fLinger = 100;
uint64_t fMaxIterations = 0;
uint64_t fNumIterations = 0;
FairMQUnmanagedRegionPtr fRegion = nullptr;
fair::mq::UnmanagedRegionPtr fRegion = nullptr;
std::mutex fMtx;
uint64_t fNumUnackedMsgs = 0;
};

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -8,30 +8,34 @@
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
#include <memory>
namespace bpo = boost::program_options;
using namespace std;
using namespace fair::mq;
struct Sink : fair::mq::Device
namespace {
struct Sink : Device
{
void InitTask() override
{
// Get the fMaxIterations value from the command line options (via fConfig)
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
fChannels.at("data").at(0).Transport()->SubscribeToRegionEvents([](FairMQRegionInfo info) {
GetChannel("data", 0).Transport()->SubscribeToRegionEvents([](RegionInfo info) {
LOG(info) << "Region event: " << info.event << ": "
<< (info.managed ? "managed" : "unmanaged")
<< ", id: " << info.id
<< ", ptr: " << info.ptr
<< ", size: " << info.size
<< ", flags: " << info.flags;
<< (info.managed ? "managed" : "unmanaged") << ", id: " << info.id
<< ", ptr: " << info.ptr << ", size: " << info.size
<< ", flags: " << info.flags;
});
}
void Run() override
{
FairMQChannel& dataInChannel = fChannels.at("data").at(0);
Channel& dataInChannel = GetChannel("data", 0);
while (!NewStatePending()) {
FairMQMessagePtr msg(dataInChannel.Transport()->CreateMessage());
auto msg(dataInChannel.Transport()->CreateMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
@@ -39,14 +43,15 @@ struct Sink : fair::mq::Device
// LOG(info) << "check: " << cptr[3];
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
break;
}
}
}
void ResetTask() override
{
fChannels.at("data").at(0).Transport()->UnsubscribeFromRegionEvents();
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
}
private:
@@ -54,14 +59,14 @@ struct Sink : fair::mq::Device
uint64_t fNumIterations = 0;
};
} // namespace
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)");
options.add_options()(
"max-iterations",
bpo::value<uint64_t>()->default_value(0),
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
}
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /*config*/)
{
return std::make_unique<Sink>();
}
unique_ptr<Device> getDevice(ProgOptions& /*config*/) { return make_unique<Sink>(); }

View File

@@ -9,22 +9,25 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
fi
msgSize="1000000"
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION' TERM
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chanAddr' TERM
SAMPLER="fairmq-ex-region-sampler"
SAMPLER+=" --id sampler1"
SAMPLER+=" --transport $transport"
SAMPLER+=" --severity debug"
SAMPLER+=" --session $SESSION"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --msg-size $msgSize"
SAMPLER+=" --region-linger 500"
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777"
SAMPLER+=" --channel-config name=$chan,type=push,method=bind,address=ipc://$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SAMPLER &
SAMPLER_PID=$!
@@ -32,14 +35,17 @@ SINK="fairmq-ex-region-sink"
SINK+=" --id sink1"
SINK+=" --transport $transport"
SINK+=" --severity debug"
SINK+=" --session $SESSION"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --verbosity veryhigh"
SINK+=" --control static --color false"
SINK+=" --max-iterations 1"
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777"
SINK+=" --channel-config name=$chan,type=pull,method=connect,address=ipc://$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
SINK_PID=$!
# wait for sampler and sink to finish
wait $SAMPLER_PID
wait $SINK_PID
rm $chanAddr

View File

@@ -24,10 +24,10 @@ 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: ")
set_tests_properties(Example.ReqRep.zeromq PROPERTIES TIMEOUT "30" 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: ")
set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received reply from server: ")
# install

View File

@@ -32,11 +32,11 @@ struct Client : fair::mq::Device
// its size,
// custom deletion function (called when transfer is done),
// and pointer to the object managing the data buffer
FairMQMessagePtr req(NewMessage(const_cast<char*>(text->c_str()), // data
fair::mq::MessagePtr req(NewMessage(const_cast<char*>(text->c_str()), // data
text->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); }, // deletion callback
text)); // object that manages the data
FairMQMessagePtr rep(NewMessage());
fair::mq::MessagePtr rep(NewMessage());
LOG(info) << "Sending \"" << fText << "\" to server.";

View File

@@ -26,7 +26,7 @@ struct Server : fair::mq::Device
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
}
bool HandleData(FairMQMessagePtr& req, int)
bool HandleData(fair::mq::MessagePtr& req, int)
{
LOG(info) << "Received request from client: \"" << std::string(static_cast<char*>(req->GetData()), req->GetSize()) << "\"";
@@ -34,7 +34,7 @@ struct Server : fair::mq::Device
LOG(info) << "Sending reply to client.";
FairMQMessagePtr rep(NewMessage(const_cast<char*>(text->c_str()), // data
fair::mq::MessagePtr rep(NewMessage(const_cast<char*>(text->c_str()), // data
text->length(), // size
[](void* /*data*/, void* object) { delete static_cast<std::string*>(object); }, // deletion callback
text)); // object that manages the data

View File

@@ -8,19 +8,22 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
SESSION="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $CLIENT_PID; kill -TERM $SERVER_PID; wait $CLIENT_PID; wait $SERVER_PID;' TERM
trap 'kill -TERM $CLIENT_PID; kill -TERM $SERVER_PID; wait $CLIENT_PID; wait $SERVER_PID; rm $chanAddr' TERM
CLIENT="fairmq-ex-req-rep-client"
CLIENT+=" --id client"
CLIENT+=" --transport $transport"
CLIENT+=" --verbosity veryhigh"
CLIENT+=" --session $SESSION"
CLIENT+=" --session $session"
CLIENT+=" --shm-segment-size 100000000"
CLIENT+=" --control static --color false"
CLIENT+=" --max-iterations 1"
CLIENT+=" --channel-config name=data,type=req,method=connect,rateLogging=0,address=tcp://127.0.0.1:5005"
CLIENT+=" --channel-config name=$chan,type=req,method=connect,rateLogging=0,address=ipc://$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$CLIENT &
CLIENT_PID=$!
@@ -28,13 +31,16 @@ SERVER="fairmq-ex-req-rep-server"
SERVER+=" --id server"
SERVER+=" --transport $transport"
SERVER+=" --verbosity veryhigh"
SERVER+=" --session $SESSION"
SERVER+=" --session $session"
SERVER+=" --shm-segment-size 100000000"
SERVER+=" --control static --color false"
SERVER+=" --max-iterations 1"
SERVER+=" --channel-config name=data,type=rep,method=bind,rateLogging=0,address=tcp://127.0.0.1:5005"
SERVER+=" --channel-config name=$chan,type=rep,method=bind,rateLogging=0,address=ipc://$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SERVER &
SERVER_PID=$!
# wait for everything to finish
wait $CLIENT_PID
wait $SERVER_PID
rm $chanAddr

View File

@@ -7,6 +7,11 @@
################################################################################
if(BUILD_FAIRMQ OR BUILD_SDK)
if(BUILD_TIDY_TOOL)
include(FairMQTidy)
endif()
###########
# Version #
###########
@@ -25,7 +30,9 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
set(TOOLS_PUBLIC_HEADER_FILES
tools/CppSTL.h
tools/Exceptions.h
tools/InstanceLimit.h
tools/IO.h
tools/Network.h
tools/Process.h
tools/RateLimit.h
@@ -33,10 +40,12 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
tools/Strings.h
tools/Unique.h
tools/Version.h
Error.h
Tools.h
)
set(TOOLS_SOURCE_FILES
Error.cxx
tools/Network.cxx
tools/Process.cxx
tools/Semaphore.cxx
@@ -65,6 +74,9 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
@@ -120,6 +132,9 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
@@ -159,6 +174,7 @@ if(BUILD_FAIRMQ)
MemoryResourceTools.h
MemoryResources.h
Message.h
Parts.h
Plugin.h
PluginManager.h
PluginServices.h
@@ -167,6 +183,7 @@ if(BUILD_FAIRMQ)
ProgOptionsFwd.h
Properties.h
PropertyOutput.h
Socket.h
SuboptParser.h
TransportFactory.h
Transports.h
@@ -175,6 +192,9 @@ if(BUILD_FAIRMQ)
runDevice.h
runFairMQDevice.h
shmem/Monitor.h
shmem/Common.h
shmem/UnmanagedRegion.h
shmem/Segment.h
)
set(FAIRMQ_PRIVATE_HEADER_FILES
@@ -189,12 +209,11 @@ if(BUILD_FAIRMQ)
plugins/control/Control.h
shmem/Message.h
shmem/Poller.h
shmem/UnmanagedRegion.h
shmem/UnmanagedRegionImpl.h
shmem/Socket.h
shmem/TransportFactory.h
shmem/Common.h
shmem/Manager.h
shmem/Region.h
zeromq/Common.h
zeromq/Context.h
zeromq/Message.h
zeromq/Poller.h
@@ -217,24 +236,21 @@ if(BUILD_FAIRMQ)
# libFairMQ source files #
##########################
set(FAIRMQ_SOURCE_FILES
Channel.cxx
Device.cxx
DeviceRunner.cxx
FairMQChannel.cxx
FairMQDevice.cxx
FairMQLogger.cxx
FairMQMessage.cxx
FairMQPoller.cxx
FairMQSocket.cxx
FairMQTransportFactory.cxx
JSONParser.cxx
MemoryResources.cxx
Plugin.cxx
PluginManager.cxx
PluginServices.cxx
ProgOptions.cxx
JSONParser.cxx
Properties.cxx
SuboptParser.cxx
TransportFactory.cxx
plugins/config/Config.cxx
plugins/control/Control.cxx
MemoryResources.cxx
shmem/Common.cxx
shmem/Manager.cxx
shmem/Monitor.cxx
)
@@ -327,6 +343,9 @@ if(BUILD_FAIRMQ)
VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
###############
@@ -334,23 +353,41 @@ if(BUILD_FAIRMQ)
###############
add_executable(fairmq-bsampler devices/runBenchmarkSampler.cxx)
target_link_libraries(fairmq-bsampler FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-bsampler)
endif()
add_executable(fairmq-merger devices/runMerger.cxx)
target_link_libraries(fairmq-merger FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-merger)
endif()
add_executable(fairmq-multiplier devices/runMultiplier.cxx)
target_link_libraries(fairmq-multiplier FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-multiplier)
endif()
add_executable(fairmq-proxy devices/runProxy.cxx)
target_link_libraries(fairmq-proxy FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-proxy)
endif()
add_executable(fairmq-sink devices/runSink.cxx)
target_link_libraries(fairmq-sink FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-sink)
endif()
add_executable(fairmq-splitter devices/runSplitter.cxx)
target_link_libraries(fairmq-splitter FairMQ)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-splitter)
endif()
add_executable(fairmq-shmmonitor shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
add_executable(fairmq-shmmonitor shmem/Common.cxx shmem/Monitor.cxx shmem/Monitor.h shmem/runMonitor.cxx)
target_compile_features(fairmq-shmmonitor PUBLIC cxx_std_17)
target_compile_definitions(fairmq-shmmonitor PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
if(FAIRMQ_DEBUG_MODE)
@@ -370,12 +407,18 @@ if(BUILD_FAIRMQ)
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
)
target_compile_definitions(fairmq-shmmonitor PUBLIC FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM})
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-shmmonitor)
endif()
add_executable(fairmq-uuid-gen tools/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen PUBLIC
Boost::program_options
Tools
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-uuid-gen)
endif()
###########

View File

@@ -1,30 +1,27 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 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 "FairMQChannel.h"
#include <fairmq/tools/Strings.h>
#include <fairmq/Properties.h>
#include <boost/algorithm/string.hpp> // join/split
#include <cstddef> // size_t
#include <fairlogger/Logger.h>
#include <boost/algorithm/string.hpp> // join/split
#include <cstddef> // size_t
#include <fairmq/Channel.h>
#include <fairmq/Properties.h>
#include <fairmq/Tools.h>
#include <random>
#include <regex>
#include <set>
#include <random>
namespace fair::mq {
using namespace std;
using namespace fair::mq;
template<typename T>
T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T& ifNotFound)
T GetPropertyOrDefault(const Properties& m, const string& k, const T& ifNotFound)
{
if (m.count(k)) {
return boost::any_cast<T>(m.at(k));
@@ -32,39 +29,41 @@ T GetPropertyOrDefault(const fair::mq::Properties& m, const string& k, const T&
return ifNotFound;
}
constexpr fair::mq::Transport FairMQChannel::DefaultTransportType;
constexpr const char* FairMQChannel::DefaultTransportName;
constexpr const char* FairMQChannel::DefaultName;
constexpr const char* FairMQChannel::DefaultType;
constexpr const char* FairMQChannel::DefaultMethod;
constexpr const char* FairMQChannel::DefaultAddress;
constexpr int FairMQChannel::DefaultSndBufSize;
constexpr int FairMQChannel::DefaultRcvBufSize;
constexpr int FairMQChannel::DefaultSndKernelSize;
constexpr int FairMQChannel::DefaultRcvKernelSize;
constexpr int FairMQChannel::DefaultLinger;
constexpr int FairMQChannel::DefaultRateLogging;
constexpr int FairMQChannel::DefaultPortRangeMin;
constexpr int FairMQChannel::DefaultPortRangeMax;
constexpr bool FairMQChannel::DefaultAutoBind;
constexpr Transport Channel::DefaultTransportType;
constexpr const char* Channel::DefaultTransportName;
constexpr const char* Channel::DefaultName;
constexpr const char* Channel::DefaultType;
constexpr const char* Channel::DefaultMethod;
constexpr const char* Channel::DefaultAddress;
constexpr int Channel::DefaultSndBufSize;
constexpr int Channel::DefaultRcvBufSize;
constexpr int Channel::DefaultSndKernelSize;
constexpr int Channel::DefaultRcvKernelSize;
constexpr int Channel::DefaultSndTimeoutMs;
constexpr int Channel::DefaultRcvTimeoutMs;
constexpr int Channel::DefaultLinger;
constexpr int Channel::DefaultRateLogging;
constexpr int Channel::DefaultPortRangeMin;
constexpr int Channel::DefaultPortRangeMax;
constexpr bool Channel::DefaultAutoBind;
FairMQChannel::FairMQChannel()
: FairMQChannel(DefaultName, DefaultType, DefaultMethod, DefaultAddress, nullptr)
Channel::Channel()
: Channel(DefaultName, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{}
FairMQChannel::FairMQChannel(const string& name)
: FairMQChannel(name, DefaultType, DefaultMethod, DefaultAddress, nullptr)
Channel::Channel(const string& name)
: Channel(name, DefaultType, DefaultMethod, DefaultAddress, nullptr)
{}
FairMQChannel::FairMQChannel(const string& type, const string& method, const string& address)
: FairMQChannel(DefaultName, type, method, address, nullptr)
Channel::Channel(const string& type, const string& method, const string& address)
: Channel(DefaultName, type, method, address, nullptr)
{}
FairMQChannel::FairMQChannel(const string& name, const string& type, shared_ptr<FairMQTransportFactory> factory)
: FairMQChannel(name, type, DefaultMethod, DefaultAddress, factory)
Channel::Channel(const string& name, const string& type, shared_ptr<TransportFactory> factory)
: Channel(name, type, DefaultMethod, DefaultAddress, factory)
{}
FairMQChannel::FairMQChannel(string name, string type, string method, string address, shared_ptr<FairMQTransportFactory> factory)
Channel::Channel(string name, string type, string method, string address, shared_ptr<TransportFactory> factory)
: fTransportFactory(factory)
, fTransportType(factory ? factory->GetType() : DefaultTransportType)
, fSocket(factory ? factory->CreateSocket(type, name) : nullptr)
@@ -76,6 +75,8 @@ FairMQChannel::FairMQChannel(string name, string type, string method, string add
, fRcvBufSize(DefaultRcvBufSize)
, fSndKernelSize(DefaultSndKernelSize)
, fRcvKernelSize(DefaultRcvKernelSize)
, fSndTimeoutMs(DefaultSndTimeoutMs)
, fRcvTimeoutMs(DefaultRcvTimeoutMs)
, fLinger(DefaultLinger)
, fRateLogging(DefaultRateLogging)
, fPortRangeMin(DefaultPortRangeMin)
@@ -87,8 +88,8 @@ FairMQChannel::FairMQChannel(string name, string type, string method, string add
// LOG(warn) << "Constructing channel '" << fName << "'";
}
FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Properties& properties)
: FairMQChannel(tools::ToString(name, "[", index, "]"), "unspecified", "unspecified", "unspecified", nullptr)
Channel::Channel(const string& name, int index, const Properties& properties)
: Channel(tools::ToString(name, "[", index, "]"), "unspecified", "unspecified", "unspecified", nullptr)
{
string prefix(tools::ToString("chans.", name, ".", index, "."));
@@ -100,6 +101,8 @@ FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Prop
fRcvBufSize = GetPropertyOrDefault(properties, string(prefix + "rcvBufSize"), DefaultRcvBufSize);
fSndKernelSize = GetPropertyOrDefault(properties, string(prefix + "sndKernelSize"), DefaultSndKernelSize);
fRcvKernelSize = GetPropertyOrDefault(properties, string(prefix + "rcvKernelSize"), DefaultRcvKernelSize);
fSndTimeoutMs = GetPropertyOrDefault(properties, string(prefix + "sndTimeoutMs"), DefaultSndTimeoutMs);
fRcvTimeoutMs = GetPropertyOrDefault(properties, string(prefix + "rcvTimeoutMs"), DefaultRcvTimeoutMs);
fLinger = GetPropertyOrDefault(properties, string(prefix + "linger"), DefaultLinger);
fRateLogging = GetPropertyOrDefault(properties, string(prefix + "rateLogging"), DefaultRateLogging);
fPortRangeMin = GetPropertyOrDefault(properties, string(prefix + "portRangeMin"), DefaultPortRangeMin);
@@ -107,11 +110,11 @@ FairMQChannel::FairMQChannel(const string& name, int index, const fair::mq::Prop
fAutoBind = GetPropertyOrDefault(properties, string(prefix + "autoBind"), DefaultAutoBind);
}
FairMQChannel::FairMQChannel(const FairMQChannel& chan)
: FairMQChannel(chan, chan.fName)
Channel::Channel(const Channel& chan)
: Channel(chan, chan.fName)
{}
FairMQChannel::FairMQChannel(const FairMQChannel& chan, string newName)
Channel::Channel(const Channel& chan, string newName)
: fTransportFactory(nullptr)
, fTransportType(chan.fTransportType)
, fSocket(nullptr)
@@ -123,6 +126,8 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan, string newName)
, fRcvBufSize(chan.fRcvBufSize)
, fSndKernelSize(chan.fSndKernelSize)
, fRcvKernelSize(chan.fRcvKernelSize)
, fSndTimeoutMs(chan.fSndTimeoutMs)
, fRcvTimeoutMs(chan.fRcvTimeoutMs)
, fLinger(chan.fLinger)
, fRateLogging(chan.fRateLogging)
, fPortRangeMin(chan.fPortRangeMin)
@@ -132,7 +137,7 @@ FairMQChannel::FairMQChannel(const FairMQChannel& chan, string newName)
, fMultipart(chan.fMultipart)
{}
FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
Channel& Channel::operator=(const Channel& chan)
{
if (this == &chan) {
return *this;
@@ -149,6 +154,8 @@ FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
fRcvBufSize = chan.fRcvBufSize;
fSndKernelSize = chan.fSndKernelSize;
fRcvKernelSize = chan.fRcvKernelSize;
fSndTimeoutMs = chan.fSndTimeoutMs;
fRcvTimeoutMs = chan.fRcvTimeoutMs;
fLinger = chan.fLinger;
fRateLogging = chan.fRateLogging;
fPortRangeMin = chan.fPortRangeMin;
@@ -160,7 +167,7 @@ FairMQChannel& FairMQChannel::operator=(const FairMQChannel& chan)
return *this;
}
bool FairMQChannel::Validate()
bool Channel::Validate()
try {
stringstream ss;
ss << "Validating channel '" << fName << "'... ";
@@ -305,11 +312,11 @@ try {
LOG(debug) << ss.str();
return true;
} catch (exception& e) {
LOG(error) << "Exception caught in FairMQChannel::ValidateChannel: " << e.what();
LOG(error) << "Exception caught in Channel::ValidateChannel: " << e.what();
throw ChannelConfigurationError(tools::ToString(e.what()));
}
void FairMQChannel::Init()
void Channel::Init()
{
fSocket = fTransportFactory->CreateSocket(fType, fName);
@@ -329,12 +336,12 @@ void FairMQChannel::Init()
}
}
bool FairMQChannel::ConnectEndpoint(const string& endpoint)
bool Channel::ConnectEndpoint(const string& endpoint)
{
return fSocket->Connect(endpoint);
}
bool FairMQChannel::BindEndpoint(string& endpoint)
bool Channel::BindEndpoint(string& endpoint)
{
// try to bind to the configured port. If it fails, try random one (if AutoBind is on).
if (fSocket->Bind(endpoint)) {
@@ -374,5 +381,6 @@ bool FairMQChannel::BindEndpoint(string& endpoint)
return false;
}
}
}
} // namespace fair::mq

View File

@@ -9,12 +9,473 @@
#ifndef FAIR_MQ_CHANNEL_H
#define FAIR_MQ_CHANNEL_H
#include <FairMQChannel.h>
#include <fairmq/Message.h>
#include <fairmq/Parts.h>
#include <fairmq/Properties.h>
#include <fairmq/Socket.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/UnmanagedRegion.h>
#include <cstdint> // int64_t
#include <memory> // unique_ptr, shared_ptr
#include <stdexcept>
#include <string>
#include <utility> // std::move
#include <vector>
namespace fair::mq {
using Channel = FairMQChannel;
/**
* @class Channel Channel.h <fairmq/Channel.h>
* @brief Wrapper class for Socket and related methods
*
* The class is not thread-safe.
*/
class Channel
{
friend class Device;
} // namespace fair::mq
public:
/// Default constructor
Channel();
/// Constructor
/// @param name Channel name
Channel(const std::string& name);
/// Constructor
/// @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")
Channel(const std::string& type, const std::string& method, const std::string& address);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @param factory TransportFactory
Channel(const std::string& name, const std::string& type, std::shared_ptr<TransportFactory> 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
Channel(std::string name, std::string type, std::string method, std::string address, std::shared_ptr<TransportFactory> factory);
Channel(const std::string& name, int index, const Properties& properties);
/// Copy Constructor
Channel(const Channel&);
/// Copy Constructor (with new name)
Channel(const Channel&, std::string name);
/// Move constructor
Channel(Channel&&) = default;
/// Assignment operator
Channel& operator=(const Channel&);
/// Move assignment operator
Channel& operator=(Channel&&) = default;
/// Destructor
~Channel() = default;
// { LOG(warn) << "Destroying channel '" << fName << "'"; }
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
Socket& GetSocket() const
{
assert(fSocket); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
return *fSocket;
}
bool Bind(const std::string& address)
{
fMethod = "bind";
fAddress = address;
return fSocket->Bind(address);
}
bool Connect(const std::string& address)
{
fMethod = "connect";
fAddress = address;
return fSocket->Connect(address);
}
/// Get channel name
/// @return Returns full channel name (e.g. "data[0]")
std::string GetName() const { return fName; }
/// Get channel prefix
/// @return Returns channel prefix (e.g. "data" in "data[0]")
std::string GetPrefix() const
{
std::string prefix = fName;
prefix = prefix.erase(fName.rfind('['));
return prefix;
}
/// Get channel index
/// @return Returns channel index (e.g. 0 in "data[0]")
std::string GetIndex() const
{
std::string indexStr = fName;
indexStr.erase(indexStr.rfind(']'));
indexStr.erase(0, indexStr.rfind('[') + 1);
return indexStr;
}
/// Get socket type
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
std::string GetType() const { return fType; }
/// Get socket method
/// @return Returns socket method (bind/connect)
std::string GetMethod() const { return fMethod; }
/// Get socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
std::string GetAddress() const { return fAddress; }
/// Get channel transport name ("default", "zeromq" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
std::string GetTransportName() const { return TransportName(fTransportType); }
/// Get channel transport type
/// @return Returns channel transport type
mq::Transport GetTransportType() const { return fTransportType; }
/// Get socket send buffer size (in number of messages)
/// @return Returns socket send buffer size (in number of messages)
int GetSndBufSize() const { return fSndBufSize; }
/// Get socket receive buffer size (in number of messages)
/// @return Returns socket receive buffer size (in number of messages)
int GetRcvBufSize() const { return fRcvBufSize; }
/// Get socket kernel transmit send buffer size (in bytes)
/// @return Returns socket kernel transmit send buffer size (in bytes)
int GetSndKernelSize() const { return fSndKernelSize; }
/// Get socket kernel transmit receive buffer size (in bytes)
/// @return Returns socket kernel transmit receive buffer size (in bytes)
int GetRcvKernelSize() const { return fRcvKernelSize; }
/// Get socket default send timeout (in ms)
/// @return Returns socket default send timeout (in ms)
int GetSndTimeout() const { return fSndTimeoutMs; }
/// Get socket default receive timeout (in ms)
/// @return Returns socket default receive timeout (in ms)
int GetRcvTimeout() const { return fRcvTimeoutMs; }
/// Get linger duration (in milliseconds)
/// @return Returns linger duration (in milliseconds)
int GetLinger() const { return fLinger; }
/// Get socket rate logging interval (in seconds)
/// @return Returns socket rate logging interval (in seconds)
int GetRateLogging() const { return fRateLogging; }
/// Get start of the port range for automatic binding
/// @return start of the port range
int GetPortRangeMin() const { return fPortRangeMin; }
/// Get end of the port range for automatic binding
/// @return end of the port range
int GetPortRangeMax() const { return fPortRangeMax; }
/// Set automatic binding (pick random port if bind fails)
/// @return true/false, true if automatic binding is enabled
bool GetAutoBind() const { return fAutoBind; }
/// @par Thread Safety
/// * @e Distinct @e objects: Safe.@n
/// * @e Shared @e objects: Unsafe.
auto GetNumberOfConnectedPeers() const
{
return fSocket ? fSocket->GetNumberOfConnectedPeers() : 0;
}
/// Set channel name
/// @param name Arbitrary channel name
void UpdateName(const std::string& name) { fName = name; Invalidate(); }
/// Set socket type
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
void UpdateType(const std::string& type) { fType = type; Invalidate(); }
/// Set socket method
/// @param method Socket method (bind/connect)
void UpdateMethod(const std::string& method) { fMethod = method; Invalidate(); }
/// Set socket address
/// @param Socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
void UpdateAddress(const std::string& address) { fAddress = address; Invalidate(); }
/// Set channel transport
/// @param transport transport string ("default", "zeromq" or "shmem")
void UpdateTransport(const std::string& transport) { fTransportType = TransportType(transport); Invalidate(); }
/// Set socket send buffer size
/// @param sndBufSize Socket send buffer size (in number of messages)
void UpdateSndBufSize(int sndBufSize) { fSndBufSize = sndBufSize; Invalidate(); }
/// Set socket receive buffer size
/// @param rcvBufSize Socket receive buffer size (in number of messages)
void UpdateRcvBufSize(int rcvBufSize) { fRcvBufSize = rcvBufSize; Invalidate(); }
/// Set socket kernel transmit send buffer size (in bytes)
/// @param sndKernelSize Socket send buffer size (in bytes)
void UpdateSndKernelSize(int sndKernelSize) { fSndKernelSize = sndKernelSize; Invalidate(); }
/// Set socket kernel transmit receive buffer size (in bytes)
/// @param rcvKernelSize Socket receive buffer size (in bytes)
void UpdateRcvKernelSize(int rcvKernelSize) { fRcvKernelSize = rcvKernelSize; Invalidate(); }
/// Set socket default send timeout (in ms)
/// @param sndTimeoutMs Socket default send timeout (in ms)
void UpdateSndTimeout(int sndTimeoutMs) { fSndTimeoutMs = sndTimeoutMs; Invalidate(); }
/// Set socket default receive timeout (in ms)
/// @param rcvTimeoutMs Socket default receive timeout (in ms)
void UpdateRcvTimeout(int rcvTimeoutMs) { fRcvTimeoutMs = rcvTimeoutMs; Invalidate(); }
/// Set linger duration (in milliseconds)
/// @param duration linger duration (in milliseconds)
void UpdateLinger(int duration) { fLinger = duration; Invalidate(); }
/// Set socket rate logging interval (in seconds)
/// @param rateLogging Socket rate logging interval (in seconds)
void UpdateRateLogging(int rateLogging) { fRateLogging = rateLogging; Invalidate(); }
/// Set start of the port range for automatic binding
/// @param minPort start of the port range
void UpdatePortRangeMin(int minPort) { fPortRangeMin = minPort; Invalidate(); }
/// Set end of the port range for automatic binding
/// @param maxPort end of the port range
void UpdatePortRangeMax(int maxPort) { fPortRangeMax = maxPort; Invalidate(); }
/// Set automatic binding (pick random port if bind fails)
/// @param autobind true/false, true to enable automatic binding
void UpdateAutoBind(bool autobind) { fAutoBind = autobind; Invalidate(); }
/// 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.
bool IsValid() const { return fValid; }
/// 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);
/// invalidates the channel (requires validation to be used again).
void Invalidate() { fValid = false; }
/// Send message(s) to the socket queue.
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param sndTimeoutMs 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).
/// If not provided, default timeout will be taken.
/// @return Number of bytes that have been queued,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M, typename... Timeout>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Send(M& m, Timeout&&... sndTimeoutMs)
{
static_assert(sizeof...(sndTimeoutMs) <= 1, "Send called with too many arguments");
CheckSendCompatibility(m);
int t = fSndTimeoutMs;
if constexpr (sizeof...(sndTimeoutMs) == 1) {
t = {sndTimeoutMs...};
}
return fSocket->Send(m, t);
}
/// Receive message(s) from the socket queue.
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param rcvTimeoutMs 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).
/// If not provided, default timeout will be taken.
/// @return Number of bytes that have been received,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M, typename... Timeout>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Receive(M& m, Timeout&&... rcvTimeoutMs)
{
static_assert(sizeof...(rcvTimeoutMs) <= 1, "Receive called with too many arguments");
CheckReceiveCompatibility(m);
int t = fRcvTimeoutMs;
if constexpr (sizeof...(rcvTimeoutMs) == 1) {
t = {rcvTimeoutMs...};
}
return fSocket->Receive(m, t);
}
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() -> TransportFactory* { return fTransportFactory.get(); };
template<typename... Args>
MessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
template<typename T>
MessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
template<typename T>
MessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
static constexpr mq::Transport DefaultTransportType = mq::Transport::DEFAULT;
static constexpr const char* DefaultTransportName = "default";
static constexpr const char* DefaultName = "";
static constexpr const char* DefaultType = "unspecified";
static constexpr const char* DefaultMethod = "unspecified";
static constexpr const char* DefaultAddress = "unspecified";
static constexpr int DefaultSndBufSize = 1000;
static constexpr int DefaultRcvBufSize = 1000;
static constexpr int DefaultSndKernelSize = 0;
static constexpr int DefaultRcvKernelSize = 0;
static constexpr int DefaultSndTimeoutMs = -1;
static constexpr int DefaultRcvTimeoutMs = -1;
static constexpr int DefaultLinger = 500;
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
static constexpr bool DefaultAutoBind = true;
private:
std::shared_ptr<TransportFactory> fTransportFactory;
mq::Transport fTransportType;
std::unique_ptr<Socket> fSocket;
std::string fName;
std::string fType;
std::string fMethod;
std::string fAddress;
int fSndBufSize;
int fRcvBufSize;
int fSndKernelSize;
int fRcvKernelSize;
int fSndTimeoutMs;
int fRcvTimeoutMs;
int fLinger;
int fRateLogging;
int fPortRangeMin;
int fPortRangeMax;
bool fAutoBind;
bool fValid;
bool fMultipart;
void CheckSendCompatibility(MessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
MessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<Message*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void CheckSendCompatibility(Parts& parts) { CheckSendCompatibility(parts.fParts); }
void CheckSendCompatibility(std::vector<MessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
MessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<Message*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
}
void CheckReceiveCompatibility(MessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
void CheckReceiveCompatibility(Parts& parts) { CheckReceiveCompatibility(parts.fParts); }
void CheckReceiveCompatibility(std::vector<MessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void InitTransport(std::shared_ptr<TransportFactory> factory)
{
fTransportFactory = factory;
fTransportType = factory->GetType();
}
};
} // namespace fair::mq
// using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
using FairMQChannel = fair::mq::Channel;
#endif // FAIR_MQ_CHANNEL_H

View File

@@ -1,77 +1,79 @@
/********************************************************************************
* Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include <FairMQDevice.h>
#include <fairmq/tools/RateLimit.h>
#include <fairmq/tools/Network.h>
#include <boost/algorithm/string.hpp> // join/split
#include <list>
#include <algorithm> // std::max
#include <boost/algorithm/string.hpp> // join/split
#include <chrono>
#include <fairmq/Device.h>
#include <fairmq/Tools.h>
#include <future>
#include <iomanip>
#include <list>
#include <mutex>
#include <thread>
#include <iomanip>
#include <future>
#include <algorithm> // std::max
namespace fair::mq {
using namespace std;
using namespace fair::mq;
constexpr const char* FairMQDevice::DefaultId;
constexpr int FairMQDevice::DefaultIOThreads;
constexpr const char* FairMQDevice::DefaultTransportName;
constexpr fair::mq::Transport FairMQDevice::DefaultTransportType;
constexpr const char* FairMQDevice::DefaultNetworkInterface;
constexpr int FairMQDevice::DefaultInitTimeout;
constexpr uint64_t FairMQDevice::DefaultMaxRunTime;
constexpr float FairMQDevice::DefaultRate;
constexpr const char* FairMQDevice::DefaultSession;
constexpr const char* Device::DefaultId;
constexpr int Device::DefaultIOThreads;
constexpr const char* Device::DefaultTransportName;
constexpr mq::Transport Device::DefaultTransportType;
constexpr const char* Device::DefaultNetworkInterface;
constexpr int Device::DefaultInitTimeout;
constexpr uint64_t Device::DefaultMaxRunTime;
constexpr float Device::DefaultRate;
constexpr const char* Device::DefaultSession;
struct StateSubscription
{
fair::mq::StateMachine& fStateMachine;
fair::mq::StateQueue& fStateQueue;
StateMachine& fStateMachine;
StateQueue& fStateQueue;
string fId;
explicit StateSubscription(string id, fair::mq::StateMachine& stateMachine, fair::mq::StateQueue& stateQueue)
explicit StateSubscription(string id, StateMachine& stateMachine, StateQueue& stateQueue)
: fStateMachine(stateMachine)
, fStateQueue(stateQueue)
, fId(std::move(id))
{
fStateMachine.SubscribeToStateChange(fId, [&](fair::mq::State state) {
fStateMachine.SubscribeToStateChange(fId, [&](State state) {
fStateQueue.Push(state);
});
}
StateSubscription(const StateSubscription&) = delete;
StateSubscription(StateSubscription&&) = delete;
StateSubscription& operator=(const StateSubscription&) = delete;
StateSubscription& operator=(StateSubscription&&) = delete;
~StateSubscription() {
fStateMachine.UnsubscribeFromStateChange(fId);
}
};
FairMQDevice::FairMQDevice()
: FairMQDevice(nullptr, {0, 0, 0})
Device::Device()
: Device(nullptr, {0, 0, 0})
{}
FairMQDevice::FairMQDevice(ProgOptions& config)
: FairMQDevice(&config, {0, 0, 0})
Device::Device(ProgOptions& config)
: Device(&config, {0, 0, 0})
{}
FairMQDevice::FairMQDevice(const tools::Version version)
: FairMQDevice(nullptr, version)
Device::Device(tools::Version version)
: Device(nullptr, version)
{}
FairMQDevice::FairMQDevice(ProgOptions& config, const tools::Version version)
: FairMQDevice(&config, version)
Device::Device(ProgOptions& config, tools::Version version)
: Device(&config, version)
{}
FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
Device::Device(ProgOptions* config, tools::Version version)
: fTransportFactory(nullptr)
, fInternalConfig(config ? nullptr : make_unique<ProgOptions>())
, fConfig(config ? config : fInternalConfig.get())
@@ -97,34 +99,34 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
}
});
fStateMachine.HandleStates([&](fair::mq::State state) {
fStateMachine.HandleStates([&](State state) {
LOG(trace) << "device notified on new state: " << state;
fStateQueue.Push(state);
switch (state) {
case fair::mq::State::InitializingDevice:
case State::InitializingDevice:
InitWrapper();
break;
case fair::mq::State::Binding:
case State::Binding:
BindWrapper();
break;
case fair::mq::State::Connecting:
case State::Connecting:
ConnectWrapper();
break;
case fair::mq::State::InitializingTask:
case State::InitializingTask:
InitTaskWrapper();
break;
case fair::mq::State::Running:
case State::Running:
RunWrapper();
break;
case fair::mq::State::ResettingTask:
case State::ResettingTask:
ResetTaskWrapper();
break;
case fair::mq::State::ResettingDevice:
case State::ResettingDevice:
ResetWrapper();
break;
case fair::mq::State::Exiting:
case State::Exiting:
Exit();
break;
default:
@@ -136,7 +138,7 @@ FairMQDevice::FairMQDevice(ProgOptions* config, const tools::Version version)
fStateMachine.Start();
}
void FairMQDevice::TransitionTo(const fair::mq::State s)
void Device::TransitionTo(State s)
{
{
lock_guard<mutex> lock(fTransitionMtx);
@@ -147,7 +149,7 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
fTransitioning = true;
}
using fair::mq::State;
using mq::State;
StateQueue sq;
StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq);
@@ -203,7 +205,7 @@ void FairMQDevice::TransitionTo(const fair::mq::State s)
}
}
void FairMQDevice::InitWrapper()
void Device::InitWrapper()
{
// run initialization once CompleteInit transition is requested
fStateMachine.WaitForPendingState();
@@ -217,7 +219,7 @@ void FairMQDevice::InitWrapper()
fInitializationTimeoutInS = fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout);
try {
fDefaultTransportType = fair::mq::TransportTypes.at(fConfig->GetProperty<string>("transport", DefaultTransportName));
fDefaultTransportType = TransportTypes.at(fConfig->GetProperty<string>("transport", DefaultTransportName));
} catch (const exception& e) {
LOG(error) << "exception: " << e.what();
LOG(error) << "invalid transport type provided: " << fConfig->GetProperty<string>("transport", "not provided");
@@ -231,7 +233,7 @@ void FairMQDevice::InitWrapper()
}
}
LOG(debug) << "Setting '" << fair::mq::TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
LOG(debug) << "Setting '" << TransportNames.at(fDefaultTransportType) << "' as default transport for the device";
fTransportFactory = AddTransport(fDefaultTransportType);
string networkInterface = fConfig->GetProperty<string>("network-interface", DefaultNetworkInterface);
@@ -241,7 +243,7 @@ void FairMQDevice::InitWrapper()
int subChannelIndex = 0;
for (auto& subChannel : channel.second) {
// set channel transport
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << fair::mq::TransportNames.at(subChannel.fTransportType);
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << TransportNames.at(subChannel.fTransportType);
subChannel.InitTransport(AddTransport(subChannel.fTransportType));
if (subChannel.fMethod == "bind") {
@@ -278,7 +280,7 @@ void FairMQDevice::InitWrapper()
// ChangeState(Transition::Auto);
}
void FairMQDevice::BindWrapper()
void Device::BindWrapper()
{
// Bind channels. Here one run is enough, because bind settings should be available locally
// If necessary this could be handled in the same way as the connecting channels
@@ -294,7 +296,7 @@ void FairMQDevice::BindWrapper()
ChangeState(Transition::Auto);
}
void FairMQDevice::ConnectWrapper()
void Device::ConnectWrapper()
{
// go over the list of channels until all are initialized (and removed from the uninitialized list)
int numAttempts = 1;
@@ -331,7 +333,7 @@ void FairMQDevice::ConnectWrapper()
ChangeState(Transition::Auto);
}
void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
void Device::AttachChannels(vector<Channel*>& chans)
{
auto itr = chans.begin();
@@ -351,7 +353,7 @@ void FairMQDevice::AttachChannels(vector<FairMQChannel*>& chans)
}
}
bool FairMQDevice::AttachChannel(FairMQChannel& chan)
bool Device::AttachChannel(Channel& chan)
{
vector<string> endpoints;
string chanAddress = chan.GetAddress();
@@ -424,69 +426,66 @@ bool FairMQDevice::AttachChannel(FairMQChannel& chan)
return true;
}
void FairMQDevice::InitTaskWrapper()
void Device::InitTaskWrapper()
{
InitTask();
ChangeState(Transition::Auto);
}
void FairMQDevice::RunWrapper()
void Device::RunWrapper()
{
LOG(info) << "DEVICE: Running...";
LOG(info) << "fair::mq::Device running...";
// start the rate logger thread
future<void> rateLogger = async(launch::async, &FairMQDevice::LogSocketRates, this);
future<void> rateLogger = async(launch::async, &Device::LogSocketRates, this);
// notify transports to resume transfers
for (auto& t : fTransports) {
t.second->Resume();
}
try {
PreRun();
// change to Error state in case of an exception, to release LogSocketRates
tools::CallOnDestruction cod([&](){
ChangeState(Transition::ErrorFound);
});
// process either data callbacks or ConditionalRun/Run
if (fDataCallbacks) {
// if only one input channel, do lightweight handling without additional polling.
if (fInputChannelKeys.size() == 1 && fChannels.at(fInputChannelKeys.at(0)).size() == 1) {
HandleSingleChannelInput();
} else {// otherwise do full handling with polling
HandleMultipleChannelInput();
PreRun();
// process either data callbacks or ConditionalRun/Run
if (fDataCallbacks) {
// if only one input channel, do lightweight handling without additional polling.
if (fInputChannelKeys.size() == 1 && fChannels.at(fInputChannelKeys.at(0)).size() == 1) {
HandleSingleChannelInput();
} else {// otherwise do full handling with polling
HandleMultipleChannelInput();
}
} else {
tools::RateLimiter rateLimiter(fRate);
while (!NewStatePending() && ConditionalRun()) {
if (fRate > 0.001) {
rateLimiter.maybe_sleep();
}
} else {
tools::RateLimiter rateLimiter(fRate);
while (!NewStatePending() && ConditionalRun()) {
if (fRate > 0.001) {
rateLimiter.maybe_sleep();
}
}
Run();
}
// if Run() exited and the state is still RUNNING, transition to READY.
if (!NewStatePending()) {
UnblockTransports();
ChangeState(Transition::Stop);
}
PostRun();
} catch (const out_of_range& oor) {
LOG(error) << "out of range: " << oor.what();
LOG(error) << "incorrect/incomplete channel configuration?";
ChangeState(Transition::ErrorFound);
throw;
} catch (...) {
ChangeState(Transition::ErrorFound);
throw;
Run();
}
// if Run() exited and the state is still RUNNING, transition to READY.
if (!NewStatePending()) {
UnblockTransports();
ChangeState(Transition::Stop);
}
PostRun();
cod.disable();
rateLogger.get();
}
void FairMQDevice::HandleSingleChannelInput()
void Device::HandleSingleChannelInput()
{
bool proceed = true;
@@ -501,14 +500,14 @@ void FairMQDevice::HandleSingleChannelInput()
}
}
void FairMQDevice::HandleMultipleChannelInput()
void Device::HandleMultipleChannelInput()
{
// check if more than one transport is used
fMultitransportInputs.clear();
for (const auto& k : fInputChannelKeys) {
fair::mq::Transport t = fChannels.at(k).at(0).fTransportType;
mq::Transport t = fChannels.at(k).at(0).fTransportType;
if (fMultitransportInputs.find(t) == fMultitransportInputs.end()) {
fMultitransportInputs.insert(pair<fair::mq::Transport, vector<string>>(t, vector<string>()));
fMultitransportInputs.insert(pair<mq::Transport, vector<string>>(t, vector<string>()));
fMultitransportInputs.at(t).push_back(k);
} else {
fMultitransportInputs.at(t).push_back(k);
@@ -533,7 +532,7 @@ void FairMQDevice::HandleMultipleChannelInput()
} else { // otherwise poll directly
bool proceed = true;
FairMQPollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys));
PollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys));
while (!NewStatePending() && proceed) {
poller->Poll(200);
@@ -561,14 +560,14 @@ void FairMQDevice::HandleMultipleChannelInput()
}
}
void FairMQDevice::HandleMultipleTransportInput()
void Device::HandleMultipleTransportInput()
{
vector<thread> threads;
fMultitransportProceed = true;
for (const auto& i : fMultitransportInputs) {
threads.emplace_back(thread(&FairMQDevice::PollForTransport, this, fTransports.at(i.first).get(), i.second));
threads.emplace_back(thread(&Device::PollForTransport, this, fTransports.at(i.first).get(), i.second));
}
for (thread& t : threads) {
@@ -576,10 +575,10 @@ void FairMQDevice::HandleMultipleTransportInput()
}
}
void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const vector<string>& channelKeys)
void Device::PollForTransport(const TransportFactory* factory, const vector<string>& channelKeys)
{
try {
FairMQPollerPtr poller(factory->CreatePoller(fChannels, channelKeys));
PollerPtr poller(factory->CreatePoller(fChannels, channelKeys));
while (!NewStatePending() && fMultitransportProceed) {
poller->Poll(500);
@@ -610,14 +609,14 @@ void FairMQDevice::PollForTransport(const FairMQTransportFactory* factory, const
}
}
} catch (exception& e) {
LOG(error) << "FairMQDevice::PollForTransport() failed: " << e.what() << ", going to ERROR state.";
throw runtime_error(tools::ToString("FairMQDevice::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
LOG(error) << "fair::mq::Device::PollForTransport() failed: " << e.what() << ", going to ERROR state.";
throw runtime_error(tools::ToString("fair::mq::Device::PollForTransport() failed: ", e.what(), ", going to ERROR state."));
}
}
bool FairMQDevice::HandleMsgInput(const string& chName, const InputMsgCallback& callback, int i)
bool Device::HandleMsgInput(const string& chName, const InputMsgCallback& callback, int i)
{
unique_ptr<FairMQMessage> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage());
unique_ptr<Message> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage());
if (Receive(input, chName, i) >= 0) {
return callback(input, i);
@@ -626,9 +625,9 @@ bool FairMQDevice::HandleMsgInput(const string& chName, const InputMsgCallback&
}
}
bool FairMQDevice::HandleMultipartInput(const string& chName, const InputMultipartCallback& callback, int i)
bool Device::HandleMultipartInput(const string& chName, const InputMultipartCallback& callback, int i)
{
FairMQParts input;
Parts input;
if (Receive(input, chName, i) >= 0) {
return callback(input, i);
@@ -637,34 +636,34 @@ bool FairMQDevice::HandleMultipartInput(const string& chName, const InputMultipa
}
}
shared_ptr<FairMQTransportFactory> FairMQDevice::AddTransport(fair::mq::Transport transport)
shared_ptr<TransportFactory> Device::AddTransport(mq::Transport transport)
{
if (transport == fair::mq::Transport::DEFAULT) {
if (transport == mq::Transport::DEFAULT) {
transport = fDefaultTransportType;
}
auto i = fTransports.find(transport);
if (i == fTransports.end()) {
LOG(debug) << "Adding '" << fair::mq::TransportNames.at(transport) << "' transport";
auto tr = FairMQTransportFactory::CreateTransportFactory(fair::mq::TransportNames.at(transport), fId, fConfig);
LOG(debug) << "Adding '" << TransportNames.at(transport) << "' transport";
auto tr = TransportFactory::CreateTransportFactory(TransportNames.at(transport), fId, fConfig);
fTransports.insert({transport, tr});
return tr;
} else {
LOG(debug) << "Reusing existing '" << fair::mq::TransportNames.at(transport) << "' transport";
LOG(debug) << "Reusing existing '" << TransportNames.at(transport) << "' transport";
return i->second;
}
}
void FairMQDevice::SetConfig(ProgOptions& config)
void Device::SetConfig(ProgOptions& config)
{
fInternalConfig.reset();
fConfig = &config;
}
void FairMQDevice::LogSocketRates()
void Device::LogSocketRates()
{
vector<FairMQChannel*> filteredChannels;
vector<Channel*> filteredChannels;
vector<string> filteredChannelNames;
vector<int> logIntervals;
vector<int> intervalCounters;
@@ -760,21 +759,21 @@ void FairMQDevice::LogSocketRates()
}
}
void FairMQDevice::UnblockTransports()
void Device::UnblockTransports()
{
for (auto& transport : fTransports) {
transport.second->Interrupt();
}
}
void FairMQDevice::ResetTaskWrapper()
void Device::ResetTaskWrapper()
{
ResetTask();
ChangeState(Transition::Auto);
}
void FairMQDevice::ResetWrapper()
void Device::ResetWrapper()
{
for (auto& transport : fTransports) {
transport.second->Reset();
@@ -788,9 +787,11 @@ void FairMQDevice::ResetWrapper()
ChangeState(Transition::Auto);
}
FairMQDevice::~FairMQDevice()
Device::~Device()
{
UnsubscribeFromNewTransition("device");
fStateMachine.StopHandlingStates();
LOG(debug) << "Shutting down device " << fId;
}
} // namespace fair::mq

View File

@@ -9,13 +9,642 @@
#ifndef FAIR_MQ_DEVICE_H
#define FAIR_MQ_DEVICE_H
#include <FairMQDevice.h>
#include <algorithm> // find
#include <atomic>
#include <chrono>
#include <cstddef>
#include <fairlogger/Logger.h>
#include <fairmq/Channel.h>
#include <fairmq/Message.h>
#include <fairmq/Parts.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/StateMachine.h>
#include <fairmq/StateQueue.h>
#include <fairmq/Tools.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/UnmanagedRegion.h>
#include <functional>
#include <memory> // unique_ptr
#include <mutex>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility> // pair
#include <vector>
namespace fair::mq
namespace fair::mq {
using ChannelMap = std::unordered_map<std::string, std::vector<Channel>>;
struct OngoingTransition : std::runtime_error
{
using std::runtime_error::runtime_error;
};
using Device = ::FairMQDevice;
using InputMsgCallback = std::function<bool(MessagePtr&, int)>;
} // namespace fair::mq
using InputMultipartCallback = std::function<bool(Parts&, int)>;
class Device
{
friend class Channel;
public:
Device();
Device(ProgOptions& config);
Device(tools::Version version);
Device(ProgOptions& config, tools::Version version);
private:
Device(ProgOptions* config, tools::Version version);
public:
Device(const Device&) = delete;
Device(Device&&) = delete;
Device& operator=(const Device&) = delete;
Device& operator=(Device&&) = delete;
virtual ~Device();
/// Outputs the socket transfer rates
virtual void LogSocketRates();
template<typename Serializer, typename DataType, typename... Args>
[[deprecated]] void Serialize(Message& msg, DataType&& data, Args&&... args) const
{
Serializer().Serialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
template<typename Deserializer, typename DataType, typename... Args>
[[deprecated]] void Deserialize(Message& msg, DataType&& data, Args&&... args) const
{
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
/// Send `m` on `chan` at index `i`
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param chan channel name
/// @param i channel index
/// @return Number of queued bytes,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Send(M& m, const std::string& channel, const int index = 0)
{
return GetChannel(channel, index).Send(m);
}
/// Receive `m` on `chan` at index `i`
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param chan channel name
/// @param i channel index
/// @return Number of received bytes,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Receive(M& m, const std::string& channel, const int index = 0)
{
return GetChannel(channel, index).Receive(m);
}
/// Send `m` on `chan` at index `i`
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param chan channel name
/// @param i channel index
/// @param sndTimeoutMs 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 queued bytes,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Send(M& m, const std::string& channel, const int index, int sndTimeoutMs)
{
return GetChannel(channel, index).Send(m, sndTimeoutMs);
}
/// Receive `m` on `chan` at index `i`
/// @param m reference to MessagePtr/Parts/vector<MessagePtr>
/// @param chan channel name
/// @param i channel index
/// @param rcvTimeoutMs 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 received bytes,
/// TransferCode::timeout if timed out,
/// TransferCode::error if there was an error,
/// TransferCode::interrupted if interrupted (e.g. by requested state change)
template<typename M>
std::enable_if_t<is_transferrable<M>::value, int64_t>
Receive(M& m, const std::string& channel, const int index, int rcvTimeoutMs)
{
return GetChannel(channel, index).Receive(m, rcvTimeoutMs);
}
/// @brief Getter for default transport factory
auto Transport() const -> TransportFactory* { return fTransportFactory.get(); }
// creates message with the default device transport
template<typename... Args>
MessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
// creates message with the transport of the specified channel
template<typename... Args>
MessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
}
// creates a message that will not be cleaned up after transfer, with the default device
// transport
template<typename T>
MessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
// creates a message that will not be cleaned up after transfer, with the transport of the
// specified channel
template<typename T>
MessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewStaticMessage(data);
}
// creates a message with a copy of the provided data, with the default device transport
template<typename T>
MessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
// creates a message with a copy of the provided data, with the transport of the specified
// channel
template<typename T>
MessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewSimpleMessage(data);
}
// creates unamanaged region with the default device transport
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
// creates unmanaged region with the transport of the specified channel
template<typename... Args>
UnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewUnmanagedRegion(std::forward<Args>(args)...);
}
template<typename... Ts>
PollerPtr NewPoller(const Ts&... inputs)
{
std::vector<std::string> chans{inputs...};
// if more than one channel provided, check compatibility
if (chans.size() > 1) {
mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
for (unsigned int i = 1; i < chans.size(); ++i) {
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.";
throw std::runtime_error("poller failed: different transports within same "
"poller are not yet supported.");
}
}
}
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
}
PollerPtr NewPoller(const std::vector<Channel*>& channels)
{
// if more than one channel provided, check compatibility
if (channels.size() > 1) {
mq::Transport type = channels.at(0)->Transport()->GetType();
for (unsigned int i = 1; i < channels.size(); ++i) {
if (type != channels.at(i)->Transport()->GetType()) {
LOG(error) << "poller failed: different transports within same poller are not "
"yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same "
"poller are not yet supported.");
}
}
}
return channels.at(0)->Transport()->CreatePoller(channels);
}
/// Adds a transport to the device if it doesn't exist
/// @param transport Transport string ("zeromq"/"shmem")
std::shared_ptr<TransportFactory> AddTransport(mq::Transport transport);
/// Assigns config to the device
void SetConfig(ProgOptions& config);
/// Get pointer to the config
ProgOptions* GetConfig() const { return fConfig; }
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName,
bool (T::*memberFunction)(MessagePtr& msg, int index))
{
fDataCallbacks = true;
fMsgInputs.insert(
std::make_pair(channelName, [this, memberFunction](MessagePtr& msg, int index) {
return (static_cast<T*>(this)->*memberFunction)(msg, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMsgCallback callback)
{
fDataCallbacks = true;
fMsgInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::*memberFunction)(Parts& parts, int index))
{
fDataCallbacks = true;
fMultipartInputs.insert(
std::make_pair(channelName, [this, memberFunction](Parts& parts, int index) {
return (static_cast<T*>(this)->*memberFunction)(parts, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMultipartCallback callback)
{
fDataCallbacks = true;
fMultipartInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName)
== fInputChannelKeys.end()) {
fInputChannelKeys.push_back(channelName);
}
}
Channel& 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) << "GetChannel(): '" << channelName << "[" << index << "]' does not exist.";
throw;
}
size_t GetNumSubChannels(const std::string& channelName)
try {
return fChannels.at(channelName).size();
} catch (const std::out_of_range& oor) {
LOG(error) << "GetNumSubChannels(): '" << channelName << "' does not exist.";
throw;
}
/// @brief Get numbers of connected peers for the given channel
/// @param name channel name
/// @param index sub-channel
unsigned long GetNumberOfConnectedPeers(const std::string& channelName, int index = 0)
{
return fChannels.at(channelName).at(index).GetNumberOfConnectedPeers();
}
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) {
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
}
return ok;
}
void PrintRegisteredChannels()
{
if (fChannelRegistry.empty()) {
LOGV(info, verylow) << "no channels registered.";
} else {
for (const auto& c : fChannelRegistry) {
LOGV(info, verylow) << c.first << ":" << c.second.first << ":" << c.second.second;
}
}
}
void SetId(const std::string& id) { fId = id; }
std::string GetId() { return fId; }
const tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetProperty("io-threads", numIoThreads); }
int GetNumIoThreads() const
{
return fConfig->GetProperty<int>("io-threads", DefaultIOThreads);
}
void SetNetworkInterface(const std::string& networkInterface)
{
fConfig->SetProperty("network-interface", networkInterface);
}
std::string GetNetworkInterface() const
{
return fConfig->GetProperty<std::string>("network-interface", DefaultNetworkInterface);
}
void SetDefaultTransport(const std::string& name) { fConfig->SetProperty("transport", name); }
std::string GetDefaultTransport() const
{
return fConfig->GetProperty<std::string>("transport", DefaultTransportName);
}
void SetInitTimeoutInS(int initTimeoutInS)
{
fConfig->SetProperty("init-timeout", initTimeoutInS);
}
int GetInitTimeoutInS() const
{
return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout);
}
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"shmem")
void SetTransport(const std::string& transport)
{
fConfig->SetProperty("transport", transport);
}
/// Gets the default transport name
std::string GetTransportName() const
{
return fConfig->GetProperty<std::string>("transport", DefaultTransportName);
}
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine() { fStateMachine.ProcessWork(); };
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<typename Rep, typename Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
return !fStateMachine.WaitForPendingStateFor(
std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
}
protected:
std::shared_ptr<TransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<mq::Transport, std::shared_ptr<TransportFactory>>
fTransports; ///< Container for transports
public:
std::unordered_map<std::string, std::vector<Channel>> fChannels; ///< Device channels
std::unique_ptr<ProgOptions> fInternalConfig; ///< Internal program options configuration
ProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& name, Channel&& channel)
{
fConfig->AddChannel(name, channel);
}
protected:
std::string fId; ///< Device ID
/// Additional user initialization (can be overloaded in child classes). Prefer to use
/// InitTask().
virtual void Init() {}
virtual void Bind() {}
virtual void Connect() {}
/// Task initialization (can be overloaded in child classes)
virtual void InitTask() {}
/// Runs the device (to be overloaded in child classes)
virtual void Run() {}
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
virtual void PreRun() {}
/// Called during RUNNING state repeatedly until it returns false or device state changes
virtual bool ConditionalRun() { return false; }
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
virtual void PostRun() {}
/// Resets the user task (to be overloaded in child classes)
virtual void ResetTask() {}
/// Resets the device (can be overloaded in child classes)
virtual void Reset() {}
public:
/// @brief Request a device state transition
/// @param transition state transition
///
/// 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.
bool ChangeState(const Transition transition) { return fStateMachine.ChangeState(transition); }
/// @brief Request a device state transition
/// @param transition state transition
///
/// 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.
bool ChangeState(const std::string& transition)
{
return fStateMachine.ChangeState(GetTransition(transition));
}
/// @brief waits for the next state (any) to occur
State WaitForNextState() { return fStateQueue.WaitForNext(); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(State state) { fStateQueue.WaitForState(state); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(const std::string& state) { WaitForState(GetState(state)); }
void TransitionTo(State state);
/// @brief Subscribe with a callback to state changes
/// @param key id to identify your subscription
/// @param callback callback (called with the new state as the parameter)
///
/// The callback is called at the beginning of a new state.
/// The callback is called from the thread the state is running in.
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback)
{
fStateMachine.SubscribeToStateChange(key, callback);
}
/// @brief Unsubscribe from state changes
/// @param key id (that was used when subscribing)
void UnsubscribeFromStateChange(const std::string& key)
{
fStateMachine.UnsubscribeFromStateChange(key);
}
/// @brief Subscribe with a callback to incoming state transitions
/// @param key id to identify your subscription
/// @param callback callback (called with the incoming transition as the parameter)
/// The callback is called when new transition is initiated.
/// The callback is called from the thread that initiates the transition (via ChangeState).
void SubscribeToNewTransition(const std::string& key,
std::function<void(const Transition)> callback)
{
fStateMachine.SubscribeToNewTransition(key, callback);
}
/// @brief Unsubscribe from state transitions
/// @param key id (that was used when subscribing)
void UnsubscribeFromNewTransition(const std::string& key)
{
fStateMachine.UnsubscribeFromNewTransition(key);
}
/// @brief Returns true if a new state has been requested, signaling the current handler to
/// stop.
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
/// @brief Returns the current state
State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
/// @brief Returns the name of the current state as a string
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
/// @brief Returns name of the given state as a string
/// @param state state
[[deprecated("Use fair::mq::GetStateName from <fairmq/States.h> directly")]]
static std::string GetStateName(State state) { return fair::mq::GetStateName(state); }
/// @brief Returns name of the given transition as a string
/// @param transition transition
[[deprecated("Use fair::mq::GetTransitionName from <fairmq/States.h> directly")]]
static std::string GetTransitionName(Transition transition)
{
return fair::mq::GetTransitionName(transition);
}
static constexpr const char* DefaultId = "";
static constexpr int DefaultIOThreads = 1;
static constexpr const char* DefaultTransportName = "zeromq";
static constexpr mq::Transport DefaultTransportType = mq::Transport::ZMQ;
static constexpr const char* DefaultNetworkInterface = "default";
static constexpr int DefaultInitTimeout = 120;
static constexpr uint64_t DefaultMaxRunTime = 0;
static constexpr float DefaultRate = 0.;
static constexpr const char* DefaultSession = "default";
private:
mq::Transport fDefaultTransportType; ///< Default transport for the device
StateMachine fStateMachine;
/// 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 ResetTask() method
void ResetTaskWrapper();
/// Handles the Reset() method
void ResetWrapper();
/// Notifies transports to cease any blocking activity
void UnblockTransports();
/// Shuts down the transports and the device
void Exit() {}
/// Attach (bind/connect) channels in the list
void AttachChannels(std::vector<Channel*>& chans);
bool AttachChannel(Channel& ch);
void HandleSingleChannelInput();
void HandleMultipleChannelInput();
void HandleMultipleTransportInput();
void PollForTransport(const TransportFactory* factory,
const std::vector<std::string>& channelKeys);
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
bool HandleMultipartInput(const std::string& chName,
const InputMultipartCallback& callback,
int i);
std::vector<Channel*> fUninitializedBindingChannels;
std::vector<Channel*> fUninitializedConnectingChannels;
bool fDataCallbacks;
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
std::unordered_map<mq::Transport, std::vector<std::string>> fMultitransportInputs;
std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> fChannelRegistry;
std::vector<std::string> fInputChannelKeys;
std::mutex fMultitransportMutex;
std::atomic<bool> fMultitransportProceed;
const 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).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
};
} // namespace fair::mq
// using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
// using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] =
// fair::mq::InputMsgCallback;
// using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] =
// fair::mq::InputMultipartCallback;
// using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
using FairMQChannelMap = fair::mq::ChannelMap;
using InputMsgCallback = fair::mq::InputMsgCallback;
using InputMultipartCallback = fair::mq::InputMultipartCallback;
using FairMQDevice = fair::mq::Device;
#endif /* FAIR_MQ_DEVICE_H */

View File

@@ -120,7 +120,7 @@ auto DeviceRunner::Run() -> int
fPluginManager.ForEachPluginProgOptions([&](boost::program_options::options_description options) {
fConfig.AddToCmdLineOptions(options);
});
fConfig.AddToCmdLineOptions(fPluginManager.ProgramOptions());
fConfig.AddToCmdLineOptions(PluginManager::ProgramOptions());
////// CALL HOOK ///////
fEvents.Emit<hooks::ModifyRawCmdLineArgs>(*this);
@@ -128,7 +128,7 @@ auto DeviceRunner::Run() -> int
fConfig.ParseAll(fRawCmdLineArgs, true);
if (!HandleGeneralOptions(fConfig)) {
if (!HandleGeneralOptions(fConfig, fPrintLogo)) {
return 0;
}

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -8,13 +8,9 @@
#include "Error.h"
namespace fair::mq
{
namespace fair::mq {
const char* ErrorCategory::name() const noexcept
{
return "fairmq";
}
const char* ErrorCategory::name() const noexcept { return "fairmq"; }
std::string ErrorCategory::message(int ev) const
{
@@ -40,4 +36,4 @@ const ErrorCategory errorCategory{};
std::error_code MakeErrorCode(ErrorCode e) { return {static_cast<int>(e), errorCategory}; }
} // namespace fair::mq
} // namespace fair::mq

59
fairmq/Error.h Normal file
View File

@@ -0,0 +1,59 @@
/********************************************************************************
* Copyright (C) 2021 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_ERROR_H
#define FAIR_MQ_ERROR_H
#include <cassert>
#include <fairmq/tools/Strings.h>
#include <stdexcept>
#include <system_error>
// Macro copied from https://en.cppreference.com/w/cpp/error/assert
// Use (void) to silent unused warnings.
#define assertm(exp, msg) assert(((void)msg, exp))
namespace fair::mq {
struct RuntimeError : ::std::runtime_error
{
template<typename... T>
explicit RuntimeError(T&&... t)
: ::std::runtime_error::runtime_error(tools::ToString(std::forward<T>(t)...))
{}
};
enum class ErrorCode
{
OperationInProgress = 10,
OperationTimeout,
OperationCanceled,
DeviceChangeStateFailed,
DeviceGetPropertiesFailed,
DeviceSetPropertiesFailed
};
std::error_code MakeErrorCode(ErrorCode);
struct ErrorCategory : std::error_category
{
const char* name() const noexcept override;
std::string message(int ev) const override;
};
} // namespace fair::mq
namespace std {
template<>
struct is_error_code_enum<fair::mq::ErrorCode> : true_type
{};
} // namespace std
#endif /* FAIR_MQ_ERROR_H */

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,442 +9,12 @@
#ifndef FAIRMQCHANNEL_H_
#define FAIRMQCHANNEL_H_
#include <FairMQTransportFactory.h>
#include <FairMQUnmanagedRegion.h>
#include <FairMQSocket.h>
#include <fairmq/Transports.h>
#include <FairMQParts.h>
#include <fairmq/Properties.h>
#include <FairMQMessage.h>
#if 0
#ifndef FAIR_MQ_CHANNEL_H
#pragma GCC warning "Deprecated header: Use <fairmq/Channel.h> instead"
#endif
#endif
#include <string>
#include <memory> // unique_ptr, shared_ptr
#include <vector>
#include <mutex>
#include <stdexcept>
#include <utility> // std::move
#include <cstdint> // int64_t
/**
* @class FairMQChannel FairMQChannel.h <FairMQChannel.h>
* @brief Wrapper class for FairMQSocket and related methods
*
* The class is not thread-safe.
*/
class FairMQChannel
{
friend class FairMQDevice;
public:
/// Default constructor
FairMQChannel();
/// Constructor
/// @param name Channel name
FairMQChannel(const std::string& name);
/// Constructor
/// @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")
FairMQChannel(const std::string& type, const std::string& method, const std::string& address);
/// Constructor
/// @param name Channel name
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
/// @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(std::string name, std::string type, std::string method, std::string address, std::shared_ptr<FairMQTransportFactory> factory);
FairMQChannel(const std::string& name, int index, const fair::mq::Properties& properties);
/// Copy Constructor
FairMQChannel(const FairMQChannel&);
/// Copy Constructor (with new name)
FairMQChannel(const FairMQChannel&, std::string name);
/// Move constructor
// FairMQChannel(FairMQChannel&&) = delete;
/// Assignment operator
FairMQChannel& operator=(const FairMQChannel&);
/// Move assignment operator
// FairMQChannel& operator=(FairMQChannel&&) = delete;
/// Destructor
virtual ~FairMQChannel() = default;
// { LOG(warn) << "Destroying channel '" << fName << "'"; }
struct ChannelConfigurationError : std::runtime_error { using std::runtime_error::runtime_error; };
FairMQSocket& GetSocket() const { assert(fSocket); return *fSocket; }
bool Bind(const std::string& address)
{
fMethod = "bind";
fAddress = address;
return fSocket->Bind(address);
}
bool Connect(const std::string& address)
{
fMethod = "connect";
fAddress = address;
return fSocket->Connect(address);
}
/// Get channel name
/// @return Returns full channel name (e.g. "data[0]")
std::string GetName() const { return fName; }
/// Get channel prefix
/// @return Returns channel prefix (e.g. "data" in "data[0]")
std::string GetPrefix() const
{
std::string prefix = fName;
prefix = prefix.erase(fName.rfind('['));
return prefix;
}
/// Get channel index
/// @return Returns channel index (e.g. 0 in "data[0]")
std::string GetIndex() const
{
std::string indexStr = fName;
indexStr.erase(indexStr.rfind(']'));
indexStr.erase(0, indexStr.rfind('[') + 1);
return indexStr;
}
/// Get socket type
/// @return Returns socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
std::string GetType() const { return fType; }
/// Get socket method
/// @return Returns socket method (bind/connect)
std::string GetMethod() const { return fMethod; }
/// Get socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
/// @return Returns socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
std::string GetAddress() const { return fAddress; }
/// Get channel transport name ("default", "zeromq" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
std::string GetTransportName() const { return fair::mq::TransportName(fTransportType); }
/// Get channel transport type
/// @return Returns channel transport type
fair::mq::Transport GetTransportType() const { return fTransportType; }
/// Get socket send buffer size (in number of messages)
/// @return Returns socket send buffer size (in number of messages)
int GetSndBufSize() const { return fSndBufSize; }
/// Get socket receive buffer size (in number of messages)
/// @return Returns socket receive buffer size (in number of messages)
int GetRcvBufSize() const { return fRcvBufSize; }
/// Get socket kernel transmit send buffer size (in bytes)
/// @return Returns socket kernel transmit send buffer size (in bytes)
int GetSndKernelSize() const { return fSndKernelSize; }
/// Get socket kernel transmit receive buffer size (in bytes)
/// @return Returns socket kernel transmit receive buffer size (in bytes)
int GetRcvKernelSize() const { return fRcvKernelSize; }
/// Get linger duration (in milliseconds)
/// @return Returns linger duration (in milliseconds)
int GetLinger() const { return fLinger; }
/// Get socket rate logging interval (in seconds)
/// @return Returns socket rate logging interval (in seconds)
int GetRateLogging() const { return fRateLogging; }
/// Get start of the port range for automatic binding
/// @return start of the port range
int GetPortRangeMin() const { return fPortRangeMin; }
/// Get end of the port range for automatic binding
/// @return end of the port range
int GetPortRangeMax() const { return fPortRangeMax; }
/// Set automatic binding (pick random port if bind fails)
/// @return true/false, true if automatic binding is enabled
bool GetAutoBind() const { return fAutoBind; }
/// Set channel name
/// @param name Arbitrary channel name
void UpdateName(const std::string& name) { fName = name; Invalidate(); }
/// Set socket type
/// @param type Socket type (push/pull/pub/sub/spub/xsub/pair/req/rep/dealer/router/)
void UpdateType(const std::string& type) { fType = type; Invalidate(); }
/// Set socket method
/// @param method Socket method (bind/connect)
void UpdateMethod(const std::string& method) { fMethod = method; Invalidate(); }
/// Set socket address
/// @param Socket address (e.g. "tcp://127.0.0.1:5555" or "ipc://abc")
void UpdateAddress(const std::string& address) { fAddress = address; Invalidate(); }
/// Set channel transport
/// @param transport transport string ("default", "zeromq" or "shmem")
void UpdateTransport(const std::string& transport) { fTransportType = fair::mq::TransportType(transport); Invalidate(); }
/// Set socket send buffer size
/// @param sndBufSize Socket send buffer size (in number of messages)
void UpdateSndBufSize(const int sndBufSize) { fSndBufSize = sndBufSize; Invalidate(); }
/// Set socket receive buffer size
/// @param rcvBufSize Socket receive buffer size (in number of messages)
void UpdateRcvBufSize(const int rcvBufSize) { fRcvBufSize = rcvBufSize; Invalidate(); }
/// Set socket kernel transmit send buffer size (in bytes)
/// @param sndKernelSize Socket send buffer size (in bytes)
void UpdateSndKernelSize(const int sndKernelSize) { fSndKernelSize = sndKernelSize; Invalidate(); }
/// Set socket kernel transmit receive buffer size (in bytes)
/// @param rcvKernelSize Socket receive buffer size (in bytes)
void UpdateRcvKernelSize(const int rcvKernelSize) { fRcvKernelSize = rcvKernelSize; Invalidate(); }
/// Set linger duration (in milliseconds)
/// @param duration linger duration (in milliseconds)
void UpdateLinger(const int duration) { fLinger = duration; Invalidate(); }
/// Set socket rate logging interval (in seconds)
/// @param rateLogging Socket rate logging interval (in seconds)
void UpdateRateLogging(const int rateLogging) { fRateLogging = rateLogging; Invalidate(); }
/// Set start of the port range for automatic binding
/// @param minPort start of the port range
void UpdatePortRangeMin(const int minPort) { fPortRangeMin = minPort; Invalidate(); }
/// Set end of the port range for automatic binding
/// @param maxPort end of the port range
void UpdatePortRangeMax(const int maxPort) { fPortRangeMax = maxPort; Invalidate(); }
/// Set automatic binding (pick random port if bind fails)
/// @param autobind true/false, true to enable automatic binding
void UpdateAutoBind(const bool autobind) { fAutoBind = autobind; Invalidate(); }
/// 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.
bool IsValid() const { return fValid; }
/// 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);
/// invalidates the channel (requires validation to be used again).
void Invalidate() { fValid = false; }
/// Sends a message to the socket queue.
/// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQMessagePtr& msg, int sndTimeoutInMs = -1)
{
CheckSendCompatibility(msg);
return fSocket->Send(msg, sndTimeoutInMs);
}
/// Receives a message from the socket queue.
/// @param msg Constant reference of unique_ptr to a FairMQMessage
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQMessagePtr& msg, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msg);
return fSocket->Receive(msg, rcvTimeoutInMs);
}
/// Send a vector of messages
/// @param msgVec message vector 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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
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
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(std::vector<FairMQMessagePtr>& msgVec, int rcvTimeoutInMs = -1)
{
CheckReceiveCompatibility(msgVec);
return fSocket->Receive(msgVec, rcvTimeoutInMs);
}
/// 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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQParts& parts, int sndTimeoutInMs = -1)
{
return Send(parts.fParts, sndTimeoutInMs);
}
/// 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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQParts& parts, int rcvTimeoutInMs = -1)
{
return Receive(parts.fParts, rcvTimeoutInMs);
}
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() -> FairMQTransportFactory* { return fTransportFactory.get(); };
template<typename... Args>
FairMQMessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::DEFAULT;
static constexpr const char* DefaultTransportName = "default";
static constexpr const char* DefaultName = "";
static constexpr const char* DefaultType = "unspecified";
static constexpr const char* DefaultMethod = "unspecified";
static constexpr const char* DefaultAddress = "unspecified";
static constexpr int DefaultSndBufSize = 1000;
static constexpr int DefaultRcvBufSize = 1000;
static constexpr int DefaultSndKernelSize = 0;
static constexpr int DefaultRcvKernelSize = 0;
static constexpr int DefaultLinger = 500;
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
static constexpr bool DefaultAutoBind = true;
private:
std::shared_ptr<FairMQTransportFactory> fTransportFactory;
fair::mq::Transport fTransportType;
std::unique_ptr<FairMQSocket> fSocket;
std::string fName;
std::string fType;
std::string fMethod;
std::string fAddress;
int fSndBufSize;
int fRcvBufSize;
int fSndKernelSize;
int fRcvKernelSize;
int fLinger;
int fRateLogging;
int fPortRangeMin;
int fPortRangeMax;
bool fAutoBind;
bool fValid;
bool fMultipart;
void CheckSendCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void CheckSendCompatibility(std::vector<FairMQMessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
if (msg->GetSize() > 0) {
FairMQMessagePtr msgWrapper(NewMessage(
msg->GetData(),
msg->GetSize(),
[](void* /*data*/, void* _msg) { delete static_cast<FairMQMessage*>(_msg); },
msg.get()
));
msg.release();
msg = move(msgWrapper);
} else {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
}
void CheckReceiveCompatibility(FairMQMessagePtr& msg)
{
if (fTransportType != msg->GetType()) {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
void CheckReceiveCompatibility(std::vector<FairMQMessagePtr>& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
FairMQMessagePtr newMsg(NewMessage());
msg = move(newMsg);
}
}
}
void InitTransport(std::shared_ptr<FairMQTransportFactory> factory)
{
fTransportFactory = factory;
fTransportType = factory->GetType();
}
};
#include <fairmq/Channel.h>
#endif /* FAIRMQCHANNEL_H_ */

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2012-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,545 +9,12 @@
#ifndef FAIRMQDEVICE_H_
#define FAIRMQDEVICE_H_
#include <FairMQChannel.h>
#include <FairMQLogger.h>
#include <FairMQMessage.h>
#include <FairMQParts.h>
#include <FairMQTransportFactory.h>
#include <FairMQUnmanagedRegion.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/StateMachine.h>
#include <fairmq/StateQueue.h>
#include <fairmq/Transports.h>
#include <fairmq/tools/Version.h>
#if 0
#ifndef FAIR_MQ_DEVICE_H
#pragma GCC warning "Deprecated header: Use <fairmq/Device.h> instead"
#endif
#endif
#include <vector>
#include <memory> // unique_ptr
#include <algorithm> // find
#include <string>
#include <chrono>
#include <unordered_map>
#include <functional>
#include <stdexcept>
#include <mutex>
#include <atomic>
#include <cstddef>
#include <utility> // pair
using FairMQChannelMap = std::unordered_map<std::string, std::vector<FairMQChannel>>;
using InputMsgCallback = std::function<bool(FairMQMessagePtr&, int)>;
using InputMultipartCallback = std::function<bool(FairMQParts&, int)>;
namespace fair::mq
{
struct OngoingTransition : std::runtime_error { using std::runtime_error::runtime_error; };
}
class FairMQDevice
{
friend class FairMQChannel;
public:
/// Default constructor
FairMQDevice();
/// Constructor with external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config);
/// Constructor that sets the version
FairMQDevice(const fair::mq::tools::Version version);
/// Constructor that sets the version and external fair::mq::ProgOptions
FairMQDevice(fair::mq::ProgOptions& config, const fair::mq::tools::Version version);
private:
FairMQDevice(fair::mq::ProgOptions* config, const fair::mq::tools::Version version);
public:
/// Copy constructor (disabled)
FairMQDevice(const FairMQDevice&) = delete;
/// Assignment operator (disabled)
FairMQDevice operator=(const FairMQDevice&) = delete;
/// Default destructor
virtual ~FairMQDevice();
/// Outputs the socket transfer rates
virtual void LogSocketRates();
template<typename Serializer, typename DataType, typename... Args>
void Serialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
{
Serializer().Serialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
template<typename Deserializer, typename DataType, typename... Args>
void Deserialize(FairMQMessage& msg, DataType&& data, Args&&... args) const
{
Deserializer().Deserialize(msg, std::forward<DataType>(data), std::forward<Args>(args)...);
}
/// Shorthand method to send `msg` on `chan` at index `i`
/// @param msg message reference
/// @param chan channel name
/// @param i channel index
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
{
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
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQMessagePtr& msg, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(msg, rcvTimeoutInMs);
}
/// Shorthand method to send FairMQParts on `chan` at index `i`
/// @param parts parts reference
/// @param chan channel name
/// @param i channel index
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Send(FairMQParts& parts, const std::string& channel, const int index = 0, int sndTimeoutInMs = -1)
{
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
/// @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, TransferCode::timeout if timed out, TransferCode::error if there was an error, TransferCode::interrupted if interrupted (e.g. by requested state change)
int64_t Receive(FairMQParts& parts, const std::string& channel, const int index = 0, int rcvTimeoutInMs = -1)
{
return GetChannel(channel, index).Receive(parts.fParts, rcvTimeoutInMs);
}
/// @brief Getter for default transport factory
auto Transport() const -> FairMQTransportFactory*
{
return fTransportFactory.get();
}
// creates message with the default device transport
template<typename... Args>
FairMQMessagePtr NewMessage(Args&&... args)
{
return Transport()->CreateMessage(std::forward<Args>(args)...);
}
// creates message with the transport of the specified channel
template<typename... Args>
FairMQMessagePtr NewMessageFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewMessage(std::forward<Args>(args)...);
}
// creates a message that will not be cleaned up after transfer, with the default device transport
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return Transport()->NewStaticMessage(data);
}
// creates a message that will not be cleaned up after transfer, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewStaticMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewStaticMessage(data);
}
// creates a message with a copy of the provided data, with the default device transport
template<typename T>
FairMQMessagePtr NewSimpleMessage(const T& data)
{
return Transport()->NewSimpleMessage(data);
}
// creates a message with a copy of the provided data, with the transport of the specified channel
template<typename T>
FairMQMessagePtr NewSimpleMessageFor(const std::string& channel, int index, const T& data)
{
return GetChannel(channel, index).NewSimpleMessage(data);
}
// creates unamanaged region with the default device transport
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegion(Args&&... args)
{
return Transport()->CreateUnmanagedRegion(std::forward<Args>(args)...);
}
// creates unmanaged region with the transport of the specified channel
template<typename... Args>
FairMQUnmanagedRegionPtr NewUnmanagedRegionFor(const std::string& channel, int index, Args&&... args)
{
return GetChannel(channel, index).NewUnmanagedRegion(std::forward<Args>(args)...);
}
template<typename ...Ts>
FairMQPollerPtr NewPoller(const Ts&... inputs)
{
std::vector<std::string> chans{inputs...};
// if more than one channel provided, check compatibility
if (chans.size() > 1)
{
fair::mq::Transport type = GetChannel(chans.at(0), 0).Transport()->GetType();
for (unsigned int i = 1; i < chans.size(); ++i)
{
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.";
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
}
}
}
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
}
FairMQPollerPtr NewPoller(const std::vector<FairMQChannel*>& channels)
{
// if more than one channel provided, check compatibility
if (channels.size() > 1)
{
fair::mq::Transport type = channels.at(0)->Transport()->GetType();
for (unsigned int i = 1; i < channels.size(); ++i)
{
if (type != channels.at(i)->Transport()->GetType())
{
LOG(error) << "poller failed: different transports within same poller are not yet supported. Going to ERROR state.";
throw std::runtime_error("poller failed: different transports within same poller are not yet supported.");
}
}
}
return channels.at(0)->Transport()->CreatePoller(channels);
}
/// Adds a transport to the device if it doesn't exist
/// @param transport Transport string ("zeromq"/"shmem")
std::shared_ptr<FairMQTransportFactory> AddTransport(const fair::mq::Transport transport);
/// Assigns config to the device
void SetConfig(fair::mq::ProgOptions& config);
/// Get pointer to the config
fair::mq::ProgOptions* GetConfig() const
{
return fConfig;
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQMessagePtr& msg, int index))
{
fDataCallbacks = true;
fMsgInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQMessagePtr& msg, int index)
{
return (static_cast<T*>(this)->*memberFunction)(msg, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMsgCallback callback)
{
fDataCallbacks = true;
fMsgInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
// overload to easily bind member functions
template<typename T>
void OnData(const std::string& channelName, bool (T::* memberFunction)(FairMQParts& parts, int index))
{
fDataCallbacks = true;
fMultipartInputs.insert(std::make_pair(channelName, [this, memberFunction](FairMQParts& parts, int index)
{
return (static_cast<T*>(this)->*memberFunction)(parts, index);
}));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
void OnData(const std::string& channelName, InputMultipartCallback callback)
{
fDataCallbacks = true;
fMultipartInputs.insert(make_pair(channelName, callback));
if (find(fInputChannelKeys.begin(), fInputChannelKeys.end(), channelName) == fInputChannelKeys.end())
{
fInputChannelKeys.push_back(channelName);
}
}
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) << "requested channel has not been configured? check channel names/configuration.";
LOG(error) << "channel: " << channelName << ", index: " << index;
LOG(error) << "out of range: " << oor.what();
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) {
LOG(warn) << "Registering channel: name already registered: \"" << channelName << "\"";
}
return ok;
}
void PrintRegisteredChannels()
{
if (fChannelRegistry.empty()) {
LOGV(info, verylow) << "no channels registered.";
} else {
for (const auto& c : fChannelRegistry) {
LOGV(info, verylow) << c.first << ":" << c.second.first << ":" << c.second.second;
}
}
}
void SetId(const std::string& id) { fId = id; }
std::string GetId() { return fId; }
const fair::mq::tools::Version GetVersion() const { return fVersion; }
void SetNumIoThreads(int numIoThreads) { fConfig->SetProperty("io-threads", numIoThreads);}
int GetNumIoThreads() const { return fConfig->GetProperty<int>("io-threads", DefaultIOThreads); }
void SetNetworkInterface(const std::string& networkInterface) { fConfig->SetProperty("network-interface", networkInterface); }
std::string GetNetworkInterface() const { return fConfig->GetProperty<std::string>("network-interface", DefaultNetworkInterface); }
void SetDefaultTransport(const std::string& name) { fConfig->SetProperty("transport", name); }
std::string GetDefaultTransport() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetInitTimeoutInS(int initTimeoutInS) { fConfig->SetProperty("init-timeout", initTimeoutInS); }
int GetInitTimeoutInS() const { return fConfig->GetProperty<int>("init-timeout", DefaultInitTimeout); }
/// Sets the default transport for the device
/// @param transport Transport string ("zeromq"/"shmem")
void SetTransport(const std::string& transport) { fConfig->SetProperty("transport", transport); }
/// Gets the default transport name
std::string GetTransportName() const { return fConfig->GetProperty<std::string>("transport", DefaultTransportName); }
void SetRawCmdLineArgs(const std::vector<std::string>& args) { fRawCmdLineArgs = args; }
std::vector<std::string> GetRawCmdLineArgs() const { return fRawCmdLineArgs; }
void RunStateMachine()
{
fStateMachine.ProcessWork();
};
/// Wait for the supplied amount of time or for interruption.
/// If interrupted, returns false, otherwise true.
/// @param duration wait duration
template<typename Rep, typename Period>
bool WaitFor(std::chrono::duration<Rep, Period> const& duration)
{
return !fStateMachine.WaitForPendingStateFor(std::chrono::duration_cast<std::chrono::milliseconds>(duration).count());
}
protected:
std::shared_ptr<FairMQTransportFactory> fTransportFactory; ///< Default transport factory
std::unordered_map<fair::mq::Transport, std::shared_ptr<FairMQTransportFactory>> fTransports; ///< Container for transports
public:
std::unordered_map<std::string, std::vector<FairMQChannel>> fChannels; ///< Device channels
std::unique_ptr<fair::mq::ProgOptions> fInternalConfig; ///< Internal program options configuration
fair::mq::ProgOptions* fConfig; ///< Pointer to config (internal or external)
void AddChannel(const std::string& name, FairMQChannel&& channel)
{
fConfig->AddChannel(name, channel);
}
protected:
std::string fId; ///< Device ID
/// Additional user initialization (can be overloaded in child classes). Prefer to use InitTask().
virtual void Init() {}
virtual void Bind() {}
virtual void Connect() {}
/// Task initialization (can be overloaded in child classes)
virtual void InitTask() {}
/// Runs the device (to be overloaded in child classes)
virtual void Run() {}
/// Called in the RUNNING state once before executing the Run()/ConditionalRun() method
virtual void PreRun() {}
/// Called during RUNNING state repeatedly until it returns false or device state changes
virtual bool ConditionalRun() { return false; }
/// Called in the RUNNING state once after executing the Run()/ConditionalRun() method
virtual void PostRun() {}
/// Resets the user task (to be overloaded in child classes)
virtual void ResetTask() {}
/// Resets the device (can be overloaded in child classes)
virtual void Reset() {}
public:
/// @brief Request a device state transition
/// @param transition state transition
///
/// 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.
bool ChangeState(const fair::mq::Transition transition) { return fStateMachine.ChangeState(transition); }
/// @brief Request a device state transition
/// @param transition state transition
///
/// 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.
bool ChangeState(const std::string& transition) { return fStateMachine.ChangeState(fair::mq::GetTransition(transition)); }
/// @brief waits for the next state (any) to occur
fair::mq::State WaitForNextState() { return fStateQueue.WaitForNext(); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(fair::mq::State state) { fStateQueue.WaitForState(state); }
/// @brief waits for the specified state to occur
/// @param state state to wait for
void WaitForState(const std::string& state) { WaitForState(fair::mq::GetState(state)); }
void TransitionTo(const fair::mq::State state);
/// @brief Subscribe with a callback to state changes
/// @param key id to identify your subscription
/// @param callback callback (called with the new state as the parameter)
///
/// The callback is called at the beginning of a new state.
/// The callback is called from the thread the state is running in.
void SubscribeToStateChange(const std::string& key, std::function<void(const fair::mq::State)> callback) { fStateMachine.SubscribeToStateChange(key, callback); }
/// @brief Unsubscribe from state changes
/// @param key id (that was used when subscribing)
void UnsubscribeFromStateChange(const std::string& key) { fStateMachine.UnsubscribeFromStateChange(key); }
/// @brief Subscribe with a callback to incoming state transitions
/// @param key id to identify your subscription
/// @param callback callback (called with the incoming transition as the parameter)
/// The callback is called when new transition is initiated.
/// The callback is called from the thread that initiates the transition (via ChangeState).
void SubscribeToNewTransition(const std::string& key, std::function<void(const fair::mq::Transition)> callback) { fStateMachine.SubscribeToNewTransition(key, callback); }
/// @brief Unsubscribe from state transitions
/// @param key id (that was used when subscribing)
void UnsubscribeFromNewTransition(const std::string& key) { fStateMachine.UnsubscribeFromNewTransition(key); }
/// @brief Returns true if a new state has been requested, signaling the current handler to stop.
bool NewStatePending() const { return fStateMachine.NewStatePending(); }
/// @brief Returns the current state
fair::mq::State GetCurrentState() const { return fStateMachine.GetCurrentState(); }
/// @brief Returns the name of the current state as a string
std::string GetCurrentStateName() const { return fStateMachine.GetCurrentStateName(); }
/// @brief Returns name of the given state as a string
/// @param state state
static std::string GetStateName(const fair::mq::State state) { return fair::mq::GetStateName(state); }
/// @brief Returns name of the given transition as a string
/// @param transition transition
static std::string GetTransitionName(const fair::mq::Transition transition) { return fair::mq::GetTransitionName(transition); }
static constexpr const char* DefaultId = "";
static constexpr int DefaultIOThreads = 1;
static constexpr const char* DefaultTransportName = "zeromq";
static constexpr fair::mq::Transport DefaultTransportType = fair::mq::Transport::ZMQ;
static constexpr const char* DefaultNetworkInterface = "default";
static constexpr int DefaultInitTimeout = 120;
static constexpr uint64_t DefaultMaxRunTime = 0;
static constexpr float DefaultRate = 0.;
static constexpr const char* DefaultSession = "default";
private:
fair::mq::Transport fDefaultTransportType; ///< Default transport for the device
fair::mq::StateMachine fStateMachine;
/// 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 ResetTask() method
void ResetTaskWrapper();
/// Handles the Reset() method
void ResetWrapper();
/// Notifies transports to cease any blocking activity
void UnblockTransports();
/// Shuts down the transports and the device
void Exit() {}
/// Attach (bind/connect) channels in the list
void AttachChannels(std::vector<FairMQChannel*>& chans);
bool AttachChannel(FairMQChannel& ch);
void HandleSingleChannelInput();
void HandleMultipleChannelInput();
void HandleMultipleTransportInput();
void PollForTransport(const FairMQTransportFactory* factory, const std::vector<std::string>& channelKeys);
bool HandleMsgInput(const std::string& chName, const InputMsgCallback& callback, int i);
bool HandleMultipartInput(const std::string& chName, const InputMultipartCallback& callback, int i);
std::vector<FairMQChannel*> fUninitializedBindingChannels;
std::vector<FairMQChannel*> fUninitializedConnectingChannels;
bool fDataCallbacks;
std::unordered_map<std::string, InputMsgCallback> fMsgInputs;
std::unordered_map<std::string, InputMultipartCallback> fMultipartInputs;
std::unordered_map<fair::mq::Transport, std::vector<std::string>> fMultitransportInputs;
std::unordered_map<std::string, std::pair<uint16_t, uint16_t>> fChannelRegistry;
std::vector<std::string> fInputChannelKeys;
std::mutex fMultitransportMutex;
std::atomic<bool> fMultitransportProceed;
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).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
fair::mq::StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
};
#include <fairmq/Device.h>
#endif /* FAIRMQDEVICE_H_ */

View File

@@ -1,15 +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" *
********************************************************************************/
/**
* FairMQLogger.cxx
*
* @since 2012-12-04
* @author D. Klein, A. Rybalchenko
*/
#include "FairMQLogger.h"

View File

@@ -1,13 +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" *
********************************************************************************/
/**
* FairMQMessage.cxx
*
* @since 2012-12-05
* @author D. Klein, A. Rybalchenko
*/

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,65 +9,12 @@
#ifndef FAIRMQMESSAGE_H_
#define FAIRMQMESSAGE_H_
#include <cstddef> // for size_t
#include <memory> // unique_ptr
#include <stdexcept>
#if 0
#ifndef FAIR_MQ_MESSAGE_H
#pragma GCC warning "Deprecated header: Use <fairmq/Message.h> instead"
#endif
#endif
#include <fairmq/Transports.h>
using fairmq_free_fn = void(void* data, void* hint);
class FairMQTransportFactory;
namespace fair::mq
{
struct Alignment
{
size_t alignment;
explicit operator size_t() const { return alignment; }
};
} // namespace fair::mq
class FairMQMessage
{
public:
FairMQMessage() = default;
FairMQMessage(FairMQTransportFactory* factory) : fTransport(factory) {}
virtual void Rebuild() = 0;
virtual void Rebuild(fair::mq::Alignment alignment) = 0;
virtual void Rebuild(const size_t size) = 0;
virtual void Rebuild(const size_t size, fair::mq::Alignment alignment) = 0;
virtual void Rebuild(void* data, const size_t size, fairmq_free_fn* ffn, void* hint = nullptr) = 0;
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
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 FairMQMessage& msg) = 0;
virtual ~FairMQMessage() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQMessagePtr = std::unique_ptr<FairMQMessage>;
namespace fair::mq
{
using Message = FairMQMessage;
using MessagePtr = FairMQMessagePtr;
struct MessageError : std::runtime_error { using std::runtime_error::runtime_error; };
struct MessageBadAlloc : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#include <fairmq/Message.h>
#endif /* FAIRMQMESSAGE_H_ */

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,90 +9,12 @@
#ifndef FAIRMQPARTS_H_
#define FAIRMQPARTS_H_
#include "FairMQTransportFactory.h"
#include "FairMQMessage.h"
#if 0
#ifndef FAIR_MQ_PARTS_H
#pragma GCC warning "Deprecated header: Use <fairmq/Parts.h> instead"
#endif
#endif
#include <vector>
#include <memory> // unique_ptr
/// FairMQParts is a lightweight convenience wrapper around a vector of unique pointers to FairMQMessage, used for sending multi-part messages
class FairMQParts
{
private:
using container = std::vector<std::unique_ptr<FairMQMessage>>;
public:
/// Default constructor
FairMQParts() = default;
/// Copy Constructor
FairMQParts(const FairMQParts&) = delete;
/// Move constructor
FairMQParts(FairMQParts&& p) = default;
/// Assignment operator
FairMQParts& operator=(const FairMQParts&) = delete;
/// Constructor from argument pack of std::unique_ptr<FairMQMessage> rvalues
template <typename... Ts>
FairMQParts(Ts&&... messages) { AddPart(std::forward<Ts>(messages)...); }
/// Default destructor
~FairMQParts() = default;
/// Adds part (FairMQMessage) to the container
/// @param msg message pointer (for example created with NewMessage() method of FairMQDevice)
void AddPart(FairMQMessage* msg)
{
fParts.push_back(std::unique_ptr<FairMQMessage>(msg));
}
/// Adds part (std::unique_ptr<FairMQMessage>&) to the container (move)
/// @param msg unique pointer to FairMQMessage
/// rvalue ref (move required when passing argument)
void AddPart(std::unique_ptr<FairMQMessage>&& msg)
{
fParts.push_back(std::move(msg));
}
/// Add variable list of parts to the container (move)
template <typename... Ts>
void AddPart(std::unique_ptr<FairMQMessage>&& first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// Add content of another object by move
void AddPart(FairMQParts&& other)
{
container parts = std::move(other.fParts);
for (auto& part : parts) {
fParts.push_back(std::move(part));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
FairMQMessage& operator[](const int index) { return *(fParts[index]); }
/// Get reference to unique pointer to part in the container at index (with bounds check)
/// @param index container index
std::unique_ptr<FairMQMessage>& At(const int index) { return fParts.at(index); }
// ref version
FairMQMessage& AtRef(const int index) { return *(fParts.at(index)); }
/// Get number of parts in the container
/// @return number of parts in the container
int Size() const { return fParts.size(); }
container fParts;
// forward container iterators
using iterator = container::iterator;
using const_iterator = container::const_iterator;
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
auto end() -> decltype(fParts.end()) { return fParts.end(); }
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
};
#include <fairmq/Parts.h>
#endif /* FAIRMQPARTS_H_ */

View File

@@ -1,13 +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" *
********************************************************************************/
/**
* FairMQPoller.cxx
*
* @since 2014-01-23
* @author A. Rybalchenko
*/

View File

@@ -9,31 +9,12 @@
#ifndef FAIRMQPOLLER_H_
#define FAIRMQPOLLER_H_
#include <memory>
#include <stdexcept>
#include <string>
#if 0
#ifndef FAIR_MQ_POLLER_H
#pragma GCC warning "Deprecated header: Use <fairmq/Poller.h> instead"
#endif
#endif
class FairMQPoller
{
public:
virtual void Poll(const int timeout) = 0;
virtual bool CheckInput(const int index) = 0;
virtual bool CheckOutput(const int index) = 0;
virtual bool CheckInput(const std::string& channelKey, const int index) = 0;
virtual bool CheckOutput(const std::string& channelKey, const int index) = 0;
virtual ~FairMQPoller() = default;
};
using FairMQPollerPtr = std::unique_ptr<FairMQPoller>;
namespace fair::mq
{
using Poller = FairMQPoller;
using PollerPtr = FairMQPollerPtr;
struct PollerError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#include <fairmq/Poller.h>
#endif /* FAIRMQPOLLER_H_ */

View File

@@ -1,9 +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" *
********************************************************************************/
#include <FairMQSocket.h>

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,88 +9,12 @@
#ifndef FAIRMQSOCKET_H_
#define FAIRMQSOCKET_H_
#include "FairMQMessage.h"
#if 0
#ifndef FAIR_MQ_SOCKET_H
#pragma GCC warning "Deprecated header: Use <fairmq/Socket.h> instead"
#endif
#endif
#include <memory>
#include <ostream>
#include <stdexcept>
#include <string>
#include <vector>
class FairMQTransportFactory;
namespace fair::mq
{
enum class TransferCode : int
{
success = 0,
error = -1,
timeout = -2,
interrupted = -3
};
} // namespace fair::mq
class FairMQSocket
{
public:
FairMQSocket() = default;
FairMQSocket(FairMQTransportFactory* fac) : fTransport(fac) {}
virtual std::string GetId() const = 0;
virtual bool Bind(const std::string& address) = 0;
virtual bool Connect(const std::string& address) = 0;
virtual int64_t Send(FairMQMessagePtr& msg, int timeout = -1) = 0;
virtual int64_t 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;
/// If the backend supports it, fills the unsigned integer @a events with the ZMQ_EVENTS value
/// DISCLAIMER: this API is experimental and unsupported and might be dropped / refactored in
/// the future.
virtual int Events(uint32_t* events) = 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;
FairMQTransportFactory* GetTransport() { return fTransport; }
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
virtual ~FairMQSocket() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQSocketPtr = std::unique_ptr<FairMQSocket>;
namespace fair::mq
{
using Socket = FairMQSocket;
using SocketPtr = FairMQSocketPtr;
struct SocketError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#include <fairmq/Socket.h>
#endif /* FAIRMQSOCKET_H_ */

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,174 +9,12 @@
#ifndef FAIRMQTRANSPORTFACTORY_H_
#define FAIRMQTRANSPORTFACTORY_H_
#include <FairMQMessage.h>
#include <FairMQPoller.h>
#include <FairMQSocket.h>
#include <FairMQUnmanagedRegion.h>
#include <fairmq/MemoryResources.h>
#include <fairmq/Transports.h>
#if 0
#ifndef FAIR_MQ_TRANSPORTFACTORY_H
#pragma GCC warning "Deprecated header: Use <fairmq/TransportFactory.h> instead"
#endif
#endif
#include <string>
#include <memory> // shared_ptr
#include <vector>
#include <unordered_map>
#include <stdexcept>
#include <cstddef> // size_t
class FairMQChannel;
namespace fair::mq { class ProgOptions; }
class FairMQTransportFactory
{
private:
/// 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.
FairMQTransportFactory(std::string id);
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 (for receiving)
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage() = 0;
/// @brief Create empty FairMQMessage (for receiving), align received buffer to specified alignment
/// @param alignment alignment to align received buffer to
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(fair::mq::Alignment alignment) = 0;
/// @brief Create new FairMQMessage of specified size
/// @param size message size
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(const size_t size) = 0;
/// @brief Create new FairMQMessage of specified size and alignment
/// @param size message size
/// @param alignment message alignment
/// @return pointer to FairMQMessage
virtual FairMQMessagePtr CreateMessage(const size_t size, fair::mq::Alignment alignment) = 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) = 0;
/// @brief create a message with the buffer located within the corresponding unmanaged region
/// @param unmanagedRegion the unmanaged region that this message buffer belongs to
/// @param data message buffer (must be within the region - checked at runtime by the transport)
/// @param size size of the message
/// @param hint optional parameter, returned to the user in the FairMQRegionCallback
virtual FairMQMessagePtr CreateMessage(FairMQUnmanagedRegionPtr& unmanagedRegion, void* data, const size_t size, void* hint = 0) = 0;
/// @brief Create a socket
virtual FairMQSocketPtr CreateSocket(const std::string& type, const std::string& name) = 0;
/// @brief Create a poller for a single channel (all subchannels)
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel>& channels) const = 0;
/// @brief Create a poller for specific channels
virtual FairMQPollerPtr CreatePoller(const std::vector<FairMQChannel*>& channels) const = 0;
/// @brief 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;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
/// @brief Create new UnmanagedRegion
/// @param size size of the region
/// @param userFlags flags to be stored with the region, have no effect on the transport, but can be retrieved from the region by the user
/// @param callback callback to be called when a message belonging to this region is no longer needed by the transport
/// @param path optional parameter to pass to the underlying transport
/// @param flags optional parameter to pass to the underlying transport
/// @return pointer to UnmanagedRegion
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
virtual FairMQUnmanagedRegionPtr CreateUnmanagedRegion(const size_t size, const int64_t userFlags, FairMQRegionBulkCallback callback = nullptr, const std::string& path = "", int flags = 0, fair::mq::RegionConfig cfg = fair::mq::RegionConfig()) = 0;
/// @brief Subscribe to region events (creation, destruction, ...)
/// @param callback the callback that is called when a region event occurs
virtual void SubscribeToRegionEvents(FairMQRegionEventCallback callback) = 0;
/// @brief Check if there is an active subscription to region events
/// @return true/false
virtual bool SubscribedToRegionEvents() = 0;
/// @brief Unsubscribe from region events
virtual void UnsubscribeFromRegionEvents() = 0;
virtual std::vector<FairMQRegionInfo> GetRegionInfo() = 0;
/// Get transport type
virtual fair::mq::Transport GetType() const = 0;
virtual void Interrupt() = 0;
virtual void Resume() = 0;
virtual void Reset() = 0;
virtual ~FairMQTransportFactory() = default;
static auto CreateTransportFactory(const std::string& type, const std::string& id = "", const fair::mq::ProgOptions* config = nullptr) -> std::shared_ptr<FairMQTransportFactory>;
static void FairMQNoCleanup(void* /*data*/, void* /*obj*/)
{
}
template<typename T>
static void FairMQSimpleMsgCleanup(void* /*data*/, void* obj)
{
delete static_cast<T*>(obj);
}
template<typename T>
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!");
T* dataCopy = new T(data);
return CreateMessage(dataCopy, sizeof(T), FairMQSimpleMsgCleanup<T>, dataCopy);
}
template<std::size_t N>
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)
{
std::string* msgStr = new std::string(str);
return CreateMessage(const_cast<char*>(msgStr->c_str()), msgStr->length(), FairMQSimpleMsgCleanup<std::string>, msgStr);
}
template<typename T>
FairMQMessagePtr NewStaticMessage(const T& data)
{
return CreateMessage(data, sizeof(T), FairMQNoCleanup, nullptr);
}
FairMQMessagePtr NewStaticMessage(const std::string& str)
{
return CreateMessage(const_cast<char*>(str.c_str()), str.length(), FairMQNoCleanup, nullptr);
}
};
namespace fair::mq
{
using TransportFactory = FairMQTransportFactory;
struct TransportFactoryError : std::runtime_error { using std::runtime_error::runtime_error; };
} // namespace fair::mq
#include <fairmq/TransportFactory.h>
#endif /* FAIRMQTRANSPORTFACTORY_H_ */

View File

@@ -9,120 +9,12 @@
#ifndef FAIRMQUNMANAGEDREGION_H_
#define FAIRMQUNMANAGEDREGION_H_
#include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <fairmq/Transports.h>
#include <functional> // std::function
#include <memory> // std::unique_ptr
#include <ostream> // std::ostream
#include <vector>
#if 0
#ifndef FAIR_MQ_UNMANAGEDREGION_H
#pragma GCC warning "Deprecated header: Use <fairmq/UnmanagedRegion.h> instead"
#endif
#endif
class FairMQTransportFactory;
enum class FairMQRegionEvent : int
{
created,
destroyed,
local_only
};
struct FairMQRegionInfo
{
FairMQRegionInfo() = default;
FairMQRegionInfo(bool _managed, uint64_t _id, void* _ptr, size_t _size, int64_t _flags, FairMQRegionEvent _event)
: managed(_managed)
, id(_id)
, ptr(_ptr)
, size(_size)
, flags(_flags)
, event(_event)
{}
bool managed = true; // managed/unmanaged
uint64_t id = 0; // id of the region
void* ptr = nullptr; // pointer to the start of the region
size_t size = 0; // region size
int64_t flags = 0; // custom flags set by the creator
FairMQRegionEvent event = FairMQRegionEvent::created;
};
struct FairMQRegionBlock {
void* ptr;
size_t size;
void* hint;
FairMQRegionBlock(void* p, size_t s, void* h)
: ptr(p), size(s), hint(h)
{}
};
using FairMQRegionCallback = std::function<void(void*, size_t, void*)>;
using FairMQRegionBulkCallback = std::function<void(const std::vector<FairMQRegionBlock>&)>;
using FairMQRegionEventCallback = std::function<void(FairMQRegionInfo)>;
class FairMQUnmanagedRegion
{
public:
FairMQUnmanagedRegion() = default;
FairMQUnmanagedRegion(FairMQTransportFactory* factory) : fTransport(factory) {}
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual uint16_t GetId() const = 0;
virtual void SetLinger(uint32_t linger) = 0;
virtual uint32_t GetLinger() const = 0;
virtual fair::mq::Transport GetType() const = 0;
FairMQTransportFactory* GetTransport() { return fTransport; }
void SetTransport(FairMQTransportFactory* transport) { fTransport = transport; }
virtual ~FairMQUnmanagedRegion() = default;
private:
FairMQTransportFactory* fTransport{nullptr};
};
using FairMQUnmanagedRegionPtr = std::unique_ptr<FairMQUnmanagedRegion>;
inline std::ostream& operator<<(std::ostream& os, const FairMQRegionEvent& event)
{
switch (event) {
case FairMQRegionEvent::created:
return os << "created";
case FairMQRegionEvent::destroyed:
return os << "destroyed";
case FairMQRegionEvent::local_only:
return os << "local_only";
default:
return os << "unrecognized event";
}
}
namespace fair::mq
{
struct RegionConfig
{
RegionConfig() = default;
RegionConfig(bool l, bool z)
: lock(l), zero(z)
{}
bool lock = false;
bool zero = false;
};
using RegionCallback = FairMQRegionCallback;
using RegionBulkCallback = FairMQRegionBulkCallback;
using RegionEventCallback = FairMQRegionEventCallback;
using RegionEvent = FairMQRegionEvent;
using RegionInfo = FairMQRegionInfo;
using RegionBlock = FairMQRegionBlock;
using UnmanagedRegion = FairMQUnmanagedRegion;
using UnmanagedRegionPtr = FairMQUnmanagedRegionPtr;
} // namespace fair::mq
#include <fairmq/UnmanagedRegion.h>
#endif /* FAIRMQUNMANAGEDREGION_H_ */

View File

@@ -11,21 +11,35 @@
#include <fairmq/ProgOptionsFwd.h>
class FairMQChannel;
class FairMQDevice;
class FairMQMemoryResource;
class FairMQMessage;
class FairMQParts;
class FairMQPoller;
class FairMQRegionBlock;
class FairMQRegionConfig;
class FairMQRegionInfo;
class FairMQSocket;
class FairMQTransportFactory;
class FairMQUnmanagedRegion;
namespace fair::mq {
class FairMQMemoryResource;
}
class Channel;
class Device;
class MemoryResource;
class Message;
class Parts;
class Poller;
class RegionBlock;
class RegionConfig;
class RegionInfo;
class Socket;
class TransportFactory;
class UnmanagedRegion;
using FairMQMemoryResource = MemoryResource;
} // namespace fair::mq
using FairMQChannel = fair::mq::Channel;
using FairMQDevice = fair::mq::Device;
using FairMQMessage = fair::mq::Message;
using FairMQParts = fair::mq::Parts;
using FairMQPoller = fair::mq::Poller;
using FairMQRegionBlock = fair::mq::RegionBlock;
using FairMQRegionConfig = fair::mq::RegionConfig;
using FairMQRegionInfo = fair::mq::RegionInfo;
using FairMQSocket = fair::mq::Socket;
using FairMQTransportFactory = fair::mq::TransportFactory;
using FairMQUnmanagedRegion = fair::mq::UnmanagedRegion;
#endif // FAIR_MQ_FWDDECLS_H

View File

@@ -13,29 +13,30 @@
*/
#include "JSONParser.h"
#include "FairMQChannel.h"
#include <fairmq/PropertyOutput.h>
#include <fairmq/tools/Strings.h>
#include <fairlogger/Logger.h>
#include <boost/any.hpp>
#define BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/property_tree/json_parser.hpp>
#undef BOOST_BIND_GLOBAL_PLACEHOLDERS
#include <boost/property_tree/ptree.hpp>
#include <boost/any.hpp>
#include <fairlogger/Logger.h>
#include <fairmq/Channel.h>
#include <fairmq/JSONParser.h>
#include <fairmq/PropertyOutput.h>
#include <fairmq/tools/Strings.h>
#include <iomanip>
using namespace std;
using namespace fair::mq;
using namespace fair::mq::tools;
using namespace tools;
using namespace boost::property_tree;
namespace fair::mq
{
fair::mq::Properties PtreeParser(const ptree& pt, const string& id)
Properties PtreeParser(const ptree& pt, const string& id)
{
if (id.empty()) {
throw ParserError("no device ID provided. Provide with `--id` cmd option");
@@ -46,7 +47,7 @@ fair::mq::Properties PtreeParser(const ptree& pt, const string& id)
return helper::DeviceParser(pt.get_child("fairMQOptions"), id);
}
fair::mq::Properties JSONParser(const string& filename, const string& deviceId)
Properties JSONParser(const string& filename, const string& deviceId)
{
ptree pt;
LOG(debug) << "Parsing JSON from " << filename << " ...";
@@ -57,9 +58,9 @@ fair::mq::Properties JSONParser(const string& filename, const string& deviceId)
namespace helper
{
fair::mq::Properties DeviceParser(const ptree& fairMQOptions, const string& deviceId)
Properties DeviceParser(const ptree& fairMQOptions, const string& deviceId)
{
fair::mq::Properties properties;
Properties properties;
for (const auto& node : fairMQOptions) {
if (node.first == "devices") {
@@ -81,25 +82,27 @@ fair::mq::Properties DeviceParser(const ptree& fairMQOptions, const string& devi
return properties;
}
void ChannelParser(const ptree& tree, fair::mq::Properties& properties)
void ChannelParser(const ptree& tree, Properties& properties)
{
for (const auto& node : tree) {
if (node.first == "channels") {
for (const auto& cn : node.second) {
fair::mq::Properties commonProperties;
commonProperties.emplace("type", cn.second.get<string>("type", FairMQChannel::DefaultType));
commonProperties.emplace("method", cn.second.get<string>("method", FairMQChannel::DefaultMethod));
commonProperties.emplace("address", cn.second.get<string>("address", FairMQChannel::DefaultAddress));
commonProperties.emplace("transport", cn.second.get<string>("transport", FairMQChannel::DefaultTransportName));
commonProperties.emplace("sndBufSize", cn.second.get<int>("sndBufSize", FairMQChannel::DefaultSndBufSize));
commonProperties.emplace("rcvBufSize", cn.second.get<int>("rcvBufSize", FairMQChannel::DefaultRcvBufSize));
commonProperties.emplace("sndKernelSize", cn.second.get<int>("sndKernelSize", FairMQChannel::DefaultSndKernelSize));
commonProperties.emplace("rcvKernelSize", cn.second.get<int>("rcvKernelSize", FairMQChannel::DefaultRcvKernelSize));
commonProperties.emplace("linger", cn.second.get<int>("linger", FairMQChannel::DefaultLinger));
commonProperties.emplace("rateLogging", cn.second.get<int>("rateLogging", FairMQChannel::DefaultRateLogging));
commonProperties.emplace("portRangeMin", cn.second.get<int>("portRangeMin", FairMQChannel::DefaultPortRangeMin));
commonProperties.emplace("portRangeMax", cn.second.get<int>("portRangeMax", FairMQChannel::DefaultPortRangeMax));
commonProperties.emplace("autoBind", cn.second.get<bool>("autoBind", FairMQChannel::DefaultAutoBind));
Properties commonProperties;
commonProperties.emplace("type", cn.second.get<string>("type", Channel::DefaultType));
commonProperties.emplace("method", cn.second.get<string>("method", Channel::DefaultMethod));
commonProperties.emplace("address", cn.second.get<string>("address", Channel::DefaultAddress));
commonProperties.emplace("transport", cn.second.get<string>("transport", Channel::DefaultTransportName));
commonProperties.emplace("sndBufSize", cn.second.get<int>("sndBufSize", Channel::DefaultSndBufSize));
commonProperties.emplace("rcvBufSize", cn.second.get<int>("rcvBufSize", Channel::DefaultRcvBufSize));
commonProperties.emplace("sndKernelSize", cn.second.get<int>("sndKernelSize", Channel::DefaultSndKernelSize));
commonProperties.emplace("rcvKernelSize", cn.second.get<int>("rcvKernelSize", Channel::DefaultRcvKernelSize));
commonProperties.emplace("sndTimeoutMs", cn.second.get<int>("sndTimeoutMs", Channel::DefaultSndTimeoutMs));
commonProperties.emplace("rcvTimeoutMs", cn.second.get<int>("rcvTimeoutMs", Channel::DefaultRcvTimeoutMs));
commonProperties.emplace("linger", cn.second.get<int>("linger", Channel::DefaultLinger));
commonProperties.emplace("rateLogging", cn.second.get<int>("rateLogging", Channel::DefaultRateLogging));
commonProperties.emplace("portRangeMin", cn.second.get<int>("portRangeMin", Channel::DefaultPortRangeMin));
commonProperties.emplace("portRangeMax", cn.second.get<int>("portRangeMax", Channel::DefaultPortRangeMax));
commonProperties.emplace("autoBind", cn.second.get<bool>("autoBind", Channel::DefaultAutoBind));
string name = cn.second.get<string>("name");
int numSockets = cn.second.get<int>("numSockets", 0);
@@ -125,7 +128,7 @@ void ChannelParser(const ptree& tree, fair::mq::Properties& properties)
}
}
void SubChannelParser(const ptree& channelTree, fair::mq::Properties& properties, const string& channelName, const fair::mq::Properties& commonProperties)
void SubChannelParser(const ptree& channelTree, Properties& properties, const string& channelName, const Properties& commonProperties)
{
// for each socket in channel
int i = 0;
@@ -134,7 +137,7 @@ void SubChannelParser(const ptree& channelTree, fair::mq::Properties& properties
if (node.first == "sockets") {
for (const auto& sn : node.second) {
// a sub-channel inherits relevant properties from the common channel ...
fair::mq::Properties newProperties(commonProperties);
Properties newProperties(commonProperties);
// ... and adds/overwrites its own properties
newProperties["type"] = sn.second.get<string>("type", boost::any_cast<string>(commonProperties.at("type")));
@@ -145,6 +148,8 @@ void SubChannelParser(const ptree& channelTree, fair::mq::Properties& properties
newProperties["rcvBufSize"] = sn.second.get<int>("rcvBufSize", boost::any_cast<int>(commonProperties.at("rcvBufSize")));
newProperties["sndKernelSize"] = sn.second.get<int>("sndKernelSize", boost::any_cast<int>(commonProperties.at("sndKernelSize")));
newProperties["rcvKernelSize"] = sn.second.get<int>("rcvKernelSize", boost::any_cast<int>(commonProperties.at("rcvKernelSize")));
newProperties["sndTimeoutMs"] = sn.second.get<int>("sndTimeoutMs", boost::any_cast<int>(commonProperties.at("sndTimeoutMs")));
newProperties["rcvTimeoutMs"] = sn.second.get<int>("rcvTimeoutMs", boost::any_cast<int>(commonProperties.at("rcvTimeoutMs")));
newProperties["linger"] = sn.second.get<int>("linger", boost::any_cast<int>(commonProperties.at("linger")));
newProperties["rateLogging"] = sn.second.get<int>("rateLogging", boost::any_cast<int>(commonProperties.at("rateLogging")));
newProperties["portRangeMin"] = sn.second.get<int>("portRangeMin", boost::any_cast<int>(commonProperties.at("portRangeMin")));
@@ -172,7 +177,7 @@ void SubChannelParser(const ptree& channelTree, fair::mq::Properties& properties
LOG(trace) << "\tNo sockets specified,";
LOG(trace) << "\tapplying common settings to the channel:";
fair::mq::Properties newProperties(commonProperties);
Properties newProperties(commonProperties);
for (auto& p : newProperties) {
LOG(trace) << "\t" << setw(13) << left << p.first << " : " << p.second;

View File

@@ -12,7 +12,7 @@
///
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
#include <fairmq/FairMQTransportFactory.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/MemoryResources.h>
namespace fair::mq
@@ -28,13 +28,13 @@ template<typename ContainerT>
// pmr::polymorphic_allocator<typename
// ContainerT::value_type>,
// typename ContainerT::allocator_type>::value == true,
// FairMQMessagePtr>::type
FairMQMessagePtr getMessage(ContainerT &&container_, FairMQMemoryResource *targetResource = nullptr)
// MessagePtr>::type
MessagePtr getMessage(ContainerT &&container_, MemoryResource *targetResource = nullptr)
{
auto container = std::move(container_);
auto alloc = container.get_allocator();
auto resource = dynamic_cast<FairMQMemoryResource *>(alloc.resource());
auto resource = dynamic_cast<MemoryResource *>(alloc.resource());
if (!resource && !targetResource) {
throw std::runtime_error("Neither the container or target resource specified");
}

View File

@@ -1,10 +1,10 @@
/********************************************************************************
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018-2021 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" *
* 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
@@ -15,27 +15,24 @@
#ifndef FAIR_MQ_MEMORY_RESOURCES_H
#define FAIR_MQ_MEMORY_RESOURCES_H
#include <FairMQMessage.h>
class FairMQTransportFactory;
#include <boost/container/container_fwd.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/pmr/memory_resource.hpp>
#include <cstring>
#include <fairmq/Message.h>
#include <stdexcept>
#include <utility>
namespace fair::mq
{
namespace fair::mq {
class TransportFactory;
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
class MemoryResource : public pmr::memory_resource
{
public:
/// return the message containing data associated with the pointer (to start
@@ -43,9 +40,9 @@ class FairMQMemoryResource : public pmr::memory_resource
/// 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 MessagePtr getMessage(void* p) = 0;
virtual void* setMessage(MessagePtr) = 0;
virtual TransportFactory* getTransportFactory() noexcept = 0;
virtual size_t getNumberOfMessages() const noexcept = 0;
};
@@ -54,41 +51,42 @@ class FairMQMemoryResource : public pmr::memory_resource
/// 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
class ChannelResource : public MemoryResource
{
protected:
FairMQTransportFactory* factory{nullptr};
TransportFactory* 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;
boost::container::flat_map<void*, MessagePtr> messageMap;
public:
ChannelResource() = delete;
ChannelResource(FairMQTransportFactory* _factory)
ChannelResource(TransportFactory* _factory)
: factory(_factory)
{
if (!_factory) {
throw std::runtime_error("Tried to construct from a nullptr FairMQTransportFactory");
throw std::runtime_error(
"Tried to construct from a nullptr fair::mq::TransportFactory");
}
};
FairMQMessagePtr getMessage(void* p) override
MessagePtr getMessage(void* p) override
{
auto mes = std::move(messageMap[p]);
messageMap.erase(p);
return mes;
}
void* setMessage(FairMQMessagePtr message) override
void* setMessage(MessagePtr message) override
{
void* addr = message->GetData();
messageMap[addr] = std::move(message);
return addr;
}
FairMQTransportFactory* getTransportFactory() noexcept override { return factory; }
TransportFactory* getTransportFactory() noexcept override { return factory; }
size_t getNumberOfMessages() const noexcept override { return messageMap.size(); }
@@ -99,12 +97,16 @@ class ChannelResource : public FairMQMemoryResource
messageMap.erase(p);
};
bool do_is_equal(const pmr::memory_resource &other) const noexcept override
bool do_is_equal(const pmr::memory_resource& other) const noexcept override
{
return this == &other;
};
};
} // namespace fair::mq
// using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] =
// MemoryResource;
using FairMQMemoryResource = MemoryResource;
} // namespace fair::mq
#endif /* FAIR_MQ_MEMORY_RESOURCES_H */

View File

@@ -9,6 +9,80 @@
#ifndef FAIR_MQ_MESSAGE_H
#define FAIR_MQ_MESSAGE_H
#include <FairMQMessage.h>
#include <cstddef> // for size_t
#include <fairmq/Transports.h>
#include <memory> // unique_ptr
#include <stdexcept>
namespace fair::mq {
using FreeFn = void(void* data, void* hint);
class TransportFactory;
struct Alignment
{
size_t alignment;
explicit operator size_t() const { return alignment; }
};
struct Message
{
Message() = default;
Message(TransportFactory* factory)
: fTransport(factory)
{}
Message(const Message&) = delete;
Message(Message&&) = delete;
Message& operator=(const Message&) = delete;
Message& operator=(Message&&) = delete;
virtual void Rebuild() = 0;
virtual void Rebuild(Alignment alignment) = 0;
virtual void Rebuild(size_t size) = 0;
virtual void Rebuild(size_t size, Alignment alignment) = 0;
virtual void Rebuild(void* data, size_t size, FreeFn* ffn, void* hint = nullptr) = 0;
virtual void* GetData() const = 0;
virtual size_t GetSize() const = 0;
virtual bool SetUsedSize(size_t size) = 0;
virtual Transport GetType() const = 0;
TransportFactory* GetTransport() { return fTransport; }
void SetTransport(TransportFactory* transport) { fTransport = transport; }
/// Copy the message buffer from another message
/// Transport may choose not to physically copy the buffer, but to share across the messages.
/// Modifying the buffer after a call to Copy() is undefined behaviour.
/// @param msg message to copy the buffer from.
virtual void Copy(const Message& msg) = 0;
virtual ~Message() = default;
private:
TransportFactory* fTransport{nullptr};
};
using MessagePtr = std::unique_ptr<Message>;
struct MessageError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct MessageBadAlloc : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
// using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
// using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
using fairmq_free_fn = fair::mq::FreeFn;
using FairMQMessage = fair::mq::Message;
using FairMQMessagePtr = fair::mq::MessagePtr;
#endif // FAIR_MQ_MESSAGE_H

92
fairmq/Parts.h Normal file
View File

@@ -0,0 +1,92 @@
/********************************************************************************
* Copyright (C) 2014-2021 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_PARTS_H
#define FAIR_MQ_PARTS_H
#include <fairmq/Message.h>
#include <memory> // unique_ptr
#include <vector>
namespace fair::mq {
/// fair::mq::Parts is a lightweight convenience wrapper around a vector of unique pointers to
/// Message, used for sending multi-part messages
class Parts
{
private:
using container = std::vector<MessagePtr>;
public:
Parts() = default;
Parts(const Parts&) = delete;
Parts(Parts&&) = default;
template<typename... Ts>
Parts(Ts&&... messages) { AddPart(std::forward<Ts>(messages)...); }
Parts& operator=(const Parts&) = delete;
Parts& operator=(Parts&&) = default;
~Parts() = default;
/// Adds part (Message) to the container
/// @param msg message pointer (for example created with NewMessage() method of Device)
void AddPart(Message* msg) { fParts.push_back(MessagePtr(msg)); }
/// Adds part to the container (move)
/// @param msg unique pointer to Message
/// rvalue ref (move required when passing argument)
void AddPart(MessagePtr&& msg) { fParts.push_back(std::move(msg)); }
/// Add variable list of parts to the container (move)
template<typename... Ts>
void AddPart(MessagePtr&& first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// Add content of another object by move
void AddPart(Parts&& other)
{
container parts = std::move(other.fParts);
for (auto& part : parts) {
fParts.push_back(std::move(part));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
Message& operator[](const int index) { return *(fParts[index]); }
/// Get reference to unique pointer to part in the container at index (with bounds check)
/// @param index container index
MessagePtr& At(const int index) { return fParts.at(index); }
// ref version
Message& AtRef(const int index) { return *(fParts.at(index)); }
/// Get number of parts in the container
/// @return number of parts in the container
int Size() const { return fParts.size(); }
container fParts;
// forward container iterators
using iterator = container::iterator;
using const_iterator = container::const_iterator;
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
auto end() -> decltype(fParts.end()) { return fParts.end(); }
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
};
} // namespace fair::mq
// using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
using FairMQParts = fair::mq::Parts;
#endif /* FAIR_MQ_PARTS_H */

View File

@@ -7,7 +7,7 @@
********************************************************************************/
#include <fairmq/Plugin.h>
#include <FairMQLogger.h>
#include <fairlogger/Logger.h>
#include <utility>
using namespace std;

View File

@@ -48,7 +48,9 @@ class Plugin
PluginServices* pluginServices);
Plugin(const Plugin&) = delete;
Plugin operator=(const Plugin&) = delete;
Plugin(Plugin&&) = delete;
Plugin& operator=(const Plugin&) = delete;
Plugin& operator=(Plugin&&) = delete;
virtual ~Plugin();
@@ -72,10 +74,10 @@ class Plugin
// see <fairmq/PluginServices.h> for docs
using DeviceState = fair::mq::PluginServices::DeviceState;
using DeviceStateTransition = fair::mq::PluginServices::DeviceStateTransition;
auto ToDeviceState(const std::string& state) const -> DeviceState { return fPluginServices->ToDeviceState(state); }
auto ToDeviceStateTransition(const std::string& transition) const -> DeviceStateTransition { return fPluginServices->ToDeviceStateTransition(transition); }
auto ToStr(DeviceState state) const -> std::string { return fPluginServices->ToStr(state); }
auto ToStr(DeviceStateTransition transition) const -> std::string { return fPluginServices->ToStr(transition); }
auto ToDeviceState(const std::string& state) const -> DeviceState { return PluginServices::ToDeviceState(state); }
auto ToDeviceStateTransition(const std::string& transition) const -> DeviceStateTransition { return PluginServices::ToDeviceStateTransition(transition); }
auto ToStr(DeviceState state) const -> std::string { return PluginServices::ToStr(state); }
auto ToStr(DeviceStateTransition transition) const -> std::string { return PluginServices::ToStr(transition); }
auto GetCurrentDeviceState() const -> DeviceState { return fPluginServices->GetCurrentDeviceState(); }
auto TakeDeviceControl() -> void { fPluginServices->TakeDeviceControl(fkName); };
auto StealDeviceControl() -> void { fPluginServices->StealDeviceControl(fkName); };
@@ -89,6 +91,8 @@ class Plugin
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
auto GetNumberOfConnectedPeers(const std::string& channelName, int index = 0) -> unsigned long { return fPluginServices->GetNumberOfConnectedPeers(channelName, index); }
// device config API
// see <fairmq/PluginServices.h> for docs
auto PropertyExists(const std::string& key) -> int { return fPluginServices->PropertyExists(key); }

View File

@@ -35,7 +35,7 @@ fair::mq::PluginManager::PluginManager()
{
}
fair::mq::PluginManager::PluginManager(const vector<string> args)
fair::mq::PluginManager::PluginManager(const vector<string>& args)
: fPluginServices()
{
// Parse command line options

View File

@@ -49,7 +49,11 @@ class PluginManager
using PluginFactory = std::unique_ptr<fair::mq::Plugin>(PluginServices&);
PluginManager();
PluginManager(const std::vector<std::string> args);
PluginManager(const PluginManager&) = delete;
PluginManager(PluginManager&&) = delete;
PluginManager& operator=(const PluginManager&) = delete;
PluginManager& operator=(PluginManager&&) = delete;
PluginManager(const std::vector<std::string>& args);
~PluginManager()
{
@@ -115,7 +119,7 @@ class PluginManager
static const std::string fgkLibPrefix;
std::vector<boost::filesystem::path> fSearchPaths;
static std::vector<boost::dll::shared_library> fgDLLKeepAlive;
static std::vector<boost::dll::shared_library> fgDLLKeepAlive; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
std::unique_ptr<PluginServices> fPluginServices;
std::map<std::string, std::unique_ptr<Plugin>> fPlugins;

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,8 +9,8 @@
#ifndef FAIR_MQ_PLUGINSERVICES_H
#define FAIR_MQ_PLUGINSERVICES_H
#include <fairmq/Device.h>
#include <fairmq/States.h>
#include <FairMQDevice.h>
#include <fairmq/ProgOptions.h>
#include <fairmq/Properties.h>
@@ -40,7 +40,7 @@ class PluginServices
{
public:
PluginServices() = delete;
PluginServices(ProgOptions& config, FairMQDevice& device)
PluginServices(ProgOptions& config, Device& device)
: fConfig(config)
, fDevice(device)
{}
@@ -51,7 +51,9 @@ class PluginServices
}
PluginServices(const PluginServices&) = delete;
PluginServices operator=(const PluginServices&) = delete;
PluginServices(PluginServices&&) = delete;
PluginServices& operator=(const PluginServices&) = delete;
PluginServices& operator=(PluginServices&&) = delete;
using DeviceState = fair::mq::State;
using DeviceStateTransition = fair::mq::Transition;
@@ -117,7 +119,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) -> bool;
auto ChangeDeviceState(const std::string& controller, DeviceStateTransition next) -> bool;
/// @brief Subscribe with a callback to device state changes
/// @param subscriber id
@@ -136,6 +138,9 @@ class PluginServices
/// @param subscriber id
auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); }
/// DO NOT USE, ONLY FOR TESTING, WILL BE REMOVED (and info made available via property api)
auto GetNumberOfConnectedPeers(const std::string& channelName, int index = 0) -> unsigned long { return fDevice.GetNumberOfConnectedPeers(channelName, index); }
// Config API
/// @brief Checks a property with the given key exist in the configuration
@@ -269,7 +274,7 @@ class PluginServices
private:
fair::mq::ProgOptions& fConfig;
FairMQDevice& fDevice;
Device& fDevice;
boost::optional<std::string> fDeviceController;
mutable std::mutex fDeviceControllerMutex;
std::condition_variable fReleaseDeviceControlCondition;

View File

@@ -9,6 +9,41 @@
#ifndef FAIR_MQ_POLLER_H
#define FAIR_MQ_POLLER_H
#include <FairMQPoller.h>
#include <memory>
#include <stdexcept>
#include <string>
namespace fair::mq {
struct Poller
{
Poller() = default;
Poller(const Poller&) = delete;
Poller(Poller&&) = delete;
Poller& operator=(const Poller&) = delete;
Poller& operator=(Poller&&) = delete;
virtual void Poll(int timeout) = 0;
virtual bool CheckInput(int index) = 0;
virtual bool CheckOutput(int index) = 0;
virtual bool CheckInput(const std::string& channelKey, int index) = 0;
virtual bool CheckOutput(const std::string& channelKey, int index) = 0;
virtual ~Poller() = default;
};
using PollerPtr = std::unique_ptr<Poller>;
struct PollerError : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
// using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
using FairMQPoller = fair::mq::Poller;
using FairMQPollerPtr = fair::mq::PollerPtr;
#endif // FAIR_MQ_POLLER_H

View File

@@ -169,7 +169,7 @@ unordered_map<string, int> ProgOptions::GetChannelInfoImpl() const
for (const auto& m : fVarMap) {
if (boost::regex_match(m.first, re)) {
string chan = m.first.substr(6);
string::size_type n = chan.find(".");
string::size_type n = chan.find('.');
string chanName = chan.substr(0, n);
if (info.find(chanName) == info.end()) {
@@ -351,7 +351,7 @@ void ProgOptions::DeleteProperty(const string& key)
vm.erase(key);
}
void ProgOptions::AddChannel(const string& name, const FairMQChannel& channel)
void ProgOptions::AddChannel(const string& name, const Channel& channel)
{
lock_guard<mutex> lock(fMtx);
unordered_map<string, int> existingChannels = GetChannelInfoImpl();

View File

@@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@@ -9,22 +9,20 @@
#ifndef FAIR_MQ_PROGOPTIONS_H
#define FAIR_MQ_PROGOPTIONS_H
#include "FairMQChannel.h"
#include "FairMQLogger.h"
#include <boost/program_options.hpp>
#include <fairlogger/Logger.h>
#include <fairmq/Channel.h>
#include <fairmq/EventManager.h>
#include <fairmq/ProgOptionsFwd.h>
#include <fairmq/Properties.h>
#include <fairmq/tools/Strings.h>
#include <boost/program_options.hpp>
#include <functional>
#include <map>
#include <mutex>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <vector>
#include <stdexcept>
namespace fair::mq
{
@@ -35,13 +33,17 @@ class ProgOptions
{
public:
ProgOptions();
virtual ~ProgOptions() = default;
ProgOptions(const ProgOptions&) = delete;
ProgOptions(ProgOptions&&) = delete;
ProgOptions& operator=(const ProgOptions&) = delete;
ProgOptions& operator=(ProgOptions&&) = delete;
~ProgOptions() = default;
void ParseAll(const std::vector<std::string>& cmdArgs, bool allowUnregistered);
void ParseAll(const int argc, char const* const* argv, bool allowUnregistered = true);
void ParseAll(int argc, char const* const* argv, bool allowUnregistered = true);
void Notify();
void AddToCmdLineOptions(const boost::program_options::options_description optDesc, bool visible = true);
void AddToCmdLineOptions(boost::program_options::options_description optDesc, bool visible = true);
boost::program_options::options_description& GetCmdLineOptions();
/// @brief Checks a property with the given key exist in the configuration
@@ -174,7 +176,7 @@ class ProgOptions
/// @brief Takes the provided channel and creates properties based on it
/// @param name channel name
/// @param channel FairMQChannel reference
void AddChannel(const std::string& name, const FairMQChannel& channel);
void AddChannel(const std::string& name, const Channel& channel);
/// @brief Subscribe to property updates of type T
/// @param subscriber

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