From 5e1f05e377d0e033161c2a6a5d715d9e84184ce3 Mon Sep 17 00:00:00 2001 From: Robert Lubos Date: Mon, 14 Oct 2024 17:52:53 +0200 Subject: [PATCH] net: lwm2m: Make LwM2M context lists access thread safe System lists are not thread safe, therefore all accesses should be protected with a mutex. Introduce a LwM2M context specific mutex, and use it whenever lists defined per-context are acessed. Signed-off-by: Robert Lubos --- include/zephyr/net/lwm2m.h | 1 + subsys/net/lib/lwm2m/lwm2m_engine.c | 52 +++++++++++++++---- subsys/net/lib/lwm2m/lwm2m_engine.h | 14 +++++ subsys/net/lib/lwm2m/lwm2m_message_handling.c | 10 ++++ 4 files changed, 68 insertions(+), 9 deletions(-) diff --git a/include/zephyr/net/lwm2m.h b/include/zephyr/net/lwm2m.h index 8a2cbf557d0d484..9c4590a276790b4 100644 --- a/include/zephyr/net/lwm2m.h +++ b/include/zephyr/net/lwm2m.h @@ -217,6 +217,7 @@ struct lwm2m_ctx { sys_slist_t queued_messages; #endif sys_slist_t observer; + struct k_mutex lock; /** @endcond */ /** A pointer to currently processed request, for internal LwM2M engine diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.c b/subsys/net/lib/lwm2m/lwm2m_engine.c index be61fc46bdbd0c2..c78c2c839964355 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.c +++ b/subsys/net/lib/lwm2m/lwm2m_engine.c @@ -232,6 +232,7 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx) { #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) client_ctx->buffer_client_messages = false; + lwm2m_client_lock(client_ctx); while (!sys_slist_is_empty(&client_ctx->queued_messages)) { sys_snode_t *msg_node = sys_slist_get(&client_ctx->queued_messages); struct lwm2m_message *msg; @@ -243,6 +244,7 @@ int lwm2m_push_queued_buffers(struct lwm2m_ctx *client_ctx) msg->pending->t0 = k_uptime_get(); sys_slist_append(&msg->ctx->pending_sends, &msg->node); } + lwm2m_client_unlock(client_ctx); #endif return 0; } @@ -641,17 +643,22 @@ static int64_t check_notifications(struct lwm2m_ctx *ctx, const int64_t timestam */ static void hint_socket_state(struct lwm2m_ctx *ctx, struct lwm2m_message *ongoing_tx) { + bool empty; + size_t pendings; + if (!ctx || !ctx->set_socket_state) { return; } + lwm2m_client_lock(ctx); #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) - bool empty = sys_slist_is_empty(&ctx->pending_sends) && - sys_slist_is_empty(&ctx->queued_messages); + empty = sys_slist_is_empty(&ctx->pending_sends) && + sys_slist_is_empty(&ctx->queued_messages); #else - bool empty = sys_slist_is_empty(&ctx->pending_sends); + empty = sys_slist_is_empty(&ctx->pending_sends); #endif - size_t pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); + pendings = coap_pendings_count(ctx->pendings, ARRAY_SIZE(ctx->pendings)); + lwm2m_client_unlock(ctx); if (ongoing_tx) { /* Check if more than current TX is in pendings list*/ @@ -710,9 +717,13 @@ static int socket_recv_message(struct lwm2m_ctx *client_ctx) static int socket_send_message(struct lwm2m_ctx *ctx) { int rc; - sys_snode_t *msg_node = sys_slist_get(&ctx->pending_sends); + sys_snode_t *msg_node; struct lwm2m_message *msg; + lwm2m_client_lock(ctx); + msg_node = sys_slist_get(&ctx->pending_sends); + lwm2m_client_unlock(ctx); + if (!msg_node) { return 0; } @@ -750,11 +761,17 @@ static int socket_send_message(struct lwm2m_ctx *ctx) static void socket_reset_pollfd_events(void) { for (int i = 0; i < MAX_POLL_FD; ++i) { + bool set_pollout = false; + + if (sock_ctx[i] != NULL) { + lwm2m_client_lock(sock_ctx[i]); + set_pollout = !sys_slist_is_empty(&sock_ctx[i]->pending_sends); + lwm2m_client_unlock(sock_ctx[i]); + } + sock_fds[i].events = ZSOCK_POLLIN | - (!sock_ctx[i] || sys_slist_is_empty(&sock_ctx[i]->pending_sends) - ? 0 - : ZSOCK_POLLOUT); + (set_pollout ? ZSOCK_POLLOUT : 0); sock_fds[i].revents = 0; } } @@ -800,13 +817,20 @@ static void socket_loop(void *p1, void *p2, void *p3) for (i = 0; i < sock_nfds; ++i) { struct lwm2m_ctx *ctx = sock_ctx[i]; + bool is_empty; if (ctx == NULL) { continue; } - if (!sys_slist_is_empty(&ctx->pending_sends)) { + + lwm2m_client_lock(ctx); + is_empty = sys_slist_is_empty(&ctx->pending_sends); + lwm2m_client_unlock(ctx); + + if (!is_empty) { continue; } + next_tx = retransmit_request(ctx, now); if (next_tx < next) { next = next_tx; @@ -1285,6 +1309,16 @@ int lwm2m_engine_resume(void) return 0; } +void lwm2m_client_lock(struct lwm2m_ctx *ctx) +{ + (void)k_mutex_lock(&ctx->lock, K_FOREVER); +} + +void lwm2m_client_unlock(struct lwm2m_ctx *ctx) +{ + k_mutex_unlock(&ctx->lock); +} + static int lwm2m_engine_init(void) { for (int i = 0; i < LWM2M_ENGINE_MAX_OBSERVER_PATH; i++) { diff --git a/subsys/net/lib/lwm2m/lwm2m_engine.h b/subsys/net/lib/lwm2m/lwm2m_engine.h index 58f3e1a128acf30..a68e1869c1e95cd 100644 --- a/subsys/net/lib/lwm2m/lwm2m_engine.h +++ b/subsys/net/lib/lwm2m/lwm2m_engine.h @@ -375,4 +375,18 @@ int lwm2m_sock_nfds(void); */ void lwm2m_engine_wake_up(void); +/** + * @brief Locks the client. + * + * @param[in] client_ctx LwM2M context + */ +void lwm2m_client_lock(struct lwm2m_ctx *ctx); + +/** + * @brief Unlocks the client previously locked by lwm2m_client_lock(). + * + * @param[in] client_ctx LwM2M context + */ +void lwm2m_client_unlock(struct lwm2m_ctx *ctx); + #endif /* LWM2M_ENGINE_H */ diff --git a/subsys/net/lib/lwm2m/lwm2m_message_handling.c b/subsys/net/lib/lwm2m/lwm2m_message_handling.c index abc8a39ae8f3e75..945bee9750aef5b 100644 --- a/subsys/net/lib/lwm2m/lwm2m_message_handling.c +++ b/subsys/net/lib/lwm2m/lwm2m_message_handling.c @@ -463,6 +463,7 @@ void lwm2m_engine_context_init(struct lwm2m_ctx *client_ctx) client_ctx->buffer_client_messages = true; sys_slist_init(&client_ctx->queued_messages); #endif + k_mutex_init(&client_ctx->lock); } /* utility functions */ @@ -562,10 +563,12 @@ void lwm2m_reset_message(struct lwm2m_message *msg, bool release) lm2m_message_clear_allocations(msg); if (msg->ctx) { + lwm2m_client_lock(msg->ctx); sys_slist_find_and_remove(&msg->ctx->pending_sends, &msg->node); #if defined(CONFIG_LWM2M_QUEUE_MODE_ENABLED) sys_slist_find_and_remove(&msg->ctx->queued_messages, &msg->node); #endif + lwm2m_client_unlock(msg->ctx); } if (release) { @@ -702,7 +705,10 @@ int lwm2m_send_message_async(struct lwm2m_message *msg) return ret; } } + + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->pending_sends, &msg->node); + lwm2m_client_unlock(msg->ctx); if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_ENABLED)) { engine_update_tx_time(); @@ -723,14 +729,18 @@ int lwm2m_information_interface_send(struct lwm2m_message *msg) } if (IS_ENABLED(CONFIG_LWM2M_QUEUE_MODE_NO_MSG_BUFFERING)) { + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->pending_sends, &msg->node); + lwm2m_client_unlock(msg->ctx); lwm2m_engine_wake_up(); lwm2m_engine_connection_resume(msg->ctx); return 0; } if (msg->ctx->buffer_client_messages) { + lwm2m_client_lock(msg->ctx); sys_slist_append(&msg->ctx->queued_messages, &msg->node); + lwm2m_client_unlock(msg->ctx); lwm2m_engine_wake_up(); return 0; }