This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit d9801ca71897908a9a123ad23052a9d3969ad01b Author: Marco Casaroli <[email protected]> AuthorDate: Tue Oct 20 21:02:17 2026 +0200 include/pthread.h: Do not hide pthread_cleanup_push() in a macro. With CONFIG_TLS_NCLEANUP=0 there is no cleanup stack, and pthread_cleanup_push() and pthread_cleanup_pop() were empty macros. A program compiled and linked, but its cleanup handlers never ran: not at pthread_exit(), not at a cancellation, and not at pthread_cleanup_pop(1), where POSIX requires the handler to run. Declare the functions in every configuration. With CONFIG_TLS_NCLEANUP=0 the library does not have them, so a program that uses cleanup handlers fails to link. That is intended: a version that links could not run the handlers either, and a link error is better than handlers that are silently lost. The fix is to set CONFIG_TLS_NCLEANUP > 0. The read-write lock functions push a cleanup handler only when the cleanup stack exists, as before. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- include/pthread.h | 8 ++------ libs/libc/pthread/pthread_rwlock_rdlock.c | 6 ++++++ libs/libc/pthread/pthread_rwlock_wrlock.c | 6 ++++++ libs/libc/tls/Kconfig | 3 +++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/include/pthread.h b/include/pthread.h index 4d2187d8571..f8d7868bcdc 100644 --- a/include/pthread.h +++ b/include/pthread.h @@ -575,16 +575,12 @@ int pthread_setcanceltype(int type, FAR int *oldtype); void pthread_testcancel(void); /* A thread may set up cleanup functions to execute when the thread exits or - * is canceled. + * is canceled. They need CONFIG_TLS_NCLEANUP > 0: without it, a program + * that calls them does not link. */ -#if CONFIG_TLS_NCLEANUP > 0 void pthread_cleanup_pop(int execute); void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg); -#else -# define pthread_cleanup_pop(execute) ((void)(execute)) -# define pthread_cleanup_push(routine,arg) ((void)(routine), (void)(arg)) -#endif /* A thread can await termination of another thread and retrieve the return * value of the thread. diff --git a/libs/libc/pthread/pthread_rwlock_rdlock.c b/libs/libc/pthread/pthread_rwlock_rdlock.c index 50f9b3ca5f2..7d87d8667d4 100644 --- a/libs/libc/pthread/pthread_rwlock_rdlock.c +++ b/libs/libc/pthread/pthread_rwlock_rdlock.c @@ -35,12 +35,14 @@ * Private Functions ****************************************************************************/ +#if CONFIG_TLS_NCLEANUP > 0 static void rdlock_cleanup(FAR void *arg) { FAR pthread_rwlock_t *rw_lock = (FAR pthread_rwlock_t *)arg; pthread_mutex_unlock(&rw_lock->lock); } +#endif static int tryrdlock(FAR pthread_rwlock_t *rw_lock) { @@ -109,7 +111,9 @@ int pthread_rwlock_clockrdlock(FAR pthread_rwlock_t *rw_lock, return err; } +#if CONFIG_TLS_NCLEANUP > 0 pthread_cleanup_push(&rdlock_cleanup, rw_lock); +#endif while ((err = tryrdlock(rw_lock)) == EBUSY) { if (ts != NULL) @@ -128,7 +132,9 @@ int pthread_rwlock_clockrdlock(FAR pthread_rwlock_t *rw_lock, } } +#if CONFIG_TLS_NCLEANUP > 0 pthread_cleanup_pop(0); +#endif pthread_mutex_unlock(&rw_lock->lock); return err; diff --git a/libs/libc/pthread/pthread_rwlock_wrlock.c b/libs/libc/pthread/pthread_rwlock_wrlock.c index 02ec9f9547d..43ef48c5ebc 100644 --- a/libs/libc/pthread/pthread_rwlock_wrlock.c +++ b/libs/libc/pthread/pthread_rwlock_wrlock.c @@ -35,6 +35,7 @@ * Private Functions ****************************************************************************/ +#if CONFIG_TLS_NCLEANUP > 0 static void wrlock_cleanup(FAR void *arg) { FAR pthread_rwlock_t *rw_lock = (FAR pthread_rwlock_t *)arg; @@ -42,6 +43,7 @@ static void wrlock_cleanup(FAR void *arg) rw_lock->num_writers--; pthread_mutex_unlock(&rw_lock->lock); } +#endif /**************************************************************************** * Public Functions @@ -104,7 +106,9 @@ int pthread_rwlock_clockwrlock(FAR pthread_rwlock_t *rw_lock, rw_lock->num_writers++; +#if CONFIG_TLS_NCLEANUP > 0 pthread_cleanup_push(&wrlock_cleanup, rw_lock); +#endif while (rw_lock->write_in_progress || rw_lock->num_readers > 0) { if (ts != NULL) @@ -123,7 +127,9 @@ int pthread_rwlock_clockwrlock(FAR pthread_rwlock_t *rw_lock, } } +#if CONFIG_TLS_NCLEANUP > 0 pthread_cleanup_pop(0); +#endif if (err == 0) { diff --git a/libs/libc/tls/Kconfig b/libs/libc/tls/Kconfig index cd34a4e366d..69b8866af1b 100644 --- a/libs/libc/tls/Kconfig +++ b/libs/libc/tls/Kconfig @@ -76,5 +76,8 @@ config TLS_NCLEANUP POSIX pthread cancellation. The number of cleanup stack levels is the maximum number of pthread_cleanup_push() calls that can be made without a corresponding pthread_cleanup_pop() call. + With 0, pthread_cleanup_push() and pthread_cleanup_pop() do not + exist and a program that calls them does not link. Each level + costs two pointers in every thread. endmenu # Thread Local Storage (TLS)
