Skip to content

Commit 6ec4dc1

Browse files
seqnumber: Fix C++ interopability and mutex cleanup (#1092)
* seqnumber: Fix C++ interopability _Atomic and std::atomic are not guaranteed to be compatible. Additionally, std::atomic introduces dependencies on the C++ standard library, which is often too large for resource-constrained embedded systems. This change moves all atomic operations into seqnumber.c and uses the C11 atomic_xx operations, which are safe for both C and C++ callers. It also fixes a bug where _z_seqnumber_null was not implemented as an atomic operation. * Ensure sequence number is correctly cleaned up in the case of C99 where a mutex is present. --------- Co-authored-by: Peter van der Perk <[email protected]>
1 parent 1b655b3 commit 6ec4dc1

File tree

3 files changed

+48
-27
lines changed

3 files changed

+48
-27
lines changed

include/zenoh-pico/collections/seqnumber.h

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -21,31 +21,23 @@
2121
#include "zenoh-pico/system/platform.h"
2222
#include "zenoh-pico/utils/result.h"
2323

24-
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD != 99
25-
#ifndef __cplusplus
26-
#include <stdatomic.h>
27-
#define _Z_SEQNUMBER_TYPE _Atomic uint32_t
28-
#else
29-
#include <atomic>
30-
#define _Z_SEQNUMBER_TYPE std::atomic<uint32_t>
31-
#endif
32-
#else
33-
#define _Z_SEQNUMBER_TYPE uint32_t
34-
#endif
35-
3624
#ifdef __cplusplus
3725
extern "C" {
3826
#endif
3927

4028
typedef struct {
41-
_Z_SEQNUMBER_TYPE _seq;
29+
#if (Z_FEATURE_MULTI_THREAD == 1) && (ZENOH_C_STANDARD != 99) && !defined(__cplusplus)
30+
_Atomic uint32_t _seq;
31+
#else
32+
uint32_t _seq;
33+
#endif
4234
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD == 99 && !defined(ZENOH_COMPILER_GCC)
4335
_z_mutex_t _mutex;
4436
#endif
4537
} _z_seqnumber_t;
4638

47-
static inline _z_seqnumber_t _z_seqnumber_null(void) { return (_z_seqnumber_t){0}; }
4839
z_result_t _z_seqnumber_init(_z_seqnumber_t *seq);
40+
z_result_t _z_seqnumber_drop(_z_seqnumber_t *seq);
4941
z_result_t _z_seqnumber_fetch(_z_seqnumber_t *seq, uint32_t *value);
5042
z_result_t _z_seqnumber_fetch_and_increment(_z_seqnumber_t *seq, uint32_t *value);
5143

src/api/advanced_publisher.c

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,16 @@
2626
// Space for 10 digits + NULL
2727
#define ZE_ADVANCED_PUBLISHER_UINT32_STR_BUF_LEN 11
2828

29-
static _ze_advanced_publisher_state_t _ze_advanced_publisher_state_null(void) {
30-
_ze_advanced_publisher_state_t state = {0};
31-
state._zn = _z_session_weak_null();
32-
z_internal_publisher_null(&state._publisher);
33-
state._state_publisher_task_id = _ZP_PERIODIC_SCHEDULER_INVALID_ID;
34-
state._seqnumber = _z_seqnumber_null();
35-
return state;
29+
static z_result_t _ze_advanced_publisher_state_init(_ze_advanced_publisher_state_t *state) {
30+
if (state == NULL) {
31+
_Z_ERROR_RETURN(_Z_ERR_INVALID);
32+
}
33+
state->_heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE;
34+
state->_last_published_sn = 0;
35+
z_internal_publisher_null(&state->_publisher);
36+
state->_state_publisher_task_id = _ZP_PERIODIC_SCHEDULER_INVALID_ID;
37+
state->_zn = _z_session_weak_null();
38+
return _z_seqnumber_init(&state->_seqnumber);
3639
}
3740

3841
static bool _ze_advanced_publisher_state_check(const _ze_advanced_publisher_state_t *state) {
@@ -57,7 +60,7 @@ void _ze_advanced_publisher_state_clear(_ze_advanced_publisher_state_t *state) {
5760
}
5861
_z_session_weak_drop(&state->_zn);
5962
state->_heartbeat_mode = ZE_ADVANCED_PUBLISHER_HEARTBEAT_MODE_NONE;
60-
state->_seqnumber = _z_seqnumber_null();
63+
_z_seqnumber_drop(&state->_seqnumber);
6164
state->_last_published_sn = 0;
6265
}
6366

@@ -255,18 +258,17 @@ z_result_t ze_declare_advanced_publisher(const z_loaned_session_t *zs, ze_owned_
255258
z_publisher_drop(z_publisher_move(&pub->_val._publisher));
256259
_Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);
257260
}
258-
*state = _ze_advanced_publisher_state_null();
261+
_Z_CLEAN_RETURN_IF_ERR(_ze_advanced_publisher_state_init(state),
262+
z_publisher_drop(z_publisher_move(&pub->_val._publisher));
263+
z_free(state));
259264

260265
pub->_val._state = _ze_advanced_publisher_state_rc_new(state);
261266
if (_Z_RC_IS_NULL(&pub->_val._state)) {
267+
_ze_advanced_publisher_state_clear(state);
262268
z_free(state);
263269
z_publisher_drop(z_publisher_move(&pub->_val._publisher));
264270
_Z_ERROR_RETURN(_Z_ERR_SYSTEM_OUT_OF_MEMORY);
265271
}
266-
267-
_Z_CLEAN_RETURN_IF_ERR(_z_seqnumber_init(&state->_seqnumber),
268-
_ze_advanced_publisher_state_rc_drop(&pub->_val._state);
269-
z_publisher_drop(z_publisher_move(&pub->_val._publisher)));
270272
} else if (opt.cache.is_enabled) {
271273
pub->_val._sequencing = _ZE_ADVANCED_PUBLISHER_SEQUENCING_TIMESTAMP;
272274
} else {

src/collections/seqnumber.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@
1616

1717
#include "zenoh-pico/utils/logging.h"
1818

19+
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD != 99
20+
#include <stdatomic.h>
21+
#endif
22+
1923
z_result_t _z_seqnumber_init(_z_seqnumber_t *seq) {
2024
if (seq == NULL) {
2125
_Z_ERROR_RETURN(_Z_ERR_INVALID);
@@ -28,10 +32,27 @@ z_result_t _z_seqnumber_init(_z_seqnumber_t *seq) {
2832
}
2933
#endif
3034

35+
#if (Z_FEATURE_MULTI_THREAD == 1) && (ZENOH_C_STANDARD != 99)
36+
atomic_init(&seq->_seq, 0);
37+
#else
3138
seq->_seq = 0;
39+
#endif
40+
3241
return _Z_RES_OK;
3342
}
3443

44+
z_result_t _z_seqnumber_drop(_z_seqnumber_t *seq) {
45+
if (seq == NULL) {
46+
_Z_ERROR_RETURN(_Z_ERR_INVALID);
47+
}
48+
49+
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD == 99 && !defined(ZENOH_COMPILER_GCC)
50+
return _z_mutex_drop(&seq->_mutex);
51+
#else
52+
return _Z_RES_OK;
53+
#endif
54+
}
55+
3556
z_result_t _z_seqnumber_fetch(_z_seqnumber_t *seq, uint32_t *value) {
3657
if (seq == NULL || value == NULL) {
3758
_Z_ERROR_RETURN(_Z_ERR_INVALID);
@@ -44,7 +65,11 @@ z_result_t _z_seqnumber_fetch(_z_seqnumber_t *seq, uint32_t *value) {
4465
}
4566
#endif
4667

68+
#if (Z_FEATURE_MULTI_THREAD == 1) && (ZENOH_C_STANDARD != 99)
69+
*value = atomic_load(&seq->_seq);
70+
#else
4771
*value = seq->_seq;
72+
#endif
4873

4974
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD == 99 && !defined(ZENOH_COMPILER_GCC)
5075
res = _z_mutex_unlock(&seq->_mutex);
@@ -70,6 +95,8 @@ z_result_t _z_seqnumber_fetch_and_increment(_z_seqnumber_t *seq, uint32_t *value
7095

7196
#if Z_FEATURE_MULTI_THREAD == 1 && ZENOH_C_STANDARD == 99 && defined(ZENOH_COMPILER_GCC)
7297
*value = __sync_fetch_and_add(&seq->_seq, 1);
98+
#elif (Z_FEATURE_MULTI_THREAD == 1) && (ZENOH_C_STANDARD != 99)
99+
*value = atomic_fetch_add(&seq->_seq, 1);
73100
#else
74101
*value = seq->_seq++;
75102
#endif

0 commit comments

Comments
 (0)