Compare commits

...

192 Commits

Author SHA1 Message Date
Dennis Klein
dcea48fcee
fix: parse errors
```
/test/memory_resources/_memory_resources.cxx: In member function ‘virtual void {anonymous}::MemoryResources_allocator_Test::TestBody()’:
/test/memory_resources/_memory_resources.cxx:104:12: error: parse error in template argument list
  104 |     config.SetProperty<string>("session", to_string(session));
      |            ^~~~~~~~~~~~~~~~~~~
/test/memory_resources/_memory_resources.cxx:104:31: error: no matching function for call to ‘fair::mq::ProgOptions::SetProperty<<expression error> >(const char [8], std::string)’
  104 |     config.SetProperty<string>("session", to_string(session));
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /home/dklein/projects/FairMQ2/test/memory_resources/_memory_resources.cxx:11:
/fairmq/ProgOptions.h:269:6: note: candidate: ‘template<class T> void fair::mq::ProgOptions::SetProperty(const std::string&, T)’
  269 | void fair::mq::ProgOptions::SetProperty(const std::string& key, T val)
      |      ^~~~
/fairmq/ProgOptions.h:269:6: note:   template argument deduction/substitution failed:
/test/memory_resources/_memory_resources.cxx:104:31: error: template argument 1 is invalid
  104 |     config.SetProperty<string>("session", to_string(session));
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/test/memory_resources/_memory_resources.cxx: In member function ‘virtual void {anonymous}::MemoryResources_getMessage_Test::TestBody()’:
/test/memory_resources/_memory_resources.cxx:132:12: error: parse error in template argument list
  132 |     config.SetProperty<string>("session", to_string(session));
      |            ^~~~~~~~~~~~~~~~~~~
/test/memory_resources/_memory_resources.cxx:132:31: error: no matching function for call to ‘fair::mq::ProgOptions::SetProperty<<expression error> >(const char [8], std::string)’
  132 |     config.SetProperty<string>("session", to_string(session));
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/fairmq/ProgOptions.h:269:6: note: candidate: ‘template<class T> void fair::mq::ProgOptions::SetProperty(const std::string&, T)’
  269 | void fair::mq::ProgOptions::SetProperty(const std::string& key, T val)
      |      ^~~~
/fairmq/ProgOptions.h:269:6: note:   template argument deduction/substitution failed:
/test/memory_resources/_memory_resources.cxx:132:31: error: template argument 1 is invalid
  132 |     config.SetProperty<string>("session", to_string(session));
      |     ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
2025-06-13 08:17:53 +02:00
Giulio Eulisse
67dcf77a7f De-boostify: use std::pmr from C++17 2025-06-13 08:02:06 +02:00
Alexey Rybalchenko
24e7a5b8d0 Make shmem headers public 2025-03-17 15:16:46 +01:00
Giulio Eulisse
c11506e958
feat(EventManager): Out of line some methods 2025-01-23 15:35:26 +01:00
Dennis Klein
e4f258c9ea fix: Update copyright 2025-01-09 17:09:57 +01:00
Dennis Klein
324a27a2e1 fix(tools): No longer use removed alias io_service
Deprecated via d3bbf3756d
and removed via 49fcd03434
in Boost 1.87 or Asio 1.33.
2025-01-09 17:09:57 +01:00
Dennis Klein
c80f97b338 fix(tools): No longer use removed query API
Deprecated via 74fe2b8e14
and removed via e916bdfb1a
in Boost 1.87 or Asio 1.33.
2025-01-09 17:09:57 +01:00
Dennis Klein
76824fee36 build(googletest): Update metadata 2025-01-09 17:09:57 +01:00
dependabot[bot]
d2e4679dc8 build(deps): bump extern/googletest from 530d5c8 to 7d76a23
Bumps [extern/googletest](https://github.com/google/googletest) from `530d5c8` to `7d76a23`.
- [Release notes](https://github.com/google/googletest/releases)
- [Commits](530d5c8c84...7d76a231b0)

---
updated-dependencies:
- dependency-name: extern/googletest
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-07 18:24:47 +01:00
Alexey Rybalchenko
6bb70bd519 Update Mac CI nodes 2025-01-07 17:42:16 +01:00
Giulio Eulisse
fe2127e12f Reduce bloat due to statics
Avoid disseminating every compile unit including Message.h with TransportNames and
TransportTypes and the associated unordered_map helper methods (e.g.
murmur_hash).
2025-01-07 17:41:30 +01:00
Giulio Eulisse
41165cf16b Out of line ProgOption::SetProperty for int and std::string
The specializations are common enough to show up in O2 compilation profiles
and they are not time critical (once per run at max).
2025-01-07 17:34:22 +01:00
Dennis Klein
8fe95e644e ci: Update 2024-08-20 15:56:21 +02:00
Dennis Klein
6628a231e2 build: Adopt all CMake policies up to 3.30
Modernizing to the policy range syntax supported by
[`cmake_minimum_required`](https://cmake.org/cmake/help/latest/command/cmake_minimum_required.html)
since CMake 3.12.
2024-08-20 15:56:21 +02:00
Giulio Eulisse
91b31f0799 Hide actual container from the API 2024-05-23 15:54:24 +02:00
Alexey Rybalchenko
39cb021827 Add 'no control' controller 2024-02-19 22:09:54 +01:00
Alexey Rybalchenko
36b48f5594 Update MacOS CI entires 2024-02-16 13:12:40 +01:00
Alexey Rybalchenko
0e221b28b8 shm: use node_allocator for ref counts 2024-01-25 10:45:34 +01:00
Alexey Rybalchenko
1ee0977df4 shm: use (de)allocate_one() for ref counts 2024-01-25 10:45:34 +01:00
Alexey Rybalchenko
24d578a4ba shm: extend monitor output for refCount region 2024-01-25 10:45:34 +01:00
Christian Tacke
ce1a4499cc ci: Check codemeta/zenodo with AUTHORS/CONTRIBUTORS
If AUTHORS or CONTRIBUTORS are changed,
check that the changes are merged into codemeta.json,
and .zenodo.json.
2023-12-20 16:51:13 +01:00
Dennis Klein
7d009f0915 docs: Update installation section 2023-12-14 13:15:18 +00:00
Dennis Klein
b70b181c38
ci: Create devcontainer.json 2023-12-14 13:40:47 +01:00
dependabot[bot]
94602d23b3 build(deps): bump extern/googletest from a1cc8c5 to 530d5c8
Bumps [extern/googletest](https://github.com/google/googletest) from `a1cc8c5` to `530d5c8`.
- [Release notes](https://github.com/google/googletest/releases)
- [Commits](a1cc8c5519...530d5c8c84)

---
updated-dependencies:
- dependency-name: extern/googletest
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-14 13:35:01 +01:00
Dennis Klein
41ac755c57
ci: Fix dependabot gitsubmodule directory 2023-12-13 15:48:21 +01:00
Dennis Klein
6d4a82427b
Update dependabot.yml 2023-12-13 15:31:14 +01:00
Dennis Klein
0966dee55d
build: Enable dependabot 2023-12-13 15:26:44 +01:00
Christian Tacke
b649356c5a chore: upgrade checkout step to v4 2023-12-13 13:34:35 +01:00
Alexey Rybalchenko
2df3d909fa shm: when refCount segment size is zero, fallback to old behaviour
, which is to store reference counts inside the main data segment
2023-11-29 19:21:42 +01:00
Alexey Rybalchenko
05a2ae6a31 example: configure new script too 2023-11-29 19:21:42 +01:00
Alexey Rybalchenko
58ffdfd1f4 Remove unused ctor and constant 2023-11-29 19:21:42 +01:00
Alexey Rybalchenko
addfd071bb Fix incorrect parameters in region example scripts 2023-11-24 14:19:21 +01:00
Alexey Rybalchenko
2d27abc533 Examples: add a script for externally created region 2023-11-24 14:19:21 +01:00
Alexey Rybalchenko
faf577086a shm: fix initialization of rc segment when region is created externally 2023-11-24 14:19:21 +01:00
Alexey Rybalchenko
ff1f9b94ef shm: include rcCountSegment free memory in the monitor output 2023-11-24 14:19:21 +01:00
Alexey Rybalchenko
34e8a24c86 Examples: use multipart in the region example 2023-11-15 12:52:14 +01:00
Alexey Rybalchenko
7567a10513 shm: Bump the ref segment size 10x 2023-11-15 12:52:14 +01:00
Alexey Rybalchenko
424e22b41a shm: Throw RefCountBadAlloc if insufficient space in the ref count segment 2023-11-15 12:52:14 +01:00
Dennis Klein
961eca5276 test(PluginServices): state change subscription thread-safety 2023-11-10 13:13:13 +01:00
Alexey Rybalchenko
fbb6577625 StateMachine: Guard access to subscription containers 2023-11-10 13:13:13 +01:00
Alexey Rybalchenko
6122010694 Fix address clashes in tests 2023-10-24 15:22:21 +02:00
Giulio Eulisse
b40db42196 Use std::move rather than just move
Apparently:

  "warning: unqualified call to 'std::move' [-Wunqualified-std-cast-call]"

is default in new XCode.
2023-10-23 08:00:23 +02:00
Giulio Eulisse
f732b87def Drop unused variable
The else clause at the end makes the postincrement impossible.
2023-10-23 08:00:23 +02:00
Alexey Rybalchenko
f05a09da5a shm: Message: refactor ctors 2023-10-19 19:16:00 +02:00
Alexey Rybalchenko
5aa6c99442 shm: remove alignment member from Message 2023-10-19 19:16:00 +02:00
Alexey Rybalchenko
3c714fd9e0 Message::SetUsedSize: add optional alignment argument, to avoid storing alignment with the msg object 2023-10-19 19:16:00 +02:00
Alexey Rybalchenko
1b7532a520 Refactor shm::Message to contain sorted members of MetaHeader
Move the members of MetaHeader flat into shmem::Message and sort them by
size to reduce the size of the class.
2023-10-19 19:16:00 +02:00
Alexey Rybalchenko
f092b94c96
Update comment 2023-10-04 11:25:47 +02:00
Alexey Rybalchenko
8d28824489 Shm: Use MakeShmName to construct shm object names 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
4310d07ed1 deduplicate ipc address in a test 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
7bd31f8ff0 apply readability-else-after-return 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
1a0ab3a4e2 shm: Ref counting for unmanaged regions in a dedicated segment 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
cacf69d5f6 Replace boost::variant with std::variant 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
46f50a10ea Add example with ref-counted copy from unmanaged region 2023-09-29 11:18:24 +02:00
Alexey Rybalchenko
68038c4693 shm: Move ShmHeader into Common.h 2023-09-29 11:18:24 +02:00
Dennis Klein
1036e204d0 docs: Add "releaseNotes" field to codemeta 2023-09-11 18:07:29 +02:00
Dennis Klein
fddbbc1732 docs: Add "softwareVersion" field to codemeta 2023-09-11 18:01:42 +02:00
Giulio Eulisse
3c1723fc54 Allow sorting StateChange callbacks
If the key of the callback is a number, it will be used to invoke
callbacks with the correct ordering.
2023-09-06 09:49:30 +02:00
Christian Tacke
c3418cc7b8 chore: Run meta_update.py 2023-08-08 16:26:10 +02:00
Christian Tacke
cc00c5a6f1 docs: Add "readme" field to codemeta
A link to an introduction for people who are not experts in
the field.
2023-08-08 16:26:10 +02:00
Christian Tacke
e6bb14f535 ci: Check codemeta.json
Use the eOSSR tooling to validate our codemeta.json file
2023-08-08 16:26:10 +02:00
Christian Tacke
b18d60372c codemeta: Add GSI as "maintainer"
GSI is providing resources for maintaining FairMQ. So let's
document this in codemeta.json.
2023-08-08 16:21:48 +02:00
Giulio Eulisse
7ceccdeaa6 Print actual address we are trying to bind. 2023-06-29 12:28:23 +02:00
Dennis Klein
d1c99f7e15 ci: Update build matrix 2023-06-26 11:56:24 +02:00
Dennis Klein
bfc665d76e feat: Make the channel AutoBind default configurable 2023-06-26 11:56:24 +02:00
Dennis Klein
42d27af20f docs: Update install commands 2023-06-13 22:43:52 +02:00
Alexey Rybalchenko
25614e3e06 test: Add coverage for --shm-metadata-msg-size 2023-06-13 21:24:40 +02:00
Alexey Rybalchenko
3decac58fc test: Add data transfer and checks to protocol tests 2023-06-13 21:24:40 +02:00
Dennis Klein
f278e7e312 feat: Add new tunable --shm-metadata-msg-size
The shm metadata msg will be right-padded to the given size. This
tunable may be used to saturate the kernel msg buffers more quickly with
the effect that the ZeroMQ message queue size - on which the FairMQ
shmem transport relies upon - behaves more accurately for very small
queue sizes.

This introduces a change for the meta msg format in the multipart case:
old: | MetaHeader 1 | ... | MetaHeader n |
new: | n | MetaHeader 1 | ... | MetaHeader n | padded to fMetadataMsgSize |
where `n` is a `size_t` and contains the number of following meta headers.
Previously, this number was infered from the msg buffer size itself which is
no longer possible due to the potential padding.

Implements #432
2023-06-13 21:24:40 +02:00
Dennis Klein
491a943c63 feat: Use zmq_msg_send for single message Send 2023-06-13 21:24:40 +02:00
Dennis Klein
c47fc6f9fe feat: Move ZMsg to fair::mq::zmq
Implement move semantics.
2023-06-13 21:24:40 +02:00
Giulio Eulisse
7b259afdb5 Fix -Wunqualified-std-cast-call 2023-06-13 21:24:40 +02:00
Dennis Klein
33ddcaad5e docs: Add repology badge 2023-04-05 15:19:05 +02:00
Dennis Klein
4d5dbedeab build: Add spack develop environment 2023-03-23 14:14:08 +01:00
Dennis Klein
c8fde17b6a ci: Silence lsan hits in libzmq 2023-03-06 15:32:48 +01:00
Dennis Klein
3781495d29 build(examples): Deduplicate code into add_example helper 2023-03-06 15:32:48 +01:00
Dennis Klein
8960ce9416 fix: Use std::chrono consistently 2023-03-06 15:32:48 +01:00
Dennis Klein
05b734ee0d feat!: Migrate to std::filesystem consistently 2023-03-06 15:32:48 +01:00
Alexey Rybalchenko
f2dce91098 Make Error classes header only 2023-03-03 12:49:37 +01:00
Alexey Rybalchenko
4af0954ae9 Shm: fix unused value 2023-03-02 19:12:29 +01:00
Alexey Rybalchenko
8f60929f85 Add orcid for Alexey 2023-03-02 13:03:04 +01:00
Dennis Klein
7d401115a0 build: Update CMake policy version range 2023-03-02 11:20:35 +01:00
Dennis Klein
0aecfff133 feat(plugins)!: Remove PMIx plugin 2023-03-02 11:20:35 +01:00
Dennis Klein
2e98a4e2cb feat(ofi)!: Remove ofi transport
BREAKING CHANGE

Due to a lack of users, we remove the experimental code. The
latest implementation can be found in release v1.4.56. This does
not mean it will never be picked up again, but for now there are
no plans.
2023-03-02 11:20:35 +01:00
Dennis Klein
21735544f5 ci: Add Fedora 37 & 38 builds 2023-03-01 15:39:38 +01:00
Dennis Klein
651d779226 build: Do not sort package dependencies
Order matters!

fixes #144
2023-03-01 15:39:38 +01:00
Dennis Klein
5108f699b7 fix: Remove unused fMaxRunRuntimeInS
The corresponding config option was already
removed in v1.4.50 (see 5d45d89269)
2023-03-01 15:39:38 +01:00
Dennis Klein
c35d35a3c3 feat!: Remove Device::TransitionTo() without replacement
BREAKING CHANGE

However, this API was never advertised nor used by anyone.
2023-03-01 15:39:38 +01:00
Dennis Klein
c2fa2e8848 test: Deduplicate code and fix [-Wunused-result] 2023-03-01 15:39:38 +01:00
Dennis Klein
b25c0787c0 test: Fix [-Wunused-result] 2023-03-01 15:39:38 +01:00
Dennis Klein
84de22f80b test: Consolidate some device control logic 2023-03-01 15:39:38 +01:00
Dennis Klein
435d07eaf9 feat: Improve ChangeState API
* Add `[[nodiscard]]` to `bool Device::ChangeState()`
* Introduce throwing variant `void Device::ChangeStateOrThrow()`

resolves #441
2023-03-01 15:39:38 +01:00
Dennis Klein
5ef17fddbb feat: Deprecate Device::fChannels in preparation for #427 2023-03-01 15:39:38 +01:00
Dennis Klein
f699208e30 Merge 'v1.4.56' 2023-02-24 14:35:30 +01:00
Alexey Rybalchenko
8f5efdf74c Extend shmem docs 2023-02-24 14:28:18 +01:00
Alexey Rybalchenko
45663189a9 Turn shm-monitor off by default
resolves #459
2023-02-24 14:28:18 +01:00
Alexey Rybalchenko
61d2797971 Example tests: check exit codes 2023-02-24 14:28:18 +01:00
Alexey Rybalchenko
afd5700cca Update copyright date 2023-02-24 14:28:18 +01:00
Dennis Klein
569f2ccebf ci: Only run workflows on main repo 2023-02-24 13:59:27 +01:00
Dennis Klein
a83e401100 fix: [-Wdeprecated-declarations] 2023-02-24 13:59:27 +01:00
Dennis Klein
0a63c74849 fix: [-Wsign-compare] 2023-02-24 13:59:27 +01:00
Dennis Klein
a58b4870d7 feat(Parts): Refine and tweak
* Optimize appending another Parts container
* Remove redundant/verbose comments
* Change r-value args to move-only types into l-value args for
  readability
* Deprecate `AtRef(int)`, redundant, just dereference at call site
* Deprecate `AddPart(Message*)`, avoid owning raw pointer args
* Add various const overloads
* Add `Empty()` and `Clear()` member functions
* Add `noexcept` where applicable
2023-02-24 13:59:27 +01:00
Alexey Rybalchenko
7bf1d368a8 Device: synchronize access to transports container 2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
ae7bc6fc6c Control plugin: remove superfluous automatic transitions 2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
9093ed82dc Resume/Interrupt transports consistently
- Resume transports before state callbacks & handlers
 - Interrupt transports on new transitions
2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
efb659f0ac Device: sort includes 2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
ae51ecc659 Add Device::ResumeTransports 2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
da1c9e4400 Rename Device::UnblockTransports to Device::InterruptTransports 2023-02-22 20:55:15 +01:00
Alexey Rybalchenko
16275db125 Add test for externally (outside the session) created shmem region 2023-01-19 16:12:58 +01:00
Alexey Rybalchenko
42ce691f57 shm: error on duplicate region IDs 2023-01-19 16:12:31 +01:00
Alexey Rybalchenko
58aa2b4f88 shm: refactor UnamangedRegion: rename fRemote to fController 2023-01-19 16:12:22 +01:00
Alexey Rybalchenko
c3b273cec0 shm: Improve debug output a bit 2023-01-19 16:10:59 +01:00
Alexey Rybalchenko
a982d60ed7 example: fix incorrect config 2023-01-19 16:10:44 +01:00
Christian Tacke
1076fbf824 Add ORCiD for @MohammadAlTurany 2023-01-19 11:11:39 +01:00
Dennis Klein
d16e473b91 docs: Update fair-software.eu compliance badge
And link to the GH workflow page instead of fair-software.eu
2023-01-16 13:27:13 +01:00
Dennis Klein
ae6b60cc60 docs: Update fair-software.eu compliance badge
And link to the GH workflow page instead of fair-software.eu
2023-01-16 13:26:24 +01:00
Dennis Klein
1881986cca docs: Add fair-software.eu compliance badge 2023-01-16 13:17:09 +01:00
Dennis Klein
adf91d053d docs: Add OpenSSF Best Practices Badge 2023-01-16 13:16:56 +01:00
Dennis Klein
d3be9af9b6 docs: Add our DOI badge 2023-01-16 13:16:42 +01:00
Dennis Klein
4104636456 build: Add fair-software.eu compliance checker 2023-01-16 13:15:33 +01:00
Dennis Klein
c6dc360dc1 docs: Add fair-software.eu compliance badge 2023-01-16 13:08:13 +01:00
Dennis Klein
f04266f738 docs: Add OpenSSF Best Practices Badge 2023-01-16 13:06:08 +01:00
Dennis Klein
7e0faa297b build: Add fair-software.eu compliance checker 2023-01-16 11:44:03 +01:00
Piotr Konopka
9389030835 Warn when going to try allocate a shmem message more times 2022-11-18 09:36:52 +01:00
Alexey Rybalchenko
7697f2f4b1 Extend error message if channel(s) was not configured before timeout 2022-11-17 11:03:59 +01:00
Alexey Rybalchenko
87baf9749d Make invalid channel initialization cancellable through pending state 2022-11-17 11:03:59 +01:00
Alexey Rybalchenko
a8b7ebef09 Add operator<< to fair::mq::Channel 2022-11-17 11:03:59 +01:00
Alexey Rybalchenko
ac661dfd63 Add test for externally (outside the session) created shmem region 2022-10-05 09:13:37 +02:00
Alexey Rybalchenko
ed364a4857 shm: error on duplicate region IDs 2022-10-05 09:13:37 +02:00
Alexey Rybalchenko
9a25c4d28a shm: refactor UnamangedRegion: rename fRemote to fController 2022-10-05 09:13:37 +02:00
Alexey Rybalchenko
19e40bd32e shm: Improve debug output a bit 2022-10-05 09:13:37 +02:00
Alexey Rybalchenko
b7a4f22a13 example: fix incorrect config 2022-10-05 09:13:37 +02:00
Dennis Klein
77e04d56de fix(examples): warning: declaration class fair::mq::Device does not declare anything 2022-09-14 07:37:52 +02:00
Alexey Rybalchenko
64a09dd991 fix(examples): Disable hidden CXX_VISIBILITY_PRESET
It was not needed.
2022-09-14 07:37:52 +02:00
Dennis Klein
126475e7d2 feat(tools): Add macro to instruct the compiler to always inline 2022-09-14 07:37:52 +02:00
Dennis Klein
0e12c57ff0 build: Print summary of compile definitions 2022-09-14 07:37:52 +02:00
Dennis Klein
6eb973235a build: Add feature flag FAIRMQ_HAS_STD_PMR
Currently Clang (libc++) does not implement <memory_resource>.
2022-09-14 07:37:52 +02:00
Dennis Klein
904037d9be fix(shm): Handle pre-conditions 2022-09-14 07:37:52 +02:00
Dennis Klein
de8236491f Merge 'v1.4.55' 2022-09-12 13:29:29 +02:00
Alexey Rybalchenko
af0d668951 Shm: fix region init with external regions 2022-09-09 15:40:33 +02:00
Alexey Rybalchenko
072d7cb744 shm: add some debug output 2022-09-09 15:40:33 +02:00
Alexey Rybalchenko
f5c46ce018 region example: add options for testing with externally-created regions 2022-09-09 15:40:33 +02:00
Alexey Rybalchenko
de09018198 Shm: fix region init with external regions 2022-09-09 15:11:12 +02:00
Alexey Rybalchenko
46e568c55e shm: add some debug output 2022-09-09 15:11:12 +02:00
Alexey Rybalchenko
1870c1c060 region example: add options for testing with externally-created regions 2022-09-09 15:11:12 +02:00
Dennis Klein
c5cbc3d33b Merge 'v1.4.54' 2022-09-08 12:31:41 +02:00
Alexey Rybalchenko
fdfde95dec region example: fix race between segment reset & presence check 2022-09-08 07:43:45 +02:00
Alexey Rybalchenko
d105960444 fix(shm): Fix incorrect parameters when mapping regions 2022-09-06 08:09:47 +02:00
Dennis Klein
3aae5bae58 build: Add ORCID for Christian Tacke 2022-09-06 08:08:42 +02:00
Dennis Klein
9031029d2c build: Add ORCID for Dennis Klein 2022-09-06 08:08:34 +02:00
Dennis Klein
d478e050ba build: HTML-Format desc field in zenodo.org config 2022-09-06 08:08:14 +02:00
Dennis Klein
06b2b9b01f build: Add license hint to zenodo.org config 2022-09-06 08:08:05 +02:00
Dennis Klein
b3fa4f6e7e build: Add config for zenodo.org import 2022-09-06 08:07:46 +02:00
Alexey Rybalchenko
75e68e3e4d fix(shm): Fix incorrect parameters when mapping regions 2022-09-06 07:57:45 +02:00
Dennis Klein
83ddbcef4c build(metaUpdater): Keep original ordering when adding new entries 2022-09-02 20:39:41 +02:00
Christian Tacke
1b796b80dd build(metaUpdater): Reorder orcid in CodeMeta
`@id` is usually quite at the top of elements in schema.org
style json files.  It's usually the canonical identifier
for that element.

So reorder ORCIDs to the top in those entries.
2022-09-02 20:39:41 +02:00
Christian Tacke
9f06cfe66b build(metaUpdater): Simplify some code
* Use class attributes instead of inheritance
* Remove unused arguments
* Reformat for PEP-8
2022-09-02 20:39:41 +02:00
Christian Tacke
a37781475b build(metaUpdater): Fix Adding new "creators" to .zenodo.json
When adding new "creators" to .zenodo.json, the
kwargs['contributor_type'] is not set at all.

Instead use normal keyword handling with defaults.
2022-09-02 20:39:41 +02:00
Dennis Klein
832c83247a build(metaUpdater): Deduplicate _handle_person_list_file() 2022-09-02 11:42:37 +02:00
Christian Tacke
69e82ca60c build(metaUpdater): Handle Non-Existant Files
If .zenodo.json (or codemeta.json) isn't there, only throw
a warning, and continue.
2022-09-01 20:03:56 +02:00
Christian Tacke
8086a04fb3 build: Match on ORCID in Updater
* If an already existing entry in the json file has the
  correct ORCID, prefer it for updating, always
* Find that entry for codemeta as well
2022-09-01 19:11:30 +02:00
Dennis Klein
3367abdce3 build: Support updating the .zenodo.json metadata 2022-09-01 18:41:57 +02:00
Dennis Klein
f462e595ed build: Add ORCID for Christian Tacke 2022-09-01 17:44:16 +02:00
Dennis Klein
40fcc466a9 build: Add ORCID for Dennis Klein 2022-09-01 17:35:32 +02:00
Dennis Klein
69220a2e49 build(codemeta): Support [ORCID] syntax 2022-09-01 17:34:58 +02:00
Dennis Klein
b707a8b45e build: HTML-Format desc field in zenodo.org config 2022-09-01 16:24:41 +02:00
Dennis Klein
c9fb8ac936 build: Add license hint to zenodo.org config 2022-09-01 15:59:28 +02:00
Dennis Klein
3925feb2b6 build: Add config for zenodo.org import 2022-09-01 15:37:56 +02:00
Dennis Klein
41b4a5f027 Merge 'v1.4.53' 2022-08-31 15:55:01 +02:00
Dennis Klein
faa309556f feat(examples): Add new example with custom controller plugin (statically compiled in) 2022-08-24 14:41:14 +02:00
Alexey Rybalchenko
4587af2eb4 fix(shm): race/deadlock in region locks 2022-08-19 12:24:35 +02:00
Dennis Klein
73fd1b2c2a docs: Add our DOI badge 2022-08-12 02:48:09 +02:00
Dennis Klein
a1e5962262 build: With -O3 2022-08-12 01:50:14 +02:00
Dennis Klein
e57f746dc9 ci: Run test suite in parallel 2022-08-12 01:50:14 +02:00
Dennis Klein
9a51c7b5fb ci: Update and use images from ghcr.io/fairrootgroup/fairmq-dev 2022-08-12 01:50:14 +02:00
Dennis Klein
b3395ef26e build: ABI version is defined to be equal to the API version 2022-08-12 01:50:14 +02:00
Dennis Klein
a48344bb03 fix(tidy): Regex 2022-08-12 01:50:14 +02:00
Dennis Klein
9297308f8a fix(tidy): Only emit diagnostic if source location is valid 2022-08-12 01:50:14 +02:00
Dennis Klein
c3fdc8c08c fix(zeromq): Leaking monitor socket messages 2022-08-12 01:50:14 +02:00
Dennis Klein
4ae68b63e9 fix: Remove long obsolete hotfix version component 2022-08-12 01:50:14 +02:00
Dennis Klein
2db9bd4b82 ci: Update macOS builds 2022-08-12 01:50:14 +02:00
Dennis Klein
e202512621 build: Bump bundled GTest to @a1cc8c55 2022-08-12 01:50:14 +02:00
Dennis Klein
2513da2136 build(fairmq-tidy): Add missing EXPERIMENTAL tag 2022-08-12 01:50:14 +02:00
Dennis Klein
640becc436 build: Use kebab-case library names in install tree 2022-08-11 15:30:25 +02:00
Dennis Klein
ca420a0e0d feat(plugins): Allow kebab-case plugin names, e.g. libfairmq-plugin-pmix
Camel+snake-case plugin names are still allowed! e.g. `libFairMQPlugin_pmix`
2022-08-11 15:30:25 +02:00
Dennis Klein
b798b1e098 test: Increase robustness of the test suite for high -j 2022-08-11 15:30:25 +02:00
Dennis Klein
ac1904661a test(channel): Increase sleep time
The logic of the GetNumberOfConnectedPeers test case relies on sleeping
a certain time. We have observed the 10ms sleep time to sometimes be too
short. Increasing it to 100ms should improve test stability.
2022-08-11 15:30:25 +02:00
Dennis Klein
cfc6090405 build!: Create a single library again
BREAKING CHANGE: Removes exported targets FairMQ::Tools and
FairMQ::StateMachine. However, it is unlikely those were used
by anyone.
2022-08-11 15:30:25 +02:00
Dennis Klein
12a85c6fb1 fix: Use namespaced typenames/headers 2022-08-11 15:30:25 +02:00
Dennis Klein
0959095a39 feat: Deprecate non-namespaced headers
For more details see https://github.com/FairRootGroup/FairMQ/discussions/423
2022-08-11 15:30:25 +02:00
Dennis Klein
9ad9393d44 feat: Deprecate non-namespaced typenames
For more details see https://github.com/FairRootGroup/FairMQ/discussions/423
2022-08-11 15:30:25 +02:00
Dennis Klein
cda7282422 feat!: Remove deprecated components sdk, sdk_commands, dds_plugin
BREAKING CHANGE: Components have been moved to ODC project, see
https://github.com/FairRootGroup/FairMQ/discussions/392 for details.
2022-08-11 15:30:25 +02:00
229 changed files with 3682 additions and 12005 deletions

View File

@ -0,0 +1,5 @@
{
"image": "ghcr.io/fairrootgroup/fairmq-dev/fedora-38:latest",
"features": {
}
}

12
.github/dependabot.yml vendored Normal file
View 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
View 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

View 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

16
.github/workflows/fair-software.yml vendored Normal file
View File

@ -0,0 +1,16 @@
name: fair-software
on: push
jobs:
verify:
name: "fair-software"
runs-on: ubuntu-latest
if: github.repository == 'FairRootGroup/FairMQ'
steps:
- uses: fair-software/howfairis-github-action@0.2.1
name: Measure compliance with fair-software.eu recommendations
env:
PYCHARM_HOSTED: "Trick colorama into displaying colored output"
with:
MY_REPO_URL: "https://github.com/${{ github.repository }}"

2
.gitignore vendored
View File

@ -4,3 +4,5 @@ install
.vscode
/compile_commands.json
.cache
.spack-env
spack.lock

88
.zenodo.json Normal file
View File

@ -0,0 +1,88 @@
{
"creators": [
{
"orcid": "0000-0002-8071-4497",
"name": "Al-Turany, Mohammad"
},
{
"orcid": "0000-0003-3787-1910",
"name": "Klein, Dennis"
},
{
"name": "Kollegger, Thorsten"
},
{
"orcid": "0000-0002-6249-155X",
"name": "Rybalchenko, Alexey"
},
{
"name": "Winckler, Nicolas"
}
],
"contributors": [
{
"type": "Other",
"name": "Aphecetche, Laurent"
},
{
"type": "Other",
"name": "Binet, Sebastien"
},
{
"type": "Other",
"name": "Eulisse, Giulio"
},
{
"type": "Other",
"name": "Karabowicz, Radoslaw"
},
{
"type": "Other",
"name": "Kretz, Matthias"
},
{
"type": "Other",
"name": "Krzewicki, Mikolaj"
},
{
"type": "Other",
"name": "Lebedev, Andrey"
},
{
"type": "Other",
"name": "Mrnjavac, Teo"
},
{
"type": "Other",
"name": "Neskovic, Gvozden"
},
{
"type": "Other",
"name": "Richter, Matthias"
},
{
"type": "Other",
"orcid": "0000-0002-5321-8404",
"name": "Tacke, Christian"
},
{
"type": "Other",
"name": "Uhlig, Florian"
},
{
"type": "Other",
"name": "Wenzel, Sandro"
}
],
"description": "<p>C++ Message Queuing Library and Framework</p>",
"related_identifiers": [
{
"identifier": "https://github.com/FairRootGroup/FairMQ/",
"relation": "isSupplementTo",
"resource_type": "software",
"scheme": "url"
}
],
"title": "FairMQ",
"license": "LGPL-3.0-only"
}

View File

@ -1,5 +1,5 @@
Al-Turany, Mohammad
Klein, Dennis
Al-Turany, Mohammad [https://orcid.org/0000-0002-8071-4497]
Klein, Dennis [https://orcid.org/0000-0003-3787-1910]
Kollegger, Thorsten
Rybalchenko, Alexey
Rybalchenko, Alexey [https://orcid.org/0000-0002-6249-155X]
Winckler, Nicolas

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2024 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -8,8 +8,7 @@
# Project ######################################################################
cmake_minimum_required(VERSION 3.15 FATAL_ERROR)
cmake_policy(VERSION 3.15...3.22)
cmake_minimum_required(VERSION 3.15...3.30 FATAL_ERROR)
list(PREPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake)
include(GitHelper)
@ -27,18 +26,8 @@ fairmq_build_option(BUILD_FAIRMQ "Build FairMQ library and devices."
DEFAULT ON)
fairmq_build_option(BUILD_TESTING "Build tests."
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
fairmq_build_option(BUILD_OFI_TRANSPORT "Build experimental OFI transport."
DEFAULT OFF REQUIRES "BUILD_FAIRMQ")
fairmq_build_option(BUILD_SDK_COMMANDS "Build the FairMQ SDK commands."
DEFAULT OFF)
fairmq_build_option(BUILD_DDS_PLUGIN "Build DDS plugin."
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
fairmq_build_option(BUILD_PMIX_PLUGIN "Build PMIx plugin."
DEFAULT OFF REQUIRES "BUILD_FAIRMQ;BUILD_SDK_COMMANDS")
fairmq_build_option(BUILD_EXAMPLES "Build FairMQ examples."
DEFAULT ON REQUIRES "BUILD_FAIRMQ")
fairmq_build_option(BUILD_SDK "Build the FairMQ controller SDK."
DEFAULT OFF REQUIRES "BUILD_DDS_PLUGIN;BUILD_SDK_COMMANDS")
fairmq_build_option(BUILD_TIDY_TOOL "Build the fairmq-tidy tool."
DEFAULT OFF)
fairmq_build_option(BUILD_DOCS "Build FairMQ documentation."
@ -57,7 +46,7 @@ include(FairMQDependencies)
# Targets ######################################################################
if(BUILD_FAIRMQ OR BUILD_SDK)
if(BUILD_FAIRMQ)
add_subdirectory(fairmq)
endif()
@ -92,27 +81,12 @@ endif()
if(BUILD_TESTING)
list(APPEND PROJECT_PACKAGE_COMPONENTS tests)
endif()
if(BUILD_DDS_PLUGIN)
list(APPEND PROJECT_PACKAGE_COMPONENTS dds_plugin)
endif()
if(BUILD_PMIX_PLUGIN)
list(APPEND PROJECT_PACKAGE_COMPONENTS pmix_plugin)
endif()
if(BUILD_OFI_TRANSPORT)
list(APPEND PROJECT_PACKAGE_COMPONENTS ofi_transport)
endif()
if(BUILD_EXAMPLES)
list(APPEND PROJECT_PACKAGE_COMPONENTS examples)
endif()
if(BUILD_DOCS)
list(APPEND PROJECT_PACKAGE_COMPONENTS docs)
endif()
if(BUILD_SDK)
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk)
endif()
if(BUILD_SDK_COMMANDS)
list(APPEND PROJECT_PACKAGE_COMPONENTS sdk_commands)
endif()
if(BUILD_TIDY_TOOL)
list(APPEND PROJECT_PACKAGE_COMPONENTS tidy_tool)
endif()
@ -125,11 +99,6 @@ if(BUILD_FAIRMQ)
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_SDK OR BUILD_DDS_PLUGIN)
install(FILES cmake/Findasio.cmake
DESTINATION ${PROJECT_INSTALL_CMAKEMODDIR}
)
endif()
if(BUILD_DOCS)
install(DIRECTORY ${CMAKE_BINARY_DIR}/doxygen/html
DESTINATION ${PROJECT_INSTALL_DATADIR}/docs
@ -157,5 +126,6 @@ fairmq_summary_components()
fairmq_summary_static_analysis()
fairmq_summary_install_prefix()
fairmq_summary_debug_mode()
fairmq_summary_compile_definitions()
message(STATUS " ")
################################################################################

View File

@ -3,11 +3,11 @@ Binet, Sebastien
Eulisse, Giulio
Karabowicz, Radoslaw
Kretz, Matthias <kretz@kde.org>
Krzewicki, Mikolaj
Krzewicki, Mikolaj
Lebedev, Andrey
Mrnjavac, Teo <teo.m@cern.ch>
Neskovic, Gvozden
Richter, Matthias
Tacke, Christian
Tacke, Christian [https://orcid.org/0000-0002-5321-8404]
Uhlig, Florian
Wenzel, Sandro

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2021-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -42,15 +42,6 @@ endif()
ctest_start(Continuous)
list(APPEND options "-DDISABLE_COLOR=ON" "-DBUILD_EXAMPLES=ON" "-DBUILD_TESTING=ON")
if(HAS_ASIO AND HAS_DDS)
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_SDK=ON" "-DBUILD_DDS_PLUGIN=ON")
endif()
if(HAS_PMIX)
list(APPEND options "-DBUILD_SDK_COMMANDS=ON" "-DBUILD_PMIX_PLUGIN=ON")
endif()
if(HAS_ASIO AND HAS_ASIOFI)
list(APPEND options "-DBUILD_OFI_TRANSPORT=ON")
endif()
if(RUN_STATIC_ANALYSIS)
list(APPEND options "-DRUN_STATIC_ANALYSIS=ON")
endif()
@ -90,7 +81,7 @@ ctest_submit()
if(NOT RUN_STATIC_ANALYSIS)
ctest_test(BUILD "${CTEST_BINARY_DIRECTORY}"
PARALLEL_LEVEL 1
PARALLEL_LEVEL ${NCPUS}
SCHEDULE_RANDOM ON
RETURN_VALUE _ctest_test_ret_val)

48
Jenkinsfile vendored
View File

@ -4,20 +4,21 @@ def jobMatrix(String type, List specs) {
def nodes = [:]
for (spec in specs) {
def job = ""
def selector = ""
def selector = "slurm"
def os = ""
def ver = ""
if (type == 'build') {
job = "${spec.os}-${spec.ver}-${spec.arch}-${spec.compiler}"
selector = "${spec.os}-${spec.ver}-${spec.arch}"
if (spec.os =~ /^macos/) {
selector = "${spec.os}-${spec.ver}-${spec.arch}"
}
os = spec.os
ver = spec.ver
} else { // == 'check'
job = "${spec.name}"
selector = 'fedora-35-x86_64'
os = 'fedora'
ver = '35'
ver = '36'
}
def label = "${job}"
@ -36,14 +37,14 @@ def jobMatrix(String type, List specs) {
sh "echo \"export LABEL=\\\"\${JOB_BASE_NAME} ${label}\\\"\" >> ${jobscript}"
if (selector =~ /^macos/) {
sh """\
echo \"export DDS_ROOT=\\\"\\\$(brew --prefix dds)\\\"\" >> ${jobscript}
echo \"export PATH=\\\"\\\$(brew --prefix dds)/bin:\\\$PATH\\\"\" >> ${jobscript}
echo \"${ctestcmd}\" >> ${jobscript}
"""
sh "cat ${jobscript}"
sh "bash ${jobscript}"
} else {
def containercmd = "singularity exec --net --ipc --uts --pid -B/shared ${env.SINGULARITY_CONTAINER_ROOT}/fairmq/${os}.${ver}.sif bash -l -c \\\"${ctestcmd} ${extra}\\\""
} else { // selector == "slurm"
def imageurl = "oras://ghcr.io/fairrootgroup/fairmq-dev/${os}-${ver}-sif:latest"
def execopts = "--ipc --uts --pid -B/shared"
def containercmd = "singularity exec ${execopts} ${imageurl} bash -l -c \\\"${ctestcmd} ${extra}\\\""
sh """\
echo \"echo \\\"*** Job started at .......: \\\$(date -R)\\\"\" >> ${jobscript}
echo \"echo \\\"*** Job ID ...............: \\\${SLURM_JOB_ID}\\\"\" >> ${jobscript}
@ -67,12 +68,6 @@ def jobMatrix(String type, List specs) {
deleteDir()
githubNotify(context: "${label}", description: 'Success', status: 'SUCCESS')
} catch (e) {
def tarball = "${type}_${job}_dds_logs.tar.gz"
if (fileExists("build/test/.DDS")) {
sh "tar czvf ${tarball} -C \${WORKSPACE}/build/test .DDS/"
archiveArtifacts tarball
}
deleteDir()
githubNotify(context: "${label}", description: 'Error', status: 'ERROR')
throw e
@ -89,19 +84,24 @@ pipeline{
stage("CI") {
steps{
script {
def all = '-DHAS_ASIO=ON -DHAS_ASIOFI=ON -DHAS_PMIX=ON'
def builds = jobMatrix('build', [
[os: 'ubuntu', ver: '20.04', arch: 'x86_64', compiler: 'gcc-9', extra: all],
[os: 'fedora', ver: '32', arch: 'x86_64', compiler: 'gcc-10', extra: all],
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10', extra: all],
[os: 'fedora', ver: '34', arch: 'x86_64', compiler: 'gcc-11', extra: all],
[os: 'fedora', ver: '35', arch: 'x86_64', compiler: 'gcc-11', extra: all],
[os: 'macos', ver: '11', arch: 'x86_64', compiler: 'apple-clang-12', extra: '-DHAS_ASIO=ON'],
[os: 'macos', ver: '11', arch: 'arm64', compiler: 'apple-clang-13', extra: '-DHAS_ASIO=ON'],
[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: '24.04', arch: 'x86_64', compiler: 'gcc-13'],
[os: 'fedora', ver: '33', arch: 'x86_64', compiler: 'gcc-10'],
[os: 'fedora', ver: '34', 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: '37', arch: 'x86_64', compiler: 'gcc-12'],
[os: 'fedora', ver: '38', arch: 'x86_64', compiler: 'gcc-13'],
[os: 'fedora', ver: '39', arch: 'x86_64', compiler: 'gcc-13'],
[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 = "${all} -DCMAKE_BUILD_TYPE=Debug"
def all_debug = "-DCMAKE_BUILD_TYPE=Debug"
def checks = jobMatrix('check', [
[name: 'static-analyzers', extra: "${all_debug} -DRUN_STATIC_ANALYSIS=ON"],

View File

@ -1,5 +1,11 @@
<!-- {#mainpage} -->
# FairMQ [![license](https://alfa-ci.gsi.de/shields/badge/license-LGPL--3.0-orange.svg)](COPYRIGHT)
# FairMQ
[![license](https://alfa-ci.gsi.de/shields/badge/license-LGPL--3.0-orange.svg)](COPYRIGHT)
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.1689985.svg)](https://doi.org/10.5281/zenodo.1689985)
[![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/6915/badge)](https://bestpractices.coreinfrastructure.org/projects/6915)
[![fair-software.eu](https://img.shields.io/badge/fair--software.eu-%E2%97%8F%20%20%E2%97%8F%20%20%E2%97%8B%20%20%E2%97%8F%20%20%E2%97%8F-yellow)](https://github.com/FairRootGroup/FairMQ/actions/workflows/fair-software.yml)
[![Spack package](https://repology.org/badge/version-for-repo/spack/fairmq.svg)](https://repology.org/project/fairmq/versions)
C++ Message Queuing Library and Framework
@ -18,7 +24,8 @@ FairMQ is designed to help implementing large-scale data processing workflows ne
The core of FairMQ provides an abstract asynchronous message passing API with scalability protocols
inspired by [ZeroMQ](https://github.com/zeromq/libzmq) (e.g. PUSH/PULL, PUB/SUB).
FairMQ provides multiple implementations for its API (so-called "transports",
e.g. `zeromq`, `shmem` and `ofi` (in development)) to cover a variety of use cases
e.g. `zeromq` and `shmem` (latest release of the `ofi` transport in v1.4.56, removed since v1.5+)) to cover
a variety of use cases
(e.g. inter-thread, inter-process, inter-node communication) and machines (e.g. Ethernet, Infiniband).
In addition to this core functionality FairMQ provides a framework for creating "devices" - actors which
are communicating through message passing. FairMQ does not only allow the user to use different transport
@ -38,10 +45,10 @@ Recommended:
```bash
git clone https://github.com/FairRootGroup/FairMQ fairmq_source
cmake -S fairmq_source -B fairmq_build -GNinja -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=fairmq_install
cmake -S fairmq_source -B fairmq_build -GNinja -DCMAKE_BUILD_TYPE=Release [-DBUILD_TESTING=ON]
cmake --build fairmq_build
cmake --build fairmq_build --target test
cmake --build fairmq_build --target install
[ctest --test-dir fairmq_build --output-on-failure --schedule-random -j<ncpus>] # needs -DBUILD_TESTING=ON
cmake --install fairmq_build --prefix $(pwd)/fairmq_install
```
Please consult the [manpages of your CMake version](https://cmake.org/cmake/help/latest/manual/cmake.1.html) for more options.
@ -49,6 +56,25 @@ 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
`-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
FairMQ ships as a CMake package, so in your `CMakeLists.txt` you can discover it like this:
@ -68,27 +94,14 @@ If FairMQ is not installed in system directories, you can hint the installation:
list(PREPEND CMAKE_PREFIX_PATH /path/to/fairmq_install)
```
Optionally, you can require certain FairMQ package components and a minimum version:
```cmake
find_package(FairMQ 1.4.50 COMPONENTS ofi_transport)
```
When building FairMQ, CMake will print a summary table of all available package components.
## Dependencies
* [asio](https://github.com/chriskohlhoff/asio)
* [asiofi](https://github.com/FairRootGroup/asiofi)
* [Boost](https://www.boost.org/)
* [CMake](https://cmake.org/)
* [DDS](http://dds.gsi.de)
* [Doxygen](http://www.doxygen.org/)
* [FairCMakeModules](https://github.com/FairRootGroup/FairCMakeModules) (optionally bundled)
* [FairLogger](https://github.com/FairRootGroup/FairLogger)
* [Flatbuffers](https://google.github.io/flatbuffers/)
* [GTest](https://github.com/google/googletest) (optionally bundled)
* [PMIx](https://pmix.org/)
* [ZeroMQ](http://zeromq.org/)
Which dependencies are required depends on which components are built.
@ -102,9 +115,8 @@ On command line:
* `-DDISABLE_COLOR=ON` disables coloured console output.
* `-DBUILD_TESTING=OFF` disables building of tests.
* `-DBUILD_EXAMPLES=OFF` disables building of examples.
* `-DBUILD_OFI_TRANSPORT=ON` enables building of the experimental OFI transport.
* `-DBUILD_PMIX_PLUGIN=ON` enables building of the PMIx plugin.
* `-DBUILD_DOCS=ON` enables building of API docs.
* `-DFAIRMQ_CHANNEL_DEFAULT_AUTOBIND=OFF` disable channel `autoBind` by default
* You can hint non-system installations for dependent packages, see the #installation-from-source section above
After the `find_package(FairMQ)` call the following CMake variables are defined:
@ -161,6 +173,4 @@ After the `find_package(FairMQ)` call the following CMake variables are defined:
1. [Usage](docs/Plugins.md#71-usage)
2. [Development](docs/Plugins.md#72-development)
3. [Provided Plugins](docs/Plugins.md#73-provided-plugins)
1. [DDS](docs/Plugins.md#731-dds)
2. [PMIx](docs/Plugins.md#732-pmix)
8. [Controller SDK](docs/SDK.md)
1. [PMIx](docs/Plugins.md#731-pmix)

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2025 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -12,46 +12,19 @@ include(FairCMakeModules)
include(FairFindPackage2)
include(FairMQBundlePackageHelper)
if(BUILD_FAIRMQ OR BUILD_SDK)
if(BUILD_FAIRMQ)
set(THREADS_PREFER_PTHREAD_FLAG TRUE)
find_package2(PUBLIC Threads REQUIRED)
set(Threads_PREFIX "<system>")
endif()
if(BUILD_OFI_TRANSPORT)
find_package2(PRIVATE asiofi REQUIRED VERSION 0.5)
find_package2(PRIVATE OFI REQUIRED)
endif()
if(BUILD_SDK_COMMANDS)
find_package2(PRIVATE Flatbuffers REQUIRED)
endif()
if(BUILD_DDS_PLUGIN OR BUILD_SDK)
find_package2(PRIVATE DDS REQUIRED VERSION 3.5.13.7)
set(DDS_Boost_COMPONENTS system log log_setup regex filesystem thread)
set(DDS_Boost_VERSION 1.67)
endif()
if(BUILD_PMIX_PLUGIN)
find_package2(PRIVATE PMIx REQUIRED VERSION 2.1.4)
endif()
if(BUILD_FAIRMQ OR BUILD_SDK OR BUILD_TIDY_TOOL)
if(BUILD_FAIRMQ OR BUILD_TIDY_TOOL)
find_package2(PUBLIC FairLogger REQUIRED VERSION 1.6.0)
find_package2(PUBLIC Boost REQUIRED VERSION 1.66
COMPONENTS container program_options filesystem date_time regex
)
endif()
if(BUILD_OFI_TRANSPORT OR BUILD_SDK OR BUILD_DDS_PLUGIN)
set(__old ${CMAKE_FIND_PACKAGE_PREFER_CONFIG})
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ON)
find_package2(PUBLIC asio REQUIRED VERSION 1.18)
set(CMAKE_FIND_PACKAGE_PREFER_CONFIG ${__old})
unset(__old)
endif()
if(BUILD_FAIRMQ)
find_package2(PRIVATE ZeroMQ REQUIRED VERSION 4.1.4)
if(NOT PicoSHA2_BUNDLED)
@ -68,7 +41,7 @@ if(BUILD_TESTING)
endif()
find_package2(BUNDLED GTest REQUIRED)
if(GTest_BUNDLED)
set(GTest_VERSION "Apr 28 2021 @f5e592d8")
set(GTest_VERSION "Dec 26 2024 @7d76a23")
set(GTest_PREFIX "<bundled>")
endif()
endif()
@ -97,12 +70,6 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
if(NOT FairLogger_PREFIX AND FairLogger_ROOT)
set(FairLogger_PREFIX ${FairLogger_ROOT})
endif()
elseif(${dep} STREQUAL asiofi)
if(NOT asiofi_PREFIX AND asiofi_ROOT)
set(asiofi_PREFIX ${asiofi_ROOT})
endif()
elseif(${dep} STREQUAL DDS)
set(DDS_PREFIX "${DDS_INSTALL_PREFIX}")
elseif(${dep} STREQUAL Boost)
if(TARGET Boost::headers)
get_target_property(boost_include Boost::headers INTERFACE_INCLUDE_DIRECTORIES)
@ -116,14 +83,6 @@ if(PROJECT_PACKAGE_DEPENDENCIES)
get_filename_component(Doxygen_PREFIX ${doxygen_bin} DIRECTORY)
get_filename_component(Doxygen_PREFIX ${Doxygen_PREFIX}/.. ABSOLUTE)
unset(doxygen_bin)
elseif(${dep} STREQUAL Flatbuffers)
if(TARGET flatbuffers::flatbuffers)
get_target_property(flatbuffers_include flatbuffers::flatbuffers INTERFACE_INCLUDE_DIRECTORIES)
else()
get_target_property(flatbuffers_include flatbuffers::flatbuffers_shared INTERFACE_INCLUDE_DIRECTORIES)
endif()
get_filename_component(Flatbuffers_PREFIX ${flatbuffers_include}/.. ABSOLUTE)
unset(flatbuffers_include)
elseif(NOT ${dep}_PREFIX)
# try to guess
if(TARGET ${dep}::${dep})

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -34,8 +34,6 @@ endfunction()
# Configure/Install CMake package
macro(install_cmake_package)
list(SORT PROJECT_PACKAGE_DEPENDENCIES)
list(SORT PROJECT_INTERFACE_PACKAGE_DEPENDENCIES)
include(CMakePackageConfigHelpers)
set(PACKAGE_INSTALL_DESTINATION
${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}-${PROJECT_VERSION}

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -114,8 +114,8 @@ endif()
set(CMAKE_CONFIGURATION_TYPES "Debug" "Release" "RelWithDebInfo")
set(_warnings "-Wshadow -Wall -Wextra -Wpedantic")
set(CMAKE_CXX_FLAGS_DEBUG "-Og -g ${_warnings} ${_sanitizers}")
set(CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${_warnings} -DNDEBUG ${_sanitizers}")
set(CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O3 -g ${_warnings} -DNDEBUG ${_sanitizers}")
unset(_warnings)
unset(_sanitizers)
@ -168,9 +168,22 @@ if(CMAKE_GENERATOR STREQUAL Ninja AND ENABLE_CCACHE)
endif()
endif()
if( CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
set(FAIRMQ_HAS_STD_FILESYSTEM 0)
else()
set(FAIRMQ_HAS_STD_FILESYSTEM 1)
if(NOT DEFINED FAIRMQ_HAS_STD_FILESYSTEM)
if( ( CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9)
OR ( CMAKE_CXX_COMPILER_ID STREQUAL "Clang"
AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 9))
set(FAIRMQ_HAS_STD_FILESYSTEM 0)
else()
set(FAIRMQ_HAS_STD_FILESYSTEM 1)
endif()
endif()
if(NOT DEFINED FAIRMQ_HAS_STD_PMR)
if(CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Clang (to be more precise: libc++) currently does not implement <memory_resource>
set(FAIRMQ_HAS_STD_PMR 0)
else()
set(FAIRMQ_HAS_STD_PMR 1)
endif()
endif()

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -27,24 +27,6 @@ macro(fairmq_summary_components)
set(tests_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TESTING=ON${CR})")
endif()
message(STATUS " ${BWhite}tests${CR} ${tests_summary}")
if(BUILD_OFI_TRANSPORT)
set(ofi_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_OFI_TRANSPORT=OFF${CR})")
else()
set(ofi_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_OFI_TRANSPORT=ON${CR})")
endif()
message(STATUS " ${BWhite}ofi_transport${CR} ${ofi_summary}")
if(BUILD_DDS_PLUGIN)
set(dds_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_DDS_PLUGIN=OFF${CR})")
else()
set(dds_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_DDS_PLUGIN=ON${CR})")
endif()
message(STATUS " ${BWhite}dds_plugin${CR} ${dds_summary}")
if(BUILD_PMIX_PLUGIN)
set(pmix_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_PMIX_PLUGIN=OFF${CR})")
else()
set(pmix_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_PMIX_PLUGIN=ON${CR})")
endif()
message(STATUS " ${BWhite}pmix_plugin${CR} ${pmix_summary}")
if(BUILD_EXAMPLES)
set(examples_summary "${BGreen}YES${CR} (default, disable with ${BMagenta}-DBUILD_EXAMPLES=OFF${CR})")
else()
@ -57,39 +39,12 @@ macro(fairmq_summary_components)
set(docs_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_DOCS=ON${CR})")
endif()
message(STATUS " ${BWhite}docs${CR} ${docs_summary}")
if(BUILD_SDK)
set(sdk_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK=OFF${CR})")
else()
set(sdk_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK=ON${CR})")
endif()
message(STATUS " ${BWhite}sdk${CR} ${sdk_summary}")
if(BUILD_SDK_COMMANDS)
set(sdk_commands_summary "${BGreen}YES${CR} DEPRECATED (disable with ${BMagenta}-DBUILD_SDK_COMMANDS=OFF${CR})")
else()
set(sdk_commands_summary "${BRed} NO${CR} DEPRECATED (default, enable with ${BMagenta}-DBUILD_SDK_COMMANDS=ON${CR})")
endif()
message(STATUS " ${BWhite}sdk_commands${CR} ${sdk_commands_summary}")
if(BUILD_TIDY_TOOL)
set(sdk_tidy_summary "${BGreen}YES${CR} (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
set(sdk_tidy_summary "${BGreen}YES${CR} EXPERIMENTAL (disable with ${BMagenta}-DBUILD_TIDY_TOOL=OFF${CR})")
else()
set(sdk_tidy_summary "${BRed} NO${CR} (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
set(sdk_tidy_summary "${BRed} NO${CR} EXPERIMENTAL (default, enable with ${BMagenta}-DBUILD_TIDY_TOOL=ON${CR})")
endif()
message(STATUS " ${BWhite}tidy_tool${CR} ${sdk_tidy_summary}")
set(_deprecated)
if(BUILD_SDK)
list(APPEND _deprecated sdk)
endif()
if(BUILD_SDK_COMMANDS)
list(APPEND _deprecated sdk_commands)
endif()
if(BUILD_DDS_PLUGIN)
list(APPEND _deprecated dds_plugin)
endif()
list(JOIN _deprecated ", " _deprecated)
if(_deprecated)
message(DEPRECATION "You have selected to build deprecated components '${_deprecated}' which will be removed in a future release. See https://github.com/FairRootGroup/FairMQ/discussions/392 for more information. Use '-Wno-deprecated' to silence deprecation warnings.")
endif()
endmacro()
macro(fairmq_summary_static_analysis)
@ -138,3 +93,13 @@ macro(fairmq_summary_debug_mode)
message(STATUS " ${Cyan}DEBUG MODE${CR} ${BRed}${FAIRMQ_DEBUG_MODE}${CR} (enable with ${BMagenta}-DFAIRMQ_DEBUG_MODE=ON${CR})")
endif()
endmacro()
macro(fairmq_summary_compile_definitions)
message(STATUS " ")
message(STATUS " ${Cyan}COMPILE DEFINITION VALUE${CR}")
message(STATUS " ${BWhite}FAIRMQ_HAS_STD_FILESYSTEM${CR} ${FAIRMQ_HAS_STD_FILESYSTEM} (overridable with ${BMagenta}-DFAIRMQ_HAS_STD_FILESYSTEM=0|1${CR})")
message(STATUS " ${BWhite}FAIRMQ_HAS_STD_PMR${CR} ${FAIRMQ_HAS_STD_PMR} (overridable with ${BMagenta}-DFAIRMQ_HAS_STD_PMR=0|1${CR})")
if(DEFINED FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
message(STATUS " ${BWhite}FAIRMQ_CHANNEL_DEFAULT_AUTOBIND${CR} ${FAIRMQ_CHANNEL_DEFAULT_AUTOBIND}")
endif()
endmacro()

View File

@ -1,74 +0,0 @@
################################################################################
# Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
# The "lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix" part in all
# the PATH_SUFFIXES is here to be able to find Debian's
# libpmix-dev package. It installs everything below
# /usr/lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix
find_path(PMIx_INCLUDE_DIR
NAMES pmix.h
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
PATH_SUFFIXES include lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix/include
)
find_path(PMIx_LIBRARY_DIR
NAMES libpmix.dylib libpmix.so
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
PATH_SUFFIXES lib lib64 lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix/lib
)
find_library(PMIx_LIBRARY_SHARED
NAMES libpmix.dylib libpmix.so
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
PATH_SUFFIXES lib lib64 lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix/lib
)
find_file(PMIx_VERSION_FILE
NAMES pmix_version.h
HINTS ${PMIX_ROOT} $ENV{PMIX_ROOT}
PATH_SUFFIXES include lib/${CMAKE_LIBRARY_ARCHITECTURE}/pmix/include
)
file(READ "${PMIx_VERSION_FILE}" __version_raw)
string(REGEX MATCH "#define PMIX_VERSION_MAJOR ([0-9]?)L?"
__version_major_raw "${__version_raw}"
)
set(PMIx_VERSION_MAJOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define PMIX_VERSION_MINOR ([0-9]?)L?"
__version_minor_raw "${__version_raw}"
)
set(PMIx_VERSION_MINOR "${CMAKE_MATCH_1}")
string(REGEX MATCH "#define PMIX_VERSION_RELEASE ([0-9]?)L?"
__version_patch_raw "${__version_raw}"
)
set(PMIx_VERSION_PATCH "${CMAKE_MATCH_1}")
set(PMIx_VERSION "${PMIx_VERSION_MAJOR}.${PMIx_VERSION_MINOR}.${PMIx_VERSION_PATCH}")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(PMIx
REQUIRED_VARS
PMIx_INCLUDE_DIR
PMIx_LIBRARY_DIR
PMIx_LIBRARY_SHARED
VERSION_VAR PMIx_VERSION
)
if(NOT TARGET PMIx::libpmix AND PMIx_FOUND)
add_library(PMIx::libpmix SHARED IMPORTED)
set_target_properties(PMIx::libpmix PROPERTIES
IMPORTED_LOCATION ${PMIx_LIBRARY_SHARED}
INTERFACE_INCLUDE_DIRECTORIES ${PMIx_INCLUDE_DIR}
)
endif()

View File

@ -1,5 +1,5 @@
################################################################################
# Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2017-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
@ -20,6 +20,7 @@
# [DEPENDS dep1 [dep2 ...]]
# [LINKS linklib1 [linklib2 ...]
# [INCLUDES dir1 [dir2 ...]
# [ENVIRONMENT var1=op:val1[;var2=op:val2 ...]]
# [TIMEOUT seconds]
# [RUN_SERIAL ON/OFF])
#
@ -56,7 +57,7 @@ function(add_testsuite suitename)
cmake_parse_arguments(testsuite
""
"TIMEOUT;RUN_SERIAL"
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS"
"SOURCES;LINKS;DEPENDS;INCLUDES;DEFINITIONS;ENVIRONMENT"
${ARGN}
)
@ -77,6 +78,9 @@ function(add_testsuite suitename)
if(testsuite_DEFINITIONS)
target_compile_definitions("${target}" PUBLIC ${testsuite_DEFINITIONS})
endif()
if(testsuite_ENVIRONMENT AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
set(env "ENVIRONMENT_MODIFICATION" ${testsuite_ENVIRONMENT})
endif()
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
@ -97,6 +101,7 @@ function(add_testsuite suitename)
TEST_PREFIX ${suitename}.
PROPERTIES RUN_SERIAL ${testsuite_RUN_SERIAL}
TIMEOUT ${testsuite_TIMEOUT}
${env}
)
list(APPEND ALL_TEST_TARGETS ${target})

View File

@ -6,17 +6,29 @@
"license": "./COPYRIGHT",
"datePublished": "2018-04-15",
"developmentStatus": "active",
"softwareVersion": "master",
"releaseNotes": "https://github.com/FairRootGroup/FairMQ/releases",
"codeRepository": "https://github.com/FairRootGroup/FairMQ/",
"readme": "https://github.com/FairRootGroup/FairMQ/#readme",
"issueTracker": "https://github.com/FairRootGroup/FairMQ/issues",
"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": [
{
"@type": "Person",
"@id": "https://orcid.org/0000-0002-8071-4497",
"givenName": "Mohammad",
"familyName": "Al-Turany"
},
{
"@type": "Person",
"@id": "https://orcid.org/0000-0003-3787-1910",
"givenName": "Dennis",
"familyName": "Klein"
},
@ -27,6 +39,7 @@
},
{
"@type": "Person",
"@id": "https://orcid.org/0000-0002-6249-155X",
"givenName": "Alexey",
"familyName": "Rybalchenko"
},
@ -91,6 +104,7 @@
},
{
"@type": "Person",
"@id": "https://orcid.org/0000-0002-5321-8404",
"givenName": "Christian",
"familyName": "Tacke"
},

View File

@ -1,83 +0,0 @@
#! /usr/bin/env python3
# Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH
#
# SPDX-License-Identifier: LGPL-3.0-or-later
import argparse
import json
import re
from collections import OrderedDict
class CodeMetaManipulator(object):
def load(self, filename='codemeta.json'):
with open(filename, 'rb') as fp:
self.data = json.load(fp, object_pairs_hook=OrderedDict)
@staticmethod
def _dict_entry_cmp(dict1, dict2, field):
if (field in dict1) and (field in dict2):
return dict1[field] == dict2[field]
else:
return False
@classmethod
def find_person_entry(cls, person_list, matchdict):
for entry in person_list:
if cls._dict_entry_cmp(entry, matchdict, 'email'):
return entry
if cls._dict_entry_cmp(entry, matchdict, 'familyName') \
and cls._dict_entry_cmp(entry, matchdict, 'givenName'):
return entry
return None
@staticmethod
def update_person_entry(entry, matchdict):
if entry is None:
entry = OrderedDict()
entry['@type'] = 'Person'
for field in ('givenName', 'familyName', 'email'):
val = matchdict.get(field, None)
if val is not None:
entry[field] = val
return entry
def handle_person_list_file(self, filename, cm_field_name):
fp = open(filename, 'r', encoding='utf8')
findregex = re.compile(r'^(?P<familyName>[-\w\s]*[-\w]),\s*'
r'(?P<givenName>[-\w\s]*[-\w])\s*'
r'(?:<(?P<email>\S+@\S+)>)?$')
person_list = self.data.setdefault(cm_field_name, [])
for line in fp:
line = line.strip()
m = findregex.match(line)
if m is None:
raise RuntimeError("Could not analyze line %r" % line)
found_entry = self.find_person_entry(person_list, m.groupdict())
entry = self.update_person_entry(found_entry, m.groupdict())
if found_entry is None:
person_list.append(entry)
def save(self, filename='codemeta.json'):
with open('codemeta.json', 'w', encoding='utf8') as fp:
json.dump(self.data, fp, indent=2)
fp.write('\n')
def main():
parser = argparse.ArgumentParser(description='Update codemeta.json')
parser.add_argument('--set-version', dest='newversion')
args = parser.parse_args()
cm = CodeMetaManipulator()
cm.load()
if args.newversion is not None:
cm.data['softwareVersion'] = args.newversion
cm.handle_person_list_file('AUTHORS', 'author')
cm.handle_person_list_file('CONTRIBUTORS', 'contributor')
cm.save()
if __name__ == '__main__':
main()

View File

@ -16,11 +16,11 @@ Here is an overview of the device/channel options and when they are applied:
| Property | Applied in |
| --- | --- |
| `severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `file-severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `verbosity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `color` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `log-to-file` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<runFairMQDevice.h>`)) |
| `severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
| `file-severity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
| `verbosity` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
| `color` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
| `log-to-file` | immidiately (if `fair::mq::DeviceRunner` is used (also the case when using `<fairmq/runDevice.h>`)) |
| `id` | at the end of `fair::mq::State::InitializingDevice` |
| `io-threads` | at the end of `fair::mq::State::InitializingDevice` |
| `transport` | at the end of `fair::mq::State::InitializingDevice` |
@ -28,7 +28,6 @@ Here is an overview of the device/channel options and when they are applied:
| `init-timeout` | at the end of `fair::mq::State::InitializingDevice` |
| `shm-segment-size` | at the end of `fair::mq::State::InitializingDevice` |
| `shm-monitor` | at the end of `fair::mq::State::InitializingDevice` |
| `ofi-size-hint` | at the end of `fair::mq::State::InitializingDevice` |
| `rate` | at the end of `fair::mq::State::InitializingDevice` |
| `session` | at the end of `fair::mq::State::InitializingDevice` |
| `chan.*` | at the end of `fair::mq::State::InitializingDevice` (channel addresses can be also applied during `fair::mq::State::Binding`/`fair::mq::State::Connecting`) |

View File

@ -6,7 +6,7 @@
For unit testing it is often not feasible to boot up a full-blown distributed system with dozens of processes.
In some scenarios it is useful to not even instantiate a `FairMQDevice` at all. Please see [this example](../test/protocols/_push_pull_multipart.cxx) for single and multi threaded unit test without a device instance. If you store your transport factories and channels on the heap, pls make sure, you destroy the channels before you destroy the related transport factory for proper shutdown. Channels provide all the `Send/Receive` and `New*Message/New*Poller` APIs provided by the device too.
In some scenarios it is useful to not even instantiate a `fair::mq::Device` at all. Please see [this example](../test/protocols/_push_pull_multipart.cxx) for single and multi threaded unit test without a device instance. If you store your transport factories and channels on the heap, pls make sure, you destroy the channels before you destroy the related transport factory for proper shutdown. Channels provide all the `Send/Receive` and `New*Message/New*Poller` APIs provided by the device too.
## 4.2 Static Analysis

View File

@ -2,7 +2,7 @@
# 1. Device
The components encapsulating the tasks are called **devices** and derive from the common base class `FairMQDevice`. FairMQ provides ready to use devices to organize the dataflow between the components (without touching the contents of a message), providing functionality like merging and splitting of the data stream (see subdirectory `devices`).
The components encapsulating the tasks are called **devices** and derive from the common base class `fair::mq::Device`. FairMQ provides ready to use devices to organize the dataflow between the components (without touching the contents of a message), providing functionality like merging and splitting of the data stream (see subdirectory `devices`).
## 1.1 Topology

View File

@ -35,7 +35,7 @@ Plugin Manager:
see man ld.so(8) for details.
-P [ --plugin ] arg List of plugin names to load in
order,e.g. if the file is called
'libFairMQPlugin_example.so', just list
'libfairmq-plugin-example.so', just list
'example' or 'd:example' here.To load a
prelinked plugin, list 'p:example'
here.
@ -54,40 +54,8 @@ A more complete example which may serve as a start including example CMake code
## 7.3 Provided Plugins
### 7.3.1 DDS
### 7.3.1 PMIx
When launching a FairMQ topology via [DDS](http://dds.gsi.de/) the DDS plugin enables FairMQ devices to interact with DDS' custom command and property subsystems - enable the plugin by passing `-P dds` on the command line.
Via the property subsystem a FairMQ topology may exchange channel connection data (essentially to do service discovery) needed to connect/bind all FairMQ channels appropriately. DDS is highly optimized for this use case. See [examples/dds](examples/dds/README.md) for more details.
Via the custom command subsystem a FairMQ device can receive a number of commands. FairMQ provides a convenient command line tool `fairmq-dds-command-ui` that allows interactive or scripted control of a running FairMQ topology managed via DDS. If one develops directly against the custom command DDS API, the following table lists all the commands the DDS plugin currently understands:
| Custom Command | Response | Error | Description |
| --- | --- | --- | --- |
| `check-state` | `<ID>: <STATE> (pid: <PID>)` | n/a | Query current device state, see state machine for possible states |
| `dump-config` | `(<ID>: <PKEY> -> <PVALUE>\n)+` | n/a | Query current device config (list property key/value pairs) |
| `INIT DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `BIND` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `CONNECT` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `INIT TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RUN` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `STOP` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RESET TASK` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `RESET DEVICE` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `END` | `<ID>: queued <CMD> transition` | `<ID>: could not queue <CMD> transition` | Initiate state transition |
| `subscribe-to-heartbeats` | `heartbeat-subscription: <ID>,OK` | n/a | Subscribe to heartbeats |
| on heartbeat subscription | `heartbeat: <ID>,<PID>` | n/a | Heartbeat every 100ms |
| `unsubscribe-from-heartbeats` | `heartbeat-unsubscription: <ID>,OK` | n/a | Unsubscribe from heartbeats |
| `subscribe-to-state-changes` | `state-changes-subscription: <ID>,OK` | n/a | Subscribe to state changes |
| on state changes subscription | `state-change: <ID>,<STATE>` | n/a | State change notification |
| `unsubscribe-from-state-changes` | `state-changes-unsubscription: <ID>,OK` | n/a | Unsubscribe from state changes |
If unknown commands are received the plugin will print a warning.
### 7.3.2 PMIx
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This plugin is not (yet) very mature and serves as a proof of concept at the moment.
TODO example usage
The [PMIx](https://pmix.org/) plugin enables launching a FairMQ topology with any PMIx capable launcher, e.g. the [Open Run-Time Environment (ORTE) of OpenMPI](https://www.open-mpi.org/doc/v4.0/man1/mpirun.1.php) or the [Slurm workload manager](https://slurm.schedmd.com/srun.html). This experimental plugin has been last released in v1.4.56 and is removed in v1.5+. For now there are no plans to pick up development of it again.
← [Back](../README.md)

View File

@ -1,34 +0,0 @@
← [Back](../README.md)
# 8. Controller SDK
The FairMQ Controller Software Development Kit (`-DBUILD_SDK=ON`) contains a (as of today still experimental) set of C++ APIs that provide essential functionality to the implementer of a global controller.
The FairMQ core library only provides two local controllers - `static` (a fixed sequence of state transitions) and `interactive` (a read-eval-print-loop which reads keyboard commands from standard input). A local controller only knows how steer a single [FairMQ device](Device.md) - in fact, it runs in a thread within the device process.
A global controller has knowledge about the full topology of connected FairMQ devices. Its responsibility is to facilitate the lifecycle of a distributed FairMQ-based application (*executing a topology*), such as
* allocating/releasing compute resources from a resource management system,
* launching/setting up the run-time environment and the FairMQ devices,
* driving the device state machines in lock-step across the full topology,
* pushing the device configuration,
* monitoring (some aspects of the application's) operation,
* and handling/reporting (some) error cases.
The low-level hook to integrate FairMQ devices with such a global contoller is the [plugin mechanism](Plugins.md) in the FairMQ core library. The FairMQ Controller SDK provides C++ APIs that communicate to the endpoints exposed by such a FairMQ plugin.
At the moment, the Controller SDK only supports [DDS](https://dds.gsi.de) as resource manager and run-time environment. A second implementation based on [PMIx](https://pmix.org/) (targeting its implementation in [Slurm](https://slurm.schedmd.com/documentation.html) and [OpenRTE](https://www-lb.open-mpi.org/papers/euro-pvmmpi-2005-orte/)) is in development.
The following section give a short overview on the APIs provided.
## RMS and run-time environment
The classes [`fair::mq::sdk::DDSEnvironment`](../fairmq/sdk/DDSEnvironment.h), [`fair::mq::sdk::DDSSession`](../fairmq/sdk/DDSSession.h), and [`fair::mq::sdk::DDSTopology`](../fairmq/sdk/DDSTopology.h) are thin wrappers of most of the synchronous APIs exposed by DDS ([`dds::tools_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1tools__api.html) and [`dds::topology_api`](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1topology__api.html)). E.g. they allow to [start a DDS session](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L26-L28), [allocate resources](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L34) and [launch a topology](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L39) from a C++ program.
## Driving the global state machine
The class [`fair::mq::sdk::Topology`](../fairmq/sdk/Topology.h) adds a FairMQ-specific view on an existing DDS session that is executing a topology of FairMQ devices. One can e.g. [initiate a state transition on all devices in the topology simultaneously](https://github.com/FairRootGroup/FairMQ/blob/077eb0ef691940d764cfd1852bf3981dc812ddbd/main.cpp#L48-L49). This topology transition completes once a topology-wide barrier is passed (all devices completed the transition). This effectively exposes the device state machine as a topology state machine. The implementation is based on remote procedure calls over the [DDS intercom service](http://dds.gsi.de/doc/api-docs/DDS/html/namespacedds_1_1intercom__api.html) between the controller and the DDS plugin shipped with FairMQ (`-DBUILD_DDS_PLUGIN=ON`).
For future versions of the SDK new APIs are planned to inspect and modify the device configurations and also operate only on subsets of a given topology.
← [Back](../README.md)

View File

@ -1,51 +1,9 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-1-1-sampler sampler.cxx)
target_link_libraries(fairmq-ex-1-1-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-1-1-sink sink.cxx)
target_link_libraries(fairmq-ex-1-1-sink PRIVATE FairMQ)
add_custom_target(Example11 DEPENDS fairmq-ex-1-1-sampler fairmq-ex-1-1-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh)
add_test(NAME Example.1-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh zeromq)
set_tests_properties(Example.1-1.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
add_test(NAME Example.1-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-1.sh shmem)
set_tests_properties(Example.1-1.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
# install
install(
TARGETS
fairmq-ex-1-1-sampler
fairmq-ex-1-1-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-1.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-1-1.sh
)
add_example(NAME 1-1 DEVICE sampler sink)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -13,7 +15,7 @@ chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanAddr' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanAddr; exit 0' TERM
SAMPLER="fairmq-ex-1-1-sampler"
SAMPLER+=" --id sampler1"
@ -22,6 +24,7 @@ SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --channel-config name=$chan,type=push,method=bind,address=ipc://$chanAddr,rateLogging=0"
@ -34,6 +37,7 @@ SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --control static --color false"
SINK+=" --max-iterations 1"
SINK+=" --channel-config name=$chan,type=pull,method=connect,address=ipc://$chanAddr,rateLogging=0"
@ -44,4 +48,6 @@ SINK_PID=$!
wait $SAMPLER_PID
wait $SINK_PID
set +e
rm $chanAddr
exit 0

View File

@ -1,64 +1,9 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-1-n-1-sampler sampler.cxx)
target_link_libraries(fairmq-ex-1-n-1-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-1-n-1-processor processor.cxx)
target_link_libraries(fairmq-ex-1-n-1-processor PRIVATE FairMQ)
add_executable(fairmq-ex-1-n-1-sink sink.cxx)
target_link_libraries(fairmq-ex-1-n-1-sink PRIVATE FairMQ)
add_custom_target(Example1N1 DEPENDS fairmq-ex-1-n-1-sampler fairmq-ex-1-n-1-processor fairmq-ex-1-n-1-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(EX_CONF_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/ex-1-n-1.json ${CMAKE_CURRENT_BINARY_DIR}/ex-1-n-1.json)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh)
add_test(NAME Example.1-n-1.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh zeromq)
set_tests_properties(Example.1-n-1.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
add_test(NAME Example.1-n-1.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-1-n-1.sh shmem)
set_tests_properties(Example.1-n-1.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received: ")
# install
install(
TARGETS
fairmq-ex-1-n-1-sampler
fairmq-ex-1-n-1-processor
fairmq-ex-1-n-1-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(EX_CONF_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-1-n-1.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-1-n-1.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-1-n-1.sh
)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/ex-1-n-1.json
DESTINATION ${PROJECT_INSTALL_DATADIR}
)
add_example(NAME 1-n-1 DEVICE sampler processor sink CONFIG)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -15,7 +17,7 @@ chan1Addr="/tmp/fmq_$session""_""$chan1""_""$transport"
chan2Addr="/tmp/fmq_$session""_""$chan2""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $PROCESSOR1_PID; kill -TERM $PROCESSOR2_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $PROCESSOR1_PID; wait $PROCESSOR2_PID; rm $chan1Addr; rm $chan2Addr' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $PROCESSOR1_PID; kill -TERM $PROCESSOR2_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $PROCESSOR1_PID; wait $PROCESSOR2_PID; rm $chan1Addr; rm $chan2Addr; exit 0' TERM
SAMPLER="fairmq-ex-1-n-1-sampler"
SAMPLER+=" --id sampler1"
@ -24,6 +26,7 @@ SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $session"
SAMPLER+=" --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 2"
SAMPLER+=" --channel-config name=$chan1,type=push,method=bind,address=ipc://$chan1Addr,rateLogging=0"
@ -37,6 +40,7 @@ PROCESSOR1+=" --verbosity veryhigh"
PROCESSOR1+=" --session $session"
PROCESSOR1+=" --severity debug"
PROCESSOR1+=" --shm-segment-size 100000000"
PROCESSOR1+=" --shm-monitor true"
PROCESSOR1+=" --control static --color false"
PROCESSOR1+=" --channel-config name=$chan1,type=pull,method=connect,address=ipc://$chan1Addr,rateLogging=0"
PROCESSOR1+=" name=$chan2,type=push,method=connect,address=ipc://$chan2Addr,rateLogging=0"
@ -50,6 +54,7 @@ PROCESSOR2+=" --verbosity veryhigh"
PROCESSOR2+=" --session $session"
PROCESSOR2+=" --severity debug"
PROCESSOR2+=" --shm-segment-size 100000000"
PROCESSOR2+=" --shm-monitor true"
PROCESSOR2+=" --control static --color false"
PROCESSOR2+=" --channel-config name=$chan1,type=pull,method=connect,address=ipc://$chan1Addr,rateLogging=0"
PROCESSOR2+=" name=$chan2,type=push,method=connect,address=ipc://$chan2Addr,rateLogging=0"
@ -63,6 +68,7 @@ SINK+=" --verbosity veryhigh"
SINK+=" --session $session"
SINK+=" --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --control static --color false"
SINK+=" --max-iterations 2"
SINK+=" --channel-config name=$chan2,type=pull,method=bind,address=ipc://$chan2Addr,rateLogging=0"
@ -81,4 +87,6 @@ kill -SIGINT $PROCESSOR2_PID
wait $PROCESSOR1_PID
wait $PROCESSOR2_PID
set +e
rm $chan1Addr; rm $chan2Addr
exit 0

View File

@ -1,15 +1,145 @@
################################################################################
# Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2018-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(exe_prefix "fairmq-ex")
set(script_prefix "fairmq-start-ex")
set(test_script_prefix "test-ex")
set(testsuite "Example")
set(transports "zeromq" "shmem")
function(add_example)
cmake_parse_arguments(PARSE_ARGV 0 ARG
"CONFIG;NO_TRANSPORT;NO_TEST"
"NAME"
"DEVICE;VARIANT;TRANSPORT;SCRIPT"
)
if(ARG_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unexpected unparsed arguments: ${ARG_UNPARSED_ARGUMENTS}")
endif()
if(ARG_NAME)
set(name ${ARG_NAME})
else()
message(FATAL_ERROR "NAME arg is required")
endif()
if(ENABLE_SANITIZER_LEAK AND CMAKE_VERSION VERSION_GREATER_EQUAL 3.22)
get_filename_component(lsan_supps "${CMAKE_SOURCE_DIR}/test/leak_sanitizer_suppressions.txt" ABSOLUTE)
set(lsan_options "LSAN_OPTIONS=set:suppressions=${lsan_supps}")
endif()
if(ARG_DEVICE)
set(exe_targets)
foreach(device IN LISTS ARG_DEVICE)
set(exe "${exe_prefix}-${name}-${device}")
list(APPEND exe_targets ${exe})
add_executable(${exe} "${device}.cxx")
target_link_libraries(${exe} PRIVATE FairMQ)
endforeach()
endif()
if(ARG_TRANSPORT)
set(transports ${ARG_TRANSPORT})
endif()
if(ARG_SCRIPT)
set(scripts ${ARG_SCRIPT})
else()
set(scripts ${ARG_NAME})
endif()
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
if(ARG_CONFIG)
set(EX_CONF_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
foreach(script IN LISTS scripts)
set(script_file "${script_prefix}-${script}.sh")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}" @ONLY)
endforeach()
if(ARG_CONFIG)
set(config "ex-${name}.json")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${config}" "${CMAKE_CURRENT_BINARY_DIR}/${config}")
endif()
# test
if(NOT ARG_NO_TEST)
set(test_script "${test_script_prefix}-${name}.sh")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${test_script}.in" "${CMAKE_CURRENT_BINARY_DIR}/${test_script}")
if(ARG_NO_TRANSPORT)
set(test "${testsuite}.${name}.${transport}")
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
if(lsan_options)
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
endif()
else()
foreach(transport IN LISTS transports)
if(ARG_VARIANT)
foreach(variant IN LISTS ARG_VARIANT)
set(test "${testsuite}.${name}.${variant}.${transport}")
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport} ${variant})
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
if(lsan_options)
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
endif()
endforeach()
else()
set(test "${testsuite}.${name}.${transport}")
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${test_script} ${transport})
set_tests_properties(${test} PROPERTIES TIMEOUT "30")
if(lsan_options)
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
endif()
endif()
endforeach()
endif()
endif()
# install
install(
TARGETS ${exe_targets}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
if(ARG_CONFIG)
set(EX_CONF_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_DATADIR})
endif()
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
foreach(script IN LISTS scripts)
set(script_file "${script_prefix}-${script}.sh")
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/${script_file}.in" "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install" @ONLY)
install(
PROGRAMS "${CMAKE_CURRENT_BINARY_DIR}/${script_file}_install"
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME ${script_file}
)
endforeach()
if(ARG_CONFIG)
install(
FILES ${CMAKE_CURRENT_BINARY_DIR}/${config}
DESTINATION ${PROJECT_INSTALL_DATADIR}
)
endif()
endfunction()
add_subdirectory(1-1)
add_subdirectory(1-n-1)
add_subdirectory(builtin-devices)
add_subdirectory(copypush)
add_subdirectory(custom-controller)
add_subdirectory(dds)
add_subdirectory(multipart)
add_subdirectory(multiple-channels)

View File

@ -1,40 +1,11 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh)
add_test(NAME Example.BuiltinDevices.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq)
set_tests_properties(Example.BuiltinDevices.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
add_test(NAME Example.BuiltinDevices.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem)
set_tests_properties(Example.BuiltinDevices.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
add_test(NAME Example.BuiltinDevices.multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh zeromq true 2)
set_tests_properties(Example.BuiltinDevices.multipart.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
add_test(NAME Example.BuiltinDevices.multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-builtin-devices.sh shmem true 2)
set_tests_properties(Example.BuiltinDevices.multipart.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Configured maximum number of iterations reached")
# install
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-builtin-devices.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-builtin-devices.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-builtin-devices.sh
add_example(NAME builtin-devices
VARIANT single_msg multipart
)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -10,12 +12,9 @@ if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
if [[ $2 =~ ^[a-z]+$ ]]; then
multipart=$2
fi
if [[ $3 =~ ^[0-9]+$ ]]; then
numParts=$3
if [[ $2 =~ ^multipart$ ]]; then
multipart="true"
numParts=2
fi
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
@ -33,7 +32,7 @@ chan4Addr="/tmp/fmq_$session""_""$chan4""_""$transport"
chan5Addr="/tmp/fmq_$session""_""$chan5""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SPLITTER_PID; kill -TERM $PROXY1_PID; kill -TERM $PROXY2_PID; kill -TERM $MERGER_PID; kill -TERM $MULTIPLIER_PID; kill -TERM $SINK_PID; rm $chan1Addr; rm $chan2Addr1; rm $chan2Addr2; rm $chan3Addr1; rm $chan3Addr2; rm $chan4Addr; rm $chan5Addr' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SPLITTER_PID; kill -TERM $PROXY1_PID; kill -TERM $PROXY2_PID; kill -TERM $MERGER_PID; kill -TERM $MULTIPLIER_PID; kill -TERM $SINK_PID; rm $chan1Addr; rm $chan2Addr1; rm $chan2Addr2; rm $chan3Addr1; rm $chan3Addr2; rm $chan4Addr; rm $chan5Addr; exit 0' TERM
SAMPLER="fairmq-bsampler"
SAMPLER+=" --id bsampler1"
@ -43,6 +42,7 @@ SAMPLER+=" --color false"
SAMPLER+=" --control static"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --severity debug"
SAMPLER+=" --msg-size 100000"
SAMPLER+=" --multipart $multipart"
@ -62,6 +62,7 @@ SPLITTER+=" --color false"
SPLITTER+=" --control static"
SPLITTER+=" --verbosity veryhigh"
SPLITTER+=" --shm-segment-size 100000000"
SPLITTER+=" --shm-monitor true"
SPLITTER+=" --multipart $multipart"
SPLITTER+=" --in-channel $chan1"
SPLITTER+=" --out-channel $chan2"
@ -78,6 +79,7 @@ PROXY1+=" --color false"
PROXY1+=" --control static"
PROXY1+=" --verbosity veryhigh"
PROXY1+=" --shm-segment-size 100000000"
PROXY1+=" --shm-monitor true"
PROXY1+=" --multipart $multipart"
PROXY1+=" --in-channel $chan2"
PROXY1+=" --out-channel $chan3"
@ -94,6 +96,7 @@ PROXY2+=" --color false"
PROXY2+=" --control static"
PROXY2+=" --verbosity veryhigh"
PROXY2+=" --shm-segment-size 100000000"
PROXY2+=" --shm-monitor true"
PROXY2+=" --multipart $multipart"
PROXY2+=" --in-channel $chan2"
PROXY2+=" --out-channel $chan3"
@ -110,6 +113,7 @@ MERGER+=" --color false"
MERGER+=" --control static"
MERGER+=" --verbosity veryhigh"
MERGER+=" --shm-segment-size 100000000"
MERGER+=" --shm-monitor true"
MERGER+=" --multipart $multipart"
MERGER+=" --in-channel $chan3"
MERGER+=" --out-channel $chan4"
@ -126,6 +130,7 @@ MULTIPLIER+=" --color false"
MULTIPLIER+=" --control static"
MULTIPLIER+=" --verbosity veryhigh"
MULTIPLIER+=" --shm-segment-size 100000000"
MULTIPLIER+=" --shm-monitor true"
MULTIPLIER+=" --multipart $multipart"
MULTIPLIER+=" --in-channel $chan4"
MULTIPLIER+=" --out-channel $chan5"
@ -143,6 +148,7 @@ SINK+=" --control static"
SINK+=" --verbosity veryhigh"
SINK+=" --severity debug"
SINK+=" --multipart $multipart"
SINK+=" --shm-monitor true"
SINK+=" --max-iterations 2"
SINK+=" --in-channel $chan5"
SINK+=" --channel-config name=$chan5,type=pull,method=bind,sndBufSize=50,rcvBufSize=50,address=ipc://$chan5Addr"
@ -165,4 +171,6 @@ wait $PROXY2_PID
wait $MERGER_PID
wait $MULTIPLIER_PID
set +e
rm $chan1Addr; rm $chan2Addr1; rm $chan2Addr2; rm $chan3Addr1; rm $chan3Addr2; rm $chan4Addr; rm $chan5Addr
exit 0

View File

@ -1,52 +1,11 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-copypush-sampler sampler.cxx)
target_link_libraries(fairmq-ex-copypush-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-copypush-sink sink.cxx)
target_link_libraries(fairmq-ex-copypush-sink PRIVATE FairMQ)
add_custom_target(ExampleCopyPush DEPENDS fairmq-ex-copypush-sampler fairmq-ex-copypush-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh)
add_test(NAME Example.CopyPush.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh zeromq)
set_tests_properties(Example.CopyPush.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message: ")
add_test(NAME Example.CopyPush.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-copypush.sh shmem)
set_tests_properties(Example.CopyPush.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message: ")
# install
install(
TARGETS
fairmq-ex-copypush-sampler
fairmq-ex-copypush-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-copypush.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-copypush.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-copypush.sh
add_example(NAME copypush
DEVICE sampler sink
)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -14,7 +16,7 @@ chanAddr1="/tmp/fmq_$session""_""$chan""_1""_""$transport"
chanAddr2="/tmp/fmq_$session""_""$chan""_2""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK1_PID; kill -TERM $SINK2_PID; wait $SAMPLER_PID; wait $SINK1_PID; wait $SINK2_PID; rm $chanAddr1; rm $chanAddr2' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK1_PID; kill -TERM $SINK2_PID; wait $SAMPLER_PID; wait $SINK1_PID; wait $SINK2_PID; rm $chanAddr1; rm $chanAddr2; exit 0' TERM
SAMPLER="fairmq-ex-copypush-sampler"
SAMPLER+=" --id sampler1"
@ -22,6 +24,7 @@ SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --session $session"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
@ -35,6 +38,7 @@ SINK1+=" --transport $transport"
SINK1+=" --verbosity veryhigh"
SINK1+=" --severity debug"
SINK1+=" --shm-segment-size 100000000"
SINK1+=" --shm-monitor true"
SINK1+=" --session $session"
SINK1+=" --control static --color false"
SINK1+=" --max-iterations 1"
@ -48,6 +52,7 @@ SINK2+=" --transport $transport"
SINK2+=" --verbosity veryhigh"
SINK2+=" --severity debug"
SINK2+=" --shm-segment-size 100000000"
SINK2+=" --shm-monitor true"
SINK2+=" --session $session"
SINK2+=" --control static --color false"
SINK2+=" --max-iterations 1"
@ -60,4 +65,6 @@ wait $SAMPLER_PID
wait $SINK1_PID
wait $SINK2_PID
set +e
rm $chanAddr1; rm $chanAddr2
exit 0

View File

@ -0,0 +1,20 @@
################################################################################
# Copyright (C) 2022-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
set(name "custom-controller")
set(exe "${exe_prefix}-${name}")
add_executable(${exe} main.cxx)
target_link_libraries(${exe} PRIVATE FairMQ)
set_target_properties(${exe} PROPERTIES ENABLE_EXPORTS ON)
set(test "${testsuite}.${name}")
add_test(NAME ${test} COMMAND ${CMAKE_CURRENT_BINARY_DIR}/${exe})
set_tests_properties(${test} PROPERTIES TIMEOUT 30)
if(lsan_options)
set_tests_properties(${test} PROPERTIES ENVIRONMENT_MODIFICATION ${lsan_options})
endif()

View File

@ -0,0 +1,97 @@
/********************************************************************************
* Copyright (C) 2022 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_EXAMPLE_CUSTOM_CONTROLLER_PLUGIN
#define FAIR_MQ_EXAMPLE_CUSTOM_CONTROLLER_PLUGIN
#include <fairmq/Plugin.h>
#include <utility> // for std::forward
namespace example {
struct MyController : fair::mq::Plugin // NOLINT
{
template<typename... Args>
MyController(Args&&... args)
: Plugin(std::forward<Args>(args)...)
{
TakeDeviceControl();
SubscribeToDeviceStateChange([this](auto state) {
auto shutdown = GetProperty<bool>("please-shut-me-down", false);
try {
switch (state) {
case DeviceState::Idle: {
ChangeDeviceState(shutdown ? DeviceStateTransition::End
: DeviceStateTransition::InitDevice);
break;
}
case DeviceState::InitializingDevice: {
ChangeDeviceState(DeviceStateTransition::CompleteInit);
break;
}
case DeviceState::Initialized: {
ChangeDeviceState(DeviceStateTransition::Bind);
break;
}
case DeviceState::Bound: {
ChangeDeviceState(DeviceStateTransition::Connect);
break;
}
case DeviceState::DeviceReady: {
ChangeDeviceState(shutdown ? DeviceStateTransition::ResetDevice
: DeviceStateTransition::InitTask);
break;
}
case DeviceState::Ready: {
ChangeDeviceState(shutdown ? DeviceStateTransition::ResetTask
: DeviceStateTransition::Run);
break;
}
case DeviceState::Running: {
ChangeDeviceState(DeviceStateTransition::Stop);
break;
}
case DeviceState::Exiting: {
ReleaseDeviceControl();
break;
}
default:
break;
}
} catch (fair::mq::PluginServices::DeviceControlError const&) {
// this means we do not have device control
}
});
}
~MyController() override { ReleaseDeviceControl(); }
};
// auto MyControllerProgramOptions() -> fair::mq::Plugin::ProgOptions
// {
// auto plugin_options = boost::program_options::options_description{"MyController Plugin"};
// plugin_options.add_options()
// ("custom-dummy-option", boost::program_options::value<std::string>(), "Cool custom option.")
// ("custom-dummy-option2", boost::program_options::value<std::string>(), "Another one.");
// return plugin_options;
// }
} // namespace example
REGISTER_FAIRMQ_PLUGIN(example::MyController, // Class name
mycontroller, // Plugin name (string, lower case chars only)
(fair::mq::Plugin::Version{0, 42, 0}), // Version
"Mr. Dummy <dummy@test.net>", // Maintainer
"https://git.test.net/mycontroller.git", // Homepage
// example::MyControllerProgramOptions // Free
// function which declares custom
// program options for the plugin
fair::mq::Plugin::NoProgramOptions)
#endif /* FAIR_MQ_EXAMPLE_CUSTOM_CONTROLLER_PLUGIN */

View File

@ -0,0 +1,21 @@
/********************************************************************************
* Copyright (C) 2022 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_EXAMPLE_CUSTOM_CONTROLLER_DEVICE
#define FAIR_MQ_EXAMPLE_CUSTOM_CONTROLLER_DEVICE
#include <fairmq/Device.h>
namespace example {
using MyDevice = fair::mq::Device;
} // namespace example
#endif /* FAIR_MQ_EXAMPLE_CUSTOM_CONTROLLER_DEVICE */

View File

@ -0,0 +1,46 @@
/********************************************************************************
* Copyright (C) 2022 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 "MyController.h"
#include "MyDevice.h"
#include <chrono> // for std::chrono_literals
#include <fairlogger/Logger.h>
#include <fairmq/DeviceRunner.h>
#include <memory> // for std::make_unique
int main(int argc, char* argv[])
{
using namespace fair::mq;
using namespace std::chrono_literals;
DeviceRunner runner(argc, argv);
runner.AddHook<hooks::LoadPlugins>([](DeviceRunner& r) {
r.fPluginManager.LoadPlugin("s:mycontroller");
// 's:' stands for static because the plugin is compiled into the executable
// 'mycontroller' is the plugin name passed as second arg to REGISTER_FAIRMQ_PLUGIN
});
fair::Logger::SetConsoleSeverity(fair::Severity::debug);
runner.AddHook<hooks::InstantiateDevice>([](DeviceRunner& r) {
r.fConfig.SetProperty<int>("catch-signals", 0);
r.fConfig.SetProperty<bool>("please-shut-me-down", false);
r.fDevice = std::make_unique<example::MyDevice>(r.fConfig);
r.fDevice->SubscribeToStateChange("example", [&r](auto state) {
if (state == State::Running) {
r.fDevice->WaitFor(3s);
r.fConfig.SetProperty<bool>("please-shut-me-down", true);
}
});
});
return runner.RunWithExceptionHandlers();
}

View File

@ -1,56 +1,11 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-multipart-sampler sampler.cxx)
target_link_libraries(fairmq-ex-multipart-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-multipart-sink sink.cxx)
target_link_libraries(fairmq-ex-multipart-sink PRIVATE FairMQ)
add_custom_target(ExampleMultipart DEPENDS fairmq-ex-multipart-sampler fairmq-ex-multipart-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh)
add_test(NAME Example.Multipart.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh zeromq)
set_tests_properties(Example.Multipart.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 parts")
add_test(NAME Example.Multipart.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh shmem)
set_tests_properties(Example.Multipart.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 parts")
if(BUILD_OFI_TRANSPORT)
add_test(NAME Example.Multipart.ofi COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multipart.sh ofi)
set_tests_properties(Example.Multipart.ofi PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received message with 7 parts")
endif()
# install
install(
TARGETS
fairmq-ex-multipart-sampler
fairmq-ex-multipart-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multipart.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multipart.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-multipart.sh
add_example(NAME multipart
DEVICE sampler sink
)

View File

@ -24,6 +24,10 @@ struct Sink : fair::mq::Device
{
LOG(info) << "Received message with " << parts.Size() << " parts";
if (parts.Size() != 7) {
throw std::runtime_error("Number of received parts != 7");
}
example_multipart::Header header;
header.stopFlag = (static_cast<example_multipart::Header*>(parts.At(0)->GetData()))->stopFlag;

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -12,14 +14,10 @@ session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
chan="data"
chanAddr=""
chanIpcFile="/tmp/fmq_$session""_""$chan""_""$transport"
if [ $transport = "ofi" ]; then
chanAddr="tcp://127.0.0.1:5656"
else
chanAddr="ipc://""$chanIpcFile"
fi
chanAddr="ipc://""$chanIpcFile"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanIpcFile' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; rm $chanIpcFile; exit 0' TERM
SAMPLER="fairmq-ex-multipart-sampler"
SAMPLER+=" --id sampler1"
@ -27,6 +25,7 @@ SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --control static --color false"
SAMPLER+=" --channel-config name=$chan,type=pair,method=connect,rateLogging=0,address=$chanAddr,linger=1000"
@ -39,6 +38,7 @@ SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --control static --color false"
SINK+=" --channel-config name=$chan,type=pair,method=bind,rateLogging=0,address=$chanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$SINK &
@ -47,4 +47,6 @@ SINK_PID=$!
wait $SAMPLER_PID
wait $SINK_PID
set +e
rm $chanIpcFile
exit 0

View File

@ -1,52 +1,12 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-multiple-channels-sampler sampler.cxx)
target_link_libraries(fairmq-ex-multiple-channels-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-multiple-channels-broadcaster broadcaster.cxx)
target_link_libraries(fairmq-ex-multiple-channels-broadcaster PRIVATE FairMQ)
add_executable(fairmq-ex-multiple-channels-sink sink.cxx)
target_link_libraries(fairmq-ex-multiple-channels-sink PRIVATE FairMQ)
add_custom_target(ExampleMultipleChannels DEPENDS fairmq-ex-multiple-channels-sampler fairmq-ex-multiple-channels-broadcaster fairmq-ex-multiple-channels-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh)
add_test(NAME Example.MultipleChannels.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-channels.sh zeromq)
set_tests_properties(Example.MultipleChannels.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received messages from both sources.")
# install
install(
TARGETS
fairmq-ex-multiple-channels-sampler
fairmq-ex-multiple-channels-broadcaster
fairmq-ex-multiple-channels-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-channels.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-channels.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-multiple-channels.sh
add_example(NAME multiple-channels
DEVICE sampler broadcaster sink
TRANSPORT zeromq
)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -15,7 +17,7 @@ dataChanAddr="/tmp/fmq_$session""_""$dataChan""_""$transport"
broadcastChanAddr="/tmp/fmq_$session""_""$broadcastChan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $BROADCASTER_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $BROADCASTER_PID; rm $dataChanAddr; rm $broadcastChanAddr' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; kill -TERM $BROADCASTER_PID; wait $SAMPLER_PID; wait $SINK_PID; wait $BROADCASTER_PID; rm $dataChanAddr; rm $broadcastChanAddr; exit 0' TERM
SINK="fairmq-ex-multiple-channels-sink"
SINK+=" --id sink1"
@ -23,6 +25,7 @@ SINK+=" --session $session"
SINK+=" --transport $transport"
SINK+=" --verbosity veryhigh --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --max-iterations 1"
SINK+=" --control static --color false"
SINK+=" --channel-config name=$dataChan,type=pull,method=connect,rateLogging=0,address=ipc://$dataChanAddr"
@ -38,6 +41,7 @@ SAMPLER+=" --session $session"
SAMPLER+=" --transport $transport"
SAMPLER+=" --verbosity veryhigh --severity debug"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --max-iterations 1"
SAMPLER+=" --control static --color false"
SAMPLER+=" --channel-config name=$dataChan,type=push,method=bind,rateLogging=0,address=ipc://$dataChanAddr"
@ -51,6 +55,7 @@ BROADCASTER+=" --session $session"
BROADCASTER+=" --transport $transport"
BROADCASTER+=" --verbosity veryhigh --severity debug"
BROADCASTER+=" --shm-segment-size 100000000"
BROADCASTER+=" --shm-monitor true"
BROADCASTER+=" --control static --color false"
BROADCASTER+=" --channel-config name=$broadcastChan,type=pub,method=bind,rateLogging=0,address=ipc://$broadcastChanAddr"
@CMAKE_CURRENT_BINARY_DIR@/$BROADCASTER &
@ -65,4 +70,6 @@ kill -SIGINT $BROADCASTER_PID
# wait for broadcaster to finish
wait $BROADCASTER_PID
set +e
rm $dataChanAddr; rm $broadcastChanAddr
exit 0

View File

@ -1,51 +1,12 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-multiple-transports-sampler1 sampler1.cxx)
target_link_libraries(fairmq-ex-multiple-transports-sampler1 PRIVATE FairMQ)
add_executable(fairmq-ex-multiple-transports-sampler2 sampler2.cxx)
target_link_libraries(fairmq-ex-multiple-transports-sampler2 PRIVATE FairMQ)
add_executable(fairmq-ex-multiple-transports-sink sink.cxx)
target_link_libraries(fairmq-ex-multiple-transports-sink PRIVATE FairMQ)
add_custom_target(ExampleMultipleTransports DEPENDS fairmq-ex-multiple-transports-sampler1 fairmq-ex-multiple-transports-sampler2 fairmq-ex-multiple-transports-sink)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
add_test(NAME Example.MultipleTransports COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-multiple-transports.sh)
set_tests_properties(Example.MultipleTransports PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received messages from both sources.")
# install
install(
TARGETS
fairmq-ex-multiple-transports-sampler1
fairmq-ex-multiple-transports-sampler2
fairmq-ex-multiple-transports-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-multiple-transports.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-multiple-transports.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-multiple-transports.sh
add_example(NAME multiple-transports
DEVICE sampler1 sampler2 sink
NO_TRANSPORT
)

View File

@ -9,6 +9,8 @@
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
#include <stdexcept>
namespace bpo = boost::program_options;
struct Sink : fair::mq::Device
@ -32,7 +34,7 @@ struct Sink : fair::mq::Device
// Creates a message using the transport of channel ack
fair::mq::MessagePtr ack(NewMessageFor("ack", 0));
if (Send(ack, "ack") < 0) {
return false;
throw std::runtime_error("could not send an ack");
}
// return true if want to be called again (otherwise go to IDLE state)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
session="$(@CMAKE_BINARY_DIR@/fairmq/fairmq-uuid-gen -h)"
@ -10,12 +12,13 @@ chan1Addr="/tmp/fmq_$session""_""$chan1"
chan2Addr="/tmp/fmq_$session""_""$chan2"
ackChanAddr="/tmp/fmq_$session""_""$ackChan"
trap 'kill -TERM $SAMPLER1_PID; kill -TERM $SAMPLER2_PID; kill -TERM $SINK_PID; wait $SAMPLER1_PID; wait $SAMPLER2_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chan1Addr; rm $chan2Addr; rm $ackChanAddr' TERM
trap 'set +e; kill -TERM $SAMPLER1_PID; kill -TERM $SAMPLER2_PID; kill -TERM $SINK_PID; wait $SAMPLER1_PID; wait $SAMPLER2_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chan1Addr; rm $chan2Addr; rm $ackChanAddr; exit 0' TERM
SINK="fairmq-ex-multiple-transports-sink"
SINK+=" --id sink1"
SINK+=" --verbosity veryhigh --severity debug"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --session $session"
SINK+=" --max-iterations 1"
SINK+=" --control static --color false"
@ -31,6 +34,7 @@ SAMPLER1+=" --id sampler1"
SAMPLER1+=" --session $session"
SAMPLER1+=" --verbosity veryhigh --severity debug"
SAMPLER1+=" --shm-segment-size 100000000"
SAMPLER1+=" --shm-monitor true"
SAMPLER1+=" --max-iterations 1"
SAMPLER1+=" --control static --color false"
SAMPLER1+=" --transport shmem"
@ -44,6 +48,7 @@ SAMPLER2+=" --id sampler2"
SAMPLER2+=" --session $session"
SAMPLER2+=" --verbosity veryhigh --severity debug"
SAMPLER2+=" --shm-segment-size 100000000"
SAMPLER2+=" --shm-monitor true"
SAMPLER2+=" --max-iterations 1"
SAMPLER2+=" --control static --color false"
SAMPLER2+=" --transport zeromq"
@ -55,4 +60,6 @@ wait $SAMPLER1_PID
wait $SAMPLER2_PID
wait $SINK_PID
set +e
rm $chan1Addr; rm $chan2Addr; rm $ackChanAddr
exit 0

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2020 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2020-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -54,7 +54,7 @@ struct Receiver : fair::mq::Device
fBuffer[h.id].start = chrono::steady_clock::now();
}
// if the received ID has not previously been discarded, store the data part in the buffer
fBuffer[h.id].parts.AddPart(move(parts.At(1)));
fBuffer[h.id].parts.AddPart(std::move(parts.At(1)));
} else {
// if received ID has been previously discarded.
LOG(debug) << "Received part from an already discarded timeframe with id " << h.id;
@ -93,7 +93,7 @@ struct Receiver : fair::mq::Device
unordered_map<uint16_t, TFBuffer> fBuffer;
unordered_set<uint16_t> fDiscardedSet;
int fNumSenders = 0;
unsigned int fNumSenders = 0;
int fBufferTimeoutInMs = 5000;
int fMaxTimeframes = 0;
int fTimeframeCounter = 0;

View File

@ -1,59 +1,13 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-readout-readout readout.cxx)
target_link_libraries(fairmq-ex-readout-readout PRIVATE FairMQ)
add_executable(fairmq-ex-readout-builder builder.cxx)
target_link_libraries(fairmq-ex-readout-builder PRIVATE FairMQ)
add_executable(fairmq-ex-readout-processor processor.cxx)
target_link_libraries(fairmq-ex-readout-processor PRIVATE FairMQ)
add_executable(fairmq-ex-readout-sender sender.cxx)
target_link_libraries(fairmq-ex-readout-sender PRIVATE FairMQ)
add_executable(fairmq-ex-readout-receiver receiver.cxx)
target_link_libraries(fairmq-ex-readout-receiver PRIVATE FairMQ)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh)
# install
install(
TARGETS
fairmq-ex-readout-readout
fairmq-ex-readout-builder
fairmq-ex-readout-processor
fairmq-ex-readout-sender
fairmq-ex-readout-receiver
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-readout-processing.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-readout.sh
)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-readout-processing.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-readout-processing.sh
add_example(NAME readout
DEVICE readout builder processor sender receiver
SCRIPT readout readout-processing
NO_TEST
)

View File

@ -7,19 +7,19 @@ This examples shows two possible topologies (out of many) for a node connected t
```
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
| Readout --> Builder --> Sender | --> | Receiver |
| [# shared memory segment (unused in this topology) ##################] | ofi | |
| [# shared memory segment (unused in this topology) ##################] | zmq | |
| [# shmem unmanaged region (readout writes here, others read) ########] | | |
|------------------------------------------------------------------------| |-------------------|
```
The devices one the Readout Node communicate via shared memory transport. Readout device writes into shared memory unmanaged region. The data is then forwarded through Builder to Sender process, which sends it out via OFI transport.
The devices one the Readout Node communicate via shared memory transport. Readout device writes into shared memory unmanaged region. The data is then forwarded through Builder to Sender process, which sends it out via zeromq transport.
## Setup with generating new data on the Readout node
```
|------------------------------- Readout Node ---------------------------| |- Processing Node -|
| Readout --> Builder --> Processor --> Sender | --> | Receiver |
| [# shared memory segment (used between Proccessor and Sender) #######] | ofi | |
| [# shared memory segment (used between Proccessor and Sender) #######] | zmq | |
| [# shmem unmanaged region (readout writes here, builder & proc read) ] | | |
|------------------------------------------------------------------------| |-------------------|
```

View File

@ -31,12 +31,10 @@ SENDER="fairmq-ex-readout-sender"
SENDER+=" --id sender1"
SENDER+=" --input-name ps"
SENDER+=" --channel-config name=ps,type=pair,method=bind,address=tcp://localhost:7779,transport=shmem"
#SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=ofi"
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7780,transport=zeromq"
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
RECEIVER="fairmq-ex-readout-receiver"
RECEIVER+=" --id receiver1"
#RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=ofi"
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7780,transport=zeromq"
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &

View File

@ -25,12 +25,10 @@ SENDER="fairmq-ex-readout-sender"
SENDER+=" --id sender1"
SENDER+=" --input-name bs"
SENDER+=" --channel-config name=bs,type=pair,method=bind,address=tcp://localhost:7778,transport=shmem"
# SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=ofi"
SENDER+=" name=sr,type=pair,method=connect,address=tcp://localhost:7779,transport=zeromq"
xterm -geometry 80x23+1000+0 -hold -e @EX_BIN_DIR@/$SENDER &
RECEIVER="fairmq-ex-readout-receiver"
RECEIVER+=" --id receiver1"
# RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=ofi"
RECEIVER+=" --channel-config name=sr,type=pair,method=bind,address=tcp://localhost:7779,transport=zeromq"
xterm -geometry 80x23+1500+0 -hold -e @EX_BIN_DIR@/$RECEIVER &

View File

@ -1,54 +1,12 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-region-sampler sampler.cxx)
target_link_libraries(fairmq-ex-region-sampler PRIVATE FairMQ)
add_executable(fairmq-ex-region-sink sink.cxx)
target_link_libraries(fairmq-ex-region-sink PRIVATE FairMQ)
add_executable(fairmq-ex-region-keep-alive keep-alive.cxx)
target_link_libraries(fairmq-ex-region-keep-alive PRIVATE FairMQ)
add_custom_target(ExampleRegion DEPENDS fairmq-ex-region-sampler fairmq-ex-region-sink fairmq-ex-region-keep-alive)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh)
add_test(NAME Example.Region.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh zeromq)
set_tests_properties(Example.Region.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
add_test(NAME Example.Region.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-region.sh shmem)
set_tests_properties(Example.Region.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received [0-9*] acks")
# install
install(
TARGETS
fairmq-ex-region-sampler
fairmq-ex-region-sink
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-region.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-region.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-region.sh
add_example(NAME region
DEVICE sampler processor sink keep-alive
SCRIPT region region-advanced region-advanced-external
)

View 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 &

View 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 &

View File

@ -2,16 +2,8 @@
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="shmem"
msgSize="1000000"
if [[ $1 =~ ^[a-z]+$ ]]; then
transport=$1
fi
if [[ $2 =~ ^[0-9]+$ ]]; then
msgSize=$1
fi
transport=${1:-shmem}
msgSize=${2:-1000000}
SAMPLER="fairmq-ex-region-sampler"
SAMPLER+=" --id sampler1"
@ -19,6 +11,10 @@ SAMPLER+=" --severity debug"
SAMPLER+=" --msg-size $msgSize"
# SAMPLER+=" --rate 10"
SAMPLER+=" --transport $transport"
# SAMPLER+=" --external-region true"
# SAMPLER+=" --shm-no-cleaup true"
SAMPLER+=" --shm-monitor true"
# SAMPLER+=" --shmid 1"
SAMPLER+=" --channel-config name=data,type=push,method=bind,address=tcp://127.0.0.1:7777,sndKernelSize=212992"
xterm -geometry 120x60+0+0 -hold -e @EX_BIN_DIR@/$SAMPLER &
@ -26,5 +22,8 @@ SINK="fairmq-ex-region-sink"
SINK+=" --id sink1"
SINK+=" --severity debug"
SINK+=" --transport $transport"
# SINK+=" --shm-no-cleaup true"
SINK+=" --shm-monitor true"
# SINK+=" --shmid 1"
SINK+=" --channel-config name=data,type=pull,method=connect,address=tcp://127.0.0.1:7777,rcvKernelSize=212992"
xterm -geometry 120x60+750+0 -hold -e @EX_BIN_DIR@/$SINK &

View File

@ -19,6 +19,7 @@
#include <chrono>
#include <csignal>
#include <map>
#include <mutex>
#include <string>
#include <thread>
@ -94,10 +95,11 @@ struct ShmManager
uint64_t size = stoull(conf.at(1));
fair::mq::RegionConfig cfg;
cfg.id = id;
cfg.rcSegmentSize = 0;
cfg.size = size;
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);
LOG(info) << "Created unamanged region " << id << " of size " << region.GetSize()
<< ", starting at " << region.GetData() << ". Locking...";
@ -113,6 +115,7 @@ struct ShmManager
bool CheckPresence()
{
std::lock_guard<std::mutex> lock(localMtx);
for (const auto& sc : segmentCfgs) {
if (!(fair::mq::shmem::Monitor::SegmentIsPresent(fair::mq::shmem::ShmId{shmId}, sc.id))) {
return false;
@ -128,6 +131,7 @@ struct ShmManager
void ResetContent()
{
std::lock_guard<std::mutex> lock(localMtx);
fair::mq::shmem::Monitor::ResetContent(fair::mq::shmem::ShmId{shmId}, segmentCfgs, regionCfgs);
}
@ -145,6 +149,7 @@ struct ShmManager
}
std::string shmId;
std::mutex localMtx;
map<uint16_t, fair::mq::shmem::Segment> segments;
map<uint16_t, unique_ptr<fair::mq::shmem::UnmanagedRegion>> regions;
std::vector<fair::mq::shmem::SegmentConfig> segmentCfgs;

View 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>(); }

View File

@ -8,6 +8,7 @@
#include <fairmq/Device.h>
#include <fairmq/runDevice.h>
#include <fairmq/tools/RateLimit.h>
#include <cstdint>
#include <mutex>
@ -19,11 +20,15 @@ struct Sampler : fair::mq::Device
{
void InitTask() override
{
fExternalRegion = fConfig->GetProperty<bool>("external-region");
fMsgSize = fConfig->GetProperty<int>("msg-size");
fLinger = fConfig->GetProperty<uint32_t>("region-linger");
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 << ": "
<< (info.managed ? "managed" : "unmanaged")
<< ", id: " << info.id
@ -34,78 +39,109 @@ struct Sampler : fair::mq::Device
fair::mq::RegionConfig regionCfg;
regionCfg.linger = fLinger; // delay in ms before region destruction to collect outstanding events
regionCfg.lock = true; // mlock region after creation
regionCfg.zero = true; // zero region content after creation
fRegion = fair::mq::UnmanagedRegionPtr(NewUnmanagedRegionFor("data", // region is created using the transport of this channel...
0, // ... and this sub-channel
10000000, // region size
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
std::lock_guard<std::mutex> lock(fMtx);
fNumUnackedMsgs -= blocks.size();
if (fMaxIterations > 0) {
LOG(info) << "Received " << blocks.size() << " acks";
}
}, regionCfg));
// options for testing with an externally-created -region
if (fExternalRegion) {
regionCfg.id = 1;
regionCfg.removeOnDestruction = false;
}
regionCfg.lock = !fExternalRegion; // mlock region 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(
fChanName, // region is created using the transport of this channel...
0, // ... and this sub-channel
10000000, // region size
[this](const std::vector<fair::mq::RegionBlock>& blocks) { // callback to be called when message buffers no longer needed by transport
std::lock_guard<std::mutex> lock(fMtx);
fNumUnackedMsgs -= blocks.size();
if (fMaxIterations > 0) {
LOG(info) << "Received " << blocks.size() << " acks";
}
},
regionCfg
));
}
bool ConditionalRun() override
void Run() override
{
fair::mq::MessagePtr msg(NewMessageFor("data", // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
fMsgSize, // offset from ptr
nullptr // hint
));
// static_cast<char*>(fRegion->GetData())[3] = 97;
// LOG(info) << "check: " << static_cast<char*>(fRegion->GetData())[3];
// std::this_thread::sleep_for(std::chrono::seconds(1));
fair::mq::tools::RateLimiter rateLimiter(fSamplingRate);
std::lock_guard<std::mutex> lock(fMtx);
++fNumUnackedMsgs;
if (Send(msg, "data", 0) > 0) {
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Leaving RUNNING state.";
return false;
while (!NewStatePending()) {
fair::mq::Parts parts;
// make 64 parts
for (int i = 0; i < 64; ++i) {
parts.AddPart(NewMessageFor(
fChanName, // channel
0, // sub-channel
fRegion, // region
fRegion->GetData(), // ptr within region
fMsgSize, // offset from ptr
nullptr // hint
));
}
std::lock_guard<std::mutex> lock(fMtx);
fNumUnackedMsgs += parts.Size();
if (Send(parts, fChanName, 0) > 0) {
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured maximum number of iterations reached. Stopping sending.";
break;
}
if (fSamplingRate > 0.001) {
rateLimiter.maybe_sleep();
}
}
}
return true;
// wait for all acks to arrive
while (!NewStatePending()) {
{
std::lock_guard<std::mutex> lock(fMtx);
if (fNumUnackedMsgs == 0) {
break;
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(25));
}
if (fNumUnackedMsgs != 0) {
LOG(info) << "Done, still not acknowledged: " << fNumUnackedMsgs;
} else {
LOG(info) << "All acknowledgements received.";
}
}
void ResetTask() override
{
// give some time for acks to be received
std::this_thread::sleep_for(std::chrono::milliseconds(250));
fRegion.reset();
{
std::lock_guard<std::mutex> lock(fMtx);
if (fNumUnackedMsgs != 0) {
LOG(info) << "Done, still not acknowledged: " << fNumUnackedMsgs;
} else {
LOG(info) << "All acknowledgements received.";
}
}
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
GetChannel(fChanName, 0).Transport()->UnsubscribeFromRegionEvents();
}
private:
int fExternalRegion = false;
int fMsgSize = 10000;
uint32_t fLinger = 100;
uint64_t fMaxIterations = 0;
uint64_t fNumIterations = 0;
uint64_t fRCSegmentSize = 10000000;
fair::mq::UnmanagedRegionPtr fRegion = nullptr;
std::mutex fMtx;
uint64_t fNumUnackedMsgs = 0;
std::string fChanName;
float fSamplingRate = 0.;
};
void addCustomOptions(bpo::options_description& 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")
("sampling-rate", bpo::value<float>()->default_value(0.), "Sampling rate (Hz).")
("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")
("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*/)

View File

@ -22,7 +22,8 @@ struct Sink : Device
{
// Get the fMaxIterations value from the command line options (via fConfig)
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 << ": "
<< (info.managed ? "managed" : "unmanaged") << ", id: " << info.id
<< ", ptr: " << info.ptr << ", size: " << info.size
@ -32,15 +33,11 @@ struct Sink : Device
void Run() override
{
Channel& dataInChannel = GetChannel("data", 0);
Channel& dataIn = GetChannel(fChanName, 0);
while (!NewStatePending()) {
auto msg(dataInChannel.Transport()->CreateMessage());
dataInChannel.Receive(msg);
// void* ptr = msg->GetData();
// char* cptr = static_cast<char*>(ptr);
// LOG(info) << "check: " << cptr[3];
fair::mq::Parts parts;
dataIn.Receive(parts);
if (fMaxIterations > 0 && ++fNumIterations >= fMaxIterations) {
LOG(info) << "Configured max number of iterations reached. Leaving RUNNING state.";
@ -51,22 +48,22 @@ struct Sink : Device
void ResetTask() override
{
GetChannel("data", 0).Transport()->UnsubscribeFromRegionEvents();
GetChannel(fChanName, 0).Transport()->UnsubscribeFromRegionEvents();
}
private:
uint64_t fMaxIterations = 0;
uint64_t fNumIterations = 0;
std::string fChanName;
};
} // namespace
void addCustomOptions(bpo::options_description& options)
{
options.add_options()(
"max-iterations",
bpo::value<uint64_t>()->default_value(0),
"Maximum number of iterations of Run/ConditionalRun/OnData (0 - infinite)");
options.add_options()
("chan-name", bpo::value<std::string>()->default_value("data"), "name of the input channel")
("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<Sink>(); }

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -14,7 +16,7 @@ chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chanAddr' TERM
trap 'set +e; kill -TERM $SAMPLER_PID; kill -TERM $SINK_PID; wait $SAMPLER_PID; wait $SINK_PID; @CMAKE_BINARY_DIR@/fairmq/fairmq-shmmonitor --cleanup --session $SESSION; rm $chanAddr; exit 0' TERM
SAMPLER="fairmq-ex-region-sampler"
SAMPLER+=" --id sampler1"
@ -22,6 +24,7 @@ SAMPLER+=" --transport $transport"
SAMPLER+=" --severity debug"
SAMPLER+=" --session $session"
SAMPLER+=" --shm-segment-size 100000000"
SAMPLER+=" --shm-monitor true"
SAMPLER+=" --verbosity veryhigh"
SAMPLER+=" --control static --color false"
SAMPLER+=" --max-iterations 1"
@ -37,6 +40,7 @@ SINK+=" --transport $transport"
SINK+=" --severity debug"
SINK+=" --session $session"
SINK+=" --shm-segment-size 100000000"
SINK+=" --shm-monitor true"
SINK+=" --verbosity veryhigh"
SINK+=" --control static --color false"
SINK+=" --max-iterations 1"
@ -48,4 +52,6 @@ SINK_PID=$!
wait $SAMPLER_PID
wait $SINK_PID
set +e
rm $chanAddr
exit 0

View File

@ -1,52 +1,11 @@
################################################################################
# Copyright (C) 2014 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
################################################################################
# Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# #
# This software is distributed under the terms of the #
# GNU Lesser General Public Licence (LGPL) version 3, #
# copied verbatim in the file "LICENSE" #
################################################################################
add_executable(fairmq-ex-req-rep-client client.cxx)
target_link_libraries(fairmq-ex-req-rep-client PRIVATE FairMQ)
add_executable(fairmq-ex-req-rep-server server.cxx)
target_link_libraries(fairmq-ex-req-rep-server PRIVATE FairMQ)
add_custom_target(ExampleReqRep DEPENDS fairmq-ex-req-rep-client fairmq-ex-req-rep-server)
set(EX_BIN_DIR ${CMAKE_CURRENT_BINARY_DIR})
set(FAIRMQ_BIN_DIR ${CMAKE_BINARY_DIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh)
# test
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/test-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh)
add_test(NAME Example.ReqRep.zeromq COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh zeromq)
set_tests_properties(Example.ReqRep.zeromq PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received reply from server: ")
add_test(NAME Example.ReqRep.shmem COMMAND ${CMAKE_CURRENT_BINARY_DIR}/test-ex-req-rep.sh shmem)
set_tests_properties(Example.ReqRep.shmem PROPERTIES TIMEOUT "30" PASS_REGULAR_EXPRESSION "Received reply from server: ")
# install
install(
TARGETS
fairmq-ex-req-rep-client
fairmq-ex-req-rep-server
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
)
# configure run script with different executable paths for build and for install directories
set(EX_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR})
set(FAIRMQ_BIN_DIR ${CMAKE_INSTALL_PREFIX}/${PROJECT_INSTALL_BINDIR}/fairmq)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/fairmq-start-ex-req-rep.sh.in ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh_install)
install(
PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/fairmq-start-ex-req-rep.sh_install
DESTINATION ${PROJECT_INSTALL_BINDIR}
RENAME fairmq-start-ex-req-rep.sh
add_example(NAME req-rep
DEVICE client server
)

View File

@ -1,5 +1,7 @@
#!/bin/bash
set -e
export FAIRMQ_PATH=@FAIRMQ_BIN_DIR@
transport="zeromq"
@ -13,7 +15,7 @@ chan="data"
chanAddr="/tmp/fmq_$session""_""$chan""_""$transport"
# setup a trap to kill everything if the test fails/timeouts
trap 'kill -TERM $CLIENT_PID; kill -TERM $SERVER_PID; wait $CLIENT_PID; wait $SERVER_PID; rm $chanAddr' TERM
trap 'set +e; kill -TERM $CLIENT_PID; kill -TERM $SERVER_PID; wait $CLIENT_PID; wait $SERVER_PID; rm $chanAddr; exit 0' TERM
CLIENT="fairmq-ex-req-rep-client"
CLIENT+=" --id client"
@ -21,6 +23,7 @@ CLIENT+=" --transport $transport"
CLIENT+=" --verbosity veryhigh"
CLIENT+=" --session $session"
CLIENT+=" --shm-segment-size 100000000"
CLIENT+=" --shm-monitor true"
CLIENT+=" --control static --color false"
CLIENT+=" --max-iterations 1"
CLIENT+=" --channel-config name=$chan,type=req,method=connect,rateLogging=0,address=ipc://$chanAddr"
@ -33,6 +36,7 @@ SERVER+=" --transport $transport"
SERVER+=" --verbosity veryhigh"
SERVER+=" --session $session"
SERVER+=" --shm-segment-size 100000000"
SERVER+=" --shm-monitor true"
SERVER+=" --control static --color false"
SERVER+=" --max-iterations 1"
SERVER+=" --channel-config name=$chan,type=rep,method=bind,rateLogging=0,address=ipc://$chanAddr"
@ -43,4 +47,6 @@ SERVER_PID=$!
wait $CLIENT_PID
wait $SERVER_PID
set +e
rm $chanAddr
exit 0

2
extern/googletest vendored

@ -1 +1 @@
Subproject commit f5e592d8ee5ffb1d9af5be7f715ce3576b8bf9c4
Subproject commit 7d76a231b0e29caf86e68d1df858308cd53b2a66

View File

@ -1,12 +1,12 @@
################################################################################
# Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH #
# Copyright (C) 2012-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" #
################################################################################
if(BUILD_FAIRMQ OR BUILD_SDK)
if(BUILD_FAIRMQ)
if(BUILD_TIDY_TOOL)
include(FairMQTidy)
@ -23,135 +23,6 @@ if(BUILD_FAIRMQ OR BUILD_SDK)
DESTINATION ${PROJECT_INSTALL_INCDIR}
)
#########
# Tools #
#########
set(target Tools)
set(TOOLS_PUBLIC_HEADER_FILES
tools/CppSTL.h
tools/Exceptions.h
tools/InstanceLimit.h
tools/IO.h
tools/Network.h
tools/Process.h
tools/RateLimit.h
tools/Semaphore.h
tools/Strings.h
tools/Unique.h
tools/Version.h
Error.h
Tools.h
)
set(TOOLS_SOURCE_FILES
Error.cxx
tools/Network.cxx
tools/Process.cxx
tools/Semaphore.cxx
tools/Unique.cxx
)
add_library(${target}
${TOOLS_SOURCE_FILES}
${TOOLS_PUBLIC_HEADER_FILES}
)
target_compile_features(${target} PUBLIC cxx_std_17)
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_include_directories(${target}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(${target}
PRIVATE
FairLogger::FairLogger
Threads::Threads
Boost::boost
)
set_target_properties(${target} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
foreach(HEADER ${TOOLS_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
#################
# State Machine #
#################
set(target StateMachine)
set(FSM_PUBLIC_HEADER_FILES
StateMachine.h
States.h
StateQueue.h
)
set(FSM_SOURCE_FILES
StateMachine.cxx
States.cxx
)
add_library(${target}
${FSM_SOURCE_FILES}
${FSM_PUBLIC_HEADER_FILES}
)
target_compile_features(${target} PUBLIC cxx_std_17)
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_include_directories(${target}
PUBLIC
$<BUILD_INTERFACE:${CMAKE_SOURCE_DIR}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>
)
target_link_libraries(${target}
PUBLIC
FairLogger::FairLogger
PRIVATE
Boost::boost
Tools
)
set_target_properties(${target} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME FairMQ${target}
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
endif()
install(
TARGETS ${target}
EXPORT ${PROJECT_EXPORT_SET}
RUNTIME DESTINATION ${PROJECT_INSTALL_BINDIR}
LIBRARY DESTINATION ${PROJECT_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${PROJECT_INSTALL_LIBDIR}
)
foreach(HEADER ${FSM_PUBLIC_HEADER_FILES})
get_filename_component(_path ${HEADER} DIRECTORY)
file(TO_CMAKE_PATH ${PROJECT_INSTALL_INCDIR}/${_path} _destination)
install(FILES ${HEADER}
DESTINATION ${_destination}
)
endforeach()
endif()
if(BUILD_FAIRMQ)
##########################
# libFairMQ header files #
##########################
@ -159,6 +30,7 @@ if(BUILD_FAIRMQ)
Channel.h
Device.h
DeviceRunner.h
Error.h
EventManager.h
FairMQChannel.h
FairMQDevice.h
@ -184,17 +56,40 @@ if(BUILD_FAIRMQ)
Properties.h
PropertyOutput.h
Socket.h
StateMachine.h
States.h
StateQueue.h
SuboptParser.h
Tools.h
TransportFactory.h
Transports.h
TransportEnum.h
UnmanagedRegion.h
options/FairMQProgOptions.h
runDevice.h
runFairMQDevice.h
shmem/Monitor.h
shmem/Common.h
shmem/UnmanagedRegion.h
shmem/Manager.h
shmem/Message.h
shmem/Monitor.h
shmem/Poller.h
shmem/Segment.h
shmem/Socket.h
shmem/TransportFactory.h
shmem/UnmanagedRegion.h
shmem/UnmanagedRegionImpl.h
tools/Compiler.h
tools/CppSTL.h
tools/Exceptions.h
tools/IO.h
tools/InstanceLimit.h
tools/Network.h
tools/Process.h
tools/RateLimit.h
tools/Semaphore.h
tools/Strings.h
tools/Unique.h
tools/Version.h
)
set(FAIRMQ_PRIVATE_HEADER_FILES
@ -207,12 +102,6 @@ if(BUILD_FAIRMQ)
plugins/Builtin.h
plugins/config/Config.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/Context.h
zeromq/Message.h
@ -220,18 +109,9 @@ if(BUILD_FAIRMQ)
zeromq/UnmanagedRegion.h
zeromq/Socket.h
zeromq/TransportFactory.h
zeromq/ZMsg.h
)
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_PRIVATE_HEADER_FILES ${FAIRMQ_PRIVATE_HEADER_FILES}
ofi/Context.h
ofi/ControlMessages.h
ofi/Message.h
ofi/Socket.h
ofi/TransportFactory.h
)
endif()
##########################
# libFairMQ source files #
##########################
@ -239,6 +119,7 @@ if(BUILD_FAIRMQ)
Channel.cxx
Device.cxx
DeviceRunner.cxx
EventManager.cxx
JSONParser.cxx
MemoryResources.cxx
Plugin.cxx
@ -246,6 +127,8 @@ if(BUILD_FAIRMQ)
PluginServices.cxx
ProgOptions.cxx
Properties.cxx
StateMachine.cxx
States.cxx
SuboptParser.cxx
TransportFactory.cxx
plugins/config/Config.cxx
@ -253,16 +136,12 @@ if(BUILD_FAIRMQ)
shmem/Common.cxx
shmem/Manager.cxx
shmem/Monitor.cxx
tools/Network.cxx
tools/Process.cxx
tools/Semaphore.cxx
tools/Unique.cxx
)
if(BUILD_OFI_TRANSPORT)
set(FAIRMQ_SOURCE_FILES ${FAIRMQ_SOURCE_FILES}
ofi/Context.cxx
ofi/Message.cxx
ofi/Socket.cxx
)
endif()
###################
# configure files #
@ -286,14 +165,26 @@ if(BUILD_FAIRMQ)
############################
# preprocessor definitions #
############################
target_compile_definitions(${target} PUBLIC BOOST_ERROR_CODE_HEADER_ONLY)
target_compile_definitions(${target} PUBLIC
BOOST_ERROR_CODE_HEADER_ONLY
BOOST_ASIO_HAS_HAS_STD_CHRONO
)
if(FAIRMQ_DEBUG_MODE)
target_compile_definitions(${target} PUBLIC FAIRMQ_DEBUG_MODE)
endif()
if(BUILD_OFI_TRANSPORT)
target_compile_definitions(${target} PRIVATE BUILD_OFI_TRANSPORT)
target_compile_definitions(${target} PUBLIC
FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM}
FAIRMQ_HAS_STD_PMR=${FAIRMQ_HAS_STD_PMR}
)
if(DEFINED FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
# translate CMake boolean (TRUE, FALSE, 0, 1, OFF, ON) into C++ boolean literal (true, false)
if(FAIRMQ_CHANNEL_DEFAULT_AUTOBIND)
set(value "true")
else()
set(value "false")
endif()
target_compile_definitions(${target} PUBLIC FAIRMQ_CHANNEL_DEFAULT_AUTOBIND=${value})
endif()
target_compile_definitions(${target} PUBLIC FAIRMQ_HAS_STD_FILESYSTEM=${FAIRMQ_HAS_STD_FILESYSTEM})
#######################
@ -311,13 +202,6 @@ if(BUILD_FAIRMQ)
##################
# link libraries #
##################
if(BUILD_OFI_TRANSPORT)
set(OFI_DEPS
asio::asio
asiofi::asiofi
)
endif()
target_link_libraries(${target}
INTERFACE # only consumers link against interface dependencies
Boost::container
@ -328,20 +212,17 @@ if(BUILD_FAIRMQ)
$<$<PLATFORM_ID:Linux>:rt>
Boost::boost
Boost::program_options
Boost::filesystem
Boost::filesystem # still needed for Boost.DLL
Boost::regex
FairLogger::FairLogger
Tools
StateMachine
PRIVATE # only libFairMQ links against private dependencies
libzmq
PicoSHA2
${OFI_DEPS}
)
set_target_properties(${target} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}"
OUTPUT_NAME ${PROJECT_NAME_LOWER}
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET ${target})
@ -414,7 +295,7 @@ if(BUILD_FAIRMQ)
add_executable(fairmq-uuid-gen tools/runUuidGenerator.cxx)
target_link_libraries(fairmq-uuid-gen PUBLIC
Boost::program_options
Tools
FairMQ
)
if(BUILD_TIDY_TOOL AND RUN_FAIRMQ_TIDY)
fairmq_target_tidy(TARGET fairmq-uuid-gen)
@ -451,21 +332,3 @@ if(BUILD_FAIRMQ)
)
endforeach()
endif()
if(BUILD_SDK_COMMANDS)
add_subdirectory(sdk/commands)
endif()
if(BUILD_SDK)
add_subdirectory(sdk)
endif()
####################
# external plugins #
####################
if(BUILD_DDS_PLUGIN)
add_subdirectory(plugins/DDS)
endif()
if(BUILD_PMIX_PLUGIN)
add_subdirectory(plugins/PMIx)
endif()

View File

@ -12,6 +12,7 @@
#include <fairmq/Channel.h>
#include <fairmq/Properties.h>
#include <fairmq/Tools.h>
#include <fairmq/Transports.h>
#include <random>
#include <regex>
#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

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -14,11 +14,12 @@
#include <fairmq/Properties.h>
#include <fairmq/Socket.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/TransportEnum.h>
#include <fairmq/UnmanagedRegion.h>
#include <cstdint> // int64_t
#include <memory> // unique_ptr, shared_ptr
#include <ostream>
#include <stdexcept>
#include <string>
#include <utility> // std::move
@ -144,11 +145,11 @@ class Channel
/// Get channel transport name ("default", "zeromq" or "shmem")
/// @return Returns channel transport name (e.g. "default", "zeromq" or "shmem")
std::string GetTransportName() const { return TransportName(fTransportType); }
std::string GetTransportName() const;
/// Get 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)
/// @return Returns socket send buffer size (in number of messages)
@ -220,7 +221,7 @@ class Channel
/// Set channel transport
/// @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
/// @param sndBufSize Socket send buffer size (in number of messages)
@ -378,7 +379,19 @@ class Channel
static constexpr int DefaultRateLogging = 1;
static constexpr int DefaultPortRangeMin = 22000;
static constexpr int DefaultPortRangeMax = 23000;
#ifdef FAIRMQ_CHANNEL_DEFAULT_AUTOBIND
static constexpr bool DefaultAutoBind = FAIRMQ_CHANNEL_DEFAULT_AUTOBIND;
#else
static constexpr bool DefaultAutoBind = true;
#endif
friend std::ostream& operator<<(std::ostream& os, const Channel& ch)
{
return os << "name: " << ch.fName
<< ", type: " << ch.fType
<< ", method: " << ch.fMethod
<< ", address: " << ch.fAddress;
}
private:
std::shared_ptr<TransportFactory> fTransportFactory;
@ -416,16 +429,16 @@ class Channel
msg.get()
));
msg.release();
msg = move(msgWrapper);
msg = std::move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
msg = std::move(newMsg);
}
}
}
void CheckSendCompatibility(Parts& parts) { CheckSendCompatibility(parts.fParts); }
void CheckSendCompatibility(std::vector<MessagePtr>& msgVec)
void CheckSendCompatibility(Parts::container & msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
@ -437,10 +450,10 @@ class Channel
msg.get()
));
msg.release();
msg = move(msgWrapper);
msg = std::move(msgWrapper);
} else {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
msg = std::move(newMsg);
}
}
}
@ -450,18 +463,18 @@ class Channel
{
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
msg = std::move(newMsg);
}
}
void CheckReceiveCompatibility(Parts& parts) { CheckReceiveCompatibility(parts.fParts); }
void CheckReceiveCompatibility(std::vector<MessagePtr>& msgVec)
void CheckReceiveCompatibility(Parts::container& msgVec)
{
for (auto& msg : msgVec) {
if (fTransportType != msg->GetType()) {
MessagePtr newMsg(NewMessage());
msg = move(newMsg);
msg = std::move(newMsg);
}
}
}
@ -475,7 +488,6 @@ class Channel
} // namespace fair::mq
// using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
using FairMQChannel = fair::mq::Channel;
using FairMQChannel [[deprecated("Use fair::mq::Channel")]] = fair::mq::Channel;
#endif // FAIR_MQ_CHANNEL_H

