mirror of
https://github.com/FairRootGroup/FairMQ.git
synced 2025-10-13 16:46:47 +00:00
Compare commits
63 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
dcea48fcee | ||
|
67dcf77a7f | ||
|
24e7a5b8d0 | ||
|
c11506e958 | ||
|
e4f258c9ea | ||
|
324a27a2e1 | ||
|
c80f97b338 | ||
|
76824fee36 | ||
|
d2e4679dc8 | ||
|
6bb70bd519 | ||
|
fe2127e12f | ||
|
41165cf16b | ||
|
8fe95e644e | ||
|
6628a231e2 | ||
|
91b31f0799 | ||
|
39cb021827 | ||
|
36b48f5594 | ||
|
0e221b28b8 | ||
|
1ee0977df4 | ||
|
24d578a4ba | ||
|
ce1a4499cc | ||
|
7d009f0915 | ||
|
b70b181c38 | ||
|
94602d23b3 | ||
|
41ac755c57 | ||
|
6d4a82427b | ||
|
0966dee55d | ||
|
b649356c5a | ||
|
2df3d909fa | ||
|
05a2ae6a31 | ||
|
58ffdfd1f4 | ||
|
addfd071bb | ||
|
2d27abc533 | ||
|
faf577086a | ||
|
ff1f9b94ef | ||
|
34e8a24c86 | ||
|
7567a10513 | ||
|
424e22b41a | ||
|
961eca5276 | ||
|
fbb6577625 | ||
|
6122010694 | ||
|
b40db42196 | ||
|
f732b87def | ||
|
f05a09da5a | ||
|
5aa6c99442 | ||
|
3c714fd9e0 | ||
|
1b7532a520 | ||
|
f092b94c96 | ||
|
8d28824489 | ||
|
4310d07ed1 | ||
|
7bd31f8ff0 | ||
|
1a0ab3a4e2 | ||
|
cacf69d5f6 | ||
|
46f50a10ea | ||
|
68038c4693 | ||
|
1036e204d0 | ||
|
fddbbc1732 | ||
|
3c1723fc54 | ||
|
c3418cc7b8 | ||
|
cc00c5a6f1 | ||
|
e6bb14f535 | ||
|
b18d60372c | ||
|
7ceccdeaa6 |
5
.devcontainer/devcontainer.json
Normal file
5
.devcontainer/devcontainer.json
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{
|
||||||
|
"image": "ghcr.io/fairrootgroup/fairmq-dev/fedora-38:latest",
|
||||||
|
"features": {
|
||||||
|
}
|
||||||
|
}
|
12
.github/dependabot.yml
vendored
Normal file
12
.github/dependabot.yml
vendored
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
target-branch: "dev"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
||||||
|
- package-ecosystem: "gitsubmodule"
|
||||||
|
directory: "/"
|
||||||
|
target-branch: "dev"
|
||||||
|
schedule:
|
||||||
|
interval: "monthly"
|
29
.github/workflows/check_metadata.yaml
vendored
Normal file
29
.github/workflows/check_metadata.yaml
vendored
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
# SPDX-FileCopyrightText: 2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH, Darmstadt, Germany
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
name: Check AUTHORS and CONTRIBUTORS in metadata
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- AUTHORS
|
||||||
|
- CONTRIBUTORS
|
||||||
|
- codemeta.json
|
||||||
|
- .zenodo.json
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- AUTHORS
|
||||||
|
- CONTRIBUTORS
|
||||||
|
- codemeta.json
|
||||||
|
- .zenodo.json
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Try updating metadata
|
||||||
|
run: python meta_update.py
|
||||||
|
- name: Check for Updates
|
||||||
|
run: git diff --exit-code
|
21
.github/workflows/codemeta_validate.yaml
vendored
Normal file
21
.github/workflows/codemeta_validate.yaml
vendored
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
name: validate codemeta
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
paths:
|
||||||
|
- codemeta.json
|
||||||
|
- .github/workflows/codemeta_validate.yaml
|
||||||
|
pull_request:
|
||||||
|
paths:
|
||||||
|
- codemeta.json
|
||||||
|
- .github/workflows/codemeta_validate.yaml
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: gitlab-registry.in2p3.fr/escape2020/wp3/eossr:v1.0
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: validate codemeta
|
||||||
|
run: eossr-metadata-validator codemeta.json
|
|
@ -1,6 +1,7 @@
|
||||||
{
|
{
|
||||||
"creators": [
|
"creators": [
|
||||||
{
|
{
|
||||||
|
"orcid": "0000-0002-8071-4497",
|
||||||
"name": "Al-Turany, Mohammad"
|
"name": "Al-Turany, Mohammad"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2018-2024 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -8,8 +8,7 @@
|
||||||
|
|
||||||
|
|
||||||
# Project ######################################################################
|
# Project ######################################################################
|
||||||
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
|
cmake_minimum_required(VERSION 3.15...3.30 FATAL_ERROR)
|
||||||
cmake_policy(VERSION 3.15...3.26)
|
|
||||||
|
|
||||||
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
include(GitHelper)
|
include(GitHelper)
|
||||||
|
|
10
Jenkinsfile
vendored
10
Jenkinsfile
vendored
|
@ -43,7 +43,7 @@ def jobMatrix(String type, List specs) {
|
||||||
sh "bash ${jobscript}"
|
sh "bash ${jobscript}"
|
||||||
} else { // selector == "slurm"
|
} else { // selector == "slurm"
|
||||||
def imageurl = "oras://ghcr.io/fairrootgroup/fairmq-dev/${os}-${ver}-sif:latest"
|
def imageurl = "oras://ghcr.io/fairrootgroup/fairmq-dev/${os}-${ver}-sif:latest"
|
||||||
def execopts = "--net --ipc --uts --pid -B/shared"
|
def execopts = "--ipc --uts --pid -B/shared"
|
||||||
def containercmd = "singularity exec ${execopts} ${imageurl} bash -l -c \\\"${ctestcmd} ${extra}\\\""
|
def containercmd = "singularity exec ${execopts} ${imageurl} bash -l -c \\\"${ctestcmd} ${extra}\\\""
|
||||||
sh """\
|
sh """\
|
||||||
echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript}
|
echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript}
|
||||||
|
@ -87,14 +87,18 @@ pipeline{
|
||||||
def builds = jobMatrix('build', [
|
def builds = jobMatrix('build', [
|
||||||
[os: 'ubuntu', ver: '20.04', arch: 'x86_64', compiler: 'gcc-9'],
|
[os: 'ubuntu', ver: '20.04', arch: 'x86_64', compiler: 'gcc-9'],
|
||||||
[os: 'ubuntu', ver: '22.04', arch: 'x86_64', compiler: 'gcc-11'],
|
[os: 'ubuntu', ver: '22.04', arch: 'x86_64', compiler: 'gcc-11'],
|
||||||
|
[os: 'ubuntu', ver: '24.04', arch: 'x86_64', compiler: 'gcc-13'],
|
||||||
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'],
|
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'],
|
||||||
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11'],
|
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11'],
|
||||||
[os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11'],
|
[os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11'],
|
||||||
[os: 'fedora', ver: '36', arch: 'x86_64', compiler: 'gcc-12'],
|
[os: 'fedora', ver: '36', arch: 'x86_64', compiler: 'gcc-12'],
|
||||||
[os: 'fedora', ver: '37', arch: 'x86_64', compiler: 'gcc-12'],
|
[os: 'fedora', ver: '37', arch: 'x86_64', compiler: 'gcc-12'],
|
||||||
[os: 'fedora', ver: '38', arch: 'x86_64', compiler: 'gcc-13'],
|
[os: 'fedora', ver: '38', arch: 'x86_64', compiler: 'gcc-13'],
|
||||||
[os: 'macos', ver: '12', arch: 'x86_64', compiler: 'apple-clang-14'],
|
[os: 'fedora', ver: '39', arch: 'x86_64', compiler: 'gcc-13'],
|
||||||
[os: 'macos', ver: '13', arch: 'arm64', compiler: 'apple-clang-14'],
|
[os: 'fedora', ver: '40', arch: 'x86_64', compiler: 'gcc-14'],
|
||||||
|
[os: 'macos', ver: '14', arch: 'x86_64', compiler: 'apple-clang-16'],
|
||||||
|
[os: 'macos', ver: '15', arch: 'x86_64', compiler: 'apple-clang-16'],
|
||||||
|
[os: 'macos', ver: '15', arch: 'arm64', compiler: 'apple-clang-16'],
|
||||||
])
|
])
|
||||||
|
|
||||||
def all_debug = "-DCMAKE_BUILD_TYPE=Debug"
|
def all_debug = "-DCMAKE_BUILD_TYPE=Debug"
|
||||||
|
|
22
README.md
22
README.md
|
@ -45,9 +45,9 @@ Recommended:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://github.com/FairRootGroup/FairMQ fairmq_source
|
git clone https://github.com/FairRootGroup/FairMQ fairmq_source
|
||||||
cmake -S fairmq_source -B fairmq_build -GNinja -DCMAKE_BUILD_TYPE=Release
|
cmake -S fairmq_source -B fairmq_build -GNinja -DCMAKE_BUILD_TYPE=Release [-DBUILD_TESTING=ON]
|
||||||
cmake --build fairmq_build
|
cmake --build fairmq_build
|
||||||
ctest --test-dir fairmq_build --output-on-failure --schedule-random -j<ncpus>
|
[ctest --test-dir fairmq_build --output-on-failure --schedule-random -j<ncpus>] # needs -DBUILD_TESTING=ON
|
||||||
cmake --install fairmq_build --prefix $(pwd)/fairmq_install
|
cmake --install fairmq_build --prefix $(pwd)/fairmq_install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -56,6 +56,24 @@ Please consult the [manpages of your CMake version](https://cmake.org/cmake/help
|
||||||
If dependencies are not installed in standard system directories, you can hint the installation location via
|
If dependencies are not installed in standard system directories, you can hint the installation location via
|
||||||
`-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...` (`*_ROOT` variables can also be environment variables).
|
`-DCMAKE_PREFIX_PATH=...` or per dependency via `-D{DEPENDENCY}_ROOT=...` (`*_ROOT` variables can also be environment variables).
|
||||||
|
|
||||||
|
## Installation via Spack
|
||||||
|
|
||||||
|
Prerequisite: [Spack](https://spack.readthedocs.io/en/latest/getting_started.html)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
spack info fairmq # inspect build options
|
||||||
|
spack install fairmq # build latest packaged version with default options
|
||||||
|
```
|
||||||
|
|
||||||
|
Build FairMQ's dependencies via Spack for development:
|
||||||
|
```bash
|
||||||
|
git clone -b dev https://github.com/FairRootGroup/FairMQ fairmq_source
|
||||||
|
spack --env fairmq_source install # installs deps declared in fairmq_source/spack.yaml
|
||||||
|
spack env activate fairmq_source # sets $CMAKE_PREFIX_PATH which is used by CMake to find FairMQ's deps
|
||||||
|
cmake -S fairmq_source -B fairmq_build -GNinja -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON
|
||||||
|
# develop, compile, test
|
||||||
|
spack env deactivate # at end of dev session, or simply close the shell
|
||||||
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2018-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -41,7 +41,7 @@ if(BUILD_TESTING)
|
||||||
endif()
|
endif()
|
||||||
find_package2(BUNDLED GTest REQUIRED)
|
find_package2(BUNDLED GTest REQUIRED)
|
||||||
if(GTest_BUNDLED)
|
if(GTest_BUNDLED)
|
||||||
set(GTest_VERSION "Apr 8 2022 @a1cc8c55")
|
set(GTest_VERSION "Dec 26 2024 @7d76a23")
|
||||||
set(GTest_PREFIX "<bundled>")
|
set(GTest_PREFIX "<bundled>")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -6,12 +6,23 @@
|
||||||
"license": "./COPYRIGHT",
|
"license": "./COPYRIGHT",
|
||||||
"datePublished": "2018-04-15",
|
"datePublished": "2018-04-15",
|
||||||
"developmentStatus": "active",
|
"developmentStatus": "active",
|
||||||
|
"softwareVersion": "master",
|
||||||
|
"releaseNotes": "https://github.com/FairRootGroup/FairMQ/releases",
|
||||||
"codeRepository": "https://github.com/FairRootGroup/FairMQ/",
|
"codeRepository": "https://github.com/FairRootGroup/FairMQ/",
|
||||||
|
"readme": "https://github.com/FairRootGroup/FairMQ/#readme",
|
||||||
"issueTracker": "https://github.com/FairRootGroup/FairMQ/issues",
|
"issueTracker": "https://github.com/FairRootGroup/FairMQ/issues",
|
||||||
"identifier": "https://doi.org/10.5281/zenodo.1689985",
|
"identifier": "https://doi.org/10.5281/zenodo.1689985",
|
||||||
|
"maintainer": [
|
||||||
|
{
|
||||||
|
"@type": "ResearchOrganisation",
|
||||||
|
"@id": "https://ror.org/02k8cbn47",
|
||||||
|
"name": "GSI Helmholtz Centre for Heavy Ion Research"
|
||||||
|
}
|
||||||
|
],
|
||||||
"author": [
|
"author": [
|
||||||
{
|
{
|
||||||
"@type": "Person",
|
"@type": "Person",
|
||||||
|
"@id": "https://orcid.org/0000-0002-8071-4497",
|
||||||
"givenName": "Mohammad",
|
"givenName": "Mohammad",
|
||||||
"familyName": "Al-Turany"
|
"familyName": "Al-Turany"
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,7 +61,7 @@ function(add_example)
|
||||||
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
|
||||||
foreach(script IN LISTS scripts)
|
foreach(script IN LISTS scripts)
|
||||||
set(script_file "${script_prefix}-${script}.sh")
|
set(script_file "${script_prefix}-${script}.sh")
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}")
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}" @ONLY)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
if(ARG_CONFIG)
|
if(ARG_CONFIG)
|
||||||
|
@ -119,7 +119,7 @@ function(add_example)
|
||||||
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
|
||||||
foreach(script IN LISTS scripts)
|
foreach(script IN LISTS scripts)
|
||||||
set(script_file "${script_prefix}-${script}.sh")
|
set(script_file "${script_prefix}-${script}.sh")
|
||||||
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install")
|
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install" @ONLY)
|
||||||
install(
|
install(
|
||||||
PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install"
|
PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install"
|
||||||
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
DESTINATION ${PROJECT_INSTALL_BINDIR}
|
||||||
|
|
|
@ -7,5 +7,6 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
add_example(NAME region
|
add_example(NAME region
|
||||||
DEVICE sampler sink keep-alive
|
DEVICE sampler processor sink keep-alive
|
||||||
|
SCRIPT region region-advanced region-advanced-external
|
||||||
)
|
)
|
||||||
|
|
95
examples/region/fairmq-start-ex-region-advanced-external.sh.in
Executable file
95
examples/region/fairmq-start-ex-region-advanced-external.sh.in
Executable file
|
@ -0,0 +1,95 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||||
|
|
||||||
|
transport=${1:-shmem}
|
||||||
|
msgSize=${2:-1000000}
|
||||||
|
|
||||||
|
SAMPLER="fairmq-ex-region-sampler"
|
||||||
|
SAMPLER+=" --id sampler1"
|
||||||
|
# SAMPLER+=" --sampling-rate 10"
|
||||||
|
SAMPLER+=" --severity debug"
|
||||||
|
SAMPLER+=" --msg-size $msgSize"
|
||||||
|
SAMPLER+=" --transport $transport"
|
||||||
|
SAMPLER+=" --shmid 1"
|
||||||
|
SAMPLER+=" --shm-monitor false"
|
||||||
|
SAMPLER+=" --rc-segment-size 200000000"
|
||||||
|
SAMPLER+=" --external-region true"
|
||||||
|
SAMPLER+=" --shm-no-cleanup true"
|
||||||
|
SAMPLER+=" --chan-name data1"
|
||||||
|
SAMPLER+=" --channel-config name=data1,type=push,method=bind,address=tcp://127.0.0.1:7777"
|
||||||
|
xterm -geometry 90x60+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||||
|
|
||||||
|
PROCESSOR1="fairmq-ex-region-processor"
|
||||||
|
PROCESSOR1+=" --id processor1"
|
||||||
|
PROCESSOR1+=" --severity debug"
|
||||||
|
PROCESSOR1+=" --transport $transport"
|
||||||
|
PROCESSOR1+=" --shmid 1"
|
||||||
|
PROCESSOR1+=" --shm-segment-id 1"
|
||||||
|
PROCESSOR1+=" --shm-monitor false"
|
||||||
|
PROCESSOR1+=" --shm-no-cleanup true"
|
||||||
|
PROCESSOR1+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||||
|
PROCESSOR1+=" name=data2,type=push,method=bind,address=tcp://127.0.0.1:7778"
|
||||||
|
PROCESSOR1+=" name=data3,type=push,method=bind,address=tcp://127.0.0.1:7779"
|
||||||
|
xterm -geometry 90x40+550+40 -hold -e @EX_BIN_DIR@/$PROCESSOR1 &
|
||||||
|
|
||||||
|
PROCESSOR2="fairmq-ex-region-processor"
|
||||||
|
PROCESSOR2+=" --id processor2"
|
||||||
|
PROCESSOR2+=" --severity debug"
|
||||||
|
PROCESSOR2+=" --transport $transport"
|
||||||
|
PROCESSOR2+=" --shmid 1"
|
||||||
|
PROCESSOR2+=" --shm-segment-id 2"
|
||||||
|
PROCESSOR2+=" --shm-monitor false"
|
||||||
|
PROCESSOR2+=" --shm-no-cleanup true"
|
||||||
|
PROCESSOR2+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||||
|
PROCESSOR2+=" name=data2,type=push,method=bind,address=tcp://127.0.0.1:7788"
|
||||||
|
PROCESSOR2+=" name=data3,type=push,method=bind,address=tcp://127.0.0.1:7789"
|
||||||
|
xterm -geometry 90x40+550+600 -hold -e @EX_BIN_DIR@/$PROCESSOR2 &
|
||||||
|
|
||||||
|
SINK1_1="fairmq-ex-region-sink"
|
||||||
|
SINK1_1+=" --id sink1_1"
|
||||||
|
SINK1_1+=" --severity debug"
|
||||||
|
SINK1_1+=" --chan-name data2"
|
||||||
|
SINK1_1+=" --transport $transport"
|
||||||
|
SINK1_1+=" --shmid 1"
|
||||||
|
SINK1_1+=" --shm-segment-id 1"
|
||||||
|
SINK1_1+=" --shm-monitor false"
|
||||||
|
SINK1_1+=" --shm-no-cleanup true"
|
||||||
|
SINK1_1+=" --channel-config name=data2,type=pull,method=connect,address=tcp://127.0.0.1:7778"
|
||||||
|
xterm -geometry 90x20+1100+0 -hold -e @EX_BIN_DIR@/$SINK1_1 &
|
||||||
|
|
||||||
|
SINK1_2="fairmq-ex-region-sink"
|
||||||
|
SINK1_2+=" --id sink1_2"
|
||||||
|
SINK1_2+=" --severity debug"
|
||||||
|
SINK1_2+=" --chan-name data3"
|
||||||
|
SINK1_2+=" --transport $transport"
|
||||||
|
SINK1_2+=" --shmid 1"
|
||||||
|
SINK1_2+=" --shm-segment-id 1"
|
||||||
|
SINK1_2+=" --shm-monitor false"
|
||||||
|
SINK1_2+=" --shm-no-cleanup true"
|
||||||
|
SINK1_2+=" --channel-config name=data3,type=pull,method=connect,address=tcp://127.0.0.1:7779"
|
||||||
|
xterm -geometry 90x20+1100+300 -hold -e @EX_BIN_DIR@/$SINK1_2 &
|
||||||
|
|
||||||
|
SINK2_1="fairmq-ex-region-sink"
|
||||||
|
SINK2_1+=" --id sink2_1"
|
||||||
|
SINK2_1+=" --severity debug"
|
||||||
|
SINK2_1+=" --chan-name data2"
|
||||||
|
SINK2_1+=" --transport $transport"
|
||||||
|
SINK2_1+=" --shmid 1"
|
||||||
|
SINK2_1+=" --shm-segment-id 2"
|
||||||
|
SINK2_1+=" --shm-monitor false"
|
||||||
|
SINK2_1+=" --shm-no-cleanup true"
|
||||||
|
SINK2_1+=" --channel-config name=data2,type=pull,method=connect,address=tcp://127.0.0.1:7788"
|
||||||
|
xterm -geometry 90x20+1100+600 -hold -e @EX_BIN_DIR@/$SINK2_1 &
|
||||||
|
|
||||||
|
SINK2_2="fairmq-ex-region-sink"
|
||||||
|
SINK2_2+=" --id sink2_2"
|
||||||
|
SINK2_2+=" --severity debug"
|
||||||
|
SINK2_2+=" --chan-name data3"
|
||||||
|
SINK2_2+=" --transport $transport"
|
||||||
|
SINK2_2+=" --shmid 1"
|
||||||
|
SINK2_2+=" --shm-segment-id 2"
|
||||||
|
SINK2_2+=" --shm-monitor false"
|
||||||
|
SINK2_2+=" --shm-no-cleanup true"
|
||||||
|
SINK2_2+=" --channel-config name=data3,type=pull,method=connect,address=tcp://127.0.0.1:7789"
|
||||||
|
xterm -geometry 90x20+1100+900 -hold -e @EX_BIN_DIR@/$SINK2_2 &
|
80
examples/region/fairmq-start-ex-region-advanced.sh.in
Executable file
80
examples/region/fairmq-start-ex-region-advanced.sh.in
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||||
|
|
||||||
|
transport=${1:-shmem}
|
||||||
|
msgSize=${2:-1000000}
|
||||||
|
|
||||||
|
SAMPLER="fairmq-ex-region-sampler"
|
||||||
|
SAMPLER+=" --id sampler1"
|
||||||
|
# SAMPLER+=" --sampling-rate 10"
|
||||||
|
SAMPLER+=" --severity debug"
|
||||||
|
SAMPLER+=" --msg-size $msgSize"
|
||||||
|
SAMPLER+=" --transport $transport"
|
||||||
|
#SAMPLER+=" --rc-segment-size 0"
|
||||||
|
SAMPLER+=" --shm-monitor true"
|
||||||
|
SAMPLER+=" --chan-name data1"
|
||||||
|
SAMPLER+=" --channel-config name=data1,type=push,method=bind,address=tcp://127.0.0.1:7777"
|
||||||
|
xterm -geometry 90x60+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
|
||||||
|
|
||||||
|
PROCESSOR1="fairmq-ex-region-processor"
|
||||||
|
PROCESSOR1+=" --id processor1"
|
||||||
|
PROCESSOR1+=" --severity debug"
|
||||||
|
PROCESSOR1+=" --transport $transport"
|
||||||
|
PROCESSOR1+=" --shm-segment-id 1"
|
||||||
|
PROCESSOR1+=" --shm-monitor true"
|
||||||
|
PROCESSOR1+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||||
|
PROCESSOR1+=" name=data2,type=push,method=bind,address=tcp://127.0.0.1:7778"
|
||||||
|
PROCESSOR1+=" name=data3,type=push,method=bind,address=tcp://127.0.0.1:7779"
|
||||||
|
xterm -geometry 90x40+550+40 -hold -e @EX_BIN_DIR@/$PROCESSOR1 &
|
||||||
|
|
||||||
|
PROCESSOR2="fairmq-ex-region-processor"
|
||||||
|
PROCESSOR2+=" --id processor2"
|
||||||
|
PROCESSOR2+=" --severity debug"
|
||||||
|
PROCESSOR2+=" --transport $transport"
|
||||||
|
PROCESSOR2+=" --shm-segment-id 2"
|
||||||
|
PROCESSOR2+=" --shm-monitor true"
|
||||||
|
PROCESSOR2+=" --channel-config name=data1,type=pull,method=connect,address=tcp://127.0.0.1:7777"
|
||||||
|
PROCESSOR2+=" name=data2,type=push,method=bind,address=tcp://127.0.0.1:7788"
|
||||||
|
PROCESSOR2+=" name=data3,type=push,method=bind,address=tcp://127.0.0.1:7789"
|
||||||
|
xterm -geometry 90x40+550+600 -hold -e @EX_BIN_DIR@/$PROCESSOR2 &
|
||||||
|
|
||||||
|
SINK1_1="fairmq-ex-region-sink"
|
||||||
|
SINK1_1+=" --id sink1_1"
|
||||||
|
SINK1_1+=" --severity debug"
|
||||||
|
SINK1_1+=" --chan-name data2"
|
||||||
|
SINK1_1+=" --transport $transport"
|
||||||
|
SINK1_1+=" --shm-segment-id 1"
|
||||||
|
SINK1_1+=" --shm-monitor true"
|
||||||
|
SINK1_1+=" --channel-config name=data2,type=pull,method=connect,address=tcp://127.0.0.1:7778"
|
||||||
|
xterm -geometry 90x20+1100+0 -hold -e @EX_BIN_DIR@/$SINK1_1 &
|
||||||
|
|
||||||
|
SINK1_2="fairmq-ex-region-sink"
|
||||||
|
SINK1_2+=" --id sink1_2"
|
||||||
|
SINK1_2+=" --severity debug"
|
||||||
|
SINK1_2+=" --chan-name data3"
|
||||||
|
SINK1_2+=" --transport $transport"
|
||||||
|
SINK1_2+=" --shm-segment-id 1"
|
||||||
|
SINK1_2+=" --shm-monitor true"
|
||||||
|
SINK1_2+=" --channel-config name=data3,type=pull,method=connect,address=tcp://127.0.0.1:7779"
|
||||||
|
xterm -geometry 90x20+1100+300 -hold -e @EX_BIN_DIR@/$SINK1_2 &
|
||||||
|
|
||||||
|
SINK2_1="fairmq-ex-region-sink"
|
||||||
|
SINK2_1+=" --id sink2_1"
|
||||||
|
SINK2_1+=" --severity debug"
|
||||||
|
SINK2_1+=" --chan-name data2"
|
||||||
|
SINK2_1+=" --transport $transport"
|
||||||
|
SINK2_1+=" --shm-segment-id 2"
|
||||||
|
SINK2_1+=" --shm-monitor true"
|
||||||
|
SINK2_1+=" --channel-config name=data2,type=pull,method=connect,address=tcp://127.0.0.1:7788"
|
||||||
|
xterm -geometry 90x20+1100+600 -hold -e @EX_BIN_DIR@/$SINK2_1 &
|
||||||
|
|
||||||
|
SINK2_2="fairmq-ex-region-sink"
|
||||||
|
SINK2_2+=" --id sink2_2"
|
||||||
|
SINK2_2+=" --severity debug"
|
||||||
|
SINK2_2+=" --chan-name data3"
|
||||||
|
SINK2_2+=" --transport $transport"
|
||||||
|
SINK2_2+=" --shm-segment-id 2"
|
||||||
|
SINK2_2+=" --shm-monitor true"
|
||||||
|
SINK2_2+=" --channel-config name=data3,type=pull,method=connect,address=tcp://127.0.0.1:7789"
|
||||||
|
xterm -geometry 90x20+1100+900 -hold -e @EX_BIN_DIR@/$SINK2_2 &
|
|
@ -2,16 +2,8 @@
|
||||||
|
|
||||||
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
|
||||||
|
|
||||||
transport="shmem"
|
transport=${1:-shmem}
|
||||||
msgSize="1000000"
|
msgSize=${2:-1000000}
|
||||||
|
|
||||||
if [[ $1 =~ ^[a-z]+$ ]]; then
|
|
||||||
transport=$1
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $2 =~ ^[0-9]+$ ]]; then
|
|
||||||
msgSize=$1
|
|
||||||
fi
|
|
||||||
|
|
||||||
SAMPLER="fairmq-ex-region-sampler"
|
SAMPLER="fairmq-ex-region-sampler"
|
||||||
SAMPLER+=" --id sampler1"
|
SAMPLER+=" --id sampler1"
|
||||||
|
|
|
@ -95,10 +95,11 @@ struct ShmManager
|
||||||
uint64_t size = stoull(conf.at(1));
|
uint64_t size = stoull(conf.at(1));
|
||||||
fair::mq::RegionConfig cfg;
|
fair::mq::RegionConfig cfg;
|
||||||
cfg.id = id;
|
cfg.id = id;
|
||||||
|
cfg.rcSegmentSize = 0;
|
||||||
cfg.size = size;
|
cfg.size = size;
|
||||||
regionCfgs.push_back(cfg);
|
regionCfgs.push_back(cfg);
|
||||||
|
|
||||||
auto ret = regions.emplace(id, make_unique<fair::mq::shmem::UnmanagedRegion>(shmId, id, size));
|
auto ret = regions.emplace(id, make_unique<fair::mq::shmem::UnmanagedRegion>(shmId, cfg));
|
||||||
fair::mq::shmem::UnmanagedRegion& region = *(ret.first->second);
|
fair::mq::shmem::UnmanagedRegion& region = *(ret.first->second);
|
||||||
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize()
|
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize()
|
||||||
<< ", starting at " << region.GetData() << ". Locking...";
|
<< ", starting at " << region.GetData() << ". Locking...";
|
||||||
|
|
80
examples/region/processor.cxx
Normal file
80
examples/region/processor.cxx
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* 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 <fairmq/Device.h>
|
||||||
|
#include <fairmq/runDevice.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace bpo = boost::program_options;
|
||||||
|
using namespace std;
|
||||||
|
using namespace fair::mq;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct Processor : Device
|
||||||
|
{
|
||||||
|
void InitTask() override
|
||||||
|
{
|
||||||
|
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||||
|
GetChannel("data1", 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run() override
|
||||||
|
{
|
||||||
|
Channel& dataIn = GetChannel("data1", 0);
|
||||||
|
Channel& dataOut1 = GetChannel("data2", 0);
|
||||||
|
Channel& dataOut2 = GetChannel("data3", 0);
|
||||||
|
|
||||||
|
while (!NewStatePending()) {
|
||||||
|
fair::mq::Parts inParts;
|
||||||
|
dataIn.Receive(inParts);
|
||||||
|
|
||||||
|
fair::mq::Parts outParts1;
|
||||||
|
fair::mq::Parts outParts2;
|
||||||
|
|
||||||
|
for (const auto& inPart : inParts) {
|
||||||
|
outParts1.AddPart(NewMessage());
|
||||||
|
outParts1.fParts.back()->Copy(*inPart);
|
||||||
|
|
||||||
|
outParts2.AddPart(NewMessage());
|
||||||
|
outParts2.fParts.back()->Copy(*inPart);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataOut1.Send(outParts1);
|
||||||
|
dataOut2.Send(outParts2);
|
||||||
|
|
||||||
|
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||||
|
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ResetTask() override
|
||||||
|
{
|
||||||
|
GetChannel("data1", 0).Transport()->UnsubscribeFromRegionEvents();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
uint64_t fMaxIterations = 0;
|
||||||
|
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)");
|
||||||
|
}
|
||||||
|
|
||||||
|
unique_ptr<Device> getDevice(ProgOptions& /*config*/) { return make_unique<Processor>(); }
|
|
@ -8,6 +8,7 @@
|
||||||
|
|
||||||
#include <fairmq/Device.h>
|
#include <fairmq/Device.h>
|
||||||
#include <fairmq/runDevice.h>
|
#include <fairmq/runDevice.h>
|
||||||
|
#include <fairmq/tools/RateLimit.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
@ -23,8 +24,11 @@ struct Sampler : fair::mq::Device
|
||||||
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
fMsgSize = fConfig->GetProperty<int>("msg-size");
|
||||||
fLinger = fConfig->GetProperty<uint32_t>("region-linger");
|
fLinger = fConfig->GetProperty<uint32_t>("region-linger");
|
||||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||||
|
fChanName = fConfig->GetProperty<std::string>("chan-name");
|
||||||
|
fSamplingRate = fConfig->GetProperty<float>("sampling-rate");
|
||||||
|
fRCSegmentSize = fConfig->GetProperty<uint64_t>("rc-segment-size");
|
||||||
|
|
||||||
GetChannel("data", 0).Transport()->SubscribeToRegionEvents([](fair::mq::RegionInfo info) {
|
GetChannel(fChanName, 0).Transport()->SubscribeToRegionEvents([](fair::mq::RegionInfo info) {
|
||||||
LOG(info) << "Region event: " << info.event << ": "
|
LOG(info) << "Region event: " << info.event << ": "
|
||||||
<< (info.managed ? "managed" : "unmanaged")
|
<< (info.managed ? "managed" : "unmanaged")
|
||||||
<< ", id: " << info.id
|
<< ", id: " << info.id
|
||||||
|
@ -42,8 +46,9 @@ struct Sampler : fair::mq::Device
|
||||||
}
|
}
|
||||||
regionCfg.lock = !fExternalRegion; // mlock region after creation
|
regionCfg.lock = !fExternalRegion; // mlock region after creation
|
||||||
regionCfg.zero = !fExternalRegion; // zero region content after creation
|
regionCfg.zero = !fExternalRegion; // zero region content after creation
|
||||||
|
regionCfg.rcSegmentSize = fRCSegmentSize; // size of the corresponding reference count segment
|
||||||
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor(
|
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor(
|
||||||
"data", // region is created using the transport of this channel...
|
fChanName, // region is created using the transport of this channel...
|
||||||
0, // ... and this sub-channel
|
0, // ... and this sub-channel
|
||||||
10000000, // region size
|
10000000, // region size
|
||||||
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
|
||||||
|
@ -59,22 +64,33 @@ struct Sampler : fair::mq::Device
|
||||||
|
|
||||||
void Run() override
|
void Run() override
|
||||||
{
|
{
|
||||||
|
|
||||||
|
fair::mq::tools::RateLimiter rateLimiter(fSamplingRate);
|
||||||
|
|
||||||
while (!NewStatePending()) {
|
while (!NewStatePending()) {
|
||||||
fair::mq::MessagePtr msg(NewMessageFor("data", // channel
|
fair::mq::Parts parts;
|
||||||
|
// make 64 parts
|
||||||
|
for (int i = 0; i < 64; ++i) {
|
||||||
|
parts.AddPart(NewMessageFor(
|
||||||
|
fChanName, // channel
|
||||||
0, // sub-channel
|
0, // sub-channel
|
||||||
fRegion, // region
|
fRegion, // region
|
||||||
fRegion->GetData(), // ptr within region
|
fRegion->GetData(), // ptr within region
|
||||||
fMsgSize, // offset from ptr
|
fMsgSize, // offset from ptr
|
||||||
nullptr // hint
|
nullptr // hint
|
||||||
));
|
));
|
||||||
|
}
|
||||||
|
|
||||||
std::lock_guard<std::mutex> lock(fMtx);
|
std::lock_guard<std::mutex> lock(fMtx);
|
||||||
++fNumUnackedMsgs;
|
fNumUnackedMsgs += parts.Size();
|
||||||
if (Send(msg, "data", 0) > 0) {
|
if (Send(parts, fChanName, 0) > 0) {
|
||||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||||
LOG(info) << "Configured maximum number of iterations reached. Stopping sending.";
|
LOG(info) << "Configured maximum number of iterations reached. Stopping sending.";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (fSamplingRate > 0.001) {
|
||||||
|
rateLimiter.maybe_sleep();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,7 +115,7 @@ struct Sampler : fair::mq::Device
|
||||||
void ResetTask() override
|
void ResetTask() override
|
||||||
{
|
{
|
||||||
fRegion.reset();
|
fRegion.reset();
|
||||||
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
|
GetChannel(fChanName, 0).Transport()->UnsubscribeFromRegionEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -108,18 +124,24 @@ struct Sampler : fair::mq::Device
|
||||||
uint32_t fLinger = 100;
|
uint32_t fLinger = 100;
|
||||||
uint64_t fMaxIterations = 0;
|
uint64_t fMaxIterations = 0;
|
||||||
uint64_t fNumIterations = 0;
|
uint64_t fNumIterations = 0;
|
||||||
|
uint64_t fRCSegmentSize = 10000000;
|
||||||
fair::mq::UnmanagedRegionPtr fRegion = nullptr;
|
fair::mq::UnmanagedRegionPtr fRegion = nullptr;
|
||||||
std::mutex fMtx;
|
std::mutex fMtx;
|
||||||
uint64_t fNumUnackedMsgs = 0;
|
uint64_t fNumUnackedMsgs = 0;
|
||||||
|
std::string fChanName;
|
||||||
|
float fSamplingRate = 0.;
|
||||||
};
|
};
|
||||||
|
|
||||||
void addCustomOptions(bpo::options_description& options)
|
void addCustomOptions(bpo::options_description& options)
|
||||||
{
|
{
|
||||||
options.add_options()
|
options.add_options()
|
||||||
|
("chan-name", bpo::value<std::string>()->default_value("data"), "name of the output channel")
|
||||||
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
|
("msg-size", bpo::value<int>()->default_value(1000), "Message size in bytes")
|
||||||
|
("sampling-rate", bpo::value<float>()->default_value(0.), "Sampling rate (Hz).")
|
||||||
("region-linger", bpo::value<uint32_t>()->default_value(100), "Linger period for regions")
|
("region-linger", bpo::value<uint32_t>()->default_value(100), "Linger period for regions")
|
||||||
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)")
|
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)")
|
||||||
("external-region", bpo::value<bool>()->default_value(false), "Use region created by another process");
|
("external-region", bpo::value<bool>()->default_value(false), "Use region created by another process")
|
||||||
|
("rc-segment-size", bpo::value<uint64_t>()->default_value(10000000), "Size of the reference count segment for Unamanged Region");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /*config*/)
|
std::unique_ptr<fair::mq::Device> getDevice(fair::mq::ProgOptions& /*config*/)
|
||||||
|
|
|
@ -22,7 +22,8 @@ struct Sink : Device
|
||||||
{
|
{
|
||||||
// Get the fMaxIterations value from the command line options (via fConfig)
|
// Get the fMaxIterations value from the command line options (via fConfig)
|
||||||
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
fMaxIterations = fConfig->GetProperty<uint64_t>("max-iterations");
|
||||||
GetChannel("data", 0).Transport()->SubscribeToRegionEvents([](RegionInfo info) {
|
fChanName = fConfig->GetProperty<std::string>("chan-name");
|
||||||
|
GetChannel(fChanName, 0).Transport()->SubscribeToRegionEvents([](RegionInfo info) {
|
||||||
LOG(info) << "Region event: " << info.event << ": "
|
LOG(info) << "Region event: " << info.event << ": "
|
||||||
<< (info.managed ? "managed" : "unmanaged") << ", id: " << info.id
|
<< (info.managed ? "managed" : "unmanaged") << ", id: " << info.id
|
||||||
<< ", ptr: " << info.ptr << ", size: " << info.size
|
<< ", ptr: " << info.ptr << ", size: " << info.size
|
||||||
|
@ -32,15 +33,11 @@ struct Sink : Device
|
||||||
|
|
||||||
void Run() override
|
void Run() override
|
||||||
{
|
{
|
||||||
Channel& dataInChannel = GetChannel("data", 0);
|
Channel& dataIn = GetChannel(fChanName, 0);
|
||||||
|
|
||||||
while (!NewStatePending()) {
|
while (!NewStatePending()) {
|
||||||
auto msg(dataInChannel.Transport()->CreateMessage());
|
fair::mq::Parts parts;
|
||||||
dataInChannel.Receive(msg);
|
dataIn.Receive(parts);
|
||||||
|
|
||||||
// void* ptr = msg->GetData();
|
|
||||||
// char* cptr = static_cast<char*>(ptr);
|
|
||||||
// LOG(info) << "check: " << cptr[3];
|
|
||||||
|
|
||||||
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
|
||||||
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
|
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
|
||||||
|
@ -51,22 +48,22 @@ struct Sink : Device
|
||||||
|
|
||||||
void ResetTask() override
|
void ResetTask() override
|
||||||
{
|
{
|
||||||
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
|
GetChannel(fChanName, 0).Transport()->UnsubscribeFromRegionEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint64_t fMaxIterations = 0;
|
uint64_t fMaxIterations = 0;
|
||||||
uint64_t fNumIterations = 0;
|
uint64_t fNumIterations = 0;
|
||||||
|
std::string fChanName;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void addCustomOptions(bpo::options_description& options)
|
void addCustomOptions(bpo::options_description& options)
|
||||||
{
|
{
|
||||||
options.add_options()(
|
options.add_options()
|
||||||
"max-iterations",
|
("chan-name", bpo::value<std::string>()->default_value("data"), "name of the input channel")
|
||||||
bpo::value<uint64_t>()->default_value(0),
|
("max-iterations", bpo::value<uint64_t>()->default_value(0), "Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
||||||
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unique_ptr<Device> getDevice(ProgOptions& /*config*/) { return make_unique<Sink>(); }
|
unique_ptr<Device> getDevice(ProgOptions& /*config*/) { return make_unique<Sink>(); }
|
||||||
|
|
2
extern/googletest
vendored
2
extern/googletest
vendored
|
@ -1 +1 @@
|
||||||
Subproject commit a1cc8c55195661a58ad60c3bb062a0b9c302710d
|
Subproject commit 7d76a231b0e29caf86e68d1df858308cd53b2a66
|
|
@ -1,5 +1,5 @@
|
||||||
################################################################################
|
################################################################################
|
||||||
# Copyright (C) 2012-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
# Copyright (C) 2012-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
|
||||||
# #
|
# #
|
||||||
# This software is distributed under the terms of the #
|
# This software is distributed under the terms of the #
|
||||||
# GNU Lesser General Public Licence (LGPL) version 3, #
|
# GNU Lesser General Public Licence (LGPL) version 3, #
|
||||||
|
@ -63,14 +63,21 @@ if(BUILD_FAIRMQ)
|
||||||
Tools.h
|
Tools.h
|
||||||
TransportFactory.h
|
TransportFactory.h
|
||||||
Transports.h
|
Transports.h
|
||||||
|
TransportEnum.h
|
||||||
UnmanagedRegion.h
|
UnmanagedRegion.h
|
||||||
options/FairMQProgOptions.h
|
options/FairMQProgOptions.h
|
||||||
runDevice.h
|
runDevice.h
|
||||||
runFairMQDevice.h
|
runFairMQDevice.h
|
||||||
shmem/Common.h
|
shmem/Common.h
|
||||||
|
shmem/Manager.h
|
||||||
|
shmem/Message.h
|
||||||
shmem/Monitor.h
|
shmem/Monitor.h
|
||||||
|
shmem/Poller.h
|
||||||
shmem/Segment.h
|
shmem/Segment.h
|
||||||
|
shmem/Socket.h
|
||||||
|
shmem/TransportFactory.h
|
||||||
shmem/UnmanagedRegion.h
|
shmem/UnmanagedRegion.h
|
||||||
|
shmem/UnmanagedRegionImpl.h
|
||||||
tools/Compiler.h
|
tools/Compiler.h
|
||||||
tools/CppSTL.h
|
tools/CppSTL.h
|
||||||
tools/Exceptions.h
|
tools/Exceptions.h
|
||||||
|
@ -95,12 +102,6 @@ if(BUILD_FAIRMQ)
|
||||||
plugins/Builtin.h
|
plugins/Builtin.h
|
||||||
plugins/config/Config.h
|
plugins/config/Config.h
|
||||||
plugins/control/Control.h
|
plugins/control/Control.h
|
||||||
shmem/Message.h
|
|
||||||
shmem/Poller.h
|
|
||||||
shmem/UnmanagedRegionImpl.h
|
|
||||||
shmem/Socket.h
|
|
||||||
shmem/TransportFactory.h
|
|
||||||
shmem/Manager.h
|
|
||||||
zeromq/Common.h
|
zeromq/Common.h
|
||||||
zeromq/Context.h
|
zeromq/Context.h
|
||||||
zeromq/Message.h
|
zeromq/Message.h
|
||||||
|
@ -118,6 +119,7 @@ if(BUILD_FAIRMQ)
|
||||||
Channel.cxx
|
Channel.cxx
|
||||||
Device.cxx
|
Device.cxx
|
||||||
DeviceRunner.cxx
|
DeviceRunner.cxx
|
||||||
|
EventManager.cxx
|
||||||
JSONParser.cxx
|
JSONParser.cxx
|
||||||
MemoryResources.cxx
|
MemoryResources.cxx
|
||||||
Plugin.cxx
|
Plugin.cxx
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
#include <fairmq/Channel.h>
|
#include <fairmq/Channel.h>
|
||||||
#include <fairmq/Properties.h>
|
#include <fairmq/Properties.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
|
#include <fairmq/Transports.h>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include <set>
|
#include <set>
|
||||||
|
@ -383,4 +384,10 @@ bool Channel::BindEndpoint(string& endpoint)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Channel::GetTransportName() const { return TransportName(fTransportType); }
|
||||||
|
|
||||||
|
Transport Channel::GetTransportType() const { return fTransportType; }
|
||||||
|
|
||||||
|
void Channel::UpdateTransport(const std::string& transport) { fTransportType = TransportType(transport); Invalidate(); }
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#include <fairmq/Properties.h>
|
#include <fairmq/Properties.h>
|
||||||
#include <fairmq/Socket.h>
|
#include <fairmq/Socket.h>
|
||||||
#include <fairmq/TransportFactory.h>
|
#include <fairmq/TransportFactory.h>
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/TransportEnum.h>
|
||||||
#include <fairmq/UnmanagedRegion.h>
|
#include <fairmq/UnmanagedRegion.h>
|
||||||
|
|
||||||
#include <cstdint> // int64_t
|
#include <cstdint> // int64_t
|
||||||
|
@ -145,11 +145,11 @@ class Channel
|
||||||
|
|
||||||
/// Get channel transport name ("default", "zeromq" or "shmem")
|
/// Get channel transport name ("default", "zeromq" or "shmem")
|
||||||
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
|
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
|
||||||
std::string GetTransportName() const { return TransportName(fTransportType); }
|
std::string GetTransportName() const;
|
||||||
|
|
||||||
/// Get channel transport type
|
/// Get channel transport type
|
||||||
/// @return Returns channel transport type
|
/// @return Returns channel transport type
|
||||||
mq::Transport GetTransportType() const { return fTransportType; }
|
mq::Transport GetTransportType() const;
|
||||||
|
|
||||||
/// Get socket send buffer size (in number of messages)
|
/// Get socket send buffer size (in number of messages)
|
||||||
/// @return Returns socket send buffer size (in number of messages)
|
/// @return Returns socket send buffer size (in number of messages)
|
||||||
|
@ -221,7 +221,7 @@ class Channel
|
||||||
|
|
||||||
/// Set channel transport
|
/// Set channel transport
|
||||||
/// @param transport transport string ("default", "zeromq" or "shmem")
|
/// @param transport transport string ("default", "zeromq" or "shmem")
|
||||||
void UpdateTransport(const std::string& transport) { fTransportType = TransportType(transport); Invalidate(); }
|
void UpdateTransport(const std::string& transport);
|
||||||
|
|
||||||
/// Set socket send buffer size
|
/// Set socket send buffer size
|
||||||
/// @param sndBufSize Socket send buffer size (in number of messages)
|
/// @param sndBufSize Socket send buffer size (in number of messages)
|
||||||
|
@ -438,7 +438,7 @@ class Channel
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckSendCompatibility(Parts& parts) { CheckSendCompatibility(parts.fParts); }
|
void CheckSendCompatibility(Parts& parts) { CheckSendCompatibility(parts.fParts); }
|
||||||
void CheckSendCompatibility(std::vector<MessagePtr>& msgVec)
|
void CheckSendCompatibility(Parts::container & msgVec)
|
||||||
{
|
{
|
||||||
for (auto& msg : msgVec) {
|
for (auto& msg : msgVec) {
|
||||||
if (fTransportType != msg->GetType()) {
|
if (fTransportType != msg->GetType()) {
|
||||||
|
@ -468,7 +468,7 @@ class Channel
|
||||||
}
|
}
|
||||||
|
|
||||||
void CheckReceiveCompatibility(Parts& parts) { CheckReceiveCompatibility(parts.fParts); }
|
void CheckReceiveCompatibility(Parts& parts) { CheckReceiveCompatibility(parts.fParts); }
|
||||||
void CheckReceiveCompatibility(std::vector<MessagePtr>& msgVec)
|
void CheckReceiveCompatibility(Parts::container& msgVec)
|
||||||
{
|
{
|
||||||
for (auto& msg : msgVec) {
|
for (auto& msg : msgVec) {
|
||||||
if (fTransportType != msg->GetType()) {
|
if (fTransportType != msg->GetType()) {
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
// FairMQ
|
// FairMQ
|
||||||
#include <fairmq/Device.h>
|
#include <fairmq/Device.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
|
#include <fairmq/Transports.h>
|
||||||
|
|
||||||
// boost
|
// boost
|
||||||
#include <boost/algorithm/string.hpp> // join/split
|
#include <boost/algorithm/string.hpp> // join/split
|
||||||
|
@ -176,7 +177,6 @@ void Device::InitWrapper()
|
||||||
|
|
||||||
// Fill the uninitialized channel containers
|
// Fill the uninitialized channel containers
|
||||||
for (auto& channel : GetChannels()) {
|
for (auto& channel : GetChannels()) {
|
||||||
int subChannelIndex = 0;
|
|
||||||
for (auto& subChannel : channel.second) {
|
for (auto& subChannel : channel.second) {
|
||||||
// set channel transport
|
// set channel transport
|
||||||
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << TransportNames.at(subChannel.fTransportType);
|
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << TransportNames.at(subChannel.fTransportType);
|
||||||
|
@ -208,8 +208,6 @@ void Device::InitWrapper()
|
||||||
LOG(error) << "Cannot update configuration. Socket method (bind/connect) for channel '" << subChannel.fName << "' not specified.";
|
LOG(error) << "Cannot update configuration. Socket method (bind/connect) for channel '" << subChannel.fName << "' not specified.";
|
||||||
throw runtime_error(tools::ToString("Cannot update configuration. Socket method (bind/connect) for channel ", subChannel.fName, " not specified."));
|
throw runtime_error(tools::ToString("Cannot update configuration. Socket method (bind/connect) for channel ", subChannel.fName, " not specified."));
|
||||||
}
|
}
|
||||||
|
|
||||||
subChannelIndex++;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +286,7 @@ void Device::AttachChannels(vector<Channel*>& chans)
|
||||||
// remove the channel from the uninitialized container
|
// remove the channel from the uninitialized container
|
||||||
itr = chans.erase(itr);
|
itr = chans.erase(itr);
|
||||||
} else {
|
} else {
|
||||||
LOG(error) << "failed to attach channel " << (*itr)->fName << " (" << (*itr)->fMethod << ")";
|
LOG(error) << "failed to attach channel " << (*itr)->fName << " (" << (*itr)->fMethod << " on " << (*itr)->fAddress << ")";
|
||||||
++itr;
|
++itr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <fairmq/StateQueue.h>
|
#include <fairmq/StateQueue.h>
|
||||||
#include <fairmq/Tools.h>
|
#include <fairmq/Tools.h>
|
||||||
#include <fairmq/TransportFactory.h>
|
#include <fairmq/TransportFactory.h>
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/TransportEnum.h>
|
||||||
#include <fairmq/UnmanagedRegion.h>
|
#include <fairmq/UnmanagedRegion.h>
|
||||||
|
|
||||||
// logger
|
// logger
|
||||||
|
|
20
fairmq/EventManager.cxx
Normal file
20
fairmq/EventManager.cxx
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2025 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 "EventManager.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <typeindex>
|
||||||
|
|
||||||
|
template std::shared_ptr<
|
||||||
|
fair::mq::EventManager::Signal<fair::mq::PropertyChangeAsString, std::string>>
|
||||||
|
fair::mq::EventManager::GetSignal<fair::mq::PropertyChangeAsString, std::string>(
|
||||||
|
const std::pair<std::type_index, std::type_index>& key) const;
|
||||||
|
|
||||||
|
template void fair::mq::EventManager::Subscribe<fair::mq::PropertyChangeAsString, std::string>(
|
||||||
|
const std::string& subscriber,
|
||||||
|
std::function<void(typename fair::mq::PropertyChangeAsString::KeyType, std::string)>);
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2014-2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -57,27 +57,8 @@ class EventManager
|
||||||
template<typename E, typename ...Args>
|
template<typename E, typename ...Args>
|
||||||
using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
|
using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
|
||||||
|
|
||||||
template<typename E, typename ...Args>
|
template<typename E, typename... Args>
|
||||||
auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void
|
auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void;
|
||||||
{
|
|
||||||
const std::type_index event_type_index{typeid(E)};
|
|
||||||
const std::type_index callback_type_index{typeid(std::function<void(typename E::KeyType, Args...)>)};
|
|
||||||
const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
|
|
||||||
const auto connectionsKey = std::make_pair(subscriber, signalsKey);
|
|
||||||
|
|
||||||
const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock{fMutex};
|
|
||||||
|
|
||||||
if (fConnections.find(connectionsKey) != fConnections.end())
|
|
||||||
{
|
|
||||||
fConnections.at(connectionsKey).disconnect();
|
|
||||||
fConnections.erase(connectionsKey);
|
|
||||||
}
|
|
||||||
fConnections.insert({connectionsKey, connection});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename E, typename ...Args>
|
template<typename E, typename ...Args>
|
||||||
auto Unsubscribe(const std::string& subscriber) -> void
|
auto Unsubscribe(const std::string& subscriber) -> void
|
||||||
|
@ -119,12 +100,17 @@ class EventManager
|
||||||
mutable std::mutex fMutex;
|
mutable std::mutex fMutex;
|
||||||
|
|
||||||
template<typename E, typename ...Args>
|
template<typename E, typename ...Args>
|
||||||
auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
|
auto GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>;
|
||||||
{
|
}; /* class EventManager */
|
||||||
|
|
||||||
|
struct PropertyChangeAsString : Event<std::string> {};
|
||||||
|
|
||||||
|
template<typename E, typename... Args>
|
||||||
|
auto EventManager::GetSignal(const SignalsKey& key) const -> std::shared_ptr<Signal<E, Args...>>
|
||||||
|
{
|
||||||
std::lock_guard<std::mutex> lock{fMutex};
|
std::lock_guard<std::mutex> lock{fMutex};
|
||||||
|
|
||||||
if (fSignals.find(key) == fSignals.end())
|
if (fSignals.find(key) == fSignals.end()) {
|
||||||
{
|
|
||||||
// wrapper is needed because boost::signals2::signal is neither copyable nor movable
|
// wrapper is needed because boost::signals2::signal is neither copyable nor movable
|
||||||
// and I don't know how else to insert it into the map
|
// and I don't know how else to insert it into the map
|
||||||
auto signal = std::make_shared<Signal<E, Args...>>();
|
auto signal = std::make_shared<Signal<E, Args...>>();
|
||||||
|
@ -132,8 +118,40 @@ class EventManager
|
||||||
}
|
}
|
||||||
|
|
||||||
return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
|
return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename E, typename... Args>
|
||||||
|
auto EventManager::Subscribe(const std::string& subscriber,
|
||||||
|
std::function<void(typename E::KeyType, Args...)> callback) -> void
|
||||||
|
{
|
||||||
|
const std::type_index event_type_index{typeid(E)};
|
||||||
|
const std::type_index callback_type_index{
|
||||||
|
typeid(std::function<void(typename E::KeyType, Args...)>)};
|
||||||
|
const auto signalsKey = std::make_pair(event_type_index, callback_type_index);
|
||||||
|
const auto connectionsKey = std::make_pair(subscriber, signalsKey);
|
||||||
|
|
||||||
|
const auto connection = GetSignal<E, Args...>(signalsKey)->connect(callback);
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock{fMutex};
|
||||||
|
|
||||||
|
if (fConnections.find(connectionsKey) != fConnections.end()) {
|
||||||
|
fConnections.at(connectionsKey).disconnect();
|
||||||
|
fConnections.erase(connectionsKey);
|
||||||
}
|
}
|
||||||
}; /* class EventManager */
|
fConnections.insert({connectionsKey, connection});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern template std::shared_ptr<
|
||||||
|
fair::mq::EventManager::Signal<fair::mq::PropertyChangeAsString, std::string>>
|
||||||
|
fair::mq::EventManager::GetSignal<fair::mq::PropertyChangeAsString, std::string>(
|
||||||
|
const std::pair<std::type_index, std::type_index>& key) const;
|
||||||
|
|
||||||
|
extern template void
|
||||||
|
fair::mq::EventManager::Subscribe<fair::mq::PropertyChangeAsString, std::string>(
|
||||||
|
const std::string& subscriber,
|
||||||
|
std::function<void(typename fair::mq::PropertyChangeAsString::KeyType, std::string)>);
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
|
|
||||||
#include <boost/container/container_fwd.hpp>
|
#include <boost/container/container_fwd.hpp>
|
||||||
#include <boost/container/flat_map.hpp>
|
#include <boost/container/flat_map.hpp>
|
||||||
#include <boost/container/pmr/memory_resource.hpp>
|
#include <memory_resource>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fairmq/Message.h>
|
#include <fairmq/Message.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -27,7 +27,7 @@ namespace fair::mq {
|
||||||
|
|
||||||
class TransportFactory;
|
class TransportFactory;
|
||||||
using byte = unsigned char;
|
using byte = unsigned char;
|
||||||
namespace pmr = boost::container::pmr;
|
namespace pmr = std::pmr;
|
||||||
|
|
||||||
/// All FairMQ related memory resources need to inherit from this interface
|
/// All FairMQ related memory resources need to inherit from this interface
|
||||||
/// class for the
|
/// class for the
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define FAIR_MQ_MESSAGE_H
|
#define FAIR_MQ_MESSAGE_H
|
||||||
|
|
||||||
#include <cstddef> // for size_t
|
#include <cstddef> // for size_t
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/TransportEnum.h>
|
||||||
#include <memory> // unique_ptr
|
#include <memory> // unique_ptr
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ struct Message
|
||||||
virtual void* GetData() const = 0;
|
virtual void* GetData() const = 0;
|
||||||
virtual size_t GetSize() const = 0;
|
virtual size_t GetSize() const = 0;
|
||||||
|
|
||||||
virtual bool SetUsedSize(size_t size) = 0;
|
virtual bool SetUsedSize(size_t size, Alignment alignment = Alignment{0}) = 0;
|
||||||
|
|
||||||
virtual Transport GetType() const = 0;
|
virtual Transport GetType() const = 0;
|
||||||
TransportFactory* GetTransport() { return fTransport; }
|
TransportFactory* GetTransport() { return fTransport; }
|
||||||
|
@ -76,6 +76,11 @@ struct MessageBadAlloc : std::runtime_error
|
||||||
using std::runtime_error::runtime_error;
|
using std::runtime_error::runtime_error;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct RefCountBadAlloc : std::runtime_error
|
||||||
|
{
|
||||||
|
using std::runtime_error::runtime_error;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
|
||||||
using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
|
using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
|
||||||
|
|
|
@ -448,3 +448,6 @@ void ProgOptions::PrintOptionsRaw() const
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
|
||||||
|
template void fair::mq::ProgOptions::SetProperty<std::string>(const std::string& key, std::string val);
|
||||||
|
template void fair::mq::ProgOptions::SetProperty<int>(const std::string& key, int val);
|
||||||
|
|
|
@ -129,17 +129,7 @@ class ProgOptions
|
||||||
/// @param key
|
/// @param key
|
||||||
/// @param val
|
/// @param val
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void SetProperty(const std::string& key, T val)
|
void SetProperty(const std::string& key, T val);
|
||||||
{
|
|
||||||
std::unique_lock<std::mutex> lock(fMtx);
|
|
||||||
|
|
||||||
SetVarMapValue<typename std::decay<T>::type>(key, val);
|
|
||||||
|
|
||||||
lock.unlock();
|
|
||||||
|
|
||||||
fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);
|
|
||||||
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @brief Updates an existing config property (or fails if it doesn't exist)
|
/// @brief Updates an existing config property (or fails if it doesn't exist)
|
||||||
/// @param key
|
/// @param key
|
||||||
|
@ -275,5 +265,20 @@ class ProgOptions
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fair::mq
|
} // namespace fair::mq
|
||||||
|
template <typename T>
|
||||||
|
void fair::mq::ProgOptions::SetProperty(const std::string& key, T val)
|
||||||
|
{
|
||||||
|
std::unique_lock<std::mutex> lock(fMtx);
|
||||||
|
|
||||||
|
SetVarMapValue<typename std::decay<T>::type>(key, val);
|
||||||
|
|
||||||
|
lock.unlock();
|
||||||
|
|
||||||
|
fEvents.Emit<fair::mq::PropertyChange, typename std::decay<T>::type>(key, val);
|
||||||
|
fEvents.Emit<fair::mq::PropertyChangeAsString, std::string>(key, GetPropertyAsString(key));
|
||||||
|
}
|
||||||
|
|
||||||
|
extern template void fair::mq::ProgOptions::SetProperty<int>(const std::string& key, int val);
|
||||||
|
extern template void fair::mq::ProgOptions::SetProperty<std::string>(const std::string& key, std::string val);
|
||||||
|
|
||||||
#endif /* FAIR_MQ_PROGOPTIONS_H */
|
#endif /* FAIR_MQ_PROGOPTIONS_H */
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2014-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -29,7 +29,6 @@ using Property = boost::any;
|
||||||
using Properties = std::map<std::string, Property>;
|
using Properties = std::map<std::string, Property>;
|
||||||
|
|
||||||
struct PropertyChange : Event<std::string> {};
|
struct PropertyChange : Event<std::string> {};
|
||||||
struct PropertyChangeAsString : Event<std::string> {};
|
|
||||||
|
|
||||||
class PropertyHelper
|
class PropertyHelper
|
||||||
{
|
{
|
||||||
|
|
|
@ -52,8 +52,8 @@ struct Socket
|
||||||
|
|
||||||
virtual int64_t Send(MessagePtr& msg, int timeout = -1) = 0;
|
virtual int64_t Send(MessagePtr& msg, int timeout = -1) = 0;
|
||||||
virtual int64_t Receive(MessagePtr& msg, int timeout = -1) = 0;
|
virtual int64_t Receive(MessagePtr& msg, int timeout = -1) = 0;
|
||||||
virtual int64_t Send(std::vector<std::unique_ptr<Message>>& msgVec, int timeout = -1) = 0;
|
virtual int64_t Send(Parts::container& msgVec, int timeout = -1) = 0;
|
||||||
virtual int64_t Receive(std::vector<std::unique_ptr<Message>>& msgVec, int timeout = -1) = 0;
|
virtual int64_t Receive(Parts::container & msgVec, int timeout = -1) = 0;
|
||||||
virtual int64_t Send(Parts& parts, int timeout = -1) { return Send(parts.fParts, timeout); }
|
virtual int64_t Send(Parts& parts, int timeout = -1) { return Send(parts.fParts, timeout); }
|
||||||
virtual int64_t Receive(Parts& parts, int timeout = -1) { return Receive(parts.fParts, timeout); }
|
virtual int64_t Receive(Parts& parts, int timeout = -1) { return Receive(parts.fParts, timeout); }
|
||||||
|
|
||||||
|
|
|
@ -177,6 +177,7 @@ struct Machine_ : public state_machine_def<Machine_>
|
||||||
atomic<bool> fLastTransitionResult;
|
atomic<bool> fLastTransitionResult;
|
||||||
|
|
||||||
mutex fStateMtx;
|
mutex fStateMtx;
|
||||||
|
mutex fSubscriptionsMtx;
|
||||||
atomic<bool> fNewStatePending;
|
atomic<bool> fNewStatePending;
|
||||||
condition_variable fNewStatePendingCV;
|
condition_variable fNewStatePendingCV;
|
||||||
|
|
||||||
|
@ -310,12 +311,17 @@ try {
|
||||||
|
|
||||||
void StateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
void StateMachine::SubscribeToStateChange(const string& key, function<void(const State)> callback)
|
||||||
{
|
{
|
||||||
static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fStateChangeSignal.connect(callback)});
|
// Check if the key has a integer value as prefix, if yes, decode it.
|
||||||
|
int i = strtol(key.c_str(), nullptr, 10);
|
||||||
|
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||||
|
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
|
||||||
|
fsm->fStateChangeSignalsMap.insert({key, fsm->fStateChangeSignal.connect(i, callback)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::UnsubscribeFromStateChange(const string& key)
|
void StateMachine::UnsubscribeFromStateChange(const string& key)
|
||||||
{
|
{
|
||||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||||
|
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
|
||||||
if (fsm->fStateChangeSignalsMap.count(key)) {
|
if (fsm->fStateChangeSignalsMap.count(key)) {
|
||||||
fsm->fStateChangeSignalsMap.at(key).disconnect();
|
fsm->fStateChangeSignalsMap.at(key).disconnect();
|
||||||
fsm->fStateChangeSignalsMap.erase(key);
|
fsm->fStateChangeSignalsMap.erase(key);
|
||||||
|
@ -355,12 +361,15 @@ void StateMachine::StopHandlingStates()
|
||||||
|
|
||||||
void StateMachine::SubscribeToNewTransition(const string& key, function<void(const Transition)> callback)
|
void StateMachine::SubscribeToNewTransition(const string& key, function<void(const Transition)> callback)
|
||||||
{
|
{
|
||||||
static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignalsMap.insert({key, static_pointer_cast<FairMQFSM>(fFsm)->fNewTransitionSignal.connect(callback)});
|
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||||
|
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
|
||||||
|
fsm->fNewTransitionSignalsMap.insert({key, fsm->fNewTransitionSignal.connect(callback)});
|
||||||
}
|
}
|
||||||
|
|
||||||
void StateMachine::UnsubscribeFromNewTransition(const string& key)
|
void StateMachine::UnsubscribeFromNewTransition(const string& key)
|
||||||
{
|
{
|
||||||
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
|
||||||
|
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
|
||||||
if (fsm->fNewTransitionSignalsMap.count(key)) {
|
if (fsm->fNewTransitionSignalsMap.count(key)) {
|
||||||
fsm->fNewTransitionSignalsMap.at(key).disconnect();
|
fsm->fNewTransitionSignalsMap.at(key).disconnect();
|
||||||
fsm->fNewTransitionSignalsMap.erase(key);
|
fsm->fNewTransitionSignalsMap.erase(key);
|
||||||
|
|
22
fairmq/TransportEnum.h
Normal file
22
fairmq/TransportEnum.h
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/********************************************************************************
|
||||||
|
* Copyright (C) 2014-2025 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_TRANSPORTENUMS_H
|
||||||
|
#define FAIR_MQ_TRANSPORTENUMS_H
|
||||||
|
|
||||||
|
namespace fair::mq {
|
||||||
|
|
||||||
|
enum class Transport {
|
||||||
|
DEFAULT,
|
||||||
|
ZMQ,
|
||||||
|
SHM
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FAIR_MQ_TRANSPORTENUMS_H
|
|
@ -14,7 +14,7 @@
|
||||||
#include <fairmq/Message.h>
|
#include <fairmq/Message.h>
|
||||||
#include <fairmq/Poller.h>
|
#include <fairmq/Poller.h>
|
||||||
#include <fairmq/Socket.h>
|
#include <fairmq/Socket.h>
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/TransportEnum.h>
|
||||||
#include <fairmq/UnmanagedRegion.h>
|
#include <fairmq/UnmanagedRegion.h>
|
||||||
#include <memory> // shared_ptr
|
#include <memory> // shared_ptr
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#define FAIR_MQ_TRANSPORTS_H
|
#define FAIR_MQ_TRANSPORTS_H
|
||||||
|
|
||||||
#include <fairmq/tools/Strings.h>
|
#include <fairmq/tools/Strings.h>
|
||||||
|
#include <fairmq/TransportEnum.h>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
@ -18,13 +19,6 @@
|
||||||
|
|
||||||
namespace fair::mq {
|
namespace fair::mq {
|
||||||
|
|
||||||
enum class Transport
|
|
||||||
{
|
|
||||||
DEFAULT,
|
|
||||||
ZMQ,
|
|
||||||
SHM
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TransportError : std::runtime_error
|
struct TransportError : std::runtime_error
|
||||||
{
|
{
|
||||||
using std::runtime_error::runtime_error;
|
using std::runtime_error::runtime_error;
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#ifndef FAIR_MQ_UNMANAGEDREGION_H
|
#ifndef FAIR_MQ_UNMANAGEDREGION_H
|
||||||
#define FAIR_MQ_UNMANAGEDREGION_H
|
#define FAIR_MQ_UNMANAGEDREGION_H
|
||||||
|
|
||||||
#include <fairmq/Transports.h>
|
#include <fairmq/TransportEnum.h>
|
||||||
|
|
||||||
#include <cstddef> // size_t
|
#include <cstddef> // size_t
|
||||||
#include <cstdint> // uint32_t
|
#include <cstdint> // uint32_t
|
||||||
|
@ -134,6 +134,7 @@ struct RegionConfig
|
||||||
int creationFlags = 0; /// flags passed to the underlying transport on region creation
|
int creationFlags = 0; /// flags passed to the underlying transport on region creation
|
||||||
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
int64_t userFlags = 0; /// custom flags that have no effect on the transport, but can be retrieved from the region by the user
|
||||||
uint64_t size = 0; /// region size
|
uint64_t size = 0; /// region size
|
||||||
|
uint64_t rcSegmentSize = 100000000; /// size of the segment that stores reference counts when "soft"-copying the messages
|
||||||
std::string path = ""; /// file path, if the region is backed by a file
|
std::string path = ""; /// file path, if the region is backed by a file
|
||||||
std::optional<uint16_t> id = std::nullopt; /// region id
|
std::optional<uint16_t> id = std::nullopt; /// region id
|
||||||
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
uint32_t linger = 100; /// delay in ms before region destruction to collect outstanding events
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2018-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
#define FAIRMQ_GIT_DATE "@PROJECT_GIT_DATE@"
|
||||||
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
#define FAIRMQ_REPO_URL "https://github.com/FairRootGroup/FairMQ"
|
||||||
#define FAIRMQ_LICENSE "LGPL-3.0"
|
#define FAIRMQ_LICENSE "LGPL-3.0"
|
||||||
#define FAIRMQ_COPYRIGHT "2012-2023 GSI"
|
#define FAIRMQ_COPYRIGHT "2012-2025 GSI"
|
||||||
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
#define FAIRMQ_BUILD_TYPE "@CMAKE_BUILD_TYPE@"
|
||||||
|
|
||||||
#endif // FAIR_MQ_VERSION_H
|
#endif // FAIR_MQ_VERSION_H
|
||||||
|
|
|
@ -65,13 +65,17 @@ Control::Control(const string& name, Plugin::Version version, const string& main
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TakeDeviceControl();
|
|
||||||
|
|
||||||
auto control = GetProperty<string>("control");
|
auto control = GetProperty<string>("control");
|
||||||
|
|
||||||
|
if (control != "none") {
|
||||||
|
TakeDeviceControl();
|
||||||
|
}
|
||||||
|
|
||||||
if (control == "static") {
|
if (control == "static") {
|
||||||
LOG(debug) << "Running builtin controller: static";
|
LOG(debug) << "Running builtin controller: static";
|
||||||
fControllerThread = thread(&Control::StaticMode, this);
|
fControllerThread = thread(&Control::StaticMode, this);
|
||||||
|
} else if (control == "none") {
|
||||||
|
LOG(debug) << "Builtin controller: disabled";
|
||||||
} else if (control == "gui") {
|
} else if (control == "gui") {
|
||||||
LOG(debug) << "Running builtin controller: gui";
|
LOG(debug) << "Running builtin controller: gui";
|
||||||
fControllerThread = thread(&Control::GUIMode, this);
|
fControllerThread = thread(&Control::GUIMode, this);
|
||||||
|
@ -142,7 +146,7 @@ auto ControlPluginProgramOptions() -> Plugin::ProgOptions
|
||||||
namespace po = boost::program_options;
|
namespace po = boost::program_options;
|
||||||
auto pluginOptions = po::options_description{"Control (builtin) Plugin"};
|
auto pluginOptions = po::options_description{"Control (builtin) Plugin"};
|
||||||
pluginOptions.add_options()
|
pluginOptions.add_options()
|
||||||
("control", po::value<string>()->default_value("dynamic"), "Control mode, 'static' or 'dynamic' (aliases for dynamic are external and interactive)")
|
("control", po::value<string>()->default_value("dynamic"), "Control mode, 'static' or 'dynamic' (aliases for dynamic are external and interactive), 'none', 'gui'")
|
||||||
("catch-signals", po::value<int >()->default_value(1), "Enable signal handling (1/0).");
|
("catch-signals", po::value<int >()->default_value(1), "Enable signal handling (1/0).");
|
||||||
return pluginOptions;
|
return pluginOptions;
|
||||||
}
|
}
|
||||||
|
@ -271,11 +275,11 @@ auto Control::InteractiveMode() -> void
|
||||||
try {
|
try {
|
||||||
RunStartupSequence();
|
RunStartupSequence();
|
||||||
|
|
||||||
if(!fDeviceShutdownRequested) {
|
if (!fDeviceShutdownRequested) {
|
||||||
RunREPL();
|
RunREPL();
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!fDeviceShutdownRequested) {
|
if (!fDeviceShutdownRequested) {
|
||||||
RunShutdownSequence();
|
RunShutdownSequence();
|
||||||
}
|
}
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
} catch (PluginServices::DeviceControlError& e) {
|
||||||
|
@ -404,7 +408,7 @@ try {
|
||||||
// or for device shutdown request (Ctrl-C)
|
// or for device shutdown request (Ctrl-C)
|
||||||
fStateQueue.WaitForNextOrCustom([this]{ return fDeviceShutdownRequested.load(); });
|
fStateQueue.WaitForNextOrCustom([this]{ return fDeviceShutdownRequested.load(); });
|
||||||
|
|
||||||
if(!fDeviceShutdownRequested) {
|
if (!fDeviceShutdownRequested) {
|
||||||
RunShutdownSequence();
|
RunShutdownSequence();
|
||||||
}
|
}
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
} catch (PluginServices::DeviceControlError& e) {
|
||||||
|
@ -421,7 +425,7 @@ try {
|
||||||
// Wait for device shutdown request (Ctrl-C)
|
// Wait for device shutdown request (Ctrl-C)
|
||||||
fStateQueue.WaitForCustom([this]{ return fDeviceShutdownRequested.load(); });
|
fStateQueue.WaitForCustom([this]{ return fDeviceShutdownRequested.load(); });
|
||||||
|
|
||||||
if(!fDeviceShutdownRequested) {
|
if (!fDeviceShutdownRequested) {
|
||||||
RunShutdownSequence();
|
RunShutdownSequence();
|
||||||
}
|
}
|
||||||
} catch (PluginServices::DeviceControlError& e) {
|
} catch (PluginServices::DeviceControlError& e) {
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include <functional> // std::equal_to
|
#include <functional> // std::equal_to
|
||||||
|
|
||||||
#include <boost/functional/hash.hpp>
|
#include <boost/functional/hash.hpp>
|
||||||
|
// #include <boost/interprocess/allocators/adaptive_pool.hpp>
|
||||||
|
#include <boost/interprocess/allocators/node_allocator.hpp>
|
||||||
#include <boost/interprocess/allocators/allocator.hpp>
|
#include <boost/interprocess/allocators/allocator.hpp>
|
||||||
#include <boost/interprocess/containers/map.hpp>
|
#include <boost/interprocess/containers/map.hpp>
|
||||||
#include <boost/interprocess/containers/string.hpp>
|
#include <boost/interprocess/containers/string.hpp>
|
||||||
|
@ -21,10 +23,12 @@
|
||||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||||
#include <boost/interprocess/mem_algo/simple_seq_fit.hpp>
|
#include <boost/interprocess/mem_algo/simple_seq_fit.hpp>
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/variant.hpp>
|
#include <variant>
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
namespace fair::mq::shmem
|
namespace fair::mq::shmem
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -41,6 +45,36 @@ using RBTreeBestFitSegment = boost::interprocess::basic_managed_shared_memory<ch
|
||||||
boost::interprocess::null_index>;
|
boost::interprocess::null_index>;
|
||||||
// boost::interprocess::iset_index>;
|
// boost::interprocess::iset_index>;
|
||||||
|
|
||||||
|
inline std::string MakeShmName(const std::string& shmId, const std::string& type) {
|
||||||
|
return std::string("fmq_" + shmId + "_" + type);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::string MakeShmName(const std::string& shmId, const std::string& type, int index) {
|
||||||
|
return std::string(MakeShmName(shmId, type) + "_" + std::to_string(index));
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RefCount
|
||||||
|
{
|
||||||
|
explicit RefCount(uint16_t c)
|
||||||
|
: count(c)
|
||||||
|
{}
|
||||||
|
|
||||||
|
uint16_t Get() { return count.load(); }
|
||||||
|
uint16_t Increment() { return count.fetch_add(1); }
|
||||||
|
uint16_t Decrement() { return count.fetch_sub(1); }
|
||||||
|
|
||||||
|
std::atomic<uint16_t> count;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Number of nodes allocated at once when the allocator runs out of nodes.
|
||||||
|
static constexpr size_t numNodesPerBlock = 4096;
|
||||||
|
// Maximum number of totally free blocks that the adaptive node pool will hold.
|
||||||
|
// The rest of the totally free blocks will be deallocated with the segment manager.
|
||||||
|
// static constexpr size_t maxFreeBlocks = 2;
|
||||||
|
|
||||||
|
using RefCountPool = boost::interprocess::node_allocator<RefCount, boost::interprocess::managed_shared_memory::segment_manager, numNodesPerBlock>;
|
||||||
|
// using RefCountPool = boost::interprocess::adaptive_pool<RefCount, boost::interprocess::managed_shared_memory::segment_manager, numNodesPerBlock, maxFreeBlocks>;
|
||||||
|
|
||||||
using SegmentManager = boost::interprocess::managed_shared_memory::segment_manager;
|
using SegmentManager = boost::interprocess::managed_shared_memory::segment_manager;
|
||||||
using VoidAlloc = boost::interprocess::allocator<void, SegmentManager>;
|
using VoidAlloc = boost::interprocess::allocator<void, SegmentManager>;
|
||||||
using CharAlloc = boost::interprocess::allocator<char, SegmentManager>;
|
using CharAlloc = boost::interprocess::allocator<char, SegmentManager>;
|
||||||
|
@ -48,6 +82,90 @@ using Str = boost::interprocess::basic_string<char, std::char_traits<
|
||||||
using StrAlloc = boost::interprocess::allocator<Str, SegmentManager>;
|
using StrAlloc = boost::interprocess::allocator<Str, SegmentManager>;
|
||||||
using StrVector = boost::interprocess::vector<Str, StrAlloc>;
|
using StrVector = boost::interprocess::vector<Str, StrAlloc>;
|
||||||
|
|
||||||
|
// ShmHeader stores user buffer alignment and the reference count in the following structure:
|
||||||
|
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
||||||
|
// The alignment of Hdr depends on the alignment of std::atomic and is stored in the first entry
|
||||||
|
struct ShmHeader
|
||||||
|
{
|
||||||
|
struct Hdr
|
||||||
|
{
|
||||||
|
uint16_t userOffset;
|
||||||
|
std::atomic<uint16_t> refCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Hdr* HdrPtr(char* ptr)
|
||||||
|
{
|
||||||
|
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
||||||
|
// ^
|
||||||
|
return reinterpret_cast<Hdr*>(ptr + sizeof(uint16_t) + *(reinterpret_cast<uint16_t*>(ptr)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t HdrPartSize() // [HdrOffset(uint16_t)][Hdr alignment][Hdr]
|
||||||
|
{
|
||||||
|
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
||||||
|
// <--------------------------------------->
|
||||||
|
return sizeof(uint16_t) + alignof(Hdr) + sizeof(Hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::atomic<uint16_t>& RefCountPtr(char* ptr)
|
||||||
|
{
|
||||||
|
// get the ref count ptr from the Hdr
|
||||||
|
return HdrPtr(ptr)->refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t UserOffset(char* ptr)
|
||||||
|
{
|
||||||
|
return HdrPartSize() + HdrPtr(ptr)->userOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* UserPtr(char* ptr)
|
||||||
|
{
|
||||||
|
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
||||||
|
// ^
|
||||||
|
return ptr + HdrPartSize() + HdrPtr(ptr)->userOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t RefCount(char* ptr) { return RefCountPtr(ptr).load(); }
|
||||||
|
static uint16_t IncrementRefCount(char* ptr) { return RefCountPtr(ptr).fetch_add(1); }
|
||||||
|
static uint16_t DecrementRefCount(char* ptr) { return RefCountPtr(ptr).fetch_sub(1); }
|
||||||
|
|
||||||
|
static size_t FullSize(size_t size, size_t alignment)
|
||||||
|
{
|
||||||
|
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
||||||
|
// <--------------------------------------------------------------------------->
|
||||||
|
return HdrPartSize() + alignment + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Construct(char* ptr, size_t alignment)
|
||||||
|
{
|
||||||
|
// place the Hdr in the aligned location, fill it and store its offset to HdrOffset
|
||||||
|
|
||||||
|
// the address alignment should be at least 2
|
||||||
|
assert(reinterpret_cast<uintptr_t>(ptr) % 2 == 0);
|
||||||
|
|
||||||
|
// offset to the beginning of the Hdr. store it in the beginning
|
||||||
|
uint16_t hdrOffset = alignof(Hdr) - ((reinterpret_cast<uintptr_t>(ptr) + sizeof(uint16_t)) % alignof(Hdr));
|
||||||
|
memcpy(ptr, &hdrOffset, sizeof(hdrOffset));
|
||||||
|
|
||||||
|
// offset to the beginning of the user buffer, store in Hdr together with the ref count
|
||||||
|
uint16_t userOffset = alignment - ((reinterpret_cast<uintptr_t>(ptr) + HdrPartSize()) % alignment);
|
||||||
|
new(ptr + sizeof(uint16_t) + hdrOffset) Hdr{ userOffset, std::atomic<uint16_t>(1) };
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Destruct(char* ptr) { RefCountPtr(ptr).~atomic(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MetaHeader
|
||||||
|
{
|
||||||
|
size_t fSize; // size of the shm buffer
|
||||||
|
size_t fHint; // user-defined value, given by the user on message creation and returned to the user on "buffer no longer needed"-callbacks
|
||||||
|
boost::interprocess::managed_shared_memory::handle_t fHandle; // handle to shm buffer, convertible to shm buffer ptr
|
||||||
|
mutable boost::interprocess::managed_shared_memory::handle_t fShared; // handle to the buffer storing the ref count for shared buffers
|
||||||
|
uint16_t fRegionId; // id of the unmanaged region
|
||||||
|
mutable uint16_t fSegmentId; // id of the managed segment
|
||||||
|
bool fManaged; // true = managed segment, false = unmanaged region
|
||||||
|
};
|
||||||
|
|
||||||
enum class AllocationAlgorithm : int
|
enum class AllocationAlgorithm : int
|
||||||
{
|
{
|
||||||
rbtree_best_fit,
|
rbtree_best_fit,
|
||||||
|
@ -56,19 +174,12 @@ enum class AllocationAlgorithm : int
|
||||||
|
|
||||||
struct RegionInfo
|
struct RegionInfo
|
||||||
{
|
{
|
||||||
RegionInfo(const VoidAlloc& alloc)
|
RegionInfo(const char* path, int flags, uint64_t userFlags, uint64_t size, uint64_t rcSegmentSize, const VoidAlloc& alloc)
|
||||||
: fPath("", alloc)
|
|
||||||
, fCreationFlags(0)
|
|
||||||
, fUserFlags(0)
|
|
||||||
, fSize(0)
|
|
||||||
, fDestroyed(false)
|
|
||||||
{}
|
|
||||||
|
|
||||||
RegionInfo(const char* path, int flags, uint64_t userFlags, uint64_t size, const VoidAlloc& alloc)
|
|
||||||
: fPath(path, alloc)
|
: fPath(path, alloc)
|
||||||
, fCreationFlags(flags)
|
, fCreationFlags(flags)
|
||||||
, fUserFlags(userFlags)
|
, fUserFlags(userFlags)
|
||||||
, fSize(size)
|
, fSize(size)
|
||||||
|
, fRCSegmentSize(rcSegmentSize)
|
||||||
, fDestroyed(false)
|
, fDestroyed(false)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
@ -76,6 +187,7 @@ struct RegionInfo
|
||||||
int fCreationFlags;
|
int fCreationFlags;
|
||||||
uint64_t fUserFlags;
|
uint64_t fUserFlags;
|
||||||
uint64_t fSize;
|
uint64_t fSize;
|
||||||
|
uint64_t fRCSegmentSize;
|
||||||
bool fDestroyed;
|
bool fDestroyed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -143,17 +255,6 @@ struct RegionCounter
|
||||||
std::atomic<uint16_t> fCount;
|
std::atomic<uint16_t> fCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MetaHeader
|
|
||||||
{
|
|
||||||
size_t fSize;
|
|
||||||
size_t fHint;
|
|
||||||
boost::interprocess::managed_shared_memory::handle_t fHandle;
|
|
||||||
mutable boost::interprocess::managed_shared_memory::handle_t fShared;
|
|
||||||
uint16_t fRegionId;
|
|
||||||
mutable uint16_t fSegmentId;
|
|
||||||
bool fManaged;
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef FAIRMQ_DEBUG_MODE
|
#ifdef FAIRMQ_DEBUG_MODE
|
||||||
struct MsgCounter
|
struct MsgCounter
|
||||||
{
|
{
|
||||||
|
@ -219,73 +320,7 @@ std::string makeShmIdStr(const std::string& sessionId);
|
||||||
std::string makeShmIdStr(uint64_t val);
|
std::string makeShmIdStr(uint64_t val);
|
||||||
uint64_t makeShmIdUint64(const std::string& sessionId);
|
uint64_t makeShmIdUint64(const std::string& sessionId);
|
||||||
|
|
||||||
|
struct SegmentBufferShrink
|
||||||
struct SegmentSize : public boost::static_visitor<size_t>
|
|
||||||
{
|
|
||||||
template<typename S>
|
|
||||||
size_t operator()(S& s) const { return s.get_size(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentAddress : public boost::static_visitor<void*>
|
|
||||||
{
|
|
||||||
template<typename S>
|
|
||||||
void* operator()(S& s) const { return s.get_address(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentMemoryZeroer : public boost::static_visitor<>
|
|
||||||
{
|
|
||||||
template<typename S>
|
|
||||||
void operator()(S& s) const { s.zero_free_memory(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentFreeMemory : public boost::static_visitor<size_t>
|
|
||||||
{
|
|
||||||
template<typename S>
|
|
||||||
size_t operator()(S& s) const { return s.get_free_memory(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentHandleFromAddress : public boost::static_visitor<boost::interprocess::managed_shared_memory::handle_t>
|
|
||||||
{
|
|
||||||
SegmentHandleFromAddress(const void* _ptr) : ptr(_ptr) {}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
boost::interprocess::managed_shared_memory::handle_t operator()(S& s) const { return s.get_handle_from_address(ptr); }
|
|
||||||
|
|
||||||
const void* ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentAddressFromHandle : public boost::static_visitor<char*>
|
|
||||||
{
|
|
||||||
SegmentAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t _handle) : handle(_handle) {}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
char* operator()(S& s) const { return reinterpret_cast<char*>(s.get_address_from_handle(handle)); }
|
|
||||||
|
|
||||||
const boost::interprocess::managed_shared_memory::handle_t handle;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentAllocate : public boost::static_visitor<char*>
|
|
||||||
{
|
|
||||||
SegmentAllocate(const size_t _size) : size(_size) {}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
char* operator()(S& s) const { return reinterpret_cast<char*>(s.allocate(size)); }
|
|
||||||
|
|
||||||
const size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentAllocateAligned : public boost::static_visitor<void*>
|
|
||||||
{
|
|
||||||
SegmentAllocateAligned(const size_t _size, const size_t _alignment) : size(_size), alignment(_alignment) {}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
void* operator()(S& s) const { return s.allocate_aligned(size, alignment); }
|
|
||||||
|
|
||||||
const size_t size;
|
|
||||||
const size_t alignment;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct SegmentBufferShrink : public boost::static_visitor<char*>
|
|
||||||
{
|
{
|
||||||
SegmentBufferShrink(const size_t _new_size, char* _local_ptr)
|
SegmentBufferShrink(const size_t _new_size, char* _local_ptr)
|
||||||
: new_size(_new_size)
|
: new_size(_new_size)
|
||||||
|
@ -303,16 +338,6 @@ struct SegmentBufferShrink : public boost::static_visitor<char*>
|
||||||
mutable char* local_ptr;
|
mutable char* local_ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct SegmentDeallocate : public boost::static_visitor<>
|
|
||||||
{
|
|
||||||
SegmentDeallocate(char* _ptr) : ptr(_ptr) {}
|
|
||||||
|
|
||||||
template<typename S>
|
|
||||||
void operator()(S& s) const { return s.deallocate(ptr); }
|
|
||||||
|
|
||||||
char* ptr;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace fair::mq::shmem
|
} // namespace fair::mq::shmem
|
||||||
|
|
||||||
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
#endif /* FAIR_MQ_SHMEM_COMMON_H_ */
|
||||||
|
|
|
@ -24,7 +24,6 @@
|
||||||
#include <boost/interprocess/sync/interprocess_condition.hpp>
|
#include <boost/interprocess/sync/interprocess_condition.hpp>
|
||||||
#include <boost/interprocess/sync/interprocess_mutex.hpp>
|
#include <boost/interprocess/sync/interprocess_mutex.hpp>
|
||||||
#include <boost/interprocess/sync/named_mutex.hpp>
|
#include <boost/interprocess/sync/named_mutex.hpp>
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <algorithm> // max
|
#include <algorithm> // max
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
@ -42,6 +41,7 @@
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <utility> // pair
|
#include <utility> // pair
|
||||||
|
#include <variant>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <unistd.h> // getuid
|
#include <unistd.h> // getuid
|
||||||
|
@ -51,79 +51,6 @@
|
||||||
namespace fair::mq::shmem
|
namespace fair::mq::shmem
|
||||||
{
|
{
|
||||||
|
|
||||||
// ShmHeader stores user buffer alignment and the reference count in the following structure:
|
|
||||||
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
|
||||||
// The alignment of Hdr depends on the alignment of std::atomic and is stored in the first entry
|
|
||||||
struct ShmHeader
|
|
||||||
{
|
|
||||||
struct Hdr
|
|
||||||
{
|
|
||||||
uint16_t userOffset;
|
|
||||||
std::atomic<uint16_t> refCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Hdr* HdrPtr(char* ptr)
|
|
||||||
{
|
|
||||||
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
|
||||||
// ^
|
|
||||||
return reinterpret_cast<Hdr*>(ptr + sizeof(uint16_t) + *(reinterpret_cast<uint16_t*>(ptr)));
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t HdrPartSize() // [HdrOffset(uint16_t)][Hdr alignment][Hdr]
|
|
||||||
{
|
|
||||||
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
|
||||||
// <--------------------------------------->
|
|
||||||
return sizeof(uint16_t) + alignof(Hdr) + sizeof(Hdr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::atomic<uint16_t>& RefCountPtr(char* ptr)
|
|
||||||
{
|
|
||||||
// get the ref count ptr from the Hdr
|
|
||||||
return HdrPtr(ptr)->refCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t UserOffset(char* ptr)
|
|
||||||
{
|
|
||||||
return HdrPartSize() + HdrPtr(ptr)->userOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* UserPtr(char* ptr)
|
|
||||||
{
|
|
||||||
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
|
||||||
// ^
|
|
||||||
return ptr + HdrPartSize() + HdrPtr(ptr)->userOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint16_t RefCount(char* ptr) { return RefCountPtr(ptr).load(); }
|
|
||||||
static uint16_t IncrementRefCount(char* ptr) { return RefCountPtr(ptr).fetch_add(1); }
|
|
||||||
static uint16_t DecrementRefCount(char* ptr) { return RefCountPtr(ptr).fetch_sub(1); }
|
|
||||||
|
|
||||||
static size_t FullSize(size_t size, size_t alignment)
|
|
||||||
{
|
|
||||||
// [HdrOffset(uint16_t)][Hdr alignment][Hdr][user buffer alignment][user buffer]
|
|
||||||
// <--------------------------------------------------------------------------->
|
|
||||||
return HdrPartSize() + alignment + size;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Construct(char* ptr, size_t alignment)
|
|
||||||
{
|
|
||||||
// place the Hdr in the aligned location, fill it and store its offset to HdrOffset
|
|
||||||
|
|
||||||
// the address alignment should be at least 2
|
|
||||||
assert(reinterpret_cast<uintptr_t>(ptr) % 2 == 0);
|
|
||||||
|
|
||||||
// offset to the beginning of the Hdr. store it in the beginning
|
|
||||||
uint16_t hdrOffset = alignof(Hdr) - ((reinterpret_cast<uintptr_t>(ptr) + sizeof(uint16_t)) % alignof(Hdr));
|
|
||||||
memcpy(ptr, &hdrOffset, sizeof(hdrOffset));
|
|
||||||
|
|
||||||
// offset to the beginning of the user buffer, store in Hdr together with the ref count
|
|
||||||
uint16_t userOffset = alignment - ((reinterpret_cast<uintptr_t>(ptr) + HdrPartSize()) % alignment);
|
|
||||||
new(ptr + sizeof(uint16_t) + hdrOffset) Hdr{ userOffset, std::atomic<uint16_t>(1) };
|
|
||||||
}
|
|
||||||
|
|
||||||
static void Destruct(char* ptr) { RefCountPtr(ptr).~atomic(); }
|
|
||||||
};
|
|
||||||
|
|
||||||
class Manager
|
class Manager
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -131,7 +58,7 @@ class Manager
|
||||||
: fShmId64(config ? config->GetProperty<uint64_t>("shmid", makeShmIdUint64(sessionName)) : makeShmIdUint64(sessionName))
|
: fShmId64(config ? config->GetProperty<uint64_t>("shmid", makeShmIdUint64(sessionName)) : makeShmIdUint64(sessionName))
|
||||||
, fShmId(makeShmIdStr(fShmId64))
|
, fShmId(makeShmIdStr(fShmId64))
|
||||||
, fSegmentId(config ? config->GetProperty<uint16_t>("shm-segment-id", 0) : 0)
|
, fSegmentId(config ? config->GetProperty<uint16_t>("shm-segment-id", 0) : 0)
|
||||||
, fManagementSegment(boost::interprocess::open_or_create, std::string("fmq_" + fShmId + "_mng").c_str(), kManagementSegmentSize)
|
, fManagementSegment(boost::interprocess::open_or_create, MakeShmName(fShmId, "mng").c_str(), kManagementSegmentSize)
|
||||||
, fShmVoidAlloc(fManagementSegment.get_segment_manager())
|
, fShmVoidAlloc(fManagementSegment.get_segment_manager())
|
||||||
, fShmMtx(fManagementSegment.find_or_construct<boost::interprocess::interprocess_mutex>(boost::interprocess::unique_instance)())
|
, fShmMtx(fManagementSegment.find_or_construct<boost::interprocess::interprocess_mutex>(boost::interprocess::unique_instance)())
|
||||||
, fNumObservedEvents(0)
|
, fNumObservedEvents(0)
|
||||||
|
@ -231,7 +158,7 @@ class Manager
|
||||||
bool createdSegment = false;
|
bool createdSegment = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::string segmentName("fmq_" + fShmId + "_m_" + std::to_string(fSegmentId));
|
std::string segmentName = MakeShmName(fShmId, "m", fSegmentId);
|
||||||
auto it = fShmSegments->find(fSegmentId);
|
auto it = fShmSegments->find(fSegmentId);
|
||||||
if (it == fShmSegments->end()) {
|
if (it == fShmSegments->end()) {
|
||||||
// no segment with given id exists, creating
|
// no segment with given id exists, creating
|
||||||
|
@ -266,8 +193,8 @@ class Manager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LOG(debug) << (createdSegment ? "Created" : "Opened") << " managed shared memory segment " << "fmq_" << fShmId << "_m_" << fSegmentId
|
LOG(debug) << (createdSegment ? "Created" : "Opened") << " managed shared memory segment " << "fmq_" << fShmId << "_m_" << fSegmentId
|
||||||
<< ". Size: " << boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId)) << " bytes."
|
<< ". Size: " << std::visit([](auto& s) { return s.get_size(); }, fSegments.at(fSegmentId)) << " bytes."
|
||||||
<< " Available: " << boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId)) << " bytes."
|
<< " Available: " << std::visit([](auto& s) { return s.get_free_memory(); }, fSegments.at(fSegmentId)) << " bytes."
|
||||||
<< " Allocation algorithm: " << allocationAlgorithm;
|
<< " Allocation algorithm: " << allocationAlgorithm;
|
||||||
} catch (interprocess_exception& bie) {
|
} catch (interprocess_exception& bie) {
|
||||||
LOG(error) << "Failed to create/open shared memory segment '" << "fmq_" << fShmId << "_m_" << fSegmentId << "': " << bie.what();
|
LOG(error) << "Failed to create/open shared memory segment '" << "fmq_" << fShmId << "_m_" << fSegmentId << "': " << bie.what();
|
||||||
|
@ -305,14 +232,16 @@ class Manager
|
||||||
void ZeroSegment(uint16_t id)
|
void ZeroSegment(uint16_t id)
|
||||||
{
|
{
|
||||||
LOG(debug) << "Zeroing the managed segment free memory...";
|
LOG(debug) << "Zeroing the managed segment free memory...";
|
||||||
boost::apply_visitor(SegmentMemoryZeroer(), fSegments.at(id));
|
std::visit([](auto& s) { return s.zero_free_memory(); }, fSegments.at(id));
|
||||||
LOG(debug) << "Successfully zeroed the managed segment free memory.";
|
LOG(debug) << "Successfully zeroed the managed segment free memory.";
|
||||||
}
|
}
|
||||||
|
|
||||||
void MlockSegment(uint16_t id)
|
void MlockSegment(uint16_t id)
|
||||||
{
|
{
|
||||||
LOG(debug) << "Locking the managed segment memory pages...";
|
LOG(debug) << "Locking the managed segment memory pages...";
|
||||||
if (mlock(boost::apply_visitor(SegmentAddress(), fSegments.at(id)), boost::apply_visitor(SegmentSize(), fSegments.at(id))) == -1) {
|
if (mlock(
|
||||||
|
std::visit([](auto& s) { return s.get_address(); }, fSegments.at(id)),
|
||||||
|
std::visit([](auto& s) { return s.get_size(); }, fSegments.at(id))) == -1) {
|
||||||
LOG(error) << "Could not lock the managed segment memory. Code: " << errno << ", reason: " << strerror(errno);
|
LOG(error) << "Could not lock the managed segment memory. Code: " << errno << ", reason: " << strerror(errno);
|
||||||
throw TransportError(tools::ToString("Could not lock the managed segment memory: ", strerror(errno)));
|
throw TransportError(tools::ToString("Could not lock the managed segment memory: ", strerror(errno)));
|
||||||
}
|
}
|
||||||
|
@ -327,7 +256,7 @@ class Manager
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
try {
|
try {
|
||||||
named_mutex monitorStatus(open_only, std::string("fmq_" + id + "_ms").c_str());
|
named_mutex monitorStatus(open_only, MakeShmName(id, "ms").c_str());
|
||||||
LOG(debug) << "Found fairmq-shmmonitor for shared memory id " << id;
|
LOG(debug) << "Found fairmq-shmmonitor for shared memory id " << id;
|
||||||
} catch (interprocess_exception&) {
|
} catch (interprocess_exception&) {
|
||||||
LOG(debug) << "no fairmq-shmmonitor found for shared memory id " << id << ", starting...";
|
LOG(debug) << "no fairmq-shmmonitor found for shared memory id " << id << ", starting...";
|
||||||
|
@ -336,7 +265,7 @@ class Manager
|
||||||
int numTries = 0;
|
int numTries = 0;
|
||||||
do {
|
do {
|
||||||
try {
|
try {
|
||||||
named_mutex monitorStatus(open_only, std::string("fmq_" + id + "_ms").c_str());
|
named_mutex monitorStatus(open_only, MakeShmName(id, "ms").c_str());
|
||||||
LOG(debug) << "Started fairmq-shmmonitor for shared memory id " << id;
|
LOG(debug) << "Started fairmq-shmmonitor for shared memory id " << id;
|
||||||
break;
|
break;
|
||||||
} catch (interprocess_exception&) {
|
} catch (interprocess_exception&) {
|
||||||
|
@ -410,6 +339,12 @@ class Manager
|
||||||
LOG(debug) << "Unmanaged region (view) already present, promoting to controller";
|
LOG(debug) << "Unmanaged region (view) already present, promoting to controller";
|
||||||
region->BecomeController(cfg);
|
region->BecomeController(cfg);
|
||||||
} else {
|
} else {
|
||||||
|
// we need to update local config, if the region information already exists
|
||||||
|
auto info = fShmRegions->find(id);
|
||||||
|
if (info != fShmRegions->end()) {
|
||||||
|
cfg.rcSegmentSize = info->second.fRCSegmentSize;
|
||||||
|
}
|
||||||
|
|
||||||
auto res = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, size, true, cfg));
|
auto res = fRegions.emplace(id, std::make_unique<UnmanagedRegion>(fShmId, size, true, cfg));
|
||||||
region = res.first->second.get();
|
region = res.first->second.get();
|
||||||
}
|
}
|
||||||
|
@ -466,7 +401,8 @@ class Manager
|
||||||
auto it = fRegions.find(id);
|
auto it = fRegions.find(id);
|
||||||
if (it != fRegions.end()) {
|
if (it != fRegions.end()) {
|
||||||
return it->second.get();
|
return it->second.get();
|
||||||
} else {
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
RegionConfig cfg;
|
RegionConfig cfg;
|
||||||
// get region info
|
// get region info
|
||||||
|
@ -475,6 +411,7 @@ class Manager
|
||||||
RegionInfo regionInfo = fShmRegions->at(id);
|
RegionInfo regionInfo = fShmRegions->at(id);
|
||||||
cfg.id = id;
|
cfg.id = id;
|
||||||
cfg.creationFlags = regionInfo.fCreationFlags;
|
cfg.creationFlags = regionInfo.fCreationFlags;
|
||||||
|
cfg.rcSegmentSize = regionInfo.fRCSegmentSize;
|
||||||
cfg.path = regionInfo.fPath.c_str();
|
cfg.path = regionInfo.fPath.c_str();
|
||||||
}
|
}
|
||||||
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
// LOG(debug) << "Located remote region with id '" << id << "', path: '" << cfg.path << "', flags: '" << cfg.creationFlags << "'";
|
||||||
|
@ -492,7 +429,6 @@ class Manager
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveRegion(uint16_t id)
|
void RemoveRegion(uint16_t id)
|
||||||
{
|
{
|
||||||
|
@ -529,8 +465,8 @@ class Manager
|
||||||
info.managed = true;
|
info.managed = true;
|
||||||
info.id = segmentId;
|
info.id = segmentId;
|
||||||
info.event = RegionEvent::created;
|
info.event = RegionEvent::created;
|
||||||
info.ptr = boost::apply_visitor(SegmentAddress(), fSegments.at(segmentId));
|
info.ptr = std::visit([](auto& s) { return s.get_address(); }, fSegments.at(segmentId));
|
||||||
info.size = boost::apply_visitor(SegmentSize(), fSegments.at(segmentId));
|
info.size = std::visit([](auto& s) { return s.get_size(); }, fSegments.at(segmentId));
|
||||||
result.push_back(info);
|
result.push_back(info);
|
||||||
} catch (const std::out_of_range& oor) {
|
} catch (const std::out_of_range& oor) {
|
||||||
LOG(error) << "could not find segment with id " << segmentId;
|
LOG(error) << "could not find segment with id " << segmentId;
|
||||||
|
@ -549,6 +485,7 @@ class Manager
|
||||||
cfg.id = info.id;
|
cfg.id = info.id;
|
||||||
cfg.creationFlags = regionInfo.fCreationFlags;
|
cfg.creationFlags = regionInfo.fCreationFlags;
|
||||||
cfg.path = regionInfo.fPath.c_str();
|
cfg.path = regionInfo.fPath.c_str();
|
||||||
|
cfg.rcSegmentSize = regionInfo.fRCSegmentSize;
|
||||||
regionCfgs.emplace(info.id, cfg);
|
regionCfgs.emplace(info.id, cfg);
|
||||||
// fill the ptr+size info after shmLock is released, to avoid constructing local region under it
|
// fill the ptr+size info after shmLock is released, to avoid constructing local region under it
|
||||||
} else {
|
} else {
|
||||||
|
@ -710,9 +647,9 @@ class Manager
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
|
|
||||||
if (segmentInfo.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
if (segmentInfo.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||||
fSegments.emplace(id, RBTreeBestFitSegment(open_only, std::string("fmq_" + fShmId + "_m_" + std::to_string(id)).c_str()));
|
fSegments.emplace(id, RBTreeBestFitSegment(open_only, MakeShmName(fShmId, "m", id).c_str()));
|
||||||
} else {
|
} else {
|
||||||
fSegments.emplace(id, SimpleSeqFitSegment(open_only, std::string("fmq_" + fShmId + "_m_" + std::to_string(id)).c_str()));
|
fSegments.emplace(id, SimpleSeqFitSegment(open_only, MakeShmName(fShmId, "m", id).c_str()));
|
||||||
}
|
}
|
||||||
} catch (std::out_of_range& oor) {
|
} catch (std::out_of_range& oor) {
|
||||||
LOG(error) << "Could not get segment with id '" << id << "': " << oor.what();
|
LOG(error) << "Could not get segment with id '" << id << "': " << oor.what();
|
||||||
|
@ -724,11 +661,11 @@ class Manager
|
||||||
|
|
||||||
boost::interprocess::managed_shared_memory::handle_t GetHandleFromAddress(const void* ptr, uint16_t segmentId) const
|
boost::interprocess::managed_shared_memory::handle_t GetHandleFromAddress(const void* ptr, uint16_t segmentId) const
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(SegmentHandleFromAddress(ptr), fSegments.at(segmentId));
|
return std::visit([ptr](auto& s) { return s.get_handle_from_address(ptr); }, fSegments.at(segmentId));
|
||||||
}
|
}
|
||||||
char* GetAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t handle, uint16_t segmentId) const
|
char* GetAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t handle, uint16_t segmentId) const
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(SegmentAddressFromHandle(handle), fSegments.at(segmentId));
|
return std::visit([handle](auto& s) { return reinterpret_cast<char*>(s.get_address_from_handle(handle)); }, fSegments.at(segmentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* Allocate(size_t size, size_t alignment = 0)
|
char* Allocate(size_t size, size_t alignment = 0)
|
||||||
|
@ -741,24 +678,32 @@ class Manager
|
||||||
|
|
||||||
while (!ptr) {
|
while (!ptr) {
|
||||||
try {
|
try {
|
||||||
size_t segmentSize = boost::apply_visitor(SegmentSize(), fSegments.at(fSegmentId));
|
size_t segmentSize = std::visit([](auto& s) { return s.get_size(); }, fSegments.at(fSegmentId));
|
||||||
if (fullSize > segmentSize) {
|
if (fullSize > segmentSize) {
|
||||||
throw MessageBadAlloc(tools::ToString("Requested message size (", fullSize, ") exceeds segment size (", segmentSize, ")"));
|
throw MessageBadAlloc(tools::ToString("Requested message size (", fullSize, ") exceeds segment size (", segmentSize, ")"));
|
||||||
}
|
}
|
||||||
|
|
||||||
ptr = boost::apply_visitor(SegmentAllocate{fullSize}, fSegments.at(fSegmentId));
|
ptr = std::visit([fullSize](auto& s) { return reinterpret_cast<char*>(s.allocate(fullSize)); }, fSegments.at(fSegmentId));
|
||||||
ShmHeader::Construct(ptr, alignment);
|
ShmHeader::Construct(ptr, alignment);
|
||||||
} catch (boost::interprocess::bad_alloc& ba) {
|
} catch (boost::interprocess::bad_alloc& ba) {
|
||||||
// LOG(warn) << "Shared memory full...";
|
// LOG(warn) << "Shared memory full...";
|
||||||
if (fBadAllocMaxAttempts >= 0 && ++numAttempts >= fBadAllocMaxAttempts) {
|
if (fBadAllocMaxAttempts >= 0 && ++numAttempts >= fBadAllocMaxAttempts) {
|
||||||
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size, ", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default", ", free memory: ", boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId))));
|
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size,
|
||||||
|
", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default",
|
||||||
|
", free memory: ", std::visit([](auto& s) { return s.get_free_memory(); }, fSegments.at(fSegmentId))));
|
||||||
}
|
}
|
||||||
if (numAttempts == 1 && fBadAllocMaxAttempts > 1) {
|
if (numAttempts == 1 && fBadAllocMaxAttempts > 1) {
|
||||||
LOG(warn) << tools::ToString("shmem: could not create a message of size ", size, ", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default", ", free memory: ", boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId)), ". Will try ", (fBadAllocMaxAttempts > 1 ? (std::to_string(fBadAllocMaxAttempts - 1)) + " more times" : " until success"), ", in ", fBadAllocAttemptIntervalInMs, "ms intervals");
|
LOG(warn) << tools::ToString("shmem: could not create a message of size ", size,
|
||||||
|
", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default",
|
||||||
|
", free memory: ", std::visit([](auto& s) { return s.get_free_memory(); }, fSegments.at(fSegmentId)),
|
||||||
|
". Will try ", (fBadAllocMaxAttempts > 1 ? (std::to_string(fBadAllocMaxAttempts - 1)) + " more times" : " until success"),
|
||||||
|
", in ", fBadAllocAttemptIntervalInMs, "ms intervals");
|
||||||
}
|
}
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(fBadAllocAttemptIntervalInMs));
|
std::this_thread::sleep_for(std::chrono::milliseconds(fBadAllocAttemptIntervalInMs));
|
||||||
if (Interrupted()) {
|
if (Interrupted()) {
|
||||||
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size, ", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default", ", free memory: ", boost::apply_visitor(SegmentFreeMemory(), fSegments.at(fSegmentId))));
|
throw MessageBadAlloc(tools::ToString("shmem: could not create a message of size ", size,
|
||||||
|
", alignment: ", (alignment != 0) ? std::to_string(alignment) : "default",
|
||||||
|
", free memory: ", std::visit([](auto& s) { return s.get_free_memory(); }, fSegments.at(fSegmentId))));
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -792,12 +737,12 @@ class Manager
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ShmHeader::Destruct(ptr);
|
ShmHeader::Destruct(ptr);
|
||||||
boost::apply_visitor(SegmentDeallocate(ptr), fSegments.at(segmentId));
|
std::visit([ptr](auto& s) { s.deallocate(ptr); }, fSegments.at(segmentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* ShrinkInPlace(size_t newSize, char* localPtr, uint16_t segmentId)
|
char* ShrinkInPlace(size_t newSize, char* localPtr, uint16_t segmentId)
|
||||||
{
|
{
|
||||||
return boost::apply_visitor(SegmentBufferShrink(newSize, localPtr), fSegments.at(segmentId));
|
return std::visit(SegmentBufferShrink(newSize, localPtr), fSegments.at(segmentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t GetSegmentId() const { return fSegmentId; }
|
uint16_t GetSegmentId() const { return fSegmentId; }
|
||||||
|
@ -845,7 +790,7 @@ class Manager
|
||||||
uint64_t fShmId64;
|
uint64_t fShmId64;
|
||||||
std::string fShmId;
|
std::string fShmId;
|
||||||
uint16_t fSegmentId;
|
uint16_t fSegmentId;
|
||||||
std::unordered_map<uint16_t, boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> fSegments; // TODO: refactor to use Segment class
|
std::unordered_map<uint16_t, std::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> fSegments; // TODO: refactor to use Segment class
|
||||||
boost::interprocess::managed_shared_memory fManagementSegment; // TODO: refactor to use ManagementSegment class
|
boost::interprocess::managed_shared_memory fManagementSegment; // TODO: refactor to use ManagementSegment class
|
||||||
VoidAlloc fShmVoidAlloc;
|
VoidAlloc fShmVoidAlloc;
|
||||||
boost::interprocess::interprocess_mutex* fShmMtx;
|
boost::interprocess::interprocess_mutex* fShmMtx;
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "UnmanagedRegionImpl.h"
|
#include "UnmanagedRegionImpl.h"
|
||||||
#include <fairmq/Message.h>
|
#include <fairmq/Message.h>
|
||||||
#include <fairmq/UnmanagedRegion.h>
|
#include <fairmq/UnmanagedRegion.h>
|
||||||
|
#include <fairmq/Transports.h>
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
|
@ -36,60 +37,34 @@ class Message final : public fair::mq::Message
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Message(Manager& manager, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: Message(manager, Alignment{0}, factory)
|
||||||
, fManager(manager)
|
{}
|
||||||
, fQueued(false)
|
|
||||||
, fMeta{0, 0, -1, -1, 0, fManager.GetSegmentId(), true}
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
|
||||||
fManager.IncrementMsgCounter();
|
|
||||||
}
|
|
||||||
|
|
||||||
Message(Manager& manager, Alignment alignment, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, Alignment /* alignment */, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fQueued(false)
|
, fSegmentId(fManager.GetSegmentId())
|
||||||
, fMeta{0, 0, -1, -1, 0, fManager.GetSegmentId(), true}
|
|
||||||
, fAlignment(alignment.alignment)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
{
|
||||||
fManager.IncrementMsgCounter();
|
fManager.IncrementMsgCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Message(Manager& manager, const size_t size, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, const size_t size, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: Message(manager, size, Alignment{0}, factory)
|
||||||
, fManager(manager)
|
{}
|
||||||
, fQueued(false)
|
|
||||||
, fMeta{0, 0, -1, -1, 0, fManager.GetSegmentId(), true}
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
|
||||||
InitializeChunk(size);
|
|
||||||
fManager.IncrementMsgCounter();
|
|
||||||
}
|
|
||||||
|
|
||||||
Message(Manager& manager, const size_t size, Alignment alignment, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, const size_t size, Alignment alignment, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fQueued(false)
|
, fSegmentId(fManager.GetSegmentId())
|
||||||
, fMeta{0, 0, -1, -1, 0, fManager.GetSegmentId(), true}
|
|
||||||
, fAlignment(alignment.alignment)
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
{
|
||||||
InitializeChunk(size, fAlignment);
|
InitializeChunk(size, alignment.alignment);
|
||||||
fManager.IncrementMsgCounter();
|
fManager.IncrementMsgCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Message(Manager& manager, void* data, const size_t size, fair::mq::FreeFn* ffn, void* hint = nullptr, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, void* data, const size_t size, fair::mq::FreeFn* ffn, void* hint = nullptr, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fQueued(false)
|
, fSegmentId(fManager.GetSegmentId())
|
||||||
, fMeta{0, 0, -1, -1, 0, fManager.GetSegmentId(), true}
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(nullptr)
|
|
||||||
{
|
{
|
||||||
if (InitializeChunk(size)) {
|
if (InitializeChunk(size)) {
|
||||||
std::memcpy(fLocalPtr, data, size);
|
std::memcpy(fLocalPtr, data, size);
|
||||||
|
@ -105,10 +80,12 @@ class Message final : public fair::mq::Message
|
||||||
Message(Manager& manager, UnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, UnmanagedRegionPtr& region, void* data, const size_t size, void* hint = 0, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fQueued(false)
|
|
||||||
, fMeta{size, reinterpret_cast<size_t>(hint), -1, -1, static_cast<UnmanagedRegionImpl*>(region.get())->fRegionId, fManager.GetSegmentId(), false}
|
|
||||||
, fRegionPtr(nullptr)
|
|
||||||
, fLocalPtr(static_cast<char*>(data))
|
, fLocalPtr(static_cast<char*>(data))
|
||||||
|
, fSize(size)
|
||||||
|
, fHint(reinterpret_cast<size_t>(hint))
|
||||||
|
, fRegionId(static_cast<UnmanagedRegionImpl*>(region.get())->fRegionId)
|
||||||
|
, fSegmentId(fManager.GetSegmentId())
|
||||||
|
, fManaged(false)
|
||||||
{
|
{
|
||||||
if (region->GetType() != GetType()) {
|
if (region->GetType() != GetType()) {
|
||||||
LOG(error) << "region type (" << region->GetType() << ") does not match message type (" << GetType() << ")";
|
LOG(error) << "region type (" << region->GetType() << ") does not match message type (" << GetType() << ")";
|
||||||
|
@ -117,7 +94,7 @@ class Message final : public fair::mq::Message
|
||||||
|
|
||||||
if (reinterpret_cast<const char*>(data) >= reinterpret_cast<const char*>(region->GetData()) &&
|
if (reinterpret_cast<const char*>(data) >= reinterpret_cast<const char*>(region->GetData()) &&
|
||||||
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize()) {
|
reinterpret_cast<const char*>(data) <= reinterpret_cast<const char*>(region->GetData()) + region->GetSize()) {
|
||||||
fMeta.fHandle = (boost::interprocess::managed_shared_memory::handle_t)(reinterpret_cast<const char*>(data) - reinterpret_cast<const char*>(region->GetData()));
|
fHandle = (boost::interprocess::managed_shared_memory::handle_t)(reinterpret_cast<const char*>(data) - reinterpret_cast<const char*>(region->GetData()));
|
||||||
} else {
|
} else {
|
||||||
LOG(error) << "trying to create region message with data from outside the region";
|
LOG(error) << "trying to create region message with data from outside the region";
|
||||||
throw TransportError("trying to create region message with data from outside the region");
|
throw TransportError("trying to create region message with data from outside the region");
|
||||||
|
@ -128,10 +105,13 @@ class Message final : public fair::mq::Message
|
||||||
Message(Manager& manager, MetaHeader& hdr, fair::mq::TransportFactory* factory = nullptr)
|
Message(Manager& manager, MetaHeader& hdr, fair::mq::TransportFactory* factory = nullptr)
|
||||||
: fair::mq::Message(factory)
|
: fair::mq::Message(factory)
|
||||||
, fManager(manager)
|
, fManager(manager)
|
||||||
, fQueued(false)
|
, fSize(hdr.fSize)
|
||||||
, fMeta{hdr}
|
, fHint(hdr.fHint)
|
||||||
, fRegionPtr(nullptr)
|
, fHandle(hdr.fHandle)
|
||||||
, fLocalPtr(nullptr)
|
, fShared(hdr.fShared)
|
||||||
|
, fRegionId(hdr.fRegionId)
|
||||||
|
, fSegmentId(hdr.fSegmentId)
|
||||||
|
, fManaged(hdr.fManaged)
|
||||||
{
|
{
|
||||||
fManager.IncrementMsgCounter();
|
fManager.IncrementMsgCounter();
|
||||||
}
|
}
|
||||||
|
@ -147,11 +127,10 @@ class Message final : public fair::mq::Message
|
||||||
fQueued = false;
|
fQueued = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rebuild(Alignment alignment) override
|
void Rebuild(Alignment /* alignment */) override
|
||||||
{
|
{
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
fQueued = false;
|
fQueued = false;
|
||||||
fAlignment = alignment.alignment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rebuild(size_t size) override
|
void Rebuild(size_t size) override
|
||||||
|
@ -165,8 +144,7 @@ class Message final : public fair::mq::Message
|
||||||
{
|
{
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
fQueued = false;
|
fQueued = false;
|
||||||
fAlignment = alignment.alignment;
|
InitializeChunk(size, alignment.alignment);
|
||||||
InitializeChunk(size, fAlignment);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Rebuild(void* data, size_t size, fair::mq::FreeFn* ffn, void* hint = nullptr) override
|
void Rebuild(void* data, size_t size, fair::mq::FreeFn* ffn, void* hint = nullptr) override
|
||||||
|
@ -187,17 +165,17 @@ class Message final : public fair::mq::Message
|
||||||
void* GetData() const override
|
void* GetData() const override
|
||||||
{
|
{
|
||||||
if (!fLocalPtr) {
|
if (!fLocalPtr) {
|
||||||
if (fMeta.fManaged) {
|
if (fManaged) {
|
||||||
if (fMeta.fSize > 0) {
|
if (fSize > 0) {
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(fSegmentId);
|
||||||
fLocalPtr = ShmHeader::UserPtr(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
fLocalPtr = ShmHeader::UserPtr(fManager.GetAddressFromHandle(fHandle, fSegmentId));
|
||||||
} else {
|
} else {
|
||||||
fLocalPtr = nullptr;
|
fLocalPtr = nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
fRegionPtr = fManager.GetRegionFromCache(fRegionId);
|
||||||
if (fRegionPtr) {
|
if (fRegionPtr) {
|
||||||
fLocalPtr = reinterpret_cast<char*>(fRegionPtr->GetData()) + fMeta.fHandle;
|
fLocalPtr = reinterpret_cast<char*>(fRegionPtr->GetData()) + fHandle;
|
||||||
} else {
|
} else {
|
||||||
// LOG(warn) << "could not get pointer from a region message";
|
// LOG(warn) << "could not get pointer from a region message";
|
||||||
fLocalPtr = nullptr;
|
fLocalPtr = nullptr;
|
||||||
|
@ -208,37 +186,41 @@ class Message final : public fair::mq::Message
|
||||||
return static_cast<void*>(fLocalPtr);
|
return static_cast<void*>(fLocalPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetSize() const override { return fMeta.fSize; }
|
size_t GetSize() const override { return fSize; }
|
||||||
|
|
||||||
bool SetUsedSize(size_t newSize) override
|
bool SetUsedSize(size_t newSize, Alignment alignment = Alignment{0}) override
|
||||||
{
|
{
|
||||||
if (newSize == fMeta.fSize) {
|
if (newSize == fSize) {
|
||||||
return true;
|
return true;
|
||||||
} else if (newSize == 0) {
|
} else if (newSize == 0) {
|
||||||
Deallocate();
|
Deallocate();
|
||||||
return true;
|
return true;
|
||||||
} else if (newSize <= fMeta.fSize) {
|
} else if (newSize <= fSize) {
|
||||||
try {
|
try {
|
||||||
|
char* oldPtr = fManager.GetAddressFromHandle(fHandle, fSegmentId);
|
||||||
try {
|
try {
|
||||||
char* oldPtr = fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId);
|
|
||||||
uint16_t userOffset = ShmHeader::UserOffset(oldPtr);
|
uint16_t userOffset = ShmHeader::UserOffset(oldPtr);
|
||||||
char* ptr = fManager.ShrinkInPlace(userOffset + newSize, oldPtr, fMeta.fSegmentId);
|
char* ptr = fManager.ShrinkInPlace(userOffset + newSize, oldPtr, fSegmentId);
|
||||||
fLocalPtr = ShmHeader::UserPtr(ptr);
|
fLocalPtr = ShmHeader::UserPtr(ptr);
|
||||||
fMeta.fSize = newSize;
|
fSize = newSize;
|
||||||
return true;
|
return true;
|
||||||
} catch (boost::interprocess::bad_alloc& e) {
|
} catch (boost::interprocess::bad_alloc& e) {
|
||||||
// if shrinking fails (can happen due to boost alignment requirements):
|
// if shrinking fails (can happen due to boost alignment requirements):
|
||||||
// unused size >= 1000000 bytes: reallocate fully
|
// unused size >= 1000000 bytes: reallocate fully
|
||||||
// unused size < 1000000 bytes: simply reset the size and keep the rest of the buffer until message destruction
|
// unused size < 1000000 bytes: simply reset the size and keep the rest of the buffer until message destruction
|
||||||
if (fMeta.fSize - newSize >= 1000000) {
|
if (fSize - newSize >= 1000000) {
|
||||||
char* ptr = fManager.Allocate(newSize, fAlignment);
|
if (alignment.alignment == 0) {
|
||||||
|
// if no alignment is provided, take the minimum alignment of the old pointer, but no more than 4096
|
||||||
|
alignment.alignment = 1 << std::min(__builtin_ctz(reinterpret_cast<size_t>(oldPtr)), 12);
|
||||||
|
}
|
||||||
|
char* ptr = fManager.Allocate(newSize, alignment.alignment);
|
||||||
char* userPtr = ShmHeader::UserPtr(ptr);
|
char* userPtr = ShmHeader::UserPtr(ptr);
|
||||||
std::memcpy(userPtr, fLocalPtr, newSize);
|
std::memcpy(userPtr, fLocalPtr, newSize);
|
||||||
fManager.Deallocate(fMeta.fHandle, fMeta.fSegmentId);
|
fManager.Deallocate(fHandle, fSegmentId);
|
||||||
fLocalPtr = userPtr;
|
fLocalPtr = userPtr;
|
||||||
fMeta.fHandle = fManager.GetHandleFromAddress(ptr, fMeta.fSegmentId);
|
fHandle = fManager.GetHandleFromAddress(ptr, fSegmentId);
|
||||||
}
|
}
|
||||||
fMeta.fSize = newSize;
|
fSize = newSize;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} catch (boost::interprocess::interprocess_exception& e) {
|
} catch (boost::interprocess::interprocess_exception& e) {
|
||||||
|
@ -255,123 +237,178 @@ class Message final : public fair::mq::Message
|
||||||
|
|
||||||
uint16_t GetRefCount() const
|
uint16_t GetRefCount() const
|
||||||
{
|
{
|
||||||
if (fMeta.fHandle < 0) {
|
if (fHandle < 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fMeta.fManaged) { // managed segment
|
if (fManaged) { // managed segment
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(fSegmentId);
|
||||||
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fHandle, fSegmentId));
|
||||||
} else { // unmanaged region
|
|
||||||
if (fMeta.fShared < 0) { // UR msg is not yet shared
|
|
||||||
return 1;
|
|
||||||
} else {
|
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
|
||||||
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
|
||||||
}
|
}
|
||||||
|
if (fShared < 0) { // UR msg is not yet shared
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fRegionPtr = fManager.GetRegionFromCache(fRegionId);
|
||||||
|
if (!fRegionPtr) {
|
||||||
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", fRegionId));
|
||||||
|
}
|
||||||
|
if (fRegionPtr->fRcSegmentSize > 0) {
|
||||||
|
return fRegionPtr->GetRefCountAddressFromHandle(fShared)->Get();
|
||||||
|
} else {
|
||||||
|
fManager.GetSegment(fSegmentId);
|
||||||
|
return ShmHeader::RefCount(fManager.GetAddressFromHandle(fShared, fSegmentId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Copy(const fair::mq::Message& other) override
|
void Copy(const fair::mq::Message& other) override
|
||||||
{
|
{
|
||||||
const Message& otherMsg = static_cast<const Message&>(other);
|
const Message& otherMsg = static_cast<const Message&>(other);
|
||||||
if (otherMsg.fMeta.fHandle < 0) {
|
|
||||||
// if the other message is not initialized, close this one too and return
|
// if the other message is not initialized, close this one too and return
|
||||||
|
if (otherMsg.fHandle < 0) {
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fMeta.fHandle >= 0) {
|
|
||||||
// if this msg is already initialized, close it first
|
// if this msg is already initialized, close it first
|
||||||
|
if (fHandle >= 0) {
|
||||||
CloseMessage();
|
CloseMessage();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (otherMsg.fMeta.fManaged) { // managed segment
|
// increment ref count
|
||||||
fMeta = otherMsg.fMeta;
|
if (otherMsg.fManaged) { // msg in managed segment
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(otherMsg.fSegmentId);
|
||||||
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(otherMsg.fHandle, otherMsg.fSegmentId));
|
||||||
} else { // unmanaged region
|
} else { // msg in unmanaged region
|
||||||
if (otherMsg.fMeta.fShared < 0) { // if UR msg is not yet shared
|
fRegionPtr = fManager.GetRegionFromCache(otherMsg.fRegionId);
|
||||||
// TODO: minimize the size to 0 and don't create extra space for user buffer alignment
|
if (!fRegionPtr) {
|
||||||
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", otherMsg.fRegionId));
|
||||||
|
}
|
||||||
|
if (fRegionPtr->fRcSegmentSize > 0) {
|
||||||
|
if (otherMsg.fShared < 0) {
|
||||||
|
// UR msg not yet shared, create the reference counting object with count 2
|
||||||
|
try {
|
||||||
|
otherMsg.fShared = fRegionPtr->HandleFromAddress(&(fRegionPtr->MakeRefCount(2)));
|
||||||
|
} catch (boost::interprocess::bad_alloc& ba) {
|
||||||
|
throw RefCountBadAlloc(tools::ToString("Insufficient space in the reference count segment ", otherMsg.fRegionId, ", original exception: bad_alloc: ", ba.what()));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fRegionPtr->GetRefCountAddressFromHandle(otherMsg.fShared)->Increment();
|
||||||
|
}
|
||||||
|
} else { // if RefCount segment size is 0, store the ref count in the managed segment
|
||||||
|
if (otherMsg.fShared < 0) { // if UR msg is not yet shared
|
||||||
char* ptr = fManager.Allocate(2, 0);
|
char* ptr = fManager.Allocate(2, 0);
|
||||||
// point the fShared in the unmanaged region message to the refCount holder
|
// point the fShared in the unmanaged region message to the refCount holder
|
||||||
otherMsg.fMeta.fShared = fManager.GetHandleFromAddress(ptr, fMeta.fSegmentId);
|
otherMsg.fShared = fManager.GetHandleFromAddress(ptr, fSegmentId);
|
||||||
// the message needs to be able to locate in which segment the refCount is stored
|
// the message needs to be able to locate in which segment the refCount is stored
|
||||||
otherMsg.fMeta.fSegmentId = fMeta.fSegmentId;
|
otherMsg.fSegmentId = fSegmentId;
|
||||||
// point this message to the same content as the unmanaged region message
|
|
||||||
fMeta = otherMsg.fMeta;
|
|
||||||
// increment the refCount
|
|
||||||
ShmHeader::IncrementRefCount(ptr);
|
ShmHeader::IncrementRefCount(ptr);
|
||||||
} else { // if the UR msg is already shared
|
} else { // if the UR msg is already shared
|
||||||
fMeta = otherMsg.fMeta;
|
fManager.GetSegment(otherMsg.fSegmentId);
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(otherMsg.fShared, otherMsg.fSegmentId));
|
||||||
ShmHeader::IncrementRefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// copy meta data
|
||||||
|
fSize = otherMsg.fSize;
|
||||||
|
fHint = otherMsg.fHint;
|
||||||
|
fHandle = otherMsg.fHandle;
|
||||||
|
fShared = otherMsg.fShared;
|
||||||
|
fRegionId = otherMsg.fRegionId;
|
||||||
|
fSegmentId = otherMsg.fSegmentId;
|
||||||
|
fManaged = otherMsg.fManaged;
|
||||||
|
}
|
||||||
|
|
||||||
~Message() override { CloseMessage(); }
|
~Message() override { CloseMessage(); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Manager& fManager;
|
Manager& fManager;
|
||||||
bool fQueued;
|
mutable UnmanagedRegion* fRegionPtr = nullptr;
|
||||||
MetaHeader fMeta;
|
mutable char* fLocalPtr = nullptr;
|
||||||
size_t fAlignment;
|
size_t fSize = 0; // size of the shm buffer
|
||||||
mutable UnmanagedRegion* fRegionPtr;
|
size_t fHint = 0; // user-defined value, given by the user on message creation and returned to the user on "buffer no longer needed"-callbacks
|
||||||
mutable char* fLocalPtr;
|
boost::interprocess::managed_shared_memory::handle_t fHandle = -1; // handle to shm buffer, convertible to shm buffer ptr
|
||||||
|
mutable boost::interprocess::managed_shared_memory::handle_t fShared = -1; // handle to the buffer storing the ref count for shared buffers
|
||||||
|
uint16_t fRegionId = 0; // id of the unmanaged region
|
||||||
|
mutable uint16_t fSegmentId; // id of the managed segment
|
||||||
|
bool fManaged = true; // true = managed segment, false = unmanaged region
|
||||||
|
bool fQueued = false;
|
||||||
|
|
||||||
|
void SetMeta(const MetaHeader& meta)
|
||||||
|
{
|
||||||
|
fSize = meta.fSize;
|
||||||
|
fHint = meta.fHint;
|
||||||
|
fHandle = meta.fHandle;
|
||||||
|
fShared = meta.fShared;
|
||||||
|
fRegionId = meta.fRegionId;
|
||||||
|
fSegmentId = meta.fSegmentId;
|
||||||
|
fManaged = meta.fManaged;
|
||||||
|
}
|
||||||
|
|
||||||
char* InitializeChunk(const size_t size, size_t alignment = 0)
|
char* InitializeChunk(const size_t size, size_t alignment = 0)
|
||||||
{
|
{
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
fMeta.fSize = 0;
|
fSize = 0;
|
||||||
return fLocalPtr;
|
return fLocalPtr;
|
||||||
}
|
}
|
||||||
char* ptr = fManager.Allocate(size, alignment);
|
char* ptr = fManager.Allocate(size, alignment);
|
||||||
fMeta.fHandle = fManager.GetHandleFromAddress(ptr, fMeta.fSegmentId);
|
fHandle = fManager.GetHandleFromAddress(ptr, fSegmentId);
|
||||||
fMeta.fSize = size;
|
fSize = size;
|
||||||
fLocalPtr = ShmHeader::UserPtr(ptr);
|
fLocalPtr = ShmHeader::UserPtr(ptr);
|
||||||
return fLocalPtr;
|
return fLocalPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Deallocate()
|
void Deallocate()
|
||||||
{
|
{
|
||||||
if (fMeta.fHandle >= 0 && !fQueued) {
|
if (fHandle >= 0 && !fQueued) {
|
||||||
if (fMeta.fManaged) { // managed segment
|
if (fManaged) { // managed segment
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
fManager.GetSegment(fSegmentId);
|
||||||
uint16_t refCount = ShmHeader::DecrementRefCount(fManager.GetAddressFromHandle(fMeta.fHandle, fMeta.fSegmentId));
|
uint16_t refCount = ShmHeader::DecrementRefCount(fManager.GetAddressFromHandle(fHandle, fSegmentId));
|
||||||
if (refCount == 1) {
|
if (refCount == 1) {
|
||||||
fManager.Deallocate(fMeta.fHandle, fMeta.fSegmentId);
|
fManager.Deallocate(fHandle, fSegmentId);
|
||||||
}
|
}
|
||||||
} else { // unmanaged region
|
} else { // unmanaged region
|
||||||
if (fMeta.fShared >= 0) {
|
if (fShared >= 0) {
|
||||||
// make sure segment is initialized in this transport
|
fRegionPtr = fManager.GetRegionFromCache(fRegionId);
|
||||||
fManager.GetSegment(fMeta.fSegmentId);
|
if (!fRegionPtr) {
|
||||||
// release unmanaged region block if ref count is one
|
throw TransportError(tools::ToString("Cannot get unmanaged region with id ", fRegionId));
|
||||||
uint16_t refCount = ShmHeader::DecrementRefCount(fManager.GetAddressFromHandle(fMeta.fShared, fMeta.fSegmentId));
|
}
|
||||||
|
if (fRegionPtr->fRcSegmentSize > 0) {
|
||||||
|
uint16_t refCount = fRegionPtr->GetRefCountAddressFromHandle(fShared)->Decrement();
|
||||||
if (refCount == 1) {
|
if (refCount == 1) {
|
||||||
fManager.Deallocate(fMeta.fShared, fMeta.fSegmentId);
|
fRegionPtr->RemoveRefCount(*(fRegionPtr->GetRefCountAddressFromHandle(fShared)));
|
||||||
ReleaseUnmanagedRegionBlock();
|
ReleaseUnmanagedRegionBlock();
|
||||||
}
|
}
|
||||||
|
} else { // if RefCount segment size is 0, get the ref count from the managed segment
|
||||||
|
// make sure segment is initialized in this transport
|
||||||
|
fManager.GetSegment(fSegmentId);
|
||||||
|
// release unmanaged region block if ref count is one
|
||||||
|
uint16_t refCount = ShmHeader::DecrementRefCount(fManager.GetAddressFromHandle(fShared, fSegmentId));
|
||||||
|
if (refCount == 1) {
|
||||||
|
fManager.Deallocate(fShared, fSegmentId);
|
||||||
|
ReleaseUnmanagedRegionBlock();
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
ReleaseUnmanagedRegionBlock();
|
ReleaseUnmanagedRegionBlock();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fMeta.fHandle = -1;
|
fHandle = -1;
|
||||||
fLocalPtr = nullptr;
|
fLocalPtr = nullptr;
|
||||||
fMeta.fSize = 0;
|
fSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReleaseUnmanagedRegionBlock()
|
void ReleaseUnmanagedRegionBlock()
|
||||||
{
|
{
|
||||||
if (!fRegionPtr) {
|
if (!fRegionPtr) {
|
||||||
fRegionPtr = fManager.GetRegionFromCache(fMeta.fRegionId);
|
fRegionPtr = fManager.GetRegionFromCache(fRegionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fRegionPtr) {
|
if (fRegionPtr) {
|
||||||
fRegionPtr->ReleaseBlock({fMeta.fHandle, fMeta.fSize, fMeta.fHint});
|
fRegionPtr->ReleaseBlock({fHandle, fSize, fHint});
|
||||||
} else {
|
} else {
|
||||||
LOG(warn) << "region ack queue for id " << fMeta.fRegionId << " no longer exist. Not sending ack";
|
LOG(warn) << "region ack queue for id " << fRegionId << " no longer exist. Not sending ack";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +416,6 @@ class Message final : public fair::mq::Message
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
Deallocate();
|
Deallocate();
|
||||||
fAlignment = 0;
|
|
||||||
fManager.DecrementMsgCounter();
|
fManager.DecrementMsgCounter();
|
||||||
} catch (SharedMemoryError& sme) {
|
} catch (SharedMemoryError& sme) {
|
||||||
LOG(error) << "error closing message: " << sme.what();
|
LOG(error) << "error closing message: " << sme.what();
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ Monitor::Monitor(string shmId, bool selfDestruct, bool interactive, bool viewOnl
|
||||||
{
|
{
|
||||||
if (!fViewOnly) {
|
if (!fViewOnly) {
|
||||||
try {
|
try {
|
||||||
bipc::named_mutex monitorStatus(bipc::create_only, string("fmq_" + fShmId + "_ms").c_str());
|
bipc::named_mutex monitorStatus(bipc::create_only, MakeShmName(fShmId, "ms").c_str());
|
||||||
} catch (bie&) {
|
} catch (bie&) {
|
||||||
if (fInteractive) {
|
if (fInteractive) {
|
||||||
LOG(error) << "fairmq-shmmonitor for shm id " << fShmId << " is already running. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`, or run in view-only mode (-v)";
|
LOG(error) << "fairmq-shmmonitor for shm id " << fShmId << " is already running. Try `fairmq-shmmonitor --cleanup --shmid " << fShmId << "`, or run in view-only mode (-v)";
|
||||||
|
@ -132,7 +133,7 @@ void Monitor::Watch()
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
managed_shared_memory managementSegment(open_read_only, std::string("fmq_" + fShmId + "_mng").c_str());
|
managed_shared_memory managementSegment(open_read_only, MakeShmName(fShmId, "mng").c_str());
|
||||||
|
|
||||||
fSeenOnce = true;
|
fSeenOnce = true;
|
||||||
|
|
||||||
|
@ -180,11 +181,11 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
managed_shared_memory managementSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
managed_shared_memory managementSegment(open_read_only, MakeShmName(shmId.shmId, "mng").c_str());
|
||||||
VoidAlloc allocInstance(managementSegment.get_segment_manager());
|
VoidAlloc allocInstance(managementSegment.get_segment_manager());
|
||||||
|
|
||||||
Uint16SegmentInfoHashMap* shmSegments = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
Uint16SegmentInfoHashMap* shmSegments = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||||
std::unordered_map<uint16_t, boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> segments;
|
std::unordered_map<uint16_t, std::variant<RBTreeBestFitSegment, SimpleSeqFitSegment>> segments;
|
||||||
|
|
||||||
Uint16RegionInfoHashMap* shmRegions = managementSegment.find<Uint16RegionInfoHashMap>(unique_instance).first;
|
Uint16RegionInfoHashMap* shmRegions = managementSegment.find<Uint16RegionInfoHashMap>(unique_instance).first;
|
||||||
|
|
||||||
|
@ -199,9 +200,9 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
|
|
||||||
for (const auto& s : *shmSegments) {
|
for (const auto& s : *shmSegments) {
|
||||||
if (s.second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
if (s.second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||||
segments.emplace(s.first, RBTreeBestFitSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + to_string(s.first)).c_str()));
|
segments.emplace(s.first, RBTreeBestFitSegment(open_read_only, MakeShmName(shmId.shmId, "m", s.first).c_str()));
|
||||||
} else {
|
} else {
|
||||||
segments.emplace(s.first, SimpleSeqFitSegment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + to_string(s.first)).c_str()));
|
segments.emplace(s.first, SimpleSeqFitSegment(open_read_only, MakeShmName(shmId.shmId, "m", s.first).c_str()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,8 +235,8 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
<< ", managed segments:\n";
|
<< ", managed segments:\n";
|
||||||
|
|
||||||
for (const auto& s : segments) {
|
for (const auto& s : segments) {
|
||||||
size_t free = boost::apply_visitor(SegmentFreeMemory(), s.second);
|
size_t free = std::visit([](auto& seg){ return seg.get_free_memory(); }, s.second);
|
||||||
size_t total = boost::apply_visitor(SegmentSize(), s.second);
|
size_t total = std::visit([](auto& seg){ return seg.get_size(); }, s.second);
|
||||||
size_t used = total - free;
|
size_t used = total - free;
|
||||||
|
|
||||||
std::string msgCount;
|
std::string msgCount;
|
||||||
|
@ -267,12 +268,21 @@ bool Monitor::PrintShm(const ShmId& shmId)
|
||||||
|
|
||||||
if (shmRegions && !shmRegions->empty()) {
|
if (shmRegions && !shmRegions->empty()) {
|
||||||
ss << "\n unmanaged regions:";
|
ss << "\n unmanaged regions:";
|
||||||
for (const auto& r : *shmRegions) {
|
for (const auto& [id, info] : *shmRegions) {
|
||||||
ss << "\n [" << r.first << "]: " << (r.second.fDestroyed ? "destroyed" : "alive");
|
ss << "\n [" << id << "]: " << (info.fDestroyed ? "destroyed" : "alive");
|
||||||
ss << ", size: " << r.second.fSize;
|
ss << ", size: " << info.fSize;
|
||||||
|
|
||||||
|
try {
|
||||||
|
managed_shared_memory rcCountSegment(open_read_only, MakeShmName(shmId.shmId, "rrc", id).c_str());
|
||||||
|
auto size = rcCountSegment.get_size();
|
||||||
|
auto free = rcCountSegment.get_free_memory();
|
||||||
|
ss << ", rcCountSegment size: " << size << ", free: " << free << ", used: " << size - free;
|
||||||
|
} catch (bie&) {
|
||||||
|
ss << ", rcCountSegment: not found";
|
||||||
|
}
|
||||||
|
|
||||||
// try {
|
// try {
|
||||||
// boost::interprocess::message_queue q(open_only, std::string("fmq_" + std::string(shmId) + "_rgq_" + to_string(r.first)).c_str());
|
// boost::interprocess::message_queue q(open_only, std::string("fmq_" + std::string(shmId) + "_rgq_" + to_string(id)).c_str());
|
||||||
// ss << ", ack queue: " << q.get_num_msg() << " messages";
|
// ss << ", ack queue: " << q.get_num_msg() << " messages";
|
||||||
// } catch (bie&) {
|
// } catch (bie&) {
|
||||||
// ss << ", ack queue: not found";
|
// ss << ", ack queue: not found";
|
||||||
|
@ -325,7 +335,7 @@ void Monitor::CheckHeartbeats()
|
||||||
while (!fTerminating) {
|
while (!fTerminating) {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||||
try {
|
try {
|
||||||
managed_shared_memory managementSegment(open_read_only, std::string("fmq_" + fShmId + "_mng").c_str());
|
managed_shared_memory managementSegment(open_read_only, MakeShmName(fShmId, "mng").c_str());
|
||||||
Heartbeat* hb = managementSegment.find<Heartbeat>(unique_instance).first;
|
Heartbeat* hb = managementSegment.find<Heartbeat>(unique_instance).first;
|
||||||
|
|
||||||
if (hb) {
|
if (hb) {
|
||||||
|
@ -407,7 +417,7 @@ void Monitor::Interactive()
|
||||||
void Monitor::PrintDebugInfo(const ShmId& shmId __attribute__((unused)))
|
void Monitor::PrintDebugInfo(const ShmId& shmId __attribute__((unused)))
|
||||||
{
|
{
|
||||||
#ifdef FAIRMQ_DEBUG_MODE
|
#ifdef FAIRMQ_DEBUG_MODE
|
||||||
string managementSegmentName("fmq_" + shmId.shmId + "_mng");
|
string managementSegmentName = MakeShmName(shmId.shmId, "mng");
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
||||||
bipc::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
bipc::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
||||||
|
@ -459,7 +469,7 @@ unordered_map<uint16_t, std::vector<BufferDebugInfo>> Monitor::GetDebugInfo(cons
|
||||||
unordered_map<uint16_t, std::vector<BufferDebugInfo>> result;
|
unordered_map<uint16_t, std::vector<BufferDebugInfo>> result;
|
||||||
|
|
||||||
#ifdef FAIRMQ_DEBUG_MODE
|
#ifdef FAIRMQ_DEBUG_MODE
|
||||||
string managementSegmentName("fmq_" + shmId.shmId + "_mng");
|
string managementSegmentName = MakeShmName(shmId.shmId, "mng");
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_only, managementSegmentName.c_str());
|
||||||
bipc::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
bipc::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
||||||
|
@ -499,7 +509,7 @@ unsigned long Monitor::GetFreeMemory(const ShmId& shmId, uint16_t segmentId)
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_only, MakeShmName(shmId.shmId, "mng").c_str());
|
||||||
boost::interprocess::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
boost::interprocess::interprocess_mutex* mtx(managementSegment.find_or_construct<bipc::interprocess_mutex>(bipc::unique_instance)());
|
||||||
boost::interprocess::scoped_lock<bipc::interprocess_mutex> lock(*mtx);
|
boost::interprocess::scoped_lock<bipc::interprocess_mutex> lock(*mtx);
|
||||||
|
|
||||||
|
@ -513,10 +523,10 @@ unsigned long Monitor::GetFreeMemory(const ShmId& shmId, uint16_t segmentId)
|
||||||
auto it = shmSegments->find(segmentId);
|
auto it = shmSegments->find(segmentId);
|
||||||
if (it != shmSegments->end()) {
|
if (it != shmSegments->end()) {
|
||||||
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||||
RBTreeBestFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
RBTreeBestFitSegment segment(open_read_only, MakeShmName(shmId.shmId, "m", segmentId).c_str());
|
||||||
return segment.get_free_memory();
|
return segment.get_free_memory();
|
||||||
} else {
|
} else {
|
||||||
SimpleSeqFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
SimpleSeqFitSegment segment(open_read_only, MakeShmName(shmId.shmId, "m", segmentId).c_str());
|
||||||
return segment.get_free_memory();
|
return segment.get_free_memory();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -538,7 +548,7 @@ bool Monitor::SegmentIsPresent(const ShmId& shmId, uint16_t segmentId)
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_read_only, MakeShmName(shmId.shmId, "mng").c_str());
|
||||||
Uint16SegmentInfoHashMap* shmSegments = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
Uint16SegmentInfoHashMap* shmSegments = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||||
|
|
||||||
if (!shmSegments) {
|
if (!shmSegments) {
|
||||||
|
@ -550,9 +560,9 @@ bool Monitor::SegmentIsPresent(const ShmId& shmId, uint16_t segmentId)
|
||||||
if (it != shmSegments->end()) {
|
if (it != shmSegments->end()) {
|
||||||
try {
|
try {
|
||||||
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
if (it->second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||||
RBTreeBestFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
RBTreeBestFitSegment segment(open_read_only, MakeShmName(shmId.shmId, "m", segmentId).c_str());
|
||||||
} else {
|
} else {
|
||||||
SimpleSeqFitSegment segment(open_read_only, std::string("fmq_" + shmId.shmId + "_m_" + std::to_string(segmentId)).c_str());
|
SimpleSeqFitSegment segment(open_read_only, MakeShmName(shmId.shmId, "m", segmentId).c_str());
|
||||||
}
|
}
|
||||||
} catch (bie&) {
|
} catch (bie&) {
|
||||||
LOG(error) << "Could not find segment with id '" << segmentId << "' for shmId '" << shmId.shmId << "'";
|
LOG(error) << "Could not find segment with id '" << segmentId << "' for shmId '" << shmId.shmId << "'";
|
||||||
|
@ -579,7 +589,7 @@ bool Monitor::RegionIsPresent(const ShmId& shmId, uint16_t regionId)
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_read_only, std::string("fmq_" + shmId.shmId + "_mng").c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_read_only, MakeShmName(shmId.shmId, "mng").c_str());
|
||||||
Uint16RegionInfoHashMap* shmRegions = managementSegment.find<Uint16RegionInfoHashMap>(bipc::unique_instance).first;
|
Uint16RegionInfoHashMap* shmRegions = managementSegment.find<Uint16RegionInfoHashMap>(bipc::unique_instance).first;
|
||||||
|
|
||||||
if (!shmRegions) {
|
if (!shmRegions) {
|
||||||
|
@ -587,7 +597,7 @@ bool Monitor::RegionIsPresent(const ShmId& shmId, uint16_t regionId)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string regionFileName("fmq_" + shmId.shmId + "_rg_" + to_string(regionId));
|
std::string regionFileName(MakeShmName(shmId.shmId, "rg", regionId));
|
||||||
|
|
||||||
auto it = shmRegions->find(regionId);
|
auto it = shmRegions->find(regionId);
|
||||||
if (it != shmRegions->end()) {
|
if (it != shmRegions->end()) {
|
||||||
|
@ -655,7 +665,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmIdT,
|
||||||
LOG(info) << "Cleaning up for shared memory id '" << shmId << "'...";
|
LOG(info) << "Cleaning up for shared memory id '" << shmId << "'...";
|
||||||
}
|
}
|
||||||
|
|
||||||
string managementSegmentName("fmq_" + shmId + "_mng");
|
string managementSegmentName = MakeShmName(shmId, "mng");
|
||||||
try {
|
try {
|
||||||
bipc::managed_shared_memory managementSegment(bipc::open_read_only, managementSegmentName.c_str());
|
bipc::managed_shared_memory managementSegment(bipc::open_read_only, managementSegmentName.c_str());
|
||||||
|
|
||||||
|
@ -673,11 +683,12 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmIdT,
|
||||||
LOG(info) << "Found UnmanagedRegion with id: " << id << ", path: '" << path << "', flags: " << flags << ", fDestroyed: " << info.fDestroyed << ".";
|
LOG(info) << "Found UnmanagedRegion with id: " << id << ", path: '" << path << "', flags: " << flags << ", fDestroyed: " << info.fDestroyed << ".";
|
||||||
}
|
}
|
||||||
if (!path.empty()) {
|
if (!path.empty()) {
|
||||||
result.emplace_back(Remove<bipc::file_mapping>(path + "fmq_" + shmId + "_rg_" + to_string(id), verbose));
|
result.emplace_back(Remove<bipc::file_mapping>(path + MakeShmName(shmId, "rg", id), verbose));
|
||||||
} else {
|
} else {
|
||||||
result.emplace_back(Remove<bipc::shared_memory_object>("fmq_" + shmId + "_rg_" + to_string(id), verbose));
|
result.emplace_back(Remove<bipc::shared_memory_object>(MakeShmName(shmId, "rg", id), verbose));
|
||||||
}
|
}
|
||||||
result.emplace_back(Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose));
|
result.emplace_back(Remove<bipc::message_queue>(MakeShmName(shmId, "rgq", id), verbose));
|
||||||
|
result.emplace_back(Remove<bipc::shared_memory_object>(MakeShmName(shmId, "rrc", id), verbose));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,7 +698,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const ShmId& shmIdT,
|
||||||
LOG(info) << "Found " << shmSegments->size() << " managed segments...";
|
LOG(info) << "Found " << shmSegments->size() << " managed segments...";
|
||||||
}
|
}
|
||||||
for (const auto& segment : *shmSegments) {
|
for (const auto& segment : *shmSegments) {
|
||||||
result.emplace_back(Remove<bipc::shared_memory_object>("fmq_" + shmId + "_m_" + to_string(segment.first), verbose));
|
result.emplace_back(Remove<bipc::shared_memory_object>(MakeShmName(shmId, "m", segment.first), verbose));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
|
@ -717,7 +728,7 @@ std::vector<std::pair<std::string, bool>> Monitor::Cleanup(const SessionId& sess
|
||||||
std::vector<std::pair<std::string, bool>> Monitor::CleanupFull(const ShmId& shmId, bool verbose /* = true */)
|
std::vector<std::pair<std::string, bool>> Monitor::CleanupFull(const ShmId& shmId, bool verbose /* = true */)
|
||||||
{
|
{
|
||||||
auto result = Cleanup(shmId, verbose);
|
auto result = Cleanup(shmId, verbose);
|
||||||
result.emplace_back(Remove<bipc::named_mutex>("fmq_" + shmId.shmId + "_ms", verbose));
|
result.emplace_back(Remove<bipc::named_mutex>(MakeShmName(shmId.shmId, "ms"), verbose));
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +748,7 @@ void Monitor::ResetContent(const ShmId& shmIdT, bool verbose /* = true */)
|
||||||
cout << "Resetting segments content for shared memory id '" << shmId << "'..." << endl;
|
cout << "Resetting segments content for shared memory id '" << shmId << "'..." << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
string managementSegmentName("fmq_" + shmId + "_mng");
|
string managementSegmentName = MakeShmName(shmId, "mng");
|
||||||
try {
|
try {
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
managed_shared_memory managementSegment(open_only, managementSegmentName.c_str());
|
managed_shared_memory managementSegment(open_only, managementSegmentName.c_str());
|
||||||
|
@ -745,18 +756,18 @@ void Monitor::ResetContent(const ShmId& shmIdT, bool verbose /* = true */)
|
||||||
Uint16SegmentInfoHashMap* segmentInfos = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
Uint16SegmentInfoHashMap* segmentInfos = managementSegment.find<Uint16SegmentInfoHashMap>(unique_instance).first;
|
||||||
if (segmentInfos) {
|
if (segmentInfos) {
|
||||||
cout << "Found info for " << segmentInfos->size() << " managed segments" << endl;
|
cout << "Found info for " << segmentInfos->size() << " managed segments" << endl;
|
||||||
for (const auto& s : *segmentInfos) {
|
for (const auto& [id, info] : *segmentInfos) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
cout << "Resetting content of segment '" << "fmq_" << shmId << "_m_" << s.first << "'..." << endl;
|
cout << "Resetting content of segment '" << MakeShmName(shmId, "m", id) << "'..." << endl;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if (s.second.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
if (info.fAllocationAlgorithm == AllocationAlgorithm::rbtree_best_fit) {
|
||||||
RBTreeBestFitSegment segment(open_only, std::string("fmq_" + shmId + "_m_" + to_string(s.first)).c_str());
|
RBTreeBestFitSegment segment(open_only, MakeShmName(shmId, "m", id).c_str());
|
||||||
void* ptr = segment.get_segment_manager();
|
void* ptr = segment.get_segment_manager();
|
||||||
size_t size = segment.get_segment_manager()->get_size();
|
size_t size = segment.get_segment_manager()->get_size();
|
||||||
new(ptr) segment_manager<char, rbtree_best_fit<mutex_family, offset_ptr<void>>, null_index>(size);
|
new(ptr) segment_manager<char, rbtree_best_fit<mutex_family, offset_ptr<void>>, null_index>(size);
|
||||||
} else {
|
} else {
|
||||||
SimpleSeqFitSegment segment(open_only, std::string("fmq_" + shmId + "_m_" + to_string(s.first)).c_str());
|
SimpleSeqFitSegment segment(open_only, MakeShmName(shmId, "m", id).c_str());
|
||||||
void* ptr = segment.get_segment_manager();
|
void* ptr = segment.get_segment_manager();
|
||||||
size_t size = segment.get_segment_manager()->get_size();
|
size_t size = segment.get_segment_manager()->get_size();
|
||||||
new(ptr) segment_manager<char, simple_seq_fit<mutex_family, offset_ptr<void>>, null_index>(size);
|
new(ptr) segment_manager<char, simple_seq_fit<mutex_family, offset_ptr<void>>, null_index>(size);
|
||||||
|
@ -766,7 +777,7 @@ void Monitor::ResetContent(const ShmId& shmIdT, bool verbose /* = true */)
|
||||||
}
|
}
|
||||||
} catch (bie& e) {
|
} catch (bie& e) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
cout << "Error resetting content of segment '" << std::string("fmq_" + shmId + "_m_" + to_string(s.first)) << "': " << e.what() << endl;
|
cout << "Error resetting content of segment '" << MakeShmName(shmId, "m", id) << "': " << e.what() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -778,7 +789,8 @@ void Monitor::ResetContent(const ShmId& shmIdT, bool verbose /* = true */)
|
||||||
if (shmRegions) {
|
if (shmRegions) {
|
||||||
for (const auto& region : *shmRegions) {
|
for (const auto& region : *shmRegions) {
|
||||||
uint16_t id = region.first;
|
uint16_t id = region.first;
|
||||||
Remove<bipc::message_queue>("fmq_" + shmId + "_rgq_" + to_string(id), verbose);
|
Remove<bipc::message_queue>(MakeShmName(shmId, "rgq", id), verbose);
|
||||||
|
Remove<bipc::shared_memory_object>(MakeShmName(shmId, "rrc", id), verbose);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (bie& e) {
|
} catch (bie& e) {
|
||||||
|
@ -807,7 +819,7 @@ void Monitor::ResetContent(const ShmId& shmIdT, const std::vector<SegmentConfig>
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
|
|
||||||
std::string shmId = shmIdT.shmId;
|
std::string shmId = shmIdT.shmId;
|
||||||
std::string managementSegmentName("fmq_" + shmId + "_mng");
|
std::string managementSegmentName = MakeShmName(shmId, "mng");
|
||||||
// delete management segment
|
// delete management segment
|
||||||
cout << "deleting management segment" << endl;
|
cout << "deleting management segment" << endl;
|
||||||
Remove<bipc::shared_memory_object>(managementSegmentName, verbose);
|
Remove<bipc::shared_memory_object>(managementSegmentName, verbose);
|
||||||
|
@ -855,7 +867,7 @@ Monitor::~Monitor()
|
||||||
Cleanup(ShmId{fShmId});
|
Cleanup(ShmId{fShmId});
|
||||||
}
|
}
|
||||||
if (!fViewOnly) {
|
if (!fViewOnly) {
|
||||||
RemoveMutex("fmq_" + fShmId + "_ms");
|
RemoveMutex(MakeShmName(fShmId, "ms"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ FairMQ Shared Memory currently uses the following names to register shared memor
|
||||||
| `fmq_<shmId>_mng` | management segment (management data) | one of the devices | devices |
|
| `fmq_<shmId>_mng` | management segment (management data) | one of the devices | devices |
|
||||||
| `fmq_<shmId>_rg_<index>` | unmanaged region(s) | one of the devices | devices with unmanaged regions |
|
| `fmq_<shmId>_rg_<index>` | unmanaged region(s) | one of the devices | devices with unmanaged regions |
|
||||||
| `fmq_<shmId>_rgq_<index>` | unmanaged region queue(s) | one of the devices | devices with unmanaged regions |
|
| `fmq_<shmId>_rgq_<index>` | unmanaged region queue(s) | one of the devices | devices with unmanaged regions |
|
||||||
|
| `fmq_<shmId>_rrc_<index>` | unmanaged region reference count pool(s) | one of the devices | devices with unmanaged regions |
|
||||||
| `fmq_<shmId>_ms` | shmmonitor status | shmmonitor | devices, shmmonitor |
|
| `fmq_<shmId>_ms` | shmmonitor status | shmmonitor | devices, shmmonitor |
|
||||||
|
|
||||||
The shmId is generated out of session id and user id.
|
The shmId is generated out of session id and user id.
|
||||||
|
|
|
@ -10,11 +10,11 @@
|
||||||
|
|
||||||
#include <fairmq/shmem/Common.h>
|
#include <fairmq/shmem/Common.h>
|
||||||
#include <fairmq/shmem/Monitor.h>
|
#include <fairmq/shmem/Monitor.h>
|
||||||
|
#include <fairmq/Transports.h>
|
||||||
#include <boost/variant.hpp>
|
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
namespace fair::mq::shmem
|
namespace fair::mq::shmem
|
||||||
{
|
{
|
||||||
|
@ -29,27 +29,23 @@ struct Segment
|
||||||
friend class Monitor;
|
friend class Monitor;
|
||||||
|
|
||||||
Segment(const std::string& shmId, uint16_t id, size_t size, SimpleSeqFit)
|
Segment(const std::string& shmId, uint16_t id, size_t size, SimpleSeqFit)
|
||||||
: fSegment(SimpleSeqFitSegment(boost::interprocess::open_or_create,
|
: fSegment(SimpleSeqFitSegment(boost::interprocess::open_or_create, MakeShmName(shmId, "m", id).c_str(), size))
|
||||||
std::string("fmq_" + shmId + "_m_" + std::to_string(id)).c_str(),
|
|
||||||
size))
|
|
||||||
{
|
{
|
||||||
Register(shmId, id, AllocationAlgorithm::simple_seq_fit);
|
Register(shmId, id, AllocationAlgorithm::simple_seq_fit);
|
||||||
}
|
}
|
||||||
|
|
||||||
Segment(const std::string& shmId, uint16_t id, size_t size, RBTreeBestFit)
|
Segment(const std::string& shmId, uint16_t id, size_t size, RBTreeBestFit)
|
||||||
: fSegment(RBTreeBestFitSegment(boost::interprocess::open_or_create,
|
: fSegment(RBTreeBestFitSegment(boost::interprocess::open_or_create, MakeShmName(shmId, "m", id).c_str(), size))
|
||||||
std::string("fmq_" + shmId + "_m_" + std::to_string(id)).c_str(),
|
|
||||||
size))
|
|
||||||
{
|
{
|
||||||
Register(shmId, id, AllocationAlgorithm::rbtree_best_fit);
|
Register(shmId, id, AllocationAlgorithm::rbtree_best_fit);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t GetSize() const { return boost::apply_visitor(SegmentSize(), fSegment); }
|
size_t GetSize() const { return std::visit([](auto& s){ return s.get_size(); }, fSegment); }
|
||||||
void* GetData() { return boost::apply_visitor(SegmentAddress(), fSegment); }
|
void* GetData() { return std::visit([](auto& s){ return s.get_address(); }, fSegment); }
|
||||||
|
|
||||||
size_t GetFreeMemory() const { return boost::apply_visitor(SegmentFreeMemory(), fSegment); }
|
size_t GetFreeMemory() const { return std::visit([](auto& s){ return s.get_free_memory(); }, fSegment); }
|
||||||
|
|
||||||
void Zero() { boost::apply_visitor(SegmentMemoryZeroer(), fSegment); }
|
void Zero() { std::visit([](auto& s){ return s.zero_free_memory(); }, fSegment); }
|
||||||
void Lock()
|
void Lock()
|
||||||
{
|
{
|
||||||
if (mlock(GetData(), GetSize()) == -1) {
|
if (mlock(GetData(), GetSize()) == -1) {
|
||||||
|
@ -59,16 +55,16 @@ struct Segment
|
||||||
|
|
||||||
static void Remove(const std::string& shmId, uint16_t id)
|
static void Remove(const std::string& shmId, uint16_t id)
|
||||||
{
|
{
|
||||||
Monitor::RemoveObject("fmq_" + shmId + "_m_" + std::to_string(id));
|
Monitor::RemoveObject(MakeShmName(shmId, "m", id));
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
boost::variant<RBTreeBestFitSegment, SimpleSeqFitSegment> fSegment;
|
std::variant<RBTreeBestFitSegment, SimpleSeqFitSegment> fSegment;
|
||||||
|
|
||||||
static void Register(const std::string& shmId, uint16_t id, AllocationAlgorithm allocAlgo)
|
static void Register(const std::string& shmId, uint16_t id, AllocationAlgorithm allocAlgo)
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
managed_shared_memory mngSegment(open_or_create, std::string("fmq_" + shmId + "_mng").c_str(), kManagementSegmentSize);
|
managed_shared_memory mngSegment(open_or_create, MakeShmName(shmId, "mng").c_str(), kManagementSegmentSize);
|
||||||
VoidAlloc alloc(mngSegment.get_segment_manager());
|
VoidAlloc alloc(mngSegment.get_segment_manager());
|
||||||
|
|
||||||
Uint16SegmentInfoHashMap* shmSegments = mngSegment.find_or_construct<Uint16SegmentInfoHashMap>(unique_instance)(alloc);
|
Uint16SegmentInfoHashMap* shmSegments = mngSegment.find_or_construct<Uint16SegmentInfoHashMap>(unique_instance)(alloc);
|
||||||
|
|
|
@ -129,9 +129,11 @@ class Socket final : public fair::mq::Socket
|
||||||
}
|
}
|
||||||
int elapsed = 0;
|
int elapsed = 0;
|
||||||
|
|
||||||
|
MetaHeader meta{ shmMsg->fSize, shmMsg->fHint, shmMsg->fHandle, shmMsg->fShared, shmMsg->fRegionId, shmMsg->fSegmentId, shmMsg->fManaged };
|
||||||
|
|
||||||
// meta msg format: | MetaHeader | padded to fMetadataMsgSize |
|
// meta msg format: | MetaHeader | padded to fMetadataMsgSize |
|
||||||
zmq::ZMsg zmqMsg(std::max(fMetadataMsgSize, sizeof(MetaHeader)));
|
zmq::ZMsg zmqMsg(std::max(fMetadataMsgSize, sizeof(MetaHeader)));
|
||||||
std::memcpy(zmqMsg.Data(), &(shmMsg->fMeta), sizeof(MetaHeader));
|
std::memcpy(zmqMsg.Data(), &meta, sizeof(MetaHeader));
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int nbytes = zmq_msg_send(zmqMsg.Msg(), fSocket, flags);
|
int nbytes = zmq_msg_send(zmqMsg.Msg(), fSocket, flags);
|
||||||
|
@ -167,7 +169,8 @@ class Socket final : public fair::mq::Socket
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
Message* shmMsg = static_cast<Message*>(msg.get());
|
Message* shmMsg = static_cast<Message*>(msg.get());
|
||||||
int nbytes = zmq_recv(fSocket, &(shmMsg->fMeta), sizeof(MetaHeader), flags);
|
MetaHeader meta;
|
||||||
|
int nbytes = zmq_recv(fSocket, &meta, sizeof(MetaHeader), flags);
|
||||||
if (nbytes > 0) {
|
if (nbytes > 0) {
|
||||||
// check for number of received messages. must be 1
|
// check for number of received messages. must be 1
|
||||||
if (static_cast<std::size_t>(nbytes) < sizeof(MetaHeader)) {
|
if (static_cast<std::size_t>(nbytes) < sizeof(MetaHeader)) {
|
||||||
|
@ -177,6 +180,8 @@ class Socket final : public fair::mq::Socket
|
||||||
"Expected minimum size of ", sizeof(MetaHeader), " bytes, received ", nbytes));
|
"Expected minimum size of ", sizeof(MetaHeader), " bytes, received ", nbytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
shmMsg->SetMeta(meta);
|
||||||
|
|
||||||
size_t size = shmMsg->GetSize();
|
size_t size = shmMsg->GetSize();
|
||||||
fBytesRx += size;
|
fBytesRx += size;
|
||||||
++fMessagesRx;
|
++fMessagesRx;
|
||||||
|
@ -195,7 +200,7 @@ class Socket final : public fair::mq::Socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Send(std::vector<MessagePtr>& msgVec, int timeout = -1) override
|
int64_t Send(Parts::container& msgVec, int timeout = -1) override
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
|
@ -218,7 +223,8 @@ class Socket final : public fair::mq::Socket
|
||||||
}
|
}
|
||||||
assertm(dynamic_cast<shmem::Message*>(msgPtr), "given mq::Message is a shmem::Message"); // NOLINT
|
assertm(dynamic_cast<shmem::Message*>(msgPtr), "given mq::Message is a shmem::Message"); // NOLINT
|
||||||
auto shmMsg = static_cast<shmem::Message*>(msgPtr); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
auto shmMsg = static_cast<shmem::Message*>(msgPtr); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||||
std::memcpy(metas++, &(shmMsg->fMeta), sizeof(MetaHeader));
|
MetaHeader meta{ shmMsg->fSize, shmMsg->fHint, shmMsg->fHandle, shmMsg->fShared, shmMsg->fRegionId, shmMsg->fSegmentId, shmMsg->fManaged };
|
||||||
|
std::memcpy(metas++, &meta, sizeof(MetaHeader));
|
||||||
}
|
}
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -230,7 +236,7 @@ class Socket final : public fair::mq::Socket
|
||||||
for (auto& msg : msgVec) {
|
for (auto& msg : msgVec) {
|
||||||
Message* shmMsg = static_cast<Message*>(msg.get());
|
Message* shmMsg = static_cast<Message*>(msg.get());
|
||||||
shmMsg->fQueued = true;
|
shmMsg->fQueued = true;
|
||||||
totalSize += shmMsg->fMeta.fSize;
|
totalSize += shmMsg->fSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// store statistics on how many messages have been sent
|
// store statistics on how many messages have been sent
|
||||||
|
@ -254,7 +260,7 @@ class Socket final : public fair::mq::Socket
|
||||||
return static_cast<int>(TransferCode::error);
|
return static_cast<int>(TransferCode::error);
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Receive(std::vector<MessagePtr>& msgVec, int timeout = -1) override
|
int64_t Receive(Parts::container& msgVec, int timeout = -1) override
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <fairmq/shmem/Monitor.h>
|
#include <fairmq/shmem/Monitor.h>
|
||||||
#include <fairmq/tools/Strings.h>
|
#include <fairmq/tools/Strings.h>
|
||||||
#include <fairmq/UnmanagedRegion.h>
|
#include <fairmq/UnmanagedRegion.h>
|
||||||
|
#include <fairmq/Transports.h>
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
|
|
||||||
|
@ -59,11 +60,13 @@ struct UnmanagedRegion
|
||||||
, fRemoveOnDestruction(cfg.removeOnDestruction)
|
, fRemoveOnDestruction(cfg.removeOnDestruction)
|
||||||
, fLinger(cfg.linger)
|
, fLinger(cfg.linger)
|
||||||
, fStopAcks(false)
|
, fStopAcks(false)
|
||||||
, fName("fmq_" + shmId + "_rg_" + std::to_string(cfg.id.value()))
|
, fName(MakeShmName(shmId, "rg", cfg.id.value()))
|
||||||
, fQueueName("fmq_" + shmId + "_rgq_" + std::to_string(cfg.id.value()))
|
, fQueueName(MakeShmName(shmId, "rgq", cfg.id.value()))
|
||||||
|
, fRefCountSegmentName(MakeShmName(shmId, "rrc", cfg.id.value()))
|
||||||
, fShmemObject()
|
, fShmemObject()
|
||||||
, fFile(nullptr)
|
, fFile(nullptr)
|
||||||
, fFileMapping()
|
, fFileMapping()
|
||||||
|
, fRcSegmentSize(cfg.rcSegmentSize)
|
||||||
, fQueue(nullptr)
|
, fQueue(nullptr)
|
||||||
, fCallback(nullptr)
|
, fCallback(nullptr)
|
||||||
, fBulkCallback(nullptr)
|
, fBulkCallback(nullptr)
|
||||||
|
@ -145,11 +148,13 @@ struct UnmanagedRegion
|
||||||
LOG(debug) << "Successfully zeroed free memory of region " << id << ".";
|
LOG(debug) << "Successfully zeroed free memory of region " << id << ".";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InitializeRefCountSegment(fRcSegmentSize);
|
||||||
|
|
||||||
if (fControlling && created) {
|
if (fControlling && created) {
|
||||||
Register(shmId, cfg);
|
Register(shmId, cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(debug) << (created ? "Created" : "Opened") << " unmanaged shared memory region: " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
LOG(debug) << (created ? "Created" : "Opened") << " unmanaged shared memory region: " << fName << " (" << (fControlling ? "controller" : "viewer") << "), refCount segment size: " << fRcSegmentSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
UnmanagedRegion() = delete;
|
UnmanagedRegion() = delete;
|
||||||
|
@ -186,6 +191,19 @@ struct UnmanagedRegion
|
||||||
|
|
||||||
bool RemoveOnDestruction() { return fRemoveOnDestruction; }
|
bool RemoveOnDestruction() { return fRemoveOnDestruction; }
|
||||||
|
|
||||||
|
RefCount& MakeRefCount(uint16_t initialCount = 1)
|
||||||
|
{
|
||||||
|
RefCount* refCount = fRefCountPool->allocate_one().get();
|
||||||
|
new (refCount) RefCount(initialCount);
|
||||||
|
return *refCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveRefCount(RefCount& refCount)
|
||||||
|
{
|
||||||
|
refCount.~RefCount();
|
||||||
|
fRefCountPool->deallocate_one(&refCount);
|
||||||
|
}
|
||||||
|
|
||||||
~UnmanagedRegion()
|
~UnmanagedRegion()
|
||||||
{
|
{
|
||||||
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
LOG(debug) << "~UnmanagedRegion(): " << fName << " (" << (fControlling ? "controller" : "viewer") << ")";
|
||||||
|
@ -208,6 +226,11 @@ struct UnmanagedRegion
|
||||||
if (Monitor::RemoveFileMapping(fName.c_str())) {
|
if (Monitor::RemoveFileMapping(fName.c_str())) {
|
||||||
LOG(trace) << "File mapping '" << fName << "' destroyed.";
|
LOG(trace) << "File mapping '" << fName << "' destroyed.";
|
||||||
}
|
}
|
||||||
|
if (fRefCountSegment) {
|
||||||
|
if (Monitor::RemoveObject(fRefCountSegmentName)) {
|
||||||
|
LOG(trace) << "Ref Count Segment '" << fRefCountSegmentName << "' destroyed.";
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
LOG(debug) << "Skipping removal of " << fName << " unmanaged region, because RegionConfig::removeOnDestruction is false";
|
LOG(debug) << "Skipping removal of " << fName << " unmanaged region, because RegionConfig::removeOnDestruction is false";
|
||||||
}
|
}
|
||||||
|
@ -235,6 +258,7 @@ struct UnmanagedRegion
|
||||||
std::atomic<bool> fStopAcks;
|
std::atomic<bool> fStopAcks;
|
||||||
std::string fName;
|
std::string fName;
|
||||||
std::string fQueueName;
|
std::string fQueueName;
|
||||||
|
std::string fRefCountSegmentName;
|
||||||
boost::interprocess::shared_memory_object fShmemObject;
|
boost::interprocess::shared_memory_object fShmemObject;
|
||||||
FILE* fFile;
|
FILE* fFile;
|
||||||
boost::interprocess::file_mapping fFileMapping;
|
boost::interprocess::file_mapping fFileMapping;
|
||||||
|
@ -244,7 +268,10 @@ struct UnmanagedRegion
|
||||||
std::condition_variable fBlockSendCV;
|
std::condition_variable fBlockSendCV;
|
||||||
std::vector<RegionBlock> fBlocksToFree;
|
std::vector<RegionBlock> fBlocksToFree;
|
||||||
const std::size_t fAckBunchSize = 256;
|
const std::size_t fAckBunchSize = 256;
|
||||||
|
uint64_t fRcSegmentSize;
|
||||||
std::unique_ptr<boost::interprocess::message_queue> fQueue;
|
std::unique_ptr<boost::interprocess::message_queue> fQueue;
|
||||||
|
std::unique_ptr<boost::interprocess::managed_shared_memory> fRefCountSegment;
|
||||||
|
std::unique_ptr<RefCountPool> fRefCountPool;
|
||||||
|
|
||||||
std::thread fAcksReceiver;
|
std::thread fAcksReceiver;
|
||||||
std::thread fAcksSender;
|
std::thread fAcksSender;
|
||||||
|
@ -262,7 +289,7 @@ struct UnmanagedRegion
|
||||||
{
|
{
|
||||||
using namespace boost::interprocess;
|
using namespace boost::interprocess;
|
||||||
LOG(debug) << "Registering unmanaged shared memory region with id " << cfg.id.value();
|
LOG(debug) << "Registering unmanaged shared memory region with id " << cfg.id.value();
|
||||||
managed_shared_memory mngSegment(open_or_create, std::string("fmq_" + shmId + "_mng").c_str(), kManagementSegmentSize);
|
managed_shared_memory mngSegment(open_or_create, MakeShmName(shmId, "mng").c_str(), kManagementSegmentSize);
|
||||||
VoidAlloc alloc(mngSegment.get_segment_manager());
|
VoidAlloc alloc(mngSegment.get_segment_manager());
|
||||||
|
|
||||||
Uint16RegionInfoHashMap* shmRegions = mngSegment.find_or_construct<Uint16RegionInfoHashMap>(unique_instance)(alloc);
|
Uint16RegionInfoHashMap* shmRegions = mngSegment.find_or_construct<Uint16RegionInfoHashMap>(unique_instance)(alloc);
|
||||||
|
@ -275,7 +302,7 @@ struct UnmanagedRegion
|
||||||
throw TransportError(tools::ToString("Unmanaged Region with id ", cfg.id.value(), " has already been registered. Only unique IDs per session are allowed."));
|
throw TransportError(tools::ToString("Unmanaged Region with id ", cfg.id.value(), " has already been registered. Only unique IDs per session are allowed."));
|
||||||
}
|
}
|
||||||
|
|
||||||
shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, alloc));
|
shmRegions->emplace(cfg.id.value(), RegionInfo(cfg.path.c_str(), cfg.creationFlags, cfg.userFlags, cfg.size, cfg.rcSegmentSize, alloc));
|
||||||
(eventCounter->fCount)++;
|
(eventCounter->fCount)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,6 +321,29 @@ struct UnmanagedRegion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InitializeRefCountSegment(uint64_t size)
|
||||||
|
{
|
||||||
|
using namespace boost::interprocess;
|
||||||
|
if (!fRefCountSegment && size > 0) {
|
||||||
|
fRefCountSegment = std::make_unique<managed_shared_memory>(open_or_create, fRefCountSegmentName.c_str(), size);
|
||||||
|
LOG(trace) << "shmem: initialized ref count segment: " << fRefCountSegmentName;
|
||||||
|
fRefCountPool = std::make_unique<RefCountPool>(fRefCountSegment->get_segment_manager());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RefCount* GetRefCountAddressFromHandle(const boost::interprocess::managed_shared_memory::handle_t handle)
|
||||||
|
{
|
||||||
|
if (fRefCountPool) {
|
||||||
|
return reinterpret_cast<RefCount*>(fRefCountSegment->get_address_from_handle(handle));
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
boost::interprocess::managed_shared_memory::handle_t HandleFromAddress(const void* ptr)
|
||||||
|
{
|
||||||
|
return fRefCountSegment->get_handle_from_address(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
void StartAckSender()
|
void StartAckSender()
|
||||||
{
|
{
|
||||||
if (!fAcksSender.joinable()) {
|
if (!fAcksSender.joinable()) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2017-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2017-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -8,12 +8,12 @@
|
||||||
|
|
||||||
#include <fairlogger/Logger.h>
|
#include <fairlogger/Logger.h>
|
||||||
#include <fairmq/tools/Network.h>
|
#include <fairmq/tools/Network.h>
|
||||||
|
#include <fairmq/tools/Strings.h>
|
||||||
|
|
||||||
#ifndef _GNU_SOURCE
|
#ifndef _GNU_SOURCE
|
||||||
#define _GNU_SOURCE // To get defns of NI_MAXSERV and NI_MAXHOST
|
#define _GNU_SOURCE // To get defns of NI_MAXSERV and NI_MAXHOST
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <boost/algorithm/string.hpp> // trim
|
#include <boost/algorithm/string.hpp> // trim
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
|
@ -158,33 +158,22 @@ string getDefaultRouteNetworkInterface()
|
||||||
}
|
}
|
||||||
|
|
||||||
string getIpFromHostname(const string& hostname)
|
string getIpFromHostname(const string& hostname)
|
||||||
{
|
try {
|
||||||
boost::asio::io_context ioc;
|
boost::asio::io_context ioc;
|
||||||
|
boost::asio::ip::tcp::resolver resolver(ioc);
|
||||||
|
|
||||||
using namespace boost::asio::ip;
|
auto const result = resolver.resolve(boost::asio::ip::tcp::v4(), hostname, "");
|
||||||
|
|
||||||
try {
|
|
||||||
tcp::resolver resolver(ioc);
|
|
||||||
tcp::resolver::query query(hostname, "");
|
|
||||||
tcp::resolver::iterator end;
|
|
||||||
|
|
||||||
auto it = find_if(static_cast<basic_resolver_iterator<tcp>>(resolver.resolve(query)),
|
|
||||||
end,
|
|
||||||
[](const tcp::endpoint& ep) { return ep.address().is_v4(); });
|
|
||||||
|
|
||||||
if (it != end) {
|
|
||||||
stringstream ss;
|
|
||||||
ss << static_cast<tcp::endpoint>(*it).address();
|
|
||||||
return ss.str();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (result.empty()) {
|
||||||
LOG(warn) << "could not find ipv4 address for hostname '" << hostname << "'";
|
LOG(warn) << "could not find ipv4 address for hostname '" << hostname << "'";
|
||||||
|
|
||||||
return "";
|
|
||||||
} catch (exception& e) {
|
|
||||||
LOG(error) << "could not resolve hostname '" << hostname << "', reason: " << e.what();
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
return ToString(result.begin()->endpoint().address());
|
||||||
|
}
|
||||||
|
catch (std::exception const& ex)
|
||||||
|
{
|
||||||
|
LOG(error) << "could not resolve hostname '" << hostname << "', reason: " << ex.what();
|
||||||
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace fair::mq::tools
|
} // namespace fair::mq::tools
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2017-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2017-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -29,7 +29,7 @@ class LinePrinter
|
||||||
public:
|
public:
|
||||||
LinePrinter(stringstream& out, string prefix)
|
LinePrinter(stringstream& out, string prefix)
|
||||||
: fOut(out)
|
: fOut(out)
|
||||||
, fPrefix(move(prefix))
|
, fPrefix(std::move(prefix))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
// prints line with prefix on both cout (thread-safe) and output stream
|
// prints line with prefix on both cout (thread-safe) and output stream
|
||||||
|
@ -64,22 +64,22 @@ execute_result execute(const string& cmd, const string& prefix, const string& in
|
||||||
|
|
||||||
p.Print(cmd);
|
p.Print(cmd);
|
||||||
|
|
||||||
ba::io_service ios;
|
ba::io_context ioc;
|
||||||
|
|
||||||
// containers for std_in
|
// containers for std_in
|
||||||
ba::const_buffer inputBuffer(ba::buffer(input));
|
ba::const_buffer inputBuffer(ba::buffer(input));
|
||||||
bp::async_pipe inputPipe(ios);
|
bp::async_pipe inputPipe(ioc);
|
||||||
// containers for std_out
|
// containers for std_out
|
||||||
ba::streambuf outputBuffer;
|
ba::streambuf outputBuffer;
|
||||||
bp::async_pipe outputPipe(ios);
|
bp::async_pipe outputPipe(ioc);
|
||||||
// containers for std_err
|
// containers for std_err
|
||||||
ba::streambuf errorBuffer;
|
ba::streambuf errorBuffer;
|
||||||
bp::async_pipe errorPipe(ios);
|
bp::async_pipe errorPipe(ioc);
|
||||||
|
|
||||||
const string delimiter = "\n";
|
const string delimiter = "\n";
|
||||||
ba::steady_timer inputTimer(ios);
|
ba::steady_timer inputTimer(ioc);
|
||||||
inputTimer.expires_after(std::chrono::milliseconds(1000)); // NOLINT
|
inputTimer.expires_after(std::chrono::milliseconds(1000)); // NOLINT
|
||||||
ba::steady_timer signalTimer(ios);
|
ba::steady_timer signalTimer(ioc);
|
||||||
signalTimer.expires_after(std::chrono::milliseconds(2000)); // NOLINT
|
signalTimer.expires_after(std::chrono::milliseconds(2000)); // NOLINT
|
||||||
|
|
||||||
// child process
|
// child process
|
||||||
|
@ -154,7 +154,7 @@ execute_result execute(const string& cmd, const string& prefix, const string& in
|
||||||
};
|
};
|
||||||
ba::async_read_until(errorPipe, errorBuffer, delimiter, onStdErr);
|
ba::async_read_until(errorPipe, errorBuffer, delimiter, onStdErr);
|
||||||
|
|
||||||
ios.run();
|
ioc.run();
|
||||||
c.wait();
|
c.wait();
|
||||||
|
|
||||||
result.exit_code = c.exit_code();
|
result.exit_code = c.exit_code();
|
||||||
|
|
|
@ -210,7 +210,7 @@ class Message final : public fair::mq::Message
|
||||||
// destroyed. Used size is applied only once in ApplyUsedSize, which is called by the socket
|
// destroyed. Used size is applied only once in ApplyUsedSize, which is called by the socket
|
||||||
// before sending. This function just updates the desired size until the actual "resizing"
|
// before sending. This function just updates the desired size until the actual "resizing"
|
||||||
// happens.
|
// happens.
|
||||||
bool SetUsedSize(size_t size) override
|
bool SetUsedSize(size_t size, Alignment /* alignment */ = Alignment{0}) override
|
||||||
{
|
{
|
||||||
if (size == GetSize()) {
|
if (size == GetSize()) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
|
|
|
@ -154,7 +154,7 @@ class Socket final : public fair::mq::Socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Send(std::vector<std::unique_ptr<fair::mq::Message>>& msgVec, int timeout = -1) override
|
int64_t Send(Parts::container& msgVec, int timeout = -1) override
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
|
@ -206,7 +206,7 @@ class Socket final : public fair::mq::Socket
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t Receive(std::vector<std::unique_ptr<fair::mq::Message>>& msgVec, int timeout = -1) override
|
int64_t Receive(Parts::container& msgVec, int timeout = -1) override
|
||||||
{
|
{
|
||||||
int flags = 0;
|
int flags = 0;
|
||||||
if (timeout == 0) {
|
if (timeout == 0) {
|
||||||
|
@ -225,7 +225,7 @@ class Socket final : public fair::mq::Socket
|
||||||
int nbytes = zmq_msg_recv(static_cast<Message*>(part.get())->GetMessage(), fSocket, flags);
|
int nbytes = zmq_msg_recv(static_cast<Message*>(part.get())->GetMessage(), fSocket, flags);
|
||||||
if (nbytes >= 0) {
|
if (nbytes >= 0) {
|
||||||
static_cast<Message*>(part.get())->Realign();
|
static_cast<Message*>(part.get())->Realign();
|
||||||
msgVec.push_back(move(part));
|
msgVec.push_back(std::move(part));
|
||||||
totalSize += nbytes;
|
totalSize += nbytes;
|
||||||
} else if (zmq_errno() == EAGAIN || zmq_errno() == EINTR) {
|
} else if (zmq_errno() == EAGAIN || zmq_errno() == EINTR) {
|
||||||
if (fCtx.Interrupted()) {
|
if (fCtx.Interrupted()) {
|
||||||
|
|
|
@ -253,7 +253,7 @@ add_testsuite(Tools
|
||||||
LINKS FairMQ
|
LINKS FairMQ
|
||||||
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
INCLUDES ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${CMAKE_CURRENT_BINARY_DIR}
|
${CMAKE_CURRENT_BINARY_DIR}
|
||||||
TIMEOUT 20
|
TIMEOUT 5
|
||||||
${environment}
|
${environment}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
#include <gtest/gtest.h>
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
|
@ -101,7 +102,7 @@ TEST(MemoryResources, allocator)
|
||||||
|
|
||||||
size_t session{tools::UuidHash()};
|
size_t session{tools::UuidHash()};
|
||||||
ProgOptions config;
|
ProgOptions config;
|
||||||
config.SetProperty<string>("session", to_string(session));
|
config.SetProperty<std::string>("session", to_string(session));
|
||||||
|
|
||||||
FactoryType factoryZMQ = TransportFactory::CreateTransportFactory("zeromq", fair::mq::tools::Uuid(), &config);
|
FactoryType factoryZMQ = TransportFactory::CreateTransportFactory("zeromq", fair::mq::tools::Uuid(), &config);
|
||||||
|
|
||||||
|
@ -129,7 +130,7 @@ TEST(MemoryResources, getMessage)
|
||||||
|
|
||||||
size_t session{tools::UuidHash()};
|
size_t session{tools::UuidHash()};
|
||||||
ProgOptions config;
|
ProgOptions config;
|
||||||
config.SetProperty<string>("session", to_string(session));
|
config.SetProperty<std::string>("session", to_string(session));
|
||||||
config.SetProperty<bool>("shm-monitor", true);
|
config.SetProperty<bool>("shm-monitor", true);
|
||||||
|
|
||||||
FactoryType factoryZMQ = TransportFactory::CreateTransportFactory("zeromq", fair::mq::tools::Uuid(), &config);
|
FactoryType factoryZMQ = TransportFactory::CreateTransportFactory("zeromq", fair::mq::tools::Uuid(), &config);
|
||||||
|
|
|
@ -50,7 +50,7 @@ auto RunPushPullWithMsgResize(string const & transport, string const & _address,
|
||||||
|
|
||||||
Channel push{"Push", "push", factory};
|
Channel push{"Push", "push", factory};
|
||||||
Channel pull{"Pull", "pull", factory};
|
Channel pull{"Pull", "pull", factory};
|
||||||
auto const address(tools::ToString(_address, "_", transport));
|
auto const address(tools::ToString(_address, "_", transport, "_", config.GetProperty<string>("session")));
|
||||||
push.Bind(address);
|
push.Bind(address);
|
||||||
pull.Connect(address);
|
pull.Connect(address);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ auto RunPushPullWithAlignment(string const& transport, string const& _address, b
|
||||||
|
|
||||||
Channel push{"Push", "push", factory};
|
Channel push{"Push", "push", factory};
|
||||||
Channel pull{"Pull", "pull", factory};
|
Channel pull{"Pull", "pull", factory};
|
||||||
auto const address(tools::ToString(_address, "_", transport));
|
auto const address(tools::ToString(_address, "_", transport, "_", config.GetProperty<string>("session")));
|
||||||
push.Bind(address);
|
push.Bind(address);
|
||||||
pull.Connect(address);
|
pull.Connect(address);
|
||||||
|
|
||||||
|
@ -211,7 +211,7 @@ auto EmptyMessage(string const& transport, string const& _address, bool expanded
|
||||||
|
|
||||||
Channel push{"Push", "push", factory};
|
Channel push{"Push", "push", factory};
|
||||||
Channel pull{"Pull", "pull", factory};
|
Channel pull{"Pull", "pull", factory};
|
||||||
auto const address(tools::ToString(_address, "_", transport));
|
auto const address(tools::ToString(_address, "_", transport, "_", config.GetProperty<string>("session")));
|
||||||
push.Bind(address);
|
push.Bind(address);
|
||||||
pull.Connect(address);
|
pull.Connect(address);
|
||||||
|
|
||||||
|
@ -287,8 +287,10 @@ auto ZeroCopy(bool expandedShmMetadata = false) -> void
|
||||||
|
|
||||||
// The "zero copy" property of the Copy() method is an implementation detail and is not guaranteed.
|
// The "zero copy" property of the Copy() method is an implementation detail and is not guaranteed.
|
||||||
// Currently it holds true for the shmem (across devices) and for zeromq (within same device) transports.
|
// Currently it holds true for the shmem (across devices) and for zeromq (within same device) transports.
|
||||||
auto ZeroCopyFromUnmanaged(string const& address, bool expandedShmMetadata = false) -> void
|
auto ZeroCopyFromUnmanaged(string const& address, bool expandedShmMetadata, uint64_t rcSegmentSize) -> void
|
||||||
{
|
{
|
||||||
|
fair::Logger::SetConsoleSeverity(fair::Severity::debug);
|
||||||
|
|
||||||
ProgOptions config1;
|
ProgOptions config1;
|
||||||
ProgOptions config2;
|
ProgOptions config2;
|
||||||
string session(tools::Uuid());
|
string session(tools::Uuid());
|
||||||
|
@ -311,18 +313,20 @@ auto ZeroCopyFromUnmanaged(string const& address, bool expandedShmMetadata = fal
|
||||||
|
|
||||||
const size_t msgSize{100};
|
const size_t msgSize{100};
|
||||||
const size_t regionSize{1000000};
|
const size_t regionSize{1000000};
|
||||||
|
RegionConfig cfg;
|
||||||
|
cfg.rcSegmentSize = rcSegmentSize;
|
||||||
tools::Semaphore blocker;
|
tools::Semaphore blocker;
|
||||||
|
|
||||||
auto region = factory1->CreateUnmanagedRegion(regionSize, [&blocker](void*, size_t, void*) {
|
auto region = factory1->CreateUnmanagedRegion(regionSize, [&blocker](void*, size_t, void*) {
|
||||||
blocker.Signal();
|
blocker.Signal();
|
||||||
});
|
}, cfg);
|
||||||
|
|
||||||
{
|
{
|
||||||
Channel push("Push", "push", factory1);
|
Channel push("Push", "push", factory1);
|
||||||
Channel pull("Pull", "pull", factory2);
|
Channel pull("Pull", "pull", factory2);
|
||||||
|
|
||||||
push.Bind(address);
|
push.Bind(address + "_" + session);
|
||||||
pull.Connect(address);
|
pull.Connect(address + "_" + session);
|
||||||
|
|
||||||
const size_t offset = 100;
|
const size_t offset = 100;
|
||||||
auto msg1(push.NewMessage(region, static_cast<char*>(region->GetData()), msgSize, nullptr));
|
auto msg1(push.NewMessage(region, static_cast<char*>(region->GetData()), msgSize, nullptr));
|
||||||
|
@ -461,12 +465,22 @@ TEST(ZeroCopy, shmem_expanded_metadata) // NOLINT
|
||||||
|
|
||||||
TEST(ZeroCopyFromUnmanaged, shmem) // NOLINT
|
TEST(ZeroCopyFromUnmanaged, shmem) // NOLINT
|
||||||
{
|
{
|
||||||
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged");
|
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged", false, 10000000);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(ZeroCopyFromUnmanaged, shmem_expanded_metadata) // NOLINT
|
TEST(ZeroCopyFromUnmanaged, shmem_expanded_metadata) // NOLINT
|
||||||
{
|
{
|
||||||
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged", true);
|
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged_expanded", true, 10000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ZeroCopyFromUnmanaged, shmem_no_rc_segment) // NOLINT
|
||||||
|
{
|
||||||
|
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged_no_rc_segment", false, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ZeroCopyFromUnmanaged, shmem_expanded_metadata_no_rc_segment) // NOLINT
|
||||||
|
{
|
||||||
|
ZeroCopyFromUnmanaged("ipc://test_zerocopy_unmanaged_expanded_no_rc_segment", true, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2017-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
|
@ -7,8 +7,12 @@
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include "Fixture.h"
|
#include "Fixture.h"
|
||||||
|
#include <array>
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
|
#include <fairmq/Tools.h>
|
||||||
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
@ -142,4 +146,27 @@ TEST_F(PluginServices, ControlStateTransitionConversions)
|
||||||
EXPECT_NO_THROW(mServices.ToStr(DeviceStateTransition::ErrorFound));
|
EXPECT_NO_THROW(mServices.ToStr(DeviceStateTransition::ErrorFound));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(PluginServices, SubscriptionThreadSafety)
|
||||||
|
{
|
||||||
|
// obviously not a perfect test, but I could segfault fmq reliably with it (without the fix)
|
||||||
|
|
||||||
|
constexpr auto attempts = 1000;
|
||||||
|
constexpr auto subscribers = 5;
|
||||||
|
|
||||||
|
std::array<std::unique_ptr<std::thread>, subscribers> threads;
|
||||||
|
auto id = 0;
|
||||||
|
for (auto& thread : threads) {
|
||||||
|
thread = std::make_unique<std::thread>([&](){
|
||||||
|
auto const subscriber = fair::mq::tools::ToString("subscriber_", id);
|
||||||
|
for (auto i = 0; i < attempts; ++i) {
|
||||||
|
mServices.SubscribeToDeviceStateChange(subscriber, [](DeviceState){});
|
||||||
|
mServices.UnsubscribeFromDeviceStateChange(subscriber);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
++id;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& thread : threads) { thread->join(); }
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
|
@ -35,6 +35,9 @@ auto RunSingleThreadedMultipart(string transport, string address1, string addres
|
||||||
config.SetProperty<size_t>("shm-metadata-msg-size", 2048);
|
config.SetProperty<size_t>("shm-metadata-msg-size", 2048);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address1 += "_" + config.GetProperty<string>("session");
|
||||||
|
address2 += "_" + config.GetProperty<string>("session");
|
||||||
|
|
||||||
auto factory = TransportFactory::CreateTransportFactory(transport, tools::Uuid(), &config);
|
auto factory = TransportFactory::CreateTransportFactory(transport, tools::Uuid(), &config);
|
||||||
|
|
||||||
Channel push1("Push1", "push", factory);
|
Channel push1("Push1", "push", factory);
|
||||||
|
@ -118,6 +121,8 @@ auto RunMultiThreadedMultipart(string transport, string address1, bool expandedS
|
||||||
config.SetProperty<size_t>("shm-metadata-msg-size", 2048);
|
config.SetProperty<size_t>("shm-metadata-msg-size", 2048);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
address1 += "_" + config.GetProperty<string>("session");
|
||||||
|
|
||||||
auto factory = TransportFactory::CreateTransportFactory(transport, tools::Uuid(), &config);
|
auto factory = TransportFactory::CreateTransportFactory(transport, tools::Uuid(), &config);
|
||||||
|
|
||||||
Channel push1("Push1", "push", factory);
|
Channel push1("Push1", "push", factory);
|
||||||
|
@ -210,7 +215,7 @@ TEST(PushPull, Multipart_MultiThreaded_ipc_shmem) // NOLINT
|
||||||
|
|
||||||
TEST(PushPull, Multipart_MultiThreaded_ipc_shmem_expanded_metadata) // NOLINT
|
TEST(PushPull, Multipart_MultiThreaded_ipc_shmem_expanded_metadata) // NOLINT
|
||||||
{
|
{
|
||||||
RunMultiThreadedMultipart("shmem", "ipc://test_Multipart_MultiThreaded_ipc_shmem_1", true);
|
RunMultiThreadedMultipart("shmem", "ipc://test_Multipart_MultiThreaded_ipc_shmem__expanded_metadata_1", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
|
@ -1,28 +1,37 @@
|
||||||
/********************************************************************************
|
/********************************************************************************
|
||||||
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
* Copyright (C) 2018-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
|
||||||
* *
|
* *
|
||||||
* This software is distributed under the terms of the *
|
* This software is distributed under the terms of the *
|
||||||
* GNU Lesser General Public Licence (LGPL) version 3, *
|
* GNU Lesser General Public Licence (LGPL) version 3, *
|
||||||
* copied verbatim in the file "LICENSE" *
|
* copied verbatim in the file "LICENSE" *
|
||||||
********************************************************************************/
|
********************************************************************************/
|
||||||
|
|
||||||
#include <gtest/gtest.h>
|
|
||||||
#include <fairmq/tools/Network.h>
|
#include <fairmq/tools/Network.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
using namespace std;
|
TEST(Tools, NetworkDefaultIP)
|
||||||
using namespace fair::mq;
|
|
||||||
|
|
||||||
TEST(Tools, Network)
|
|
||||||
{
|
{
|
||||||
string interface = fair::mq::tools::getDefaultRouteNetworkInterface();
|
auto const interface = fair::mq::tools::getDefaultRouteNetworkInterface();
|
||||||
EXPECT_NE(interface, "");
|
EXPECT_NE(interface, "");
|
||||||
string interfaceIP = fair::mq::tools::getInterfaceIP(interface);
|
auto const interfaceIP = fair::mq::tools::getInterfaceIP(interface);
|
||||||
EXPECT_NE(interfaceIP, "");
|
EXPECT_NE(interfaceIP, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(Tools, NetworkIPv4Localhost)
|
||||||
|
{
|
||||||
|
auto const ip = fair::mq::tools::getIpFromHostname("localhost");
|
||||||
|
EXPECT_FALSE(ip.empty());
|
||||||
|
EXPECT_EQ(ip, "127.0.0.1");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(Tools, NetworkInvalidHostname)
|
||||||
|
{
|
||||||
|
auto const ip = fair::mq::tools::getIpFromHostname("non.existent.domain.invalid");
|
||||||
|
EXPECT_TRUE(ip.empty());
|
||||||
|
}
|
||||||
|
|
||||||
} /* namespace */
|
} /* namespace */
|
||||||
|
|
Loading…
Reference in New Issue
Block a user