Skip to content

Commit afdd87e

Browse files
ycsinnashif
authored andcommitted
lib: os: mpsc_pbuf: do not wait when spinlock is held
Check if the spinlock is held before attempting to wait by taking the semaphore, as that would cause a context switch which isn't allowed and will trigger an assertion error when `CONFIG_SPIN_VALIDATE` is enabled. Logging in spinlock-held context when the log buffer is full can lead to an infinite assertion error loop, as the logging subsys attempts to allocate buffer when there's none available, it will try to wait for one and thus triggers the assertion error, the error message will be printed through the logging sybsys but there's no buffer available, so it will try to wait for one and triggers another assertion error.. This loop just goes on and on forever, and nothing gets printed to the terminal. Added a test to validate the fix. Signed-off-by: Yong Cong Sin <[email protected]> Signed-off-by: Yong Cong Sin <[email protected]> Signed-off-by: Maxim Adelman <[email protected]> (cherry picked from commit 1a578eb)
1 parent e6d5b78 commit afdd87e

File tree

2 files changed

+24
-1
lines changed

2 files changed

+24
-1
lines changed

lib/os/mpsc_pbuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ union mpsc_pbuf_generic *mpsc_pbuf_alloc(struct mpsc_pbuf_buffer *buffer,
373373
add_skip_item(buffer, free_wlen);
374374
cont = true;
375375
} else if (IS_ENABLED(CONFIG_MULTITHREADING) && !K_TIMEOUT_EQ(timeout, K_NO_WAIT) &&
376-
!k_is_in_isr()) {
376+
!k_is_in_isr() && arch_irq_unlocked(key.key)) {
377377
int err;
378378

379379
k_spin_unlock(&buffer->lock, key);

tests/lib/mpsc_pbuf/src/main.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,5 +1294,28 @@ ZTEST(log_buffer, test_utilization)
12941294
zassert_true(packet == NULL);
12951295
}
12961296

1297+
/* Make sure that `mpsc_pbuf_alloc()` works in spinlock-held context when buf is not available */
1298+
ZTEST(log_buffer, test_alloc_in_spinlock)
1299+
{
1300+
struct mpsc_pbuf_buffer buffer;
1301+
struct test_data_var *packet;
1302+
struct k_spinlock l = {0};
1303+
1304+
init(&buffer, 32, false);
1305+
1306+
/* Allocate all available buffer */
1307+
packet = (struct test_data_var *)mpsc_pbuf_alloc(
1308+
&buffer, 32, K_MSEC(10));
1309+
zassert_not_null(packet);
1310+
1311+
K_SPINLOCK(&l) {
1312+
/* Try to allocate another buf */
1313+
packet = (struct test_data_var *)mpsc_pbuf_alloc(
1314+
&buffer, 32, K_MSEC(10));
1315+
/* No buf is available this time */
1316+
zassert_is_null(packet);
1317+
}
1318+
}
1319+
12971320
/*test case main entry*/
12981321
ZTEST_SUITE(log_buffer, NULL, NULL, NULL, NULL, NULL);

0 commit comments

Comments
 (0)