View File

@ -1,19 +1,25 @@
/********************************************************************************
* Copyright (C) 2012-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2012-2023 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 <algorithm> // std::max, std::any_of
#include <boost/algorithm/string.hpp> // join/split
#include <chrono>
// FairMQ
#include <fairmq/Device.h>
#include <fairmq/Tools.h>
#include <fairmq/Transports.h>
// boost
#include <boost/algorithm/string.hpp> // join/split
// std
#include <algorithm> // std::max, std::any_of
#include <chrono>
#include <iomanip>
#include <list>
#include <memory> // std::make_unique
#include <memory> // std::make_unique
#include <mutex>
#include <thread>
@ -72,6 +78,9 @@ Device::Device(ProgOptions& config, tools::Version version)
: Device(&config, version)
{}
/// TODO: Remove this once Device::fChannels is no longer public
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Device::Device(ProgOptions* config, tools::Version version)
: fTransportFactory(nullptr)
, fInternalConfig(config ? nullptr : make_unique<ProgOptions>())
@ -83,18 +92,15 @@ Device::Device(ProgOptions* config, tools::Version version)
, fVersion(version)
, fRate(DefaultRate)
, fInitializationTimeoutInS(DefaultInitTimeout)
, fTransitioning(false)
{
SubscribeToNewTransition("device", [&](Transition transition) {
LOG(trace) << "device notified on new transition: " << transition;
InterruptTransports();
});
switch (transition) {
case Transition::Stop:
UnblockTransports();
break;
default:
break;
}
fStateMachine.PrepareState([&](State state) {
LOG(trace) << "Resuming transports for " << state << " state";
ResumeTransports();
});
fStateMachine.HandleStates([&](State state) {
@ -135,73 +141,7 @@ Device::Device(ProgOptions* config, tools::Version version)
fStateMachine.Start();
}
void Device::TransitionTo(State s)
{
{
lock_guard<mutex> lock(fTransitionMtx);
if (fTransitioning) {
LOG(debug) << "Attempting a transition with TransitionTo() while another one is already in progress";
throw OngoingTransition("Attempting a transition with TransitionTo() while another one is already in progress");
}
fTransitioning = true;
}
using mq::State;
StateQueue sq;
StateSubscription ss(tools::ToString(fId, ".TransitionTo"), fStateMachine, sq);
State currentState = GetCurrentState();
while (s != currentState) {
switch (currentState) {
case State::Idle:
if (s == State::Exiting) { ChangeState(Transition::End); }
else { ChangeState(Transition::InitDevice); }
break;
case State::InitializingDevice:
ChangeState(Transition::CompleteInit);
break;
case State::Initialized:
if (s == State::Exiting || s == State::Idle) { ChangeState(Transition::ResetDevice); }
else { ChangeState(Transition::Bind); }
break;
case State::Bound:
if (s == State::DeviceReady || s == State::Ready || s == State::Running) { ChangeState(Transition::Connect); }
else { ChangeState(Transition::ResetDevice); }
break;
case State::DeviceReady:
if (s == State::Running || s == State::Ready) { ChangeState(Transition::InitTask); }
else { ChangeState(Transition::ResetDevice); }
break;
case State::Ready:
if (s == State::Running) { ChangeState(Transition::Run); }
else { ChangeState(Transition::ResetTask); }
break;
case State::Running:
ChangeState(Transition::Stop);
break;
case State::Binding:
case State::Connecting:
case State::InitializingTask:
case State::ResettingDevice:
case State::ResettingTask:
LOG(debug) << "TransitionTo ignoring state: " << currentState << " (expected, automatic transition).";
break;
default:
LOG(debug) << "TransitionTo ignoring state: " << currentState;
break;
}
currentState = sq.WaitForNext();
}
{
lock_guard<mutex> lock(fTransitionMtx);
fTransitioning = false;
}
}
#pragma GCC diagnostic pop
void Device::InitWrapper()
{
@ -226,7 +166,7 @@ void Device::InitWrapper()
unordered_map<string, int> infos = fConfig->GetChannelInfo();
for (const auto& info : infos) {
for (int i = 0; i < info.second; ++i) {
fChannels[info.first].emplace_back(info.first, i, fConfig->GetPropertiesStartingWith(tools::ToString("chans.", info.first, ".", i, ".")));
GetChannels()[info.first].emplace_back(info.first, i, fConfig->GetPropertiesStartingWith(tools::ToString("chans.", info.first, ".", i, ".")));
}
}
@ -236,8 +176,7 @@ void Device::InitWrapper()
string networkInterface = fConfig->GetProperty<string>("network-interface", DefaultNetworkInterface);
// Fill the uninitialized channel containers
for (auto& channel : fChannels) {
int subChannelIndex = 0;
for (auto& channel : GetChannels()) {
for (auto& subChannel : channel.second) {
// set channel transport
LOG(debug) << "Initializing transport for channel " << subChannel.fName << ": " << TransportNames.at(subChannel.fTransportType);
@ -269,12 +208,10 @@ void Device::InitWrapper()
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."));
}
subChannelIndex++;
}
}
// ChangeState(Transition::Auto);
// ChangeStateOrThrow(Transition::Auto);
}
void Device::BindWrapper()
@ -291,7 +228,7 @@ void Device::BindWrapper()
Bind();
if (!NewStatePending()) {
ChangeState(Transition::Auto);
ChangeStateOrThrow(Transition::Auto);
}
}
@ -304,7 +241,7 @@ void Device::ConnectWrapper()
// first attempt
AttachChannels(fUninitializedConnectingChannels);
// if not all channels could be connected, update their address values from config and retry
while (!fUninitializedConnectingChannels.empty()) {
while (!fUninitializedConnectingChannels.empty() && !NewStatePending()) {
this_thread::sleep_for(chrono::milliseconds(sleepTimeInMS));
for (auto& chan : fUninitializedConnectingChannels) {
@ -317,20 +254,24 @@ void Device::ConnectWrapper()
if (numAttempts++ > maxAttempts) {
LOG(error) << "could not connect all channels after " << fInitializationTimeoutInS << " attempts";
LOG(error) << "following channels are still invalid:";
for (auto& chan : fUninitializedConnectingChannels) {
LOG(error) << "channel: " << *chan;
}
throw runtime_error(tools::ToString("could not connect all channels after ", fInitializationTimeoutInS, " attempts"));
}
AttachChannels(fUninitializedConnectingChannels);
}
if (fChannels.empty()) {
if (GetChannels().empty()) {
LOG(warn) << "No channels created after finishing initialization";
}
Connect();
if (!NewStatePending()) {
ChangeState(Transition::Auto);
ChangeStateOrThrow(Transition::Auto);
}
}
@ -345,7 +286,7 @@ void Device::AttachChannels(vector<Channel*>& chans)
// remove the channel from the uninitialized container
itr = chans.erase(itr);
} 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;
}
} else {
@ -432,7 +373,7 @@ void Device::InitTaskWrapper()
InitTask();
if (!NewStatePending()) {
ChangeState(Transition::Auto);
ChangeStateOrThrow(Transition::Auto);
}
}
@ -442,7 +383,7 @@ void Device::RunWrapper()
unique_ptr<thread> rateLogger;
// Check if rate logging thread is needed
const bool rateLogging = any_of(fChannels.cbegin(), fChannels.cend(), [](auto ch) {
const bool rateLogging = any_of(GetChannels().cbegin(), GetChannels().cend(), [](auto ch) {
return any_of(ch.second.cbegin(), ch.second.cend(), [](auto sub) { return sub.fRateLogging > 0; });
});
@ -453,15 +394,9 @@ void Device::RunWrapper()
if (rateLogging && rateLogger->joinable()) { rateLogger->join(); }
});
// notify transports to resume transfers
for (auto& t : fTransports) {
t.second->Resume();
}
// change to Error state in case of an exception, to release LogSocketRates
tools::CallOnDestruction cod([&](){
ChangeState(Transition::ErrorFound);
ChangeStateOrThrow(Transition::ErrorFound);
});
PreRun();
@ -469,7 +404,7 @@ void Device::RunWrapper()
// process either data callbacks or ConditionalRun/Run
if (fDataCallbacks) {
// if only one input channel, do lightweight handling without additional polling.
if (fInputChannelKeys.size() == 1 && fChannels.at(fInputChannelKeys.at(0)).size() == 1) {
if (fInputChannelKeys.size() == 1 && GetChannels().at(fInputChannelKeys.at(0)).size() == 1) {
HandleSingleChannelInput();
} else {// otherwise do full handling with polling
HandleMultipleChannelInput();
@ -488,8 +423,7 @@ void Device::RunWrapper()
// if Run() exited and the state is still RUNNING, transition to READY.
if (!NewStatePending()) {
UnblockTransports();
ChangeState(Transition::Stop);
ChangeStateOrThrow(Transition::Stop);
}
PostRun();
@ -517,7 +451,7 @@ void Device::HandleMultipleChannelInput()
// check if more than one transport is used
fMultitransportInputs.clear();
for (const auto& k : fInputChannelKeys) {
mq::Transport t = fChannels.at(k).at(0).fTransportType;
mq::Transport t = GetChannel(k, 0).fTransportType;
if (fMultitransportInputs.find(t) == fMultitransportInputs.end()) {
fMultitransportInputs.insert(pair<mq::Transport, vector<string>>(t, vector<string>()));
fMultitransportInputs.at(t).push_back(k);
@ -527,13 +461,13 @@ void Device::HandleMultipleChannelInput()
}
for (const auto& mi : fMsgInputs) {
for (auto& i : fChannels.at(mi.first)) {
for (auto& i : GetChannels().at(mi.first)) {
i.fMultipart = false;
}
}
for (const auto& mi : fMultipartInputs) {
for (auto& i : fChannels.at(mi.first)) {
for (auto& i : GetChannels().at(mi.first)) {
i.fMultipart = true;
}
}
@ -544,16 +478,16 @@ void Device::HandleMultipleChannelInput()
} else { // otherwise poll directly
bool proceed = true;
PollerPtr poller(fChannels.at(fInputChannelKeys.at(0)).at(0).fTransportFactory->CreatePoller(fChannels, fInputChannelKeys));
PollerPtr poller(GetChannel(fInputChannelKeys.at(0), 0).fTransportFactory->CreatePoller(GetChannels(), fInputChannelKeys));
while (!NewStatePending() && proceed) {
poller->Poll(200);
// check which inputs are ready and call their data handlers if they are.
for (const auto& ch : fInputChannelKeys) {
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i) {
for (unsigned int i = 0; i < GetChannels().at(ch).size(); ++i) {
if (poller->CheckInput(ch, i)) {
if (fChannels.at(ch).at(i).fMultipart) {
if (GetChannel(ch, i).fMultipart) {
proceed = HandleMultipartInput(ch, fMultipartInputs.at(ch), i);
} else {
proceed = HandleMsgInput(ch, fMsgInputs.at(ch), i);
@ -590,13 +524,13 @@ void Device::HandleMultipleTransportInput()
void Device::PollForTransport(const TransportFactory* factory, const vector<string>& channelKeys)
{
try {
PollerPtr poller(factory->CreatePoller(fChannels, channelKeys));
PollerPtr poller(factory->CreatePoller(GetChannels(), channelKeys));
while (!NewStatePending() && fMultitransportProceed) {
poller->Poll(500);
for (const auto& ch : channelKeys) {
for (unsigned int i = 0; i < fChannels.at(ch).size(); ++i) {
for (unsigned int i = 0; i < GetChannels().at(ch).size(); ++i) {
if (poller->CheckInput(ch, i)) {
lock_guard<mutex> lock(fMultitransportMutex);
@ -604,7 +538,7 @@ void Device::PollForTransport(const TransportFactory* factory, const vector<stri
break;
}
if (fChannels.at(ch).at(i).fMultipart) {
if (GetChannel(ch, i).fMultipart) {
fMultitransportProceed = HandleMultipartInput(ch, fMultipartInputs.at(ch), i);
} else {
fMultitransportProceed = HandleMsgInput(ch, fMsgInputs.at(ch), i);
@ -628,7 +562,7 @@ void Device::PollForTransport(const TransportFactory* factory, const vector<stri
bool Device::HandleMsgInput(const string& chName, const InputMsgCallback& callback, int i)
{
unique_ptr<Message> input(fChannels.at(chName).at(i).fTransportFactory->CreateMessage());
unique_ptr<Message> input(GetChannel(chName, i).fTransportFactory->CreateMessage());
if (Receive(input, chName, i) >= 0) {
return callback(input, i);
@ -650,6 +584,8 @@ bool Device::HandleMultipartInput(const string& chName, const InputMultipartCall
shared_ptr<TransportFactory> Device::AddTransport(mq::Transport transport)
{
lock_guard<mutex> lock(fTransportMtx);
if (transport == mq::Transport::DEFAULT) {
transport = fDefaultTransportType;
}
@ -683,7 +619,7 @@ void Device::LogSocketRates()
size_t chanNameLen = 0;
// iterate over the channels map
for (auto& channel : fChannels) {
for (auto& channel : GetChannels()) {
// iterate over the channels vector
for (auto& subChannel : channel.second) {
if (subChannel.fRateLogging > 0) {
@ -767,10 +703,19 @@ void Device::LogSocketRates()
}
}
void Device::UnblockTransports()
void Device::InterruptTransports()
{
for (auto& transport : fTransports) {
transport.second->Interrupt();
lock_guard<mutex> lock(fTransportMtx);
for (auto& [transportType, transport] : fTransports) {
transport->Interrupt();
}
}
void Device::ResumeTransports()
{
lock_guard<mutex> lock(fTransportMtx);
for (auto& [transportType, transport] : fTransports) {
transport->Resume();
}
}
@ -779,31 +724,38 @@ void Device::ResetTaskWrapper()
ResetTask();
if (!NewStatePending()) {
ChangeState(Transition::Auto);
ChangeStateOrThrow(Transition::Auto);
}
}
void Device::ResetWrapper()
{
for (auto& transport : fTransports) {
transport.second->Reset();
{
lock_guard<mutex> lock(fTransportMtx);
for (auto& [transportType, transport] : fTransports) {
transport->Reset();
}
fTransports.clear();
}
Reset();
fChannels.clear();
fTransports.clear();
GetChannels().clear();
fTransportFactory.reset();
if (!NewStatePending()) {
ChangeState(Transition::Auto);
ChangeStateOrThrow(Transition::Auto);
}
}
/// TODO: Remove this once Device::fChannels is no longer public
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
Device::~Device()
{
UnsubscribeFromNewTransition("device");
fStateMachine.StopHandlingStates();
LOG(debug) << "Shutting down device " << fId;
}
#pragma GCC diagnostic pop
} // namespace fair::mq

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2021-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,12 +9,9 @@
#ifndef FAIR_MQ_DEVICE_H
#define FAIR_MQ_DEVICE_H
#include <algorithm> // find
#include <atomic>
#include <chrono>
#include <cstddef>
#include <fairlogger/Logger.h>
// FairMQ
#include <fairmq/Channel.h>
#include <fairmq/Error.h>
#include <fairmq/Message.h>
#include <fairmq/Parts.h>
#include <fairmq/ProgOptions.h>
@ -22,8 +19,17 @@
#include <fairmq/StateQueue.h>
#include <fairmq/Tools.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/Transports.h>
#include <fairmq/TransportEnum.h>
#include <fairmq/UnmanagedRegion.h>
// logger
#include <fairlogger/Logger.h>
// std
#include <algorithm> // find
#include <atomic>
#include <chrono>
#include <cstddef>
#include <functional>
#include <memory> // unique_ptr
#include <mutex>
@ -228,7 +234,7 @@ class Device
}
}
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(fChannels, chans);
return GetChannel(chans.at(0), 0).Transport()->CreatePoller(GetChannels(), chans);
}
PollerPtr NewPoller(const std::vector<Channel*>& channels)
@ -316,7 +322,7 @@ class Device
Channel& GetChannel(const std::string& channelName, const int index = 0)
try {
return fChannels.at(channelName).at(index);
return GetChannels().at(channelName).at(index);
} catch (const std::out_of_range& oor) {
LOG(error) << "GetChannel(): '" << channelName << "[" << index << "]' does not exist.";
throw;
@ -324,7 +330,7 @@ class Device
size_t GetNumSubChannels(const std::string& channelName)
try {
return fChannels.at(channelName).size();
return GetChannels().at(channelName).size();
} catch (const std::out_of_range& oor) {
LOG(error) << "GetNumSubChannels(): '" << channelName << "' does not exist.";
throw;
@ -335,7 +341,7 @@ class Device
/// @param index sub-channel
unsigned long GetNumberOfConnectedPeers(const std::string& channelName, int index = 0)
{
return fChannels.at(channelName).at(index).GetNumberOfConnectedPeers();
return GetChannel(channelName, index).GetNumberOfConnectedPeers();
}
virtual void RegisterChannelEndpoints() {}
@ -433,7 +439,23 @@ class Device
fTransports; ///< Container for transports
public:
[[deprecated("Use GetChannels() instead.")]]
std::unordered_map<std::string, std::vector<Channel>> fChannels; ///< Device channels
std::unordered_map<std::string, std::vector<Channel>>& GetChannels()
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return fChannels;
#pragma GCC diagnostic pop
}
std::unordered_map<std::string, std::vector<Channel>> const& GetChannels() const
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
return fChannels;
#pragma GCC diagnostic pop
}
std::unique_ptr<ProgOptions> fInternalConfig; ///< Internal program options configuration
ProgOptions* fConfig; ///< Pointer to config (internal or external)
@ -477,21 +499,49 @@ class Device
public:
/// @brief Request a device state transition
/// @param transition state transition
/// @return whether the transition was successfully scheduled
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled
/// cooperatively.
bool ChangeState(const Transition transition) { return fStateMachine.ChangeState(transition); }
[[nodiscard]] bool ChangeState(const Transition transition)
{
return fStateMachine.ChangeState(transition);
}
/// @brief Request a device state transition
/// @param transition state transition
/// @return whether the transition was successfully scheduled
///
/// The state transition may not happen immediately, but when the current state evaluates the
/// pending transition event and terminates. In other words, the device states are scheduled
/// cooperatively.
bool ChangeState(const std::string& transition)
[[nodiscard]] bool ChangeState(const std::string& transition)
{
return fStateMachine.ChangeState(GetTransition(transition));
}
/// @brief Request a device state transition
/// @param transition state transition
/// @throws when the transition could not have been scheduled
///
/// Throwing version of Device::ChangeState().
void ChangeStateOrThrow(Transition transition)
{
if(!ChangeState(transition)) {
auto const err = MakeErrorCode(ErrorCode::DeviceChangeStateFailed);
throw std::system_error(err.value(),
err.category(),
tools::ToString("Invalid transition: ", transition));
}
}
/// @brief Request a device state transition
/// @param transition state transition
/// @throws when the transition could not have been scheduled
///
/// Throwing version of Device::ChangeState().
void ChangeStateOrThrow(std::string const& transition)
{
ChangeStateOrThrow(GetTransition(transition));
}
/// @brief waits for the next state (any) to occur
State WaitForNextState() { return fStateQueue.WaitForNext(); }
@ -502,8 +552,6 @@ class Device
/// @param state state to wait for
void WaitForState(const std::string& state) { WaitForState(GetState(state)); }
void TransitionTo(State state);
/// @brief Subscribe with a callback to state changes
/// @param key id to identify your subscription
/// @param callback callback (called with the new state as the parameter)
@ -588,7 +636,10 @@ class Device
void ResetWrapper();
/// Notifies transports to cease any blocking activity
void UnblockTransports();
void InterruptTransports();
/// Notifies transports to resume any blocking activity
void ResumeTransports();
/// Shuts down the transports and the device
void Exit() {}
@ -622,28 +673,19 @@ class Device
const tools::Version fVersion;
float fRate; ///< Rate limiting for ConditionalRun
uint64_t fMaxRunRuntimeInS; ///< Maximum runtime for the Running state handler, after which
///< state will change to Ready (in seconds, 0 for no limit).
int fInitializationTimeoutInS;
std::vector<std::string> fRawCmdLineArgs;
StateQueue fStateQueue;
std::mutex fTransitionMtx;
bool fTransitioning;
std::mutex fTransportMtx; ///< guards access to transports container
};
} // namespace fair::mq
// using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
// using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] =
// fair::mq::InputMsgCallback;
// using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] =
// fair::mq::InputMultipartCallback;
// using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
using FairMQChannelMap = fair::mq::ChannelMap;
using InputMsgCallback = fair::mq::InputMsgCallback;
using InputMultipartCallback = fair::mq::InputMultipartCallback;
using FairMQDevice = fair::mq::Device;
using FairMQChannelMap [[deprecated("Use fair::mq::ChannelMap")]] = fair::mq::ChannelMap;
using InputMsgCallback [[deprecated("Use fair::mq::InputMsgCallback")]] = fair::mq::InputMsgCallback;
using InputMultipartCallback [[deprecated("Use fair::mq::InputMultipartCallback")]] = fair::mq::InputMultipartCallback;
using FairMQDevice [[deprecated("Use fair::mq::Device")]] = fair::mq::Device;
#endif /* FAIR_MQ_DEVICE_H */

