From f075022beca4bb984f2fc8481ee1292b932f5ee6 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 1 Apr 2025 11:48:32 -0700 Subject: [PATCH] libc/picolibc: Make lock typing match between Zephyr and picolibc Picolibc's retargetable locking is based upon having the user own the lock type (struct __lock, along with typedef struct __lock *_LOCK_T), and then having the picolibc internal code only refer to this type via the _LOCK_T pointer typedef, leaving the actual struct undeclared there. Zephyr wants to use 'struct k_mutex' for this type; the initial picolibc port handled this by trying to redefine the picolibc locking to use 'void *' instead of 'struct __lock *' by including '#define _LOCK_T void *'. Which 'works' as long as the Zephyr code doesn't actually include picolibc's sys/lock.h. A recent picolibc change to support POSIX stdio locking has picolibc's stdio.h including sys/lock.h, which breaks Zephyr's hack. To fix this, create a real 'struct __lock' type as struct __lock { struct k_mutex m; }; Define all of the required picolibc locking API with this real type, referring to the mutex inside without needing any casts. This required switching the definition of the C library global lock from K_MUTEX_DEFINE to the open-coded version, STRUCT_SECTION_ITERABLE_ALTERNATE so that it has the correct type and still lands in the same elf section. The only mildly inappropriate code left is that lock are allocated using k_object_alloc(K_OBJ_MUTEX), which "works" because the size of 'struct __lock` will exactly match the size of 'struct k_mutex' because of C's struct allocation rules. Signed-off-by: Keith Packard --- lib/libc/picolibc/locks.c | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/lib/libc/picolibc/locks.c b/lib/libc/picolibc/locks.c index c32ab158398..b331a2f1b0c 100644 --- a/lib/libc/picolibc/locks.c +++ b/lib/libc/picolibc/locks.c @@ -7,8 +7,18 @@ #include "picolibc-hooks.h" #ifdef CONFIG_MULTITHREADING -#define _LOCK_T void * -K_MUTEX_DEFINE(__lock___libc_recursive_mutex); + +#include + +/* Define the picolibc lock type */ +struct __lock { + struct k_mutex m; +}; + +STRUCT_SECTION_ITERABLE_ALTERNATE(k_mutex, __lock, + __lock___libc_recursive_mutex) = { + .m = Z_MUTEX_INITIALIZER(__lock___libc_recursive_mutex.m), +}; #ifdef CONFIG_USERSPACE /* Grant public access to picolibc lock after boot */ @@ -32,13 +42,13 @@ void __retarget_lock_init_recursive(_LOCK_T *lock) /* Allocate mutex object */ #ifndef CONFIG_USERSPACE - *lock = malloc(sizeof(struct k_mutex)); + *lock = malloc(sizeof(struct __lock)); #else *lock = k_object_alloc(K_OBJ_MUTEX); #endif /* !CONFIG_USERSPACE */ __ASSERT(*lock != NULL, "recursive lock allocation failed"); - k_mutex_init((struct k_mutex *)*lock); + k_mutex_init(&(*lock)->m); } /* Create a new dynamic non-recursive lock */ @@ -68,7 +78,7 @@ void __retarget_lock_close(_LOCK_T lock) void __retarget_lock_acquire_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); - k_mutex_lock((struct k_mutex *)lock, K_FOREVER); + k_mutex_lock(&lock->m, K_FOREVER); } /* Acquiure non-recursive lock */ @@ -81,7 +91,7 @@ void __retarget_lock_acquire(_LOCK_T lock) int __retarget_lock_try_acquire_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); - return !k_mutex_lock((struct k_mutex *)lock, K_NO_WAIT); + return !k_mutex_lock(&lock->m, K_NO_WAIT); } /* Try acquiring non-recursive lock */ @@ -94,7 +104,7 @@ int __retarget_lock_try_acquire(_LOCK_T lock) void __retarget_lock_release_recursive(_LOCK_T lock) { __ASSERT_NO_MSG(lock != NULL); - k_mutex_unlock((struct k_mutex *)lock); + k_mutex_unlock(&lock->m); } /* Release non-recursive lock */