Skip to content

Commit 9c885e0

Browse files
committed
Update DelegateMQ library
1 parent 932bcd5 commit 9c885e0

26 files changed

Lines changed: 437 additions & 143 deletions

DelegateMQ/Common.cmake

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ if (MSVC)
88
add_compile_options("/utf-8")
99
add_compile_definitions(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING)
1010
add_compile_definitions(_SILENCE_ALL_MS_EXT_DEPRECATION_WARNINGS)
11+
12+
# Fix for spdlog bundled fmt in C++20 mode
13+
add_compile_definitions(FMT_USE_ITERATOR_TRAITS=1)
14+
add_compile_definitions(FMT_MSVC_CRT_ITERATORS=0)
1115
endif()
1216

1317

DelegateMQ/Port.cmake

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -132,20 +132,25 @@ endif()
132132
if (DMQ_UTIL STREQUAL "ON")
133133
if (DMQ_THREAD STREQUAL "DMQ_THREAD_NONE")
134134
# Bare metal: Only include utilities that DON'T need mutexes
135-
file(GLOB UTIL_SOURCES
136-
"${DMQ_ROOT_DIR}/extras/util/Fault.c*"
135+
# Fault.cpp lives in port/fault/ and is always included separately
136+
file(GLOB UTIL_SOURCES
137137
"${DMQ_ROOT_DIR}/extras/util/Fault.h"
138138
# Explicitly exclude Timer.cpp and AsyncInvoke.cpp
139139
)
140140
else()
141-
# OS/RTOS present: Include everything
142-
file(GLOB UTIL_SOURCES
143-
"${DMQ_ROOT_DIR}/extras/util/*.c*"
144-
"${DMQ_ROOT_DIR}/extras/util/*.h"
141+
# OS/RTOS present: Include everything
142+
file(GLOB UTIL_SOURCES
143+
"${DMQ_ROOT_DIR}/extras/util/*.c*"
144+
"${DMQ_ROOT_DIR}/extras/util/*.h"
145145
)
146146
endif()
147147
endif()
148148

149+
# Fault handler port — always included; override by filtering Fault.cpp from DMQ_PORT_SOURCES
150+
file(GLOB FAULT_SOURCES
151+
"${DMQ_ROOT_DIR}/port/fault/Fault.cpp"
152+
)
153+
149154
if (DMQ_ASSERTS STREQUAL "ON")
150155
add_compile_definitions(DMQ_ASSERTS)
151156
endif()
@@ -160,6 +165,7 @@ list(APPEND DMQ_PORT_ONLY_SOURCES ${TRANSPORT_SOURCES})
160165
list(APPEND DMQ_PORT_ONLY_SOURCES ${SERIALIZE_SOURCES})
161166
list(APPEND DMQ_PORT_ONLY_SOURCES ${THREAD_SOURCES})
162167
list(APPEND DMQ_PORT_ONLY_SOURCES ${OS_SOURCES})
168+
list(APPEND DMQ_PORT_ONLY_SOURCES ${FAULT_SOURCES})
163169

164170
# Extras sources: optional higher-level infrastructure (extras/ directory)
165171
set(DMQ_EXTRAS_SOURCES "")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#ifndef _DELEGATEMQ_CONFIG_DEFAULT_H
2+
#define _DELEGATEMQ_CONFIG_DEFAULT_H
3+
4+
/// @file
5+
/// @brief Default DelegateMQ library configuration.
6+
///
7+
/// To override, define DMQ_USER_CONFIG as a path to your own config header:
8+
/// -DDMQ_USER_CONFIG="path/to/DelegateMQConfig.h"
9+
/// Your config only needs to define the values you want to change.
10+
/// Unset values fall back to these defaults via DelegateMQConfig_Default.h.
11+
12+
#ifndef DMQ_DEFAULT_DISPATCH_TIMEOUT
13+
#define DMQ_DEFAULT_DISPATCH_TIMEOUT 2 // seconds
14+
#endif
15+
16+
#ifndef DMQ_MAX_TIMER_EXPIRED
17+
#define DMQ_MAX_TIMER_EXPIRED 16
18+
#endif
19+
20+
#ifndef DMQ_SIGNAL_SBO_COUNT
21+
#define DMQ_SIGNAL_SBO_COUNT 8
22+
#endif
23+
24+
#ifndef DMQ_DEFAULT_QUEUE_SIZE
25+
#define DMQ_DEFAULT_QUEUE_SIZE 20
26+
#endif
27+
28+
#ifndef DMQ_MAX_WATCHDOG_THREADS
29+
#define DMQ_MAX_WATCHDOG_THREADS 16
30+
#endif
31+
32+
#ifndef DMQ_SEQ_HISTORY_SIZE
33+
#define DMQ_SEQ_HISTORY_SIZE 8
34+
#endif
35+
36+
#ifndef DMQ_MAX_PARTICIPANTS
37+
#define DMQ_MAX_PARTICIPANTS 8
38+
#endif
39+
40+
#endif // _DELEGATEMQ_CONFIG_DEFAULT_H
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#ifndef _DELEGATEMQ_CONFIG_H
2+
#define _DELEGATEMQ_CONFIG_H
3+
4+
/// @file
5+
/// @brief User configuration for the DelegateMQ library.
6+
///
7+
/// Copy this file to your project, then point the compiler at it:
8+
/// -DDMQ_USER_CONFIG="DelegateMQConfig.h"
9+
///
10+
/// Only define the values you want to change; any omitted values
11+
/// fall back to the defaults in DelegateMQConfig_Default.h.
12+
13+
/// Timeout (seconds) used by the TIMEOUT queue-full policy on all threads.
14+
#define DMQ_DEFAULT_DISPATCH_TIMEOUT 2
15+
16+
/// Max timers processed in one tick without heap allocation.
17+
#define DMQ_MAX_TIMER_EXPIRED 16
18+
19+
/// Signal Small-Buffer Optimization count.
20+
/// Signals with <= this many subscribers are invoked without heap allocation.
21+
#define DMQ_SIGNAL_SBO_COUNT 8
22+
23+
/// Default internal message queue depth for all dmq::os::Thread ports.
24+
#define DMQ_DEFAULT_QUEUE_SIZE 20
25+
26+
/// Max number of threads that can be registered with the watchdog.
27+
#define DMQ_MAX_WATCHDOG_THREADS 16
28+
29+
/// Duplicate-detection ring buffer depth per remote Participant.
30+
/// Larger values catch more out-of-order duplicates; reduce on RAM-constrained targets.
31+
#define DMQ_SEQ_HISTORY_SIZE 8
32+
33+
/// Max number of remote Participants the DataBus can hold without heap allocation.
34+
#define DMQ_MAX_PARTICIPANTS 8
35+
36+
#endif // _DELEGATEMQ_CONFIG_H

DelegateMQ/delegate/DelegateOpt.h

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
/// @file
55
/// @brief Delegate library options header file.
66

7+
// Pull in user config if provided, otherwise use library defaults.
8+
// To provide your own config: -DDMQ_USER_CONFIG="path/to/DelegateMQConfig.h"
9+
#ifdef DMQ_USER_CONFIG
10+
#include DMQ_USER_CONFIG
11+
#endif
12+
#include "DelegateMQConfig_Default.h"
13+
714
#if defined(_WIN32) || defined(_WIN64)
815
#ifndef WIN32_LEAN_AND_MEAN
916
#define WIN32_LEAN_AND_MEAN
@@ -59,7 +66,9 @@
5966
#endif
6067

6168
#include <chrono>
62-
#if defined(DMQ_THREAD_STDLIB) || defined(DMQ_THREAD_WIN32) || defined(DMQ_THREAD_QT)
69+
#if defined(DMQ_THREAD_STDLIB) || defined(DMQ_THREAD_WIN32) || defined(DMQ_THREAD_QT) || \
70+
defined(DMQ_THREAD_FREERTOS) || defined(DMQ_THREAD_THREADX) || \
71+
defined(DMQ_THREAD_ZEPHYR) || defined(DMQ_THREAD_CMSIS_RTOS2)
6372
#include <mutex>
6473
#endif
6574

@@ -72,12 +81,10 @@
7281
// Windows / Linux / macOS / Qt (Standard Library)
7382
#include <condition_variable>
7483
#elif defined(DMQ_THREAD_FREERTOS)
75-
#include <mutex>
7684
#include "port/os/freertos/FreeRTOSClock.h"
7785
#include "port/os/freertos/FreeRTOSMutex.h"
7886
#include "port/os/freertos/FreeRTOSConditionVariable.h"
7987
#elif defined(DMQ_THREAD_THREADX)
80-
#include <mutex>
8188
#include "port/os/threadx/ThreadXClock.h"
8289
#include "port/os/threadx/ThreadXMutex.h"
8390
#include "port/os/threadx/ThreadXConditionVariable.h"
@@ -107,6 +114,28 @@ namespace dmq
107114
PortableLockGuard& operator=(const PortableLockGuard&) = delete;
108115
};
109116

117+
// --- PORTABLE SCOPED LOCK ---
118+
// Maps to std::scoped_lock on all known threaded ports (desktop + RTOS).
119+
// All RTOS mutex types satisfy BasicLockable (lock/unlock), so std::scoped_lock
120+
// works with them directly. Falls back to a no-op for DMQ_THREAD_NONE and for
121+
// any unrecognized bare-metal build where no thread model is defined.
122+
#if defined(DMQ_THREAD_STDLIB) || defined(DMQ_THREAD_WIN32) || defined(DMQ_THREAD_QT) || \
123+
defined(DMQ_THREAD_FREERTOS) || defined(DMQ_THREAD_THREADX) || \
124+
defined(DMQ_THREAD_ZEPHYR) || defined(DMQ_THREAD_CMSIS_RTOS2)
125+
template <typename... M>
126+
using ScopedLock = std::scoped_lock<M...>;
127+
#else
128+
// No-op: DMQ_THREAD_NONE or no thread model defined (bare-metal, single-threaded)
129+
template <typename... M>
130+
class ScopedLock {
131+
public:
132+
explicit ScopedLock(M&...) noexcept {}
133+
~ScopedLock() noexcept = default;
134+
ScopedLock(const ScopedLock&) = delete;
135+
ScopedLock& operator=(const ScopedLock&) = delete;
136+
};
137+
#endif
138+
110139
// @TODO: Change aliases to switch clock type globally if necessary
111140

112141
// --- CLOCK SELECTION ---
@@ -140,23 +169,31 @@ namespace dmq
140169
using TimePoint = typename Clock::time_point;
141170

142171
/// @brief Default timeout for the TIMEOUT queue-full policy across all Thread ports.
143-
/// Override per-thread at construction or project-wide before including this header.
144-
inline constexpr std::chrono::seconds DEFAULT_DISPATCH_TIMEOUT{2};
172+
/// Override via DMQ_DEFAULT_DISPATCH_TIMEOUT in DelegateMQConfig.h.
173+
inline constexpr std::chrono::seconds DEFAULT_DISPATCH_TIMEOUT{DMQ_DEFAULT_DISPATCH_TIMEOUT};
145174

146175
// --- RESOURCE LIMITS & SBO CONFIGURATION ---
147-
176+
148177
/// @brief Max timers processed in one tick without heap allocation.
149-
inline constexpr size_t MAX_TIMER_EXPIRED = 16;
178+
/// Override via DMQ_MAX_TIMER_EXPIRED in delegatemqconfig.h.
179+
inline constexpr size_t MAX_TIMER_EXPIRED = DMQ_MAX_TIMER_EXPIRED;
150180

151-
/// @brief Signal Small-Buffer Optimization (SBO) count.
181+
/// @brief Signal Small-Buffer Optimization (SBO) count.
152182
/// Signals with <= this many subscribers are invoked heap-free.
153-
inline constexpr size_t SIGNAL_SBO_COUNT = 8;
183+
/// Override via DMQ_SIGNAL_SBO_COUNT in delegatemqconfig.h.
184+
inline constexpr size_t SIGNAL_SBO_COUNT = DMQ_SIGNAL_SBO_COUNT;
154185

155186
/// @brief Default internal queue size for all dmq::os::Thread ports.
156-
inline constexpr size_t DEFAULT_QUEUE_SIZE = 20;
187+
/// Override via DMQ_DEFAULT_QUEUE_SIZE in delegatemqconfig.h.
188+
inline constexpr size_t DEFAULT_QUEUE_SIZE = DMQ_DEFAULT_QUEUE_SIZE;
157189

158190
/// @brief Max number of threads that can be monitored by the watchdog.
159-
inline constexpr size_t MAX_WATCHDOG_THREADS = 16;
191+
/// Override via DMQ_MAX_WATCHDOG_THREADS in delegatemqconfig.h.
192+
inline constexpr size_t MAX_WATCHDOG_THREADS = DMQ_MAX_WATCHDOG_THREADS;
193+
194+
/// @brief Max number of remote Participants the DataBus can hold without heap allocation.
195+
/// Override via DMQ_MAX_PARTICIPANTS in delegatemqconfig.h.
196+
inline constexpr size_t MAX_PARTICIPANTS = DMQ_MAX_PARTICIPANTS;
160197

161198
// --- MUTEX / LOCK SELECTION ---
162199
#if defined(DMQ_THREAD_STDLIB) || defined(DMQ_THREAD_WIN32) || defined(DMQ_THREAD_QT)
@@ -241,13 +278,15 @@ namespace dmq
241278
// Use stl_allocator fixed-block allocator for dynamic storage allocation
242279
#include "extras/allocator/xstring.h"
243280
#include "extras/allocator/xlist.h"
281+
#include "extras/allocator/xmap.h"
244282
#include "extras/allocator/xsstream.h"
245283
#include "extras/allocator/stl_allocator.h"
246284
#include "extras/allocator/xnew.h"
247285
#include "extras/allocator/xmake_shared.h"
248286
#else
249287
#include <string>
250288
#include <list>
289+
#include <map>
251290
#include <sstream>
252291
#include <memory>
253292
#include <utility>
@@ -288,6 +327,13 @@ namespace dmq
288327
delete p;
289328
}
290329
}
330+
331+
// Fallback xmap/xmultimap — use std::map when fixed-block allocator is disabled
332+
template <typename Key, typename Value, typename Alloc = std::allocator<std::pair<const Key, Value>>>
333+
using xmap = std::map<Key, Value, std::less<Key>, Alloc>;
334+
335+
template <typename Key, typename Value, typename Alloc = std::allocator<std::pair<const Key, Value>>>
336+
using xmultimap = std::multimap<Key, Value, std::less<Key>, Alloc>;
291337
#endif
292338