View File

@ -152,7 +152,7 @@ auto DeviceRunner::Run() -> int
fDevice->RegisterChannelEndpoints();
if (fConfig.Count("print-channels")) {
fDevice->PrintRegisteredChannels();
fDevice->ChangeState(fair::mq::Transition::End);
fDevice->ChangeStateOrThrow(fair::mq::Transition::End);
return 0;
}
@ -160,7 +160,7 @@ auto DeviceRunner::Run() -> int
if (fConfig.Count("version")) {
LOGV(info, verylow) << "FairMQ version: " << FAIRMQ_GIT_VERSION;
LOGV(info, verylow) << "User device version: " << fDevice->GetVersion();
fDevice->ChangeState(fair::mq::Transition::End);
fDevice->ChangeStateOrThrow(fair::mq::Transition::End);
return 0;
}

View File

@ -45,7 +45,7 @@ namespace fair::mq
* Each hook has access to all members of the DeviceRunner and really only differs by the point in
* time it is called.
*
* For an example usage of this class see the fairmq/runFairMQDevice.h header.
* For an example usage of this class see the <fairmq/runDevice.h> header.
*/
class DeviceRunner
{

View File

@ -1,39 +0,0 @@
/********************************************************************************
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#include "Error.h"
namespace fair::mq {
const char* ErrorCategory::name() const noexcept { return "fairmq"; }
std::string ErrorCategory::message(int ev) const
{
switch (static_cast<ErrorCode>(ev)) {
case ErrorCode::OperationInProgress:
return "async operation already in progress";
case ErrorCode::OperationTimeout:
return "async operation timed out";
case ErrorCode::OperationCanceled:
return "async operation canceled";
case ErrorCode::DeviceChangeStateFailed:
return "failed to change state of a fairmq device";
case ErrorCode::DeviceGetPropertiesFailed:
return "failed to get fairmq device properties";
case ErrorCode::DeviceSetPropertiesFailed:
return "failed to set fairmq device properties";
default:
return "(unrecognized error)";
}
}
const ErrorCategory errorCategory{};
std::error_code MakeErrorCode(ErrorCode e) { return {static_cast<int>(e), errorCategory}; }
} // namespace fair::mq

View File

@ -38,14 +38,34 @@ enum class ErrorCode
DeviceSetPropertiesFailed
};
std::error_code MakeErrorCode(ErrorCode);
struct ErrorCategory : std::error_category
{
const char* name() const noexcept override;
std::string message(int ev) const override;
const char* name() const noexcept override { return "fairmq"; }
std::string message(int ev) const override
{
switch (static_cast<ErrorCode>(ev)) {
case ErrorCode::OperationInProgress:
return "async operation already in progress";
case ErrorCode::OperationTimeout:
return "async operation timed out";
case ErrorCode::OperationCanceled:
return "async operation canceled";
case ErrorCode::DeviceChangeStateFailed:
return "failed to change state of a fairmq device";
case ErrorCode::DeviceGetPropertiesFailed:
return "failed to get fairmq device properties";
case ErrorCode::DeviceSetPropertiesFailed:
return "failed to set fairmq device properties";
default:
return "(unrecognized error)";
}
}
};
static ErrorCategory ec;
inline std::error_code MakeErrorCode(ErrorCode e) { return {static_cast<int>(e), ec}; }
} // namespace fair::mq
namespace std {

20
fairmq/EventManager.cxx Normal file
View 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)>);

View File

@ -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 *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -57,27 +57,8 @@ class EventManager
template<typename E, typename ...Args>
using Signal = boost::signals2::signal<void(typename E::KeyType, Args...)>;
template<typename E, typename ...Args>
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>
auto Subscribe(const std::string& subscriber, std::function<void(typename E::KeyType, Args...)> callback) -> void;
template<typename E, typename ...Args>
auto Unsubscribe(const std::string& subscriber) -> void
@ -119,21 +100,58 @@ class EventManager
mutable std::mutex fMutex;
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};
if (fSignals.find(key) == fSignals.end()) {
// 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
auto signal = std::make_shared<Signal<E, Args...>>();
fSignals.insert(std::make_pair(key, signal));
}
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 (fSignals.find(key) == fSignals.end())
{
// 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
auto signal = std::make_shared<Signal<E, Args...>>();
fSignals.insert(std::make_pair(key, signal));
if (fConnections.find(connectionsKey) != fConnections.end()) {
fConnections.at(connectionsKey).disconnect();
fConnections.erase(connectionsKey);
}
return boost::any_cast<std::shared_ptr<Signal<E, Args...>>>(fSignals.at(key));
fConnections.insert({connectionsKey, connection});
}
}; /* class EventManager */
}
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

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQCHANNEL_H_
#define FAIRMQCHANNEL_H_
#if 0
#ifndef FAIR_MQ_CHANNEL_H
#pragma GCC warning "Deprecated header: Use <fairmq/Channel.h> instead"
#endif
#endif
#include <fairmq/Channel.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2012-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2012-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQDEVICE_H_
#define FAIRMQDEVICE_H_
#if 0
#ifndef FAIR_MQ_DEVICE_H
#pragma GCC warning "Deprecated header: Use <fairmq/Device.h> instead"
#endif
#endif
#include <fairmq/Device.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2017-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2017-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,6 +9,8 @@
#ifndef FAIRMQLOGGER_H_
#define FAIRMQLOGGER_H_
#pragma GCC warning "Deprecated header: Use <fairlogger/Logger.h> instead"
#include <fairlogger/Logger.h>
#endif /* FAIRMQLOGGER_H_ */

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQMESSAGE_H_
#define FAIRMQMESSAGE_H_
#if 0
#ifndef FAIR_MQ_MESSAGE_H
#pragma GCC warning "Deprecated header: Use <fairmq/Message.h> instead"
#endif
#endif
#include <fairmq/Message.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQPARTS_H_
#define FAIRMQPARTS_H_
#if 0
#ifndef FAIR_MQ_PARTS_H
#pragma GCC warning "Deprecated header: Use <fairmq/Parts.h> instead"
#endif
#endif
#include <fairmq/Parts.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQPOLLER_H_
#define FAIRMQPOLLER_H_
#if 0
#ifndef FAIR_MQ_POLLER_H
#pragma GCC warning "Deprecated header: Use <fairmq/Poller.h> instead"
#endif
#endif
#include <fairmq/Poller.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQSOCKET_H_
#define FAIRMQSOCKET_H_
#if 0
#ifndef FAIR_MQ_SOCKET_H
#pragma GCC warning "Deprecated header: Use <fairmq/Socket.h> instead"
#endif
#endif
#include <fairmq/Socket.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQTRANSPORTFACTORY_H_
#define FAIRMQTRANSPORTFACTORY_H_
#if 0
#ifndef FAIR_MQ_TRANSPORTFACTORY_H
#pragma GCC warning "Deprecated header: Use <fairmq/TransportFactory.h> instead"
#endif
#endif
#include <fairmq/TransportFactory.h>

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,11 +9,9 @@
#ifndef FAIRMQUNMANAGEDREGION_H_
#define FAIRMQUNMANAGEDREGION_H_
#if 0
#ifndef FAIR_MQ_UNMANAGEDREGION_H
#pragma GCC warning "Deprecated header: Use <fairmq/UnmanagedRegion.h> instead"
#endif
#endif
#include <fairmq/UnmanagedRegion.h>

