Skip to content

Commit 4d17bee

Browse files
Multithread improvements (backport #205) (#206)
* Multithread improvements (#205) * Minor fixes * Add rmw_wait mutex * Protect static_buffer_memory access * Use new ping API * Update ci.yml * Fix * Fix linter * Apply suggestions from code review Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com> * Fix * Delete old unlock mutex * Update .github/workflows/ci.yml Co-authored-by: Antonio Cuadros <49162117+Acuadros95@users.noreply.github.com> Co-authored-by: Antonio Cuadros <acuadros1995@gmail.com> (cherry picked from commit 5de3d76) # Conflicts: # .github/workflows/ci.yml * Resolve conflicts Signed-off-by: Pablo Garrido <pablogs9@gmail.com> Co-authored-by: Pablo Garrido <pablogs9@gmail.com>
1 parent 1155805 commit 4d17bee

11 files changed

Lines changed: 83 additions & 31 deletions

File tree

rmw_microxrcedds_c/include/rmw_microros/ping.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ extern "C"
4343
* \brief Check if micro-ROS Agent is up and running.
4444
* This function can be called even when the micro-ROS context has not yet been
4545
* initialized by the application logics.
46+
* This function cannot be called concurrently with `rmw_init()` or `rmw_shutdown()`.
4647
* \param[in] timeout_ms Timeout in ms (per attempt).
4748
* \param[in] attempts Number of tries before considering the ping as failed.
4849
* \return RMW_RET_OK If micro-ROS Agent is available.
@@ -56,6 +57,7 @@ rmw_ret_t rmw_uros_ping_agent(
5657
* \brief Check if micro-ROS Agent is up and running using the transport set on the given rmw options.
5758
* This function can be called even when the micro-ROS context has not yet been initialized.
5859
* The transport will be initialized and closed once during the ping process.
60+
* This function cannot be called concurrently with `rmw_init()` or `rmw_shutdown()`.
5961
* \param[in] timeout_ms Timeout in ms (per attempt).
6062
* \param[in] attempts Number of tries before considering the ping as failed.
6163
* \param[in] rmw_options rmw options with populated transport parameters.

rmw_microxrcedds_c/src/callbacks.c

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,13 @@ void on_topic(
7070
if ((custom_subscription->datareader_id.id == object_id.id) &&
7171
(custom_subscription->datareader_id.type == object_id.type))
7272
{
73+
UXR_LOCK(&static_buffer_memory.mutex);
74+
7375
rmw_uxrce_mempool_item_t * memory_node = rmw_uxrce_get_static_input_buffer_for_entity(
7476
custom_subscription, custom_subscription->qos);
7577
if (!memory_node) {
7678
RMW_SET_ERROR_MSG("Not available static buffer memory node");
79+
UXR_UNLOCK(&static_buffer_memory.mutex);
7780
return;
7881
}
7982

@@ -86,14 +89,14 @@ void on_topic(
8689
length))
8790
{
8891
put_memory(&static_buffer_memory, memory_node);
89-
return;
92+
} else {
93+
static_buffer->owner = (void *) custom_subscription;
94+
static_buffer->length = length;
95+
static_buffer->timestamp = rmw_uros_epoch_nanos();
96+
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_SUBSCRIPTION;
9097
}
9198

92-
static_buffer->owner = (void *) custom_subscription;
93-
static_buffer->length = length;
94-
static_buffer->timestamp = rmw_uros_epoch_nanos();
95-
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_SUBSCRIPTION;
96-
99+
UXR_UNLOCK(&static_buffer_memory.mutex);
97100
return;
98101
}
99102
subscription_item = subscription_item->next;
@@ -119,10 +122,13 @@ void on_request(
119122
// Check if request is related to the service
120123
rmw_uxrce_service_t * custom_service = (rmw_uxrce_service_t *)service_item->data;
121124
if (custom_service->service_data_resquest == request_id) {
125+
UXR_LOCK(&static_buffer_memory.mutex);
126+
122127
rmw_uxrce_mempool_item_t * memory_node = rmw_uxrce_get_static_input_buffer_for_entity(
123128
custom_service, custom_service->qos);
124129
if (!memory_node) {
125130
RMW_SET_ERROR_MSG("Not available static buffer memory node");
131+
UXR_UNLOCK(&static_buffer_memory.mutex);
126132
return;
127133
}
128134

@@ -135,14 +141,15 @@ void on_request(
135141
length))
136142
{
137143
put_memory(&static_buffer_memory, memory_node);
138-
return;
144+
} else {
145+
static_buffer->owner = (void *) custom_service;
146+
static_buffer->length = length;
147+
static_buffer->related.sample_id = *sample_id;
148+
static_buffer->timestamp = rmw_uros_epoch_nanos();
149+
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_SERVICE;
139150
}
140151

141-
static_buffer->owner = (void *) custom_service;
142-
static_buffer->length = length;
143-
static_buffer->related.sample_id = *sample_id;
144-
static_buffer->timestamp = rmw_uros_epoch_nanos();
145-
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_SERVICE;
152+
UXR_UNLOCK(&static_buffer_memory.mutex);
146153

147154
return;
148155
}
@@ -169,10 +176,13 @@ void on_reply(
169176
// Check if reply is related to the client
170177
rmw_uxrce_client_t * custom_client = (rmw_uxrce_client_t *)client_item->data;
171178
if (custom_client->client_data_request == request_id) {
179+
UXR_LOCK(&static_buffer_memory.mutex);
180+
172181
rmw_uxrce_mempool_item_t * memory_node = rmw_uxrce_get_static_input_buffer_for_entity(
173182
custom_client, custom_client->qos);
174183
if (!memory_node) {
175184
RMW_SET_ERROR_MSG("Not available static buffer memory node");
185+
UXR_UNLOCK(&static_buffer_memory.mutex);
176186
return;
177187
}
178188

@@ -185,14 +195,14 @@ void on_reply(
185195
length))
186196
{
187197
put_memory(&static_buffer_memory, memory_node);
188-
return;
198+
} else {
199+
static_buffer->owner = (void *) custom_client;
200+
static_buffer->length = length;
201+
static_buffer->related.reply_id = reply_id;
202+
static_buffer->timestamp = rmw_uros_epoch_nanos();
203+
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_CLIENT;
189204
}
190-
191-
static_buffer->owner = (void *) custom_client;
192-
static_buffer->length = length;
193-
static_buffer->related.reply_id = reply_id;
194-
static_buffer->timestamp = rmw_uros_epoch_nanos();
195-
static_buffer->entity_type = RMW_UXRCE_ENTITY_TYPE_CLIENT;
205+
UXR_UNLOCK(&static_buffer_memory.mutex);
196206

197207
return;
198208
}

rmw_microxrcedds_c/src/rmw_init.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,13 @@ rmw_init(
201201
context->implementation_identifier = eprosima_microxrcedds_identifier;
202202
context->options.domain_id = options->domain_id;
203203

204+
#ifdef UCLIENT_PROFILE_MULTITHREAD
205+
if (!rmw_uxrce_wait_mutex_initialized) {
206+
UXR_INIT_LOCK(&rmw_uxrce_wait_mutex);
207+
rmw_uxrce_wait_mutex_initialized = true;
208+
}
209+
#endif // UCLIENT_PROFILE_MULTITHREAD
210+
204211
rmw_uxrce_init_session_memory(&session_memory, custom_sessions, RMW_UXRCE_MAX_SESSIONS);
205212
rmw_uxrce_init_static_input_buffer_memory(
206213
&static_buffer_memory, custom_static_buffers,

rmw_microxrcedds_c/src/rmw_microros/ping.c

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ rmw_ret_t rmw_uros_ping_agent(
3333
{
3434
bool success = false;
3535

36-
UXR_LOCK(&session_memory.mutex);
37-
38-
if (NULL == session_memory.allocateditems) {
36+
if (!session_memory.is_initialized || NULL == session_memory.allocateditems) {
37+
// There is no session available to ping. Init transport is required.
3938
#ifdef RMW_UXRCE_TRANSPORT_SERIAL
4039
uxrSerialTransport transport;
4140
#elif defined(RMW_UXRCE_TRANSPORT_UDP)
@@ -54,24 +53,23 @@ rmw_ret_t rmw_uros_ping_agent(
5453
rmw_ret_t ret = rmw_uxrce_transport_init(NULL, NULL, (void *)&transport);
5554

5655
if (RMW_RET_OK != ret) {
57-
UXR_UNLOCK(&session_memory.mutex);
5856
return ret;
5957
}
6058

6159
success = uxr_ping_agent_attempts(&transport.comm, timeout_ms, attempts);
6260
CLOSE_TRANSPORT(&transport);
6361
} else {
62+
// There is a session available to ping. Using session.
6463
rmw_uxrce_mempool_item_t * item = session_memory.allocateditems;
6564
do {
6665
rmw_context_impl_t * context = (rmw_context_impl_t *)item->data;
6766

68-
success = uxr_ping_agent_attempts(&context->transport.comm, timeout_ms, attempts);
67+
success = uxr_ping_agent_session(&context->session, timeout_ms, attempts);
68+
6969
item = item->next;
7070
} while (NULL != item && !success);
7171
}
7272

73-
UXR_UNLOCK(&session_memory.mutex);
74-
7573
return success ? RMW_RET_OK : RMW_RET_ERROR;
7674
}
7775

rmw_microxrcedds_c/src/rmw_microros_internal/memory.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ typedef struct rmw_uxrce_mempool_t
3838

3939
#ifdef UCLIENT_PROFILE_MULTITHREAD
4040
uxrMutex mutex;
41-
#endif // RMW_MICROROS_INTERNAL__UCLIENT_PROFILE_MULTITHREAD
41+
#endif // UCLIENT_PROFILE_MULTITHREAD
4242
} rmw_uxrce_mempool_t;
4343

4444
bool has_memory(

rmw_microxrcedds_c/src/rmw_microros_internal/types.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,14 @@ extern rmw_uxrce_wait_set_t custom_wait_set[RMW_UXRCE_MAX_WAIT_SETS];
294294
extern rmw_uxrce_mempool_t guard_condition_memory;
295295
extern rmw_uxrce_guard_condition_t custom_guard_condition[RMW_UXRCE_MAX_GUARD_CONDITION];
296296

297+
// Global mutexs
298+
#ifdef UCLIENT_PROFILE_MULTITHREAD
299+
// This mutex protects `need_to_be_ran` member of `session_memory` elements
300+
// between concurrent calls to `rmw_wait()`
301+
extern uxrMutex rmw_uxrce_wait_mutex;
302+
extern bool rmw_uxrce_wait_mutex_initialized;
303+
#endif // UCLIENT_PROFILE_MULTITHREAD
304+
297305
// Memory init functions
298306

299307
#define RMW_INIT_DEFINE_MEMORY(X) \

rmw_microxrcedds_c/src/rmw_request.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,10 +83,13 @@ rmw_take_request(
8383

8484
rmw_uxrce_clean_expired_static_input_buffer();
8585

86+
UXR_LOCK(&static_buffer_memory.mutex);
87+
8688
// Find first related item in static buffer memory pool
8789
rmw_uxrce_mempool_item_t * static_buffer_item =
8890
rmw_uxrce_find_static_input_buffer_by_owner((void *) custom_service);
8991
if (static_buffer_item == NULL) {
92+
UXR_UNLOCK(&static_buffer_memory.mutex);
9093
return RMW_RET_ERROR;
9194
}
9295

@@ -123,6 +126,8 @@ rmw_take_request(
123126

124127
put_memory(&static_buffer_memory, static_buffer_item);
125128

129+
UXR_UNLOCK(&static_buffer_memory.mutex);
130+
126131
if (taken != NULL) {
127132
*taken = deserialize_rv;
128133
}

rmw_microxrcedds_c/src/rmw_response.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,10 +97,13 @@ rmw_take_response(
9797

9898
rmw_uxrce_clean_expired_static_input_buffer();
9999

100+
UXR_LOCK(&static_buffer_memory.mutex);
101+
100102
// Find first related item in static buffer memory pool
101103
rmw_uxrce_mempool_item_t * static_buffer_item =
102104
rmw_uxrce_find_static_input_buffer_by_owner((void *) custom_client);
103105
if (static_buffer_item == NULL) {
106+
UXR_UNLOCK(&static_buffer_memory.mutex);
104107
return RMW_RET_ERROR;
105108
}
106109

@@ -126,6 +129,8 @@ rmw_take_response(
126129

127130
put_memory(&static_buffer_memory, static_buffer_item);
128131

132+
UXR_UNLOCK(&static_buffer_memory.mutex);
133+
129134
if (taken != NULL) {
130135
*taken = deserialize_rv;
131136
}

rmw_microxrcedds_c/src/rmw_take.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,13 @@ rmw_take_with_info(
5151

5252
rmw_uxrce_clean_expired_static_input_buffer();
5353

54+
UXR_LOCK(&static_buffer_memory.mutex);
55+
5456
// Find first related item in static buffer memory pool
5557
rmw_uxrce_mempool_item_t * static_buffer_item = rmw_uxrce_find_static_input_buffer_by_owner(
5658
(void *) custom_subscription);
5759
if (static_buffer_item == NULL) {
60+
UXR_UNLOCK(&static_buffer_memory.mutex);
5861
return RMW_RET_ERROR;
5962
}
6063

@@ -73,6 +76,8 @@ rmw_take_with_info(
7376

7477
put_memory(&static_buffer_memory, static_buffer_item);
7578

79+
UXR_UNLOCK(&static_buffer_memory.mutex);
80+
7681
if (taken != NULL) {
7782
*taken = deserialize_rv;
7883
}

rmw_microxrcedds_c/src/rmw_wait.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,14 @@ rmw_wait(
3434
(void)events;
3535
(void)wait_set;
3636

37+
// With `rmw_uxrce_wait_mutex` member `need_to_be_ran` is protected.
38+
// `session_memory` itself is not protected because it is not modified between
39+
// rmw_init and rmw_shutdown, and rmw_wait cannot be called concurrently with
40+
// those functions.
41+
UXR_LOCK(&rmw_uxrce_wait_mutex);
42+
3743
if (!services && !clients && !subscriptions && !guard_conditions) {
44+
UXR_UNLOCK(&rmw_uxrce_wait_mutex);
3845
return RMW_RET_OK;
3946
}
4047

@@ -53,8 +60,6 @@ rmw_wait(
5360

5461
rmw_uxrce_clean_expired_static_input_buffer();
5562

56-
UXR_LOCK(&session_memory.mutex);
57-
5863
// Clear run flag for all sessions
5964
rmw_uxrce_mempool_item_t * item = session_memory.allocateditems;
6065
while (item != NULL) {
@@ -63,6 +68,7 @@ rmw_wait(
6368
item = item->next;
6469
}
6570

71+
// TODO(pablogs9): What happens if there already data in one entity?
6672
// Enable flag for every XRCE session available in the entities
6773
for (size_t i = 0; services && i < services->service_count; ++i) {
6874
rmw_uxrce_service_t * custom_service = (rmw_uxrce_service_t *)services->services[i];
@@ -91,7 +97,7 @@ rmw_wait(
9197

9298
// There is no context that contais any of the wait set entities. Nothing to wait here.
9399
if (available_contexts == 0) {
94-
UXR_UNLOCK(&session_memory.mutex);
100+
UXR_UNLOCK(&rmw_uxrce_wait_mutex);
95101
return RMW_RET_OK;
96102
}
97103

@@ -108,7 +114,7 @@ rmw_wait(
108114
item = item->next;
109115
}
110116

111-
UXR_UNLOCK(&session_memory.mutex);
117+
UXR_UNLOCK(&rmw_uxrce_wait_mutex);
112118

113119
bool buffered_status = false;
114120

0 commit comments

Comments
 (0)