Skip to content

Commit 50ef472

Browse files
committed
nrf_rpc: implement timeout for response
Introduce necessary changes to support timing out waiting for a command response: 1. Handle nrf_rpc_os_msg_get() returning null data pointer, indicating that the response has not arrived within the required maximum time. 2. Introduce context mutex to protect all context members. This is necessary because now the response may arrive after the initiating thread has already released the context. Note that 2 may not sufficient solution to address another scenario where the context is freed by the initiator but is then reused before a delayed response arrives - to solve this, we likely need to introduce the concept of session ID or conversation ID to detect outdated packets. Signed-off-by: Damian Krolik <[email protected]>
1 parent 24914d1 commit 50ef472

File tree

3 files changed

+77
-13
lines changed

3 files changed

+77
-13
lines changed

nrf_rpc/CHANGELOG.rst

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,18 @@ Changelog
99

1010
All the notable changes to this project are documented on this page.
1111

12+
nRF Connect SDK v3.0.99
13+
***********************
14+
15+
Changes
16+
=======
17+
18+
* Added support for timing out waiting for a command response.
19+
This required making the following changes to the nRF RPC OS abstraction layer:
20+
21+
* Added :c:struct:`nrf_rpc_os_mutex` structure to protect the nRF RPC thread-local context.
22+
* Modified :c:func:`nrf_rpc_os_msg_get` function to unlock the thread-local context mutex, and to allow returning no data from the function if a timeout occurs.
23+
1224
nRF Connect SDK v2.8.0
1325
**********************
1426

nrf_rpc/nrf_rpc.c

Lines changed: 31 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ struct nrf_rpc_cmd_ctx {
5252
*/
5353
nrf_rpc_handler_t handler; /* Response handler provided be the user. */
5454
void *handler_data; /* Pointer for the response handler. */
55+
struct nrf_rpc_os_mutex mutex; /* Mutex for protecting all context
56+
* members. */
5557
struct nrf_rpc_os_msg recv_msg;
5658
/* Message passing between transport
5759
* receive callback and a thread that waits
@@ -187,6 +189,7 @@ static struct nrf_rpc_cmd_ctx *cmd_ctx_alloc(void)
187189
NRF_RPC_ASSERT(index < CONFIG_NRF_RPC_CMD_CTX_POOL_SIZE);
188190

189191
ctx = &cmd_ctx_pool[index];
192+
nrf_rpc_os_mutex_lock(&ctx->mutex);
190193
ctx->handler = NULL;
191194
ctx->remote_id = NRF_RPC_ID_UNKNOWN;
192195
ctx->use_count = 1;
@@ -200,6 +203,7 @@ static struct nrf_rpc_cmd_ctx *cmd_ctx_alloc(void)
200203

201204
static void cmd_ctx_free(struct nrf_rpc_cmd_ctx *ctx)
202205
{
206+
nrf_rpc_os_mutex_unlock(&ctx->mutex);
203207
nrf_rpc_os_tls_set(NULL);
204208
nrf_rpc_os_ctx_pool_release(ctx->id);
205209
}
@@ -741,7 +745,7 @@ static void receive_handler(const struct nrf_rpc_tr *transport, const uint8_t *p
741745
int err;
742746
int remote_err;
743747
struct header hdr;
744-
struct nrf_rpc_cmd_ctx *cmd_ctx;
748+
struct nrf_rpc_cmd_ctx *cmd_ctx = NULL;
745749
const struct nrf_rpc_group *group = NULL;
746750

747751
err = header_decode(packet, len, &hdr);
@@ -797,6 +801,17 @@ static void receive_handler(const struct nrf_rpc_tr *transport, const uint8_t *p
797801
err = -NRF_EBADMSG;
798802
goto cleanup_and_exit;
799803
}
804+
805+
nrf_rpc_os_mutex_lock(&cmd_ctx->mutex);
806+
807+
if (cmd_ctx->use_count == 0) {
808+
/* Context initiator has likely timed out and is no longer interested
809+
* in receiving messages for this conversation.
810+
*/
811+
nrf_rpc_os_mutex_unlock(&cmd_ctx->mutex);
812+
goto cleanup_and_exit;
813+
}
814+
800815
if (cmd_ctx->handler != NULL &&
801816
hdr.type == NRF_RPC_PACKET_TYPE_RSP &&
802817
auto_free_rx_buf(transport)) {
@@ -805,16 +820,17 @@ static void receive_handler(const struct nrf_rpc_tr *transport, const uint8_t *p
805820
cmd_ctx->handler_data);
806821
nrf_rpc_os_msg_set(&cmd_ctx->recv_msg,
807822
RESPONSE_HANDLED_PTR, 0);
823+
nrf_rpc_os_mutex_unlock(&cmd_ctx->mutex);
808824
goto cleanup_and_exit;
809825

810826
} else {
811827
nrf_rpc_os_msg_set(&cmd_ctx->recv_msg, packet, len);
828+
nrf_rpc_os_mutex_unlock(&cmd_ctx->mutex);
812829

813830
if (auto_free_rx_buf(transport)) {
814831
nrf_rpc_os_event_wait(&group->data->decode_done_event,
815832
NRF_RPC_OS_WAIT_FOREVER);
816833
}
817-
818834
}
819835
return;
820836