View File

@ -1,10 +1,10 @@
/********************************************************************************
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
/// @brief Memory allocators and interfaces related to managing memory via the
@ -12,7 +12,7 @@
///
/// @author Mikolaj Krzewicki, mkrzewic@cern.ch
#include <fairmq/FairMQTransportFactory.h>
#include <fairmq/TransportFactory.h>
#include <fairmq/MemoryResources.h>
void *fair::mq::ChannelResource::do_allocate(std::size_t bytes, std::size_t alignment)

View File

@ -1,6 +1,6 @@
/********************************************************************************
* Copyright (C) 2018 CERN and copyright holders of ALICE O2 *
* Copyright (C) 2018-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2018-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -17,7 +17,7 @@
#include <boost/container/container_fwd.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/container/pmr/memory_resource.hpp>
#include <memory_resource>
#include <cstring>
#include <fairmq/Message.h>
#include <stdexcept>
@ -27,7 +27,7 @@ namespace fair::mq {
class TransportFactory;
using byte = unsigned char;
namespace pmr = boost::container::pmr;
namespace pmr = std::pmr;
/// All FairMQ related memory resources need to inherit from this interface
/// class for the
@ -103,9 +103,7 @@ class ChannelResource : public MemoryResource
};
};
// using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] =
// MemoryResource;
using FairMQMemoryResource = MemoryResource;
using FairMQMemoryResource [[deprecated("Use fair::mq::MemoryResource")]] = MemoryResource;
} // namespace fair::mq

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -10,7 +10,7 @@
#define FAIR_MQ_MESSAGE_H
#include <cstddef> // for size_t
#include <fairmq/Transports.h>
#include <fairmq/TransportEnum.h>
#include <memory> // unique_ptr
#include <stdexcept>
@ -46,7 +46,7 @@ struct Message
virtual void* GetData() 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;
TransportFactory* GetTransport() { return fTransport; }
@ -76,13 +76,15 @@ struct MessageBadAlloc : std::runtime_error
using std::runtime_error::runtime_error;
};
struct RefCountBadAlloc : std::runtime_error
{
using std::runtime_error::runtime_error;
};
} // namespace fair::mq
// using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
// using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
// using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
using fairmq_free_fn = fair::mq::FreeFn;
using FairMQMessage = fair::mq::Message;
using FairMQMessagePtr = fair::mq::MessagePtr;
using fairmq_free_fn [[deprecated("Use fair::mq::FreeFn")]] = fair::mq::FreeFn;
using FairMQMessage [[deprecated("Use fair::mq::Message")]] = fair::mq::Message;
using FairMQMessagePtr [[deprecated("Use fair::mq::MessagePtr")]] = fair::mq::MessagePtr;
#endif // FAIR_MQ_MESSAGE_H

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -9,84 +9,89 @@
#ifndef FAIR_MQ_PARTS_H
#define FAIR_MQ_PARTS_H
#include <fairmq/Message.h>
#include <memory> // unique_ptr
#include <vector>
#include <algorithm> // std::move
#include <fairmq/Message.h> // fair::mq::MessagePtr
#include <iterator> // std::back_inserter
#include <utility> // std::move, std::forward
#include <vector> // std::vector
namespace fair::mq {
/// fair::mq::Parts is a lightweight convenience wrapper around a vector of unique pointers to
/// fair::mq::Parts is a lightweight move-only convenience wrapper around a vector of unique pointers to
/// Message, used for sending multi-part messages
class Parts
struct Parts
{
private:
using container = std::vector<MessagePtr>;
using size_type = container::size_type;
using reference = container::reference;
using const_reference = container::const_reference;
using iterator = container::iterator;
using const_iterator = container::const_iterator;
public:
Parts() = default;
Parts() noexcept(noexcept(container())) = default;
Parts(const Parts&) = delete;
Parts(Parts&&) = default;
template<typename... Ts>
Parts(Ts&&... messages) { AddPart(std::forward<Ts>(messages)...); }
Parts& operator=(const Parts&) = delete;
Parts(Parts&&) = default;
Parts& operator=(Parts&&) = default;
~Parts() = default;
/// Adds part (Message) to the container
/// @param msg message pointer (for example created with NewMessage() method of Device)
template<typename... Ps>
Parts(Ps&&... parts)
{
fParts.reserve(sizeof...(Ps));
AddPart(std::forward<Ps>(parts)...);
}
[[deprecated("Avoid owning raw pointer args, use AddPart(MessagePtr) instead.")]]
void AddPart(Message* msg) { fParts.push_back(MessagePtr(msg)); }
void AddPart(MessagePtr msg) { fParts.push_back(std::move(msg)); }
/// Adds part to the container (move)
/// @param msg unique pointer to Message
/// rvalue ref (move required when passing argument)
void AddPart(MessagePtr&& msg) { fParts.push_back(std::move(msg)); }
/// Add variable list of parts to the container (move)
template<typename... Ts>
void AddPart(MessagePtr&& first, Ts&&... remaining)
void AddPart(MessagePtr first, Ts&&... remaining)
{
AddPart(std::move(first));
AddPart(std::forward<Ts>(remaining)...);
}
/// Add content of another object by move
void AddPart(Parts&& other)
void AddPart(Parts parts)
{
container parts = std::move(other.fParts);
for (auto& part : parts) {
fParts.push_back(std::move(part));
if (fParts.empty()) {
fParts = std::move(parts.fParts);
} else {
fParts.reserve(parts.Size() + fParts.size());
std::move(std::begin(parts), std::end(parts), std::back_inserter(fParts));
}
}
/// Get reference to part in the container at index (without bounds check)
/// @param index container index
Message& operator[](const int index) { return *(fParts[index]); }
Message& operator[](size_type index) { return *(fParts[index]); }
Message const& operator[](size_type index) const { return *(fParts[index]); }
// TODO: For consistency with the STL interfaces, operator[] should not dereference,
// but I have no good idea how to fix this.
// reference operator[](size_type index) { return fParts[index]; }
// const_reference operator[](size_type index) const { return fParts[index]; }
/// Get reference to unique pointer to part in the container at index (with bounds check)
/// @param index container index
MessagePtr& At(const int index) { return fParts.at(index); }
[[deprecated("Redundant, dereference at call site e.g. '*(parts.At(index))' instead.")]]
Message& AtRef(size_type index) { return *(fParts.at(index)); }
reference At(size_type index) { return fParts.at(index); }
const_reference At(size_type index) const { return fParts.at(index); }
// ref version
Message& AtRef(const int index) { return *(fParts.at(index)); }
size_type Size() const noexcept { return fParts.size(); }
bool Empty() const noexcept { return fParts.empty(); }
void Clear() noexcept { fParts.clear(); }
/// Get number of parts in the container
/// @return number of parts in the container
int Size() const { return fParts.size(); }
// range access
iterator begin() noexcept { return fParts.begin(); }
const_iterator begin() const noexcept { return fParts.begin(); }
const_iterator cbegin() const noexcept { return fParts.cbegin(); }
iterator end() noexcept { return fParts.end(); }
const_iterator end() const noexcept { return fParts.end(); }
const_iterator cend() const noexcept { return fParts.cend(); }
container fParts;
// forward container iterators
using iterator = container::iterator;
using const_iterator = container::const_iterator;
auto begin() -> decltype(fParts.begin()) { return fParts.begin(); }
auto end() -> decltype(fParts.end()) { return fParts.end(); }
auto cbegin() -> decltype(fParts.cbegin()) { return fParts.cbegin(); }
auto cend() -> decltype(fParts.cend()) { return fParts.cend(); }
container fParts{};
};
} // namespace fair::mq
// using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
using FairMQParts = fair::mq::Parts;
using FairMQParts [[deprecated("Use fair::mq::Parts")]] = fair::mq::Parts;
#endif /* FAIR_MQ_PARTS_H */