293339
// @TODO: Select the desired logging (see Port.cmake).
@@ -303,4 +349,4 @@ namespace dmq
303349
#define LOG_ERROR(...) do {} while(0)
304350
#endif
305351

306-
#endif // _DELEGATE_OPT_H
352+
#endif // _DELEGATE_OPT_H

DelegateMQ/delegate/MulticastDelegateSafe.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,12 @@ class MulticastDelegateSafe<RetType(Args...)> : public MulticastDelegate<RetType
2424
virtual ~MulticastDelegateSafe() = default;
2525

2626
MulticastDelegateSafe(const MulticastDelegateSafe& rhs) : BaseType() {
27-
std::scoped_lock lock(m_lock, rhs.m_lock);
27+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
2828
BaseType::operator=(rhs);
2929
}
3030

3131
MulticastDelegateSafe(MulticastDelegateSafe&& rhs) : BaseType() {
32-
std::scoped_lock lock(m_lock, rhs.m_lock);
32+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
3333
BaseType::operator=(std::move(rhs));
3434
}
3535

@@ -124,7 +124,7 @@ class MulticastDelegateSafe<RetType(Args...)> : public MulticastDelegate<RetType
124124
MulticastDelegateSafe& operator=(const MulticastDelegateSafe& rhs) {
125125
if (this != &rhs) {
126126
// Lock both instances safely to prevent modification of source during copy
127-
std::scoped_lock lock(m_lock, rhs.m_lock);
127+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
128128
BaseType::operator=(rhs);
129129
}
130130
return *this;
@@ -135,7 +135,7 @@ class MulticastDelegateSafe<RetType(Args...)> : public MulticastDelegate<RetType
135135
/// @return A reference to the current object.
136136
MulticastDelegateSafe& operator=(MulticastDelegateSafe&& rhs) noexcept {
137137
if (this != &rhs) {
138-
std::scoped_lock lock(m_lock, rhs.m_lock);
138+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
139139
BaseType::operator=(std::move(rhs));
140140
}
141141
return *this;

DelegateMQ/delegate/UnicastDelegateSafe.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ class UnicastDelegateSafe<RetType(Args...)> : public UnicastDelegate<RetType(Arg
8989
/// @return A reference to the current object.
9090
UnicastDelegateSafe& operator=(const UnicastDelegateSafe& rhs) {
9191
if (this != &rhs) {
92-
std::scoped_lock lock(m_lock, rhs.m_lock);
92+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
9393
BaseType::operator=(rhs);
9494
}
9595
return *this;
@@ -100,7 +100,7 @@ class UnicastDelegateSafe<RetType(Args...)> : public UnicastDelegate<RetType(Arg
100100
/// @return A reference to the current object.
101101
UnicastDelegateSafe& operator=(UnicastDelegateSafe&& rhs) noexcept {
102102
if (this != &rhs) {
103-
std::scoped_lock lock(m_lock, rhs.m_lock);
103+
dmq::ScopedLock<RecursiveMutex, RecursiveMutex> lock(m_lock, rhs.m_lock);
104104
BaseType::operator=(std::move(rhs));
105105
}
106106
return *this;

0 commit comments

Comments
 (0)