From 1dcef90c33ce0b206269ec8b4c5851e867e2b703 Mon Sep 17 00:00:00 2001 From: Jakub Michalski Date: Mon, 19 Jan 2026 18:03:31 +0100 Subject: [PATCH 1/2] posix: fix sem_destroy EBUSY return condition The EBUSY return condition was incorrect and e.g. sem_destroy was in some cases reporting this error even if no thread was blocked by this semaphore. This commit fixes that by checking the waitqueue instead of the semaphore count. Signed-off-by: Jakub Michalski --- lib/posix/options/semaphore.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/posix/options/semaphore.c b/lib/posix/options/semaphore.c index 55ac57c5cfd3f..2ab884eccca3d 100644 --- a/lib/posix/options/semaphore.c +++ b/lib/posix/options/semaphore.c @@ -13,6 +13,7 @@ #include #include #include +#include struct nsem_obj { sys_snode_t snode; @@ -90,7 +91,7 @@ int sem_destroy(sem_t *semaphore) return -1; } - if (k_sem_count_get(semaphore)) { + if (z_waitq_head(&semaphore->wait_q) != NULL) { errno = EBUSY; return -1; } From 5acaf7203210929c264d434e0d7351b69372cc53 Mon Sep 17 00:00:00 2001 From: Jakub Michalski Date: Tue, 20 Jan 2026 17:44:54 +0100 Subject: [PATCH 2/2] posix: fix sem_destroy EBUSY test This commit modifies this test to properly check EBUSY condition Signed-off-by: Jakub Michalski --- tests/posix/semaphores/src/main.c | 44 +++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/tests/posix/semaphores/src/main.c b/tests/posix/semaphores/src/main.c index c8b566349a644..855bb850e82df 100644 --- a/tests/posix/semaphores/src/main.c +++ b/tests/posix/semaphores/src/main.c @@ -21,7 +21,7 @@ BUILD_ASSERT(WAIT_TIME_MS > 0, "WAIT_TIME_MS must be posistive"); /* based on the current structure of this unit test */ BUILD_ASSERT(CONFIG_DYNAMIC_THREAD_POOL_SIZE >= 2, "CONFIG_DYNAMIC_THREAD_POOL_SIZE must be >= 2"); -static void *child_func(void *p1) +static void *child_func_sem_post(void *p1) { sem_t *sem = (sem_t *)p1; @@ -29,9 +29,17 @@ static void *child_func(void *p1) return NULL; } +static void *child_func_sem_wait(void *p1) +{ + sem_t *sem = (sem_t *)p1; + + zassert_equal(sem_wait(sem), 0, "sem_wait failed"); + return NULL; +} + static void semaphore_test(sem_t *sem) { - pthread_t thread1, thread2; + pthread_t thread1, thread2, thread3; int val, ret; struct timespec abstime; @@ -54,7 +62,7 @@ static void semaphore_test(sem_t *sem) zassert_equal(sem_trywait(sem), -1); zassert_equal(errno, EAGAIN); - ret = pthread_create(&thread1, NULL, child_func, sem); + ret = pthread_create(&thread1, NULL, child_func_sem_post, sem); zassert_equal(ret, 0, "Thread creation failed"); zassert_equal(clock_gettime(CLOCK_REALTIME, &abstime), 0, "clock_gettime failed"); @@ -74,24 +82,44 @@ static void semaphore_test(sem_t *sem) zassert_equal(sem_destroy(sem), 0, "semaphore is not destroyed"); /* TESTPOINT: Initialize sema with 1 */ - zassert_equal(sem_init(sem, 0, 1), 0, "sem_init failed"); - zassert_equal(sem_getvalue(sem, &val), 0); - zassert_equal(val, 1); + zassert_equal(sem_init(sem, 0, 0), 0, "sem_init failed"); + + ret = pthread_create(&thread2, NULL, child_func_sem_wait, sem); + zassert_equal(ret, 0, "Thread creation failed"); + /* Switch to the child_func_sem_wait thread */ + ret = sched_yield(); + zassert_equal(ret, 0, "yielding thread failed"); + + /* TESTPOINT: Other thread is waiting for the semaphore, + * check if sem_destroy fails with EBUSY + */ zassert_equal(sem_destroy(sem), -1, "acquired semaphore is destroyed"); zassert_equal(errno, EBUSY); + zassert_equal(sem_post(sem), 0, "sem_post failed"); + zassert_ok(pthread_join(thread2, NULL)); + + /* TESTPOINT: Other thread is no longer waiting for the semaphore, + * sem_destroy should no longer fail with EBUSY + */ + zassert_equal(sem_destroy(sem), 0, "semaphore is not destroyed"); + + /* TESTPOINT: Initialize sema with 1 */ + zassert_equal(sem_init(sem, 0, 1), 0, "sem_init failed"); + /* TESTPOINT: take semaphore which is initialized with 1 */ zassert_equal(sem_trywait(sem), 0); - zassert_equal(pthread_create(&thread2, NULL, child_func, sem), 0, "Thread creation failed"); + zassert_equal(pthread_create(&thread3, NULL, child_func_sem_post, sem), 0, + "Thread creation failed"); /* TESTPOINT: Wait and acquire semaphore till thread2 gives */ zassert_equal(sem_wait(sem), 0, "sem_wait failed"); /* Make sure the threads are terminated */ zassert_ok(pthread_join(thread1, NULL)); - zassert_ok(pthread_join(thread2, NULL)); + zassert_ok(pthread_join(thread3, NULL)); } ZTEST(posix_semaphores, test_semaphore)