View File

@ -1,16 +1,17 @@
/********************************************************************************
* Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2017-2022 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/plugins/Builtin.h>
#include <fairmq/PluginManager.h>
#include <fairmq/tools/Strings.h>
#include <boost/program_options.hpp>
#include <algorithm>
#include <boost/program_options.hpp>
#include <fairlogger/Logger.h>
#include <fairmq/PluginManager.h>
#include <fairmq/plugins/Builtin.h>
#include <fairmq/tools/Strings.h>
#include <iterator>
#include <memory>
#include <sstream>
@ -18,22 +19,22 @@
#include <utility>
using namespace std;
using fair::mq::Plugin;
using fair::mq::tools::ToString;
using fair::mq::tools::ToStrVector;
using fair::mq::Plugin;
namespace fs = boost::filesystem;
namespace po = boost::program_options;
namespace dll = boost::dll;
using boost::optional;
const std::string fair::mq::PluginManager::fgkLibPrefix = "FairMQPlugin_";
const std::string fair::mq::PluginManager::fgkLibPrefix = "fairmq-plugin-";
const std::string fair::mq::PluginManager::fgkLibPrefixAlt = "FairMQPlugin_";
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive = std::vector<boost::dll::shared_library>();
std::vector<boost::dll::shared_library> fair::mq::PluginManager::fgDLLKeepAlive =
std::vector<boost::dll::shared_library>();
fair::mq::PluginManager::PluginManager()
: fPluginServices()
{
}
{}
fair::mq::PluginManager::PluginManager(const vector<string>& args)
: fPluginServices()
@ -46,7 +47,8 @@ fair::mq::PluginManager::PluginManager(const vector<string>& args)
po::store(parsed, vm);
po::notify(vm);
} catch (const po::error& e) {
throw ProgramOptionsParseError{ToString("Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
throw ProgramOptionsParseError{ToString(
"Error occured while parsing the 'Plugin Manager' program options: ", e.what())};
}
// Process plugin search paths
@ -55,24 +57,38 @@ fair::mq::PluginManager::PluginManager(const vector<string>& args)
auto searchPaths = vector<fs::path>{};
if (vm.count("plugin-search-path")) {
for (const auto& path : vm["plugin-search-path"].as<vector<string>>()) {
if (path.substr(0, 1) == "<") { prepend.emplace_back(path.substr(1)); }
else if (path.substr(0, 1) == ">") { append.emplace_back(path.substr(1)); }
else { searchPaths.emplace_back(path); }
if (path.substr(0, 1) == "<") {
prepend.emplace_back(path.substr(1));
} else if (path.substr(0, 1) == ">") {
append.emplace_back(path.substr(1));
} else {
searchPaths.emplace_back(path);
}
}
}
// Set supplied options
SetSearchPaths(searchPaths);
for(const auto& path : prepend) { PrependSearchPath(path); }
for(const auto& path : append) { AppendSearchPath(path); }
if (vm.count("plugin")) { LoadPlugins(vm["plugin"].as<vector<string>>()); }
for (const auto& path : prepend) {
PrependSearchPath(path);
}
for (const auto& path : append) {
AppendSearchPath(path);
}
if (vm.count("plugin")) {
LoadPlugins(vm["plugin"].as<vector<string>>());
}
}
auto fair::mq::PluginManager::ValidateSearchPath(const fs::path& path) -> void
{
if (path.empty()) throw BadSearchPath{"Specified path is empty."};
if (path.empty()) {
throw BadSearchPath{"Specified path is empty."};
}
// we ignore non-existing search paths
if (fs::exists(path) && !fs::is_directory(path)) throw BadSearchPath{ToString(path, " is not a directory.")};
if (fs::exists(path) && !fs::is_directory(path)) {
throw BadSearchPath{ToString(path, " is not a directory.")};
}
}
auto fair::mq::PluginManager::SetSearchPaths(const vector<fs::path>& searchPaths) -> void
@ -96,31 +112,38 @@ auto fair::mq::PluginManager::PrependSearchPath(const fs::path& path) -> void
auto fair::mq::PluginManager::ProgramOptions() -> po::options_description
{
auto plugin_options = po::options_description{"Plugin Manager"};
plugin_options.add_options()
("plugin-search-path,S", po::value<vector<string>>()->multitoken(), "List of plugin search paths.\n\n"
"* Override default search path, e.g.\n"
" -S /home/user/lib /lib\n"
"* Append(>) or prepend(<) to default search path, e.g.\n"
" -S >/lib </home/user/lib\n"
"* If you mix the overriding and appending/prepending syntaxes, the overriding paths act as default search path, e.g.\n"
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in /home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
"If nothing is found, the default dynamic library lookup is performed, see man ld.so(8) for details.")
("plugin,P", po::value<vector<string>>(), "List of plugin names to load in order,"
"e.g. if the file is called 'libFairMQPlugin_example.so', just list 'example' or 'd:example' here."
"To load a prelinked plugin, list 'p:example' here.");
plugin_options.add_options()("plugin-search-path,S",
po::value<vector<string>>()->multitoken(),
"List of plugin search paths.\n\n"
"* Override default search path, e.g.\n"
" -S /home/user/lib /lib\n"
"* Append(>) or prepend(<) to default search path, e.g.\n"
" -S >/lib </home/user/lib\n"
"* If you mix the overriding and appending/prepending syntaxes, "
"the overriding paths act as default search path, e.g.\n"
" -S /usr/lib >/lib </home/user/lib /usr/local/lib results in "
"/home/user/lib,/usr/local/lib,/usr/lib/,/lib\n"
"If nothing is found, the default dynamic library lookup is "
"performed, see man ld.so(8) for details.")(
"plugin,P",
po::value<vector<string>>(),
"List of plugin names to load in order,"
"e.g. if the file is called 'libfairmq-plugin-example.so', just list 'example' or "
"'d:example' here."
"To load a prelinked plugin, list 'p:example' here.");
return plugin_options;
}
auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
{
if (pluginName.substr(0,2) == "p:") {
if (pluginName.substr(0, 2) == "p:") {
// Mechanism A: prelinked dynamic
LoadPluginPrelinkedDynamic(pluginName.substr(2));
} else if (pluginName.substr(0,2) == "d:") {
} else if (pluginName.substr(0, 2) == "d:") {
// Mechanism B: dynamic
LoadPluginDynamic(pluginName.substr(2));
} else if (pluginName.substr(0,2) == "s:") {
} else if (pluginName.substr(0, 2) == "s:") {
// Mechanism C: static (builtin)
LoadPluginStatic(pluginName.substr(2));
} else {
@ -137,52 +160,76 @@ auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginNam
LoadSymbols(pluginName, dll::program_location());
fPluginOrder.push_back(pluginName);
} catch (boost::system::system_error& e) {
throw PluginLoadError(ToString("An error occurred while loading prelinked dynamic plugin ", pluginName, ": ", e.what()));
throw PluginLoadError(
ToString("An error occurred while loading prelinked dynamic plugin ",
pluginName,
": ",
e.what()));
}
}
}
auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> void
auto fair::mq::PluginManager::SearchPluginFile(const string& pluginName) const
-> fs::path
{
// Search plugin and load, if found
if (fPluginFactories.find(pluginName) == fPluginFactories.end()) {
auto success = false;
for (const auto& searchPath : SearchPaths()) {
try {
LoadSymbols(pluginName, searchPath / ToString(LibPrefix(), pluginName),
dll::load_mode::append_decorations | dll::load_mode::rtld_global);
fPluginOrder.push_back(pluginName);
success = true;
break;
} catch (boost::system::system_error& e) {
if (string{e.what()}.find("No such file or directory") == string::npos) {
throw PluginLoadError(
ToString("An error occurred while loading dynamic plugin ",
pluginName, ": ", e.what()));
}
}
}
if (!success) {
try {
// LoadSymbols(pluginName,
// ToString(LibPrefix(), pluginName),
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
// Not sure, why the above does not work. Workaround for now:
LoadSymbols(pluginName,
ToString("lib",
LibPrefix(),
pluginName,
boost::dll::detail::shared_library_impl::suffix().native()),
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
fPluginOrder.push_back(pluginName);
} catch (boost::system::system_error& e) {
throw PluginLoadError(
ToString("An error occurred while loading dynamic plugin ",
pluginName, ": ", e.what()));
for (const auto& searchPath : SearchPaths()) {
for (const auto& libPrefix : {fgkLibPrefix, fgkLibPrefixAlt}) {
auto const file =
searchPath
/ ToString("lib",
libPrefix,
pluginName,
boost::dll::detail::shared_library_impl::suffix().native());
auto const found = fs::exists(file);
if (found) {
return file;
}
}
}
throw PluginNotFound(ToString("Could not find plugin file for plugin ", pluginName));
}
auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> void
{
if (fPluginFactories.find(pluginName) != fPluginFactories.end()) {
return; // already loaded, nothing to do
}
// Search in configured search path
try {
LoadSymbols(pluginName, SearchPluginFile(pluginName), dll::load_mode::rtld_global);
fPluginOrder.push_back(pluginName);
return;
} catch (PluginNotFound& e) {
// ignore
} catch (boost::system::system_error& e) {
// ignore
}
// Search with system logic (including RPATH, LD_LIBRARY_PATH)
for (const auto& libPrefix : {fgkLibPrefix, fgkLibPrefixAlt}) {
try {
// LoadSymbols(pluginName,
// ToString(LibPrefix(), pluginName),
// dll::load_mode::search_system_folders | dll::load_mode::append_decorations);
// Not sure, why the above does not work. Workaround for now:
LoadSymbols(pluginName,
ToString("lib",
libPrefix,
pluginName,
boost::dll::detail::shared_library_impl::suffix().native()),
dll::load_mode::search_system_folders | dll::load_mode::rtld_global);
fPluginOrder.push_back(pluginName);
return;
} catch (boost::system::system_error& e) {
// ignore
}
}
throw PluginLoadError(ToString("Could not load dynamic plugin ",
pluginName,
" from configured search paths (-S) nor with ",
"system lookup (system libdirs, RUNPATH, $LD_LIBRARY_PATH)."));
}
auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
@ -192,20 +239,25 @@ auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void
try {
if ("control" == pluginName) {
try {
fPluginProgOptions.insert({pluginName, plugins::ControlPluginProgramOptions().value()});
fPluginProgOptions.insert(
{pluginName, plugins::ControlPluginProgramOptions().value()});
} catch (const boost::bad_optional_access&) {
/* just ignore, if no prog options are declared */
}
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
} else if ("config" == pluginName) {
try {
fPluginProgOptions.insert({pluginName, plugins::ConfigPluginProgramOptions().value()});
fPluginProgOptions.insert(
{pluginName, plugins::ConfigPluginProgramOptions().value()});
} catch (const boost::bad_optional_access&) {
/* just ignore, if no prog options are declared */
}
catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ }
} else {
LoadSymbols(pluginName, dll::program_location());
}
fPluginOrder.push_back(pluginName);
} catch (boost::system::system_error& e) {
throw PluginLoadError(ToString("An error occurred while loading static plugin ", pluginName, ": ", e.what()));
throw PluginLoadError(ToString(
"An error occurred while loading static plugin ", pluginName, ": ", e.what()));
}
}
}
@ -225,11 +277,12 @@ auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> voi
auto fair::mq::PluginManager::InstantiatePlugins() -> void
{
for(const auto& pluginName : fPluginOrder) {
for (const auto& pluginName : fPluginOrder) {
try {
InstantiatePlugin(pluginName);
} catch (std::exception& e) {
throw PluginInstantiationError(ToString("An error occurred while instantiating plugin ", pluginName, ": ", e.what()));
throw PluginInstantiationError(ToString(
"An error occurred while instantiating plugin ", pluginName, ": ", e.what()));
}
}
}

View File

@ -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 *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -13,9 +13,16 @@
#include <fairmq/PluginServices.h>
#include <fairmq/tools/Strings.h>
#if FAIRMQ_HAS_STD_FILESYSTEM
#include <filesystem>
namespace fs = std::filesystem;
#else
#define BOOST_FILESYSTEM_VERSION 3
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>
namespace fs = ::boost::filesystem;
#endif
#include <boost/optional.hpp>
#include <boost/program_options.hpp>
#include <boost/dll/import.hpp>
@ -60,12 +67,14 @@ class PluginManager
LOG(debug) << "Shutting down Plugin Manager";
}
auto SetSearchPaths(const std::vector<boost::filesystem::path>&) -> void;
auto AppendSearchPath(const boost::filesystem::path&) -> void;
auto PrependSearchPath(const boost::filesystem::path&) -> void;
auto SearchPaths() const -> const std::vector<boost::filesystem::path>& { return fSearchPaths; }
auto SetSearchPaths(const std::vector<fs::path>&) -> void;
auto AppendSearchPath(const fs::path&) -> void;
auto PrependSearchPath(const fs::path&) -> void;
auto SearchPaths() const -> const std::vector<fs::path>& { return fSearchPaths; }
struct BadSearchPath : std::invalid_argument { using std::invalid_argument::invalid_argument; };
auto SearchPluginFile(const std::string&) const -> fs::path;
struct PluginNotFound : std::runtime_error { using std::runtime_error::runtime_error; };
auto LoadPlugin(const std::string& pluginName) -> void;
auto LoadPlugins(const std::vector<std::string>& pluginNames) -> void { for(const auto& pluginName : pluginNames) { LoadPlugin(pluginName); } }
struct PluginLoadError : std::runtime_error { using std::runtime_error::runtime_error; };
@ -86,18 +95,33 @@ class PluginManager
auto WaitForPluginsToReleaseDeviceControl() -> void { fPluginServices->WaitForReleaseDeviceControl(); }
private:
static auto ValidateSearchPath(const boost::filesystem::path&) -> void;
static auto ValidateSearchPath(const fs::path&) -> void;
auto LoadPluginPrelinkedDynamic(const std::string& pluginName) -> void;
auto LoadPluginDynamic(const std::string& pluginName) -> void;
auto LoadPluginStatic(const std::string& pluginName) -> void;
template<typename... Args>
auto LoadSymbols(const std::string& pluginName, Args&&... args) -> void
#if FAIRMQ_HAS_STD_FILESYSTEM
template<typename T>
static auto AdaptPathType(T&& path)
{
if constexpr(std::is_same_v<T, std::filesystem::path>) {
return boost::filesystem::path(std::forward<T>(path));
} else {
return std::forward<T>(path);
}
}
#endif
template<typename FirstArg, typename... Args>
auto LoadSymbols(const std::string& pluginName, FirstArg&& farg, Args&&... args) -> void
{
using namespace boost::dll;
using fair::mq::tools::ToString;
auto lib = shared_library{std::forward<Args>(args)...};
#if FAIRMQ_HAS_STD_FILESYSTEM
auto lib = shared_library{AdaptPathType(std::forward<FirstArg>(farg)), std::forward<Args>(args)...};
#else
auto lib = shared_library{std::forward<FirstArg>(farg), std::forward<Args>(args)...};
#endif
fgDLLKeepAlive.push_back(lib);
fPluginFactories[pluginName] = import_alias<PluginFactory>(
@ -118,7 +142,8 @@ class PluginManager
auto InstantiatePlugin(const std::string& pluginName) -> void;
static const std::string fgkLibPrefix;
std::vector<boost::filesystem::path> fSearchPaths;
static const std::string fgkLibPrefixAlt;
std::vector<fs::path> fSearchPaths;
static std::vector<boost::dll::shared_library> fgDLLKeepAlive; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
std::map<std::string, std::function<PluginFactory>> fPluginFactories;
std::unique_ptr<PluginServices> fPluginServices;

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -41,9 +41,7 @@ struct PollerError : std::runtime_error
} // namespace fair::mq
// using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
// using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
using FairMQPoller = fair::mq::Poller;
using FairMQPollerPtr = fair::mq::PollerPtr;
using FairMQPoller [[deprecated("Use fair::mq::Poller")]] = fair::mq::Poller;
using FairMQPollerPtr [[deprecated("Use fair::mq::PollerPtr")]] = fair::mq::PollerPtr;
#endif // FAIR_MQ_POLLER_H

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -12,9 +12,7 @@
* Created on March 11, 2015, 10:20 PM
*/
#include "FairMQLogger.h"
#include <fairmq/ProgOptions.h>
#include <fairmq/tools/Strings.h>
#include <boost/any.hpp>
@ -22,6 +20,7 @@
#include <algorithm>
#include <exception>
#include <fairlogger/Logger.h>
#include <iomanip>
#include <iostream>
#include <sstream>
@ -449,3 +448,6 @@ void ProgOptions::PrintOptionsRaw() const
}
} // 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);