@@ -895,7 +911,7 @@ void nrf_rpc_decoding_done(const struct nrf_rpc_group *group, const uint8_t *pac
895911
* @param[out] rsp_len If not NULL contains response packet length.
896912
* @return 0 on success or negative error code.
897913
*/
898-
static void wait_for_response(const struct nrf_rpc_group *group, struct nrf_rpc_cmd_ctx *cmd_ctx,
914+
static int wait_for_response(const struct nrf_rpc_group *group, struct nrf_rpc_cmd_ctx *cmd_ctx,
899915
const uint8_t **rsp_packet, size_t *rsp_len)
900916
{
901917
size_t len;
@@ -907,12 +923,14 @@ static void wait_for_response(const struct nrf_rpc_group *group, struct nrf_rpc_
907923
NRF_RPC_DBG("Waiting for a response");
908924

909925
do {
910-
nrf_rpc_os_msg_get(&cmd_ctx->recv_msg, &packet, &len);
926+
nrf_rpc_os_msg_get(&cmd_ctx->recv_msg, &cmd_ctx->mutex, &packet, &len);
911927

912-
NRF_RPC_ASSERT(packet != NULL);
928+
if (packet == NULL) {
929+
return -NRF_ETIMEDOUT;
930+
}
913931

914932
if (packet == RESPONSE_HANDLED_PTR) {
915-
return;
933+
return 0;
916934
}
917935

918936
type = parse_incoming_packet(cmd_ctx, packet, len);
@@ -934,6 +952,8 @@ static void wait_for_response(const struct nrf_rpc_group *group, struct nrf_rpc_
934952

935953
nrf_rpc_decoding_done(group, &packet[NRF_RPC_HEADER_SIZE]);
936954
}
955+
956+
return 0;
937957
}
938958

939959
int nrf_rpc_cmd_common(const struct nrf_rpc_group *group, uint32_t cmd,
@@ -986,7 +1006,7 @@ int nrf_rpc_cmd_common(const struct nrf_rpc_group *group, uint32_t cmd,
9861006
err = send(group, full_packet, len + NRF_RPC_HEADER_SIZE);
9871007

9881008
if (err >= 0) {
989-
wait_for_response(group, cmd_ctx, rsp_packet, rsp_len);
1009+
err = wait_for_response(group, cmd_ctx, rsp_packet, rsp_len);
9901010
}
9911011

9921012
cmd_ctx->handler = old_handler;
@@ -1153,6 +1173,10 @@ int nrf_rpc_init(nrf_rpc_err_handler_t err_handler)
11531173

11541174
for (i = 0; i < CONFIG_NRF_RPC_CMD_CTX_POOL_SIZE; i++) {
11551175
cmd_ctx_pool[i].id = i;
1176+
err = nrf_rpc_os_mutex_init(&cmd_ctx_pool[i].mutex);
1177+
if (err < 0) {
1178+
return err;
1179+
}
11561180
err = nrf_rpc_os_msg_init(&cmd_ctx_pool[i].recv_msg);
11571181
if (err < 0) {
11581182
return err;

nrf_rpc/template/nrf_rpc_os_tmpl.h

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ extern "C" {
3232
/** @brief Structure to pass events between threads. */
3333
struct nrf_rpc_os_event;
3434

35+
/** @brief Stucture to assure exclusive access to thread contexts. */
36+
struct nrf_rpc_os_mutex;
37+
3538
/** @brief Structure to pass messages between threads. */
3639
struct nrf_rpc_os_msg;
3740

@@ -94,6 +97,26 @@ void nrf_rpc_os_event_set(struct nrf_rpc_os_event *event);
9497
*/
9598
int nrf_rpc_os_event_wait(struct nrf_rpc_os_event *event, int32_t timeout);
9699

100+
/** @brief Initialize mutex structure.
101+
*
102+
* @param mutex Pointer to mutex structure.
103+
*
104+
* @return 0 on success or negative error code.
105+
*/
106+
int nrf_rpc_os_mutex_init(struct nrf_rpc_os_mutex *mutex);
107+
108+
/** @brief Lock mutex.
109+
*
110+
* @param mutex Pointer to mutex structure.
111+
*/
112+
void nrf_rpc_os_mutex_lock(struct nrf_rpc_os_mutex *mutex);
113+
114+
/** @brief Unlock mutex.
115+
*
116+
* @param mutex Pointer to mutex structure.
117+
*/
118+
void nrf_rpc_os_mutex_unlock(struct nrf_rpc_os_mutex *mutex);
119+
97120
/** @brief Initialize message passing structure.
98121
*
99122
* @param msg Structure to initialize.
@@ -118,14 +141,19 @@ void nrf_rpc_os_msg_set(struct nrf_rpc_os_msg *msg, const uint8_t *data,
118141
/** @brief Get a message.
119142
*
120143
* If message was not set yet then this function waits.
144+
* When this function starts waiting, it atomically unlocks the passed mutex.
145+
*
146+
* This function MAY time out, which is indicated by returning a NULL data
147+
* pointer.
121148
*
122-
* @param[in] msg Message passing structure.
123-
* @param[out] data Received data pointer. Data is passed as a pointer, so no
124-
* copying is done.
125-
* @param[out] len Length of the `data`.
149+
* @param[in] msg Message passing structure.
150+
* @param[in] mutex Pointer to mutex to unlock before entering the wait state.
151+
* @param[out] data Received data pointer. Data is passed as a pointer, so no
152+
* copying is done.
153+
* @param[out] len Length of the `data`.
126154
*/
127-
void nrf_rpc_os_msg_get(struct nrf_rpc_os_msg *msg, const uint8_t **data,
128-
size_t *len);
155+
void nrf_rpc_os_msg_get(struct nrf_rpc_os_msg *msg, struct nrf_rpc_os_mutex *mutex,
156+
const uint8_t **data, size_t *len);
129157

130158
/** @brief Get TLS (Thread Local Storage) for nRF RPC.
131159
*

0 commit comments

Comments
 (0)