From 54eef9f639476ced38a46559fad218811bd9e3c9 Mon Sep 17 00:00:00 2001 From: Huang Qi Date: Thu, 29 Apr 2021 17:56:28 +0800 Subject: [PATCH] libc: Move pthread_exit to userspace Signed-off-by: Huang Qi --- include/nuttx/pthread.h | 35 ++++++++++++++++ include/sys/syscall_lookup.h | 3 +- libs/libc/pthread/Make.defs | 2 +- libs/libc/pthread/pthread_exit.c | 72 ++++++++++++++++++++++++++++++++ sched/pthread/pthread_cleanup.c | 53 +++++++++++++++++++++++ sched/pthread/pthread_exit.c | 8 +--- syscall/syscall.csv | 3 +- 7 files changed, 166 insertions(+), 10 deletions(-) create mode 100644 libs/libc/pthread/pthread_exit.c diff --git a/include/nuttx/pthread.h b/include/nuttx/pthread.h index 8dc21d94b5..477cf2c4f5 100644 --- a/include/nuttx/pthread.h +++ b/include/nuttx/pthread.h @@ -149,6 +149,41 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread, FAR const pthread_attr_t *attr, pthread_startroutine_t entry, pthread_addr_t arg); +/**************************************************************************** + * Name: nx_pthread_exit + * + * Description: + * Terminate execution of a thread started with pthread_create. + * + * Input Parameters: + * exit_valie + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void nx_pthread_exit(FAR void *exit_value) noreturn_function; + +/**************************************************************************** + * Name: pthread_cleanup_poplist + * + * Description: + * The pthread_cleanup_poplist() is function that will pop all clean-up + * functions. This function is only called from within the pthread_exit() + * + * Input Parameters: + * cleanup - The array of struct pthread_cleanup_s to fetch callbacks + * + * Returned Value: + * The index to the next available entry at the top of the stack + * + ****************************************************************************/ + +int pthread_cleanup_poplist(FAR struct pthread_cleanup_s *cleanup); + #undef EXTERN #ifdef __cplusplus } diff --git a/include/sys/syscall_lookup.h b/include/sys/syscall_lookup.h index c3f3deab91..d59467a4c7 100644 --- a/include/sys/syscall_lookup.h +++ b/include/sys/syscall_lookup.h @@ -307,7 +307,7 @@ SYSCALL_LOOKUP(telldir, 1) SYSCALL_LOOKUP(pthread_cond_wait, 2) SYSCALL_LOOKUP(nx_pthread_create, 5) SYSCALL_LOOKUP(pthread_detach, 1) - SYSCALL_LOOKUP(pthread_exit, 1) + SYSCALL_LOOKUP(nx_pthread_exit, 1) SYSCALL_LOOKUP(pthread_getschedparam, 3) SYSCALL_LOOKUP(pthread_join, 2) SYSCALL_LOOKUP(pthread_mutex_destroy, 1) @@ -330,6 +330,7 @@ SYSCALL_LOOKUP(telldir, 1) #ifdef CONFIG_PTHREAD_CLEANUP SYSCALL_LOOKUP(pthread_cleanup_push, 2) SYSCALL_LOOKUP(pthread_cleanup_pop, 1) + SYSCALL_LOOKUP(pthread_cleanup_poplist, 1) #endif #endif diff --git a/libs/libc/pthread/Make.defs b/libs/libc/pthread/Make.defs index 21497bf80b..bbdb75beac 100644 --- a/libs/libc/pthread/Make.defs +++ b/libs/libc/pthread/Make.defs @@ -40,7 +40,7 @@ CSRCS += pthread_barrierinit.c pthread_barrierdestroy.c pthread_barrierwait.c CSRCS += pthread_condattr_init.c pthread_condattr_destroy.c CSRCS += pthread_condattr_setclock.c pthread_condattr_getclock.c CSRCS += pthread_condinit.c pthread_conddestroy.c pthread_condtimedwait.c -CSRCS += pthread_create.c +CSRCS += pthread_create.c pthread_exit.c CSRCS += pthread_get_stackaddr_np.c pthread_get_stacksize_np.c CSRCS += pthread_mutexattr_init.c pthread_mutexattr_destroy.c CSRCS += pthread_mutexattr_getpshared.c pthread_mutexattr_setpshared.c diff --git a/libs/libc/pthread/pthread_exit.c b/libs/libc/pthread/pthread_exit.c new file mode 100644 index 0000000000..71271d9608 --- /dev/null +++ b/libs/libc/pthread/pthread_exit.c @@ -0,0 +1,72 @@ +/**************************************************************************** + * libs/libc/pthread/pthread_exit.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include + +#include + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: pthread_exit + * + * Description: + * Terminate execution of a thread started with pthread_create. + * + * Input Parameters: + * exit_valie + * + * Returned Value: + * None + * + * Assumptions: + * + ****************************************************************************/ + +void pthread_exit(FAR void *exit_value) +{ +#ifdef CONFIG_PTHREAD_CLEANUP + int cnt; + struct pthread_cleanup_s cleanup[CONFIG_PTHREAD_CLEANUP_STACKSIZE]; + cnt = pthread_cleanup_poplist(cleanup); + + sched_lock(); + while (cnt-- > 0) + { + struct pthread_cleanup_s cp = cleanup[cnt]; + if (cp.pc_cleaner) + cp.pc_cleaner(cp.pc_arg); + } + + sched_unlock(); +#endif + + nx_pthread_exit(exit_value); + PANIC(); +} diff --git a/sched/pthread/pthread_cleanup.c b/sched/pthread/pthread_cleanup.c index e735b15bfe..8c5dbafe33 100644 --- a/sched/pthread/pthread_cleanup.c +++ b/sched/pthread/pthread_cleanup.c @@ -208,4 +208,57 @@ void pthread_cleanup_popall(FAR struct tcb_s *tcb) } } +/**************************************************************************** + * Name: pthread_cleanup_poplist + * + * Description: + * The pthread_cleanup_poplist() is function that will pop all clean-up + * functions. This function is only called from within the pthread_exit() + * + * Input Parameters: + * cleanup - The array of struct pthread_cleanup_s to fetch callbacks + * + * Returned Value: + * The index to the next available entry at the top of the stack + * + ****************************************************************************/ + +int pthread_cleanup_poplist(FAR struct pthread_cleanup_s *cleanup) +{ + uint8_t tos = 0; + uint8_t ndx = 0; + FAR struct tcb_s *tcb = this_task(); + + DEBUGASSERT(cleanup != NULL); + DEBUGASSERT(tcb != NULL); + DEBUGASSERT(tcb->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE); + + tos = tcb->tos; + + /* Kernel threads do not support pthread APIs */ + + if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL) + { + /* Pop cleanup routine list + * + * sched_lock() should provide sufficient protection. We only need to + * have this TCB stationary; the pthread cleanup stack should never be + * modified by interrupt level logic. + */ + + sched_lock(); + while (tcb->tos > 0) + { + ndx = tcb->tos - 1; + DEBUGASSERT(ndx >= 0 && ndx < CONFIG_PTHREAD_CLEANUP_STACKSIZE); + cleanup[ndx] = tcb->stack[ndx]; + tcb->tos = ndx; + } + + sched_unlock(); + } + + return tos; +} + #endif /* CONFIG_PTHREAD_CLEANUP */ diff --git a/sched/pthread/pthread_exit.c b/sched/pthread/pthread_exit.c index bc6086fced..a7704abc0d 100644 --- a/sched/pthread/pthread_exit.c +++ b/sched/pthread/pthread_exit.c @@ -59,7 +59,7 @@ * ****************************************************************************/ -void pthread_exit(FAR void *exit_value) +void nx_pthread_exit(FAR void *exit_value) { FAR struct tcb_s *tcb = this_task(); sigset_t set = ALL_SIGNAL_SET; @@ -87,12 +87,6 @@ void pthread_exit(FAR void *exit_value) tcb->cpcount = 0; #endif -#ifdef CONFIG_PTHREAD_CLEANUP - /* Perform any stack pthread clean-up callbacks */ - - pthread_cleanup_popall(tcb); -#endif - /* Complete pending join operations */ status = pthread_completejoin(getpid(), exit_value); diff --git a/syscall/syscall.csv b/syscall/syscall.csv index a9c4658430..e88cf9e83c 100644 --- a/syscall/syscall.csv +++ b/syscall/syscall.csv @@ -84,13 +84,14 @@ "pselect","sys/select.h","","int","int","FAR fd_set *","FAR fd_set *","FAR fd_set *","FAR const struct timespec *","FAR const sigset_t *" "pthread_cancel","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","pthread_t" "pthread_cleanup_pop","pthread.h","defined(CONFIG_PTHREAD_CLEANUP)","void","int" +"pthread_cleanup_poplist","nuttx/pthread.h","defined(CONFIG_PTHREAD_CLEANUP)","int","struct pthread_cleanup_s *" "pthread_cleanup_push","pthread.h","defined(CONFIG_PTHREAD_CLEANUP)","void","pthread_cleanup_t","FAR void *" "pthread_cond_broadcast","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_cond_t *" "pthread_cond_clockwait","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_cond_t *","FAR pthread_mutex_t *","clockid_t","FAR const struct timespec *" "pthread_cond_signal","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_cond_t *" "pthread_cond_wait","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","FAR pthread_cond_t *","FAR pthread_mutex_t *" "pthread_detach","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","pthread_t" -"pthread_exit","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","noreturn","pthread_addr_t" +"nx_pthread_exit","nuttx/pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","noreturn","pthread_addr_t" "pthread_getaffinity_np","pthread.h","!defined(CONFIG_DISABLE_PTHREAD) && defined(CONFIG_SMP)","int","pthread_t","size_t","FAR cpu_set_t*" "pthread_getschedparam","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","pthread_t","FAR int *","FAR struct sched_param *" "pthread_join","pthread.h","!defined(CONFIG_DISABLE_PTHREAD)","int","pthread_t","FAR pthread_addr_t *"