View File

@ -129,17 +129,7 @@ class ProgOptions
/// @param key
/// @param val
template<typename T>
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));
}
void SetProperty(const std::string& key, T val);
/// @brief Updates an existing config property (or fails if it doesn't exist)
/// @param key
@ -275,5 +265,20 @@ class ProgOptions
};
} // 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 */

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2019-2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2019-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -13,7 +13,6 @@ namespace fair::mq {
class ProgOptions;
}
// using FairMQProgOptions [[deprecated("Use fair::mq::ProgOptions")]] = fair::mq::ProgOptions;
using FairMQProgOptions = fair::mq::ProgOptions;
using FairMQProgOptions [[deprecated("Use fair::mq::ProgOptions")]] = fair::mq::ProgOptions;
#endif /* FAIR_MQ_PROGOPTIONSFWD_H */

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2014-2018 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2014-2023 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -8,7 +8,15 @@
#include <fairmq/Properties.h>
#if FAIRMQ_HAS_STD_FILESYSTEM
#include <filesystem>
namespace fs = std::filesystem;
#else
#define BOOST_FILESYSTEM_VERSION 3
#define BOOST_FILESYSTEM_NO_DEPRECATED
#include <boost/filesystem.hpp>
namespace fs = ::boost::filesystem;
#endif
using namespace std;
using boost::any_cast;
@ -84,7 +92,12 @@ unordered_map<type_index, function<pair<string, string>(const Property&)>> Prope
{ type_index(typeid(long double)), [](const Property& p) { return getStringPair<long double>(p, "long double"); } },
{ type_index(typeid(bool)), [](const Property& p) { stringstream ss; ss << boolalpha << any_cast<bool>(p); return pair<string, string>{ ss.str(), "bool" }; } },
{ type_index(typeid(vector<bool>)), [](const Property& p) { stringstream ss; ss << boolalpha << any_cast<vector<bool>>(p); return pair<string, string>{ ss.str(), "vector<bool>>" }; } },
{ type_index(typeid(boost::filesystem::path)), [](const Property& p) { return getStringPair<boost::filesystem::path>(p, "boost::filesystem::path"); } },
{ type_index(typeid(fs::path)), [](const Property& p) { return getStringPair<fs::path>(p,
#if FAIRMQ_HAS_STD_FILESYSTEM
"std::filesystem::path"); } },
#else
"boost::filesystem::path"); } },
#endif
{ type_index(typeid(vector<char>)), [](const Property& p) { return getStringPair<vector<char>>(p, "vector<char>"); } },
{ type_index(typeid(vector<signed char>)), [](const Property& p) { return getStringPair<vector<signed char>>(p, "vector<signed char>"); } },
{ type_index(typeid(vector<unsigned char>)), [](const Property& p) { return getStringPair<vector<unsigned char>>(p, "vector<unsigned char>"); } },
@ -100,7 +113,12 @@ unordered_map<type_index, function<pair<string, string>(const Property&)>> Prope
{ type_index(typeid(vector<float>)), [](const Property& p) { return getStringPair<vector<float>>(p, "vector<float>"); } },
{ type_index(typeid(vector<double>)), [](const Property& p) { return getStringPair<vector<double>>(p, "vector<double>"); } },
{ type_index(typeid(vector<long double>)), [](const Property& p) { return getStringPair<vector<long double>>(p, "vector<long double>"); } },
{ type_index(typeid(vector<boost::filesystem::path>)), [](const Property& p) { return getStringPair<vector<boost::filesystem::path>>(p, "vector<boost::filesystem::path>"); } },
{ type_index(typeid(vector<fs::path>)), [](const Property& p) { return getStringPair<vector<fs::path>>(p,
#if FAIRMQ_HAS_STD_FILESYSTEM
"vector<std::filesystem::path>"); } },
#else
"vector<boost::filesystem::path>"); } },
#endif
};
unordered_map<type_index, void(*)(const EventManager&, const string&, const Property&)> PropertyHelper::fEventEmitters = {
@ -122,7 +140,7 @@ unordered_map<type_index, void(*)(const EventManager&, const string&, const Prop
{ type_index(typeid(long double)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, long double>(k, any_cast<long double>(p)); } },
{ type_index(typeid(bool)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, bool>(k, any_cast<bool>(p)); } },
{ type_index(typeid(vector<bool>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<bool>>(k, any_cast<vector<bool>>(p)); } },
{ type_index(typeid(boost::filesystem::path)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, boost::filesystem::path>(k, any_cast<boost::filesystem::path>(p)); } },
{ type_index(typeid(fs::path)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, fs::path>(k, any_cast<fs::path>(p)); } },
{ type_index(typeid(vector<char>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<char>>(k, any_cast<vector<char>>(p)); } },
{ type_index(typeid(vector<signed char>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<signed char>>(k, any_cast<vector<signed char>>(p)); } },
{ type_index(typeid(vector<unsigned char>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<unsigned char>>(k, any_cast<vector<unsigned char>>(p)); } },
@ -138,7 +156,7 @@ unordered_map<type_index, void(*)(const EventManager&, const string&, const Prop
{ type_index(typeid(vector<float>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<float>>(k, any_cast<vector<float>>(p)); } },
{ type_index(typeid(vector<double>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<double>>(k, any_cast<vector<double>>(p)); } },
{ type_index(typeid(vector<long double>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<long double>>(k, any_cast<vector<long double>>(p)); } },
{ type_index(typeid(vector<boost::filesystem::path>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<boost::filesystem::path>>(k, any_cast<vector<boost::filesystem::path>>(p)); } },
{ type_index(typeid(vector<fs::path>)), [](const EventManager& em, const string& k, const Property& p) { em.Emit<PropertyChange, vector<fs::path>>(k, any_cast<vector<fs::path>>(p)); } },
};
} // namespace fair::mq

View File

@ -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 *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -29,7 +29,6 @@ using Property = boost::any;
using Properties = std::map<std::string, Property>;
struct PropertyChange : Event<std::string> {};
struct PropertyChangeAsString : Event<std::string> {};
class PropertyHelper
{

View File

@ -1,26 +0,0 @@
/********************************************************************************
* Copyright (C) 2019 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
* copied verbatim in the file "LICENSE" *
********************************************************************************/
#ifndef FAIR_MQ_SDK_H
#define FAIR_MQ_SDK_H
// IWYU pragma: begin_exports
#include <fairmq/sdk/AsioAsyncOp.h>
#include <fairmq/sdk/AsioBase.h>
#include <fairmq/sdk/DDSAgent.h>
#include <fairmq/sdk/DDSEnvironment.h>
#include <fairmq/sdk/DDSInfo.h>
#include <fairmq/sdk/DDSSession.h>
#include <fairmq/sdk/DDSTask.h>
#include <fairmq/sdk/DDSTopology.h>
#include <fairmq/sdk/Error.h>
#include <fairmq/sdk/Topology.h>
#include <fairmq/sdk/Traits.h>
// IWYU pragma: end_exports
#endif // FAIR_MQ_SDK_H

View File

@ -1,5 +1,5 @@
/********************************************************************************
* Copyright (C) 2021 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* Copyright (C) 2021-2022 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH *
* *
* This software is distributed under the terms of the *
* GNU Lesser General Public Licence (LGPL) version 3, *
@ -52,8 +52,8 @@ struct Socket
virtual int64_t Send(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 Receive(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(Parts::container & msgVec, int timeout = -1) = 0;
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); }
@ -103,9 +103,7 @@ struct SocketError : std::runtime_error
} // namespace fair::mq
// using FairMQSocket [[deprecated("Use fair::mq::Socket")]] = fair::mq::Socket;
// using FairMQSocketPtr [[deprecated("Use fair::mq::SocketPtr")]] = fair::mq::SocketPtr;
using FairMQSocket = fair::mq::Socket;
using FairMQSocketPtr = fair::mq::SocketPtr;
using FairMQSocket [[deprecated("Use fair::mq::Socket")]] = fair::mq::Socket;
using FairMQSocketPtr [[deprecated("Use fair::mq::SocketPtr")]] = fair::mq::SocketPtr;
#endif // FAIR_MQ_SOCKET_H

View File

@ -157,6 +157,13 @@ struct Machine_ : public state_machine_def<Machine_>
}
}
void CallStatePrep(const State state) const
{
if (!fStatePrepSignal.empty()) {
fStatePrepSignal(state);
}
}
void CallNewTransitionCallbacks(const Transition transition) const
{
if (!fNewTransitionSignal.empty()) {
@ -170,11 +177,13 @@ struct Machine_ : public state_machine_def<Machine_>
atomic<bool> fLastTransitionResult;
mutex fStateMtx;
mutex fSubscriptionsMtx;
atomic<bool> fNewStatePending;
condition_variable fNewStatePendingCV;
boost::signals2::signal<void(const State)> fStateChangeSignal;
boost::signals2::signal<void(const State)> fStateHandleSignal;
boost::signals2::signal<void(const State)> fStatePrepSignal;
boost::signals2::signal<void(const Transition)> fNewTransitionSignal;
unordered_map<string, boost::signals2::connection> fStateChangeSignalsMap;
unordered_map<string, boost::signals2::connection> fNewTransitionSignalsMap;
@ -198,6 +207,7 @@ struct Machine_ : public state_machine_def<Machine_>
}
}
CallStatePrep(fState);
CallStateChangeCallbacks(fState);
CallStateHandler(fState);
}
@ -301,18 +311,33 @@ try {
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)
{
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
if (fsm->fStateChangeSignalsMap.count(key)) {
fsm->fStateChangeSignalsMap.at(key).disconnect();
fsm->fStateChangeSignalsMap.erase(key);
}
}
void StateMachine::PrepareState(std::function<void(const State)> callback)
{
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
if (fsm->fStatePrepSignal.empty()) {
fsm->fStatePrepSignal.connect(callback);
} else {
LOG(error) << "state preparation handler is already set";
}
}
void StateMachine::HandleStates(function<void(const State)> callback)
{
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
@ -326,6 +351,9 @@ void StateMachine::HandleStates(function<void(const State)> callback)
void StateMachine::StopHandlingStates()
{
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
if (!fsm->fStatePrepSignal.empty()) {
fsm->fStatePrepSignal.disconnect_all_slots();
}
if (!fsm->fStateHandleSignal.empty()) {
fsm->fStateHandleSignal.disconnect_all_slots();
}
@ -333,12 +361,15 @@ void StateMachine::StopHandlingStates()
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)
{
auto fsm = static_pointer_cast<FairMQFSM>(fFsm);
lock_guard<mutex> lock(fsm->fSubscriptionsMtx);
if (fsm->fNewTransitionSignalsMap.count(key)) {
fsm->fNewTransitionSignalsMap.at(key).disconnect();
fsm->fNewTransitionSignalsMap.erase(key);

View File

@ -35,6 +35,7 @@ class StateMachine
void SubscribeToStateChange(const std::string& key, std::function<void(const State)> callback);
void UnsubscribeFromStateChange(const std::string& key);
void PrepareState(std::function<void(const State)> callback);
void HandleStates(std::function<void(const State)> callback);
void StopHandlingStates();

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