Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net: lwm2m: Improve thread safety of the library #79847

Merged
merged 4 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions include/zephyr/net/lwm2m.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 61 additions & 9 deletions subsys/net/lib/lwm2m/lwm2m_engine.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
static K_KERNEL_STACK_DEFINE(engine_thread_stack, CONFIG_LWM2M_ENGINE_STACK_SIZE);
static struct k_thread engine_thread_data;

static K_MUTEX_DEFINE(engine_lock);

#define MAX_POLL_FD CONFIG_ZVFS_POLL_MAX

/* Resources */
Expand Down Expand Up @@ -232,6 +234,7 @@
{
#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;
Expand All @@ -243,6 +246,7 @@
msg->pending->t0 = k_uptime_get();
sys_slist_append(&msg->ctx->pending_sends, &msg->node);
}
lwm2m_client_unlock(client_ctx);
#endif
return 0;
}
Expand Down Expand Up @@ -365,6 +369,8 @@
int64_t remaining, next = INT64_MAX;
int i;

lwm2m_client_lock(client_ctx);

for (i = 0, p = client_ctx->pendings; i < ARRAY_SIZE(client_ctx->pendings); i++, p++) {
if (!p->timeout) {
continue;
Expand Down Expand Up @@ -402,6 +408,8 @@
}
}

lwm2m_client_unlock(client_ctx);

return next;
}
static int64_t engine_next_service_timestamp(void)
Expand Down Expand Up @@ -641,17 +649,22 @@
*/
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*/
Expand Down Expand Up @@ -710,9 +723,13 @@
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;
}
Expand Down Expand Up @@ -750,12 +767,18 @@
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;

Check notice on line 781 in subsys/net/lib/lwm2m/lwm2m_engine.c

View workflow job for this annotation

GitHub Actions / Run compliance checks on patch series (PR)

You may want to run clang-format on this change

subsys/net/lib/lwm2m/lwm2m_engine.c:781 - sock_fds[i].events = - ZSOCK_POLLIN | - (set_pollout ? ZSOCK_POLLOUT : 0); + sock_fds[i].events = ZSOCK_POLLIN | (set_pollout ? ZSOCK_POLLOUT : 0);
}
}

Expand Down Expand Up @@ -800,13 +823,20 @@

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;
Expand Down Expand Up @@ -1285,6 +1315,26 @@
return 0;
}

void lwm2m_engine_lock(void)
{
(void)k_mutex_lock(&engine_lock, K_FOREVER);
}

void lwm2m_engine_unlock(void)
{
k_mutex_unlock(&engine_lock);
}

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++) {
Expand Down Expand Up @@ -1326,7 +1376,9 @@

lwm2m_clear_block_contexts();
#if defined(CONFIG_LWM2M_COAP_BLOCK_TRANSFER)
lwm2m_engine_lock();
(void)memset(output_block_contexts, 0, sizeof(output_block_contexts));
lwm2m_engine_unlock();
#endif

STRUCT_SECTION_FOREACH(lwm2m_init_func, init) {
Expand Down
24 changes: 24 additions & 0 deletions subsys/net/lib/lwm2m/lwm2m_engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -375,4 +375,28 @@ int lwm2m_sock_nfds(void);
*/
void lwm2m_engine_wake_up(void);

/**
* @brief Locks the access to shared LwM2M engine variables.
*/
void lwm2m_engine_lock(void);

/**
* @brief Unlocks the access to shared LwM2M engine variables.
*/
void lwm2m_engine_unlock(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);

pdgendt marked this conversation as resolved.
Show resolved Hide resolved
#endif /* LWM2M_ENGINE_H */
Loading
Loading