libc: Move pthread_cleanup to user space
Signed-off-by: Huang Qi <huangqi3@xiaomi.com>
This commit is contained in:
parent
103925b2b7
commit
f1a92e9cbb
@ -168,21 +168,24 @@ int nx_pthread_create(pthread_trampoline_t trampoline, FAR pthread_t *thread,
|
||||
void nx_pthread_exit(FAR void *exit_value) noreturn_function;
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pthread_cleanup_poplist
|
||||
* Name: pthread_cleanup_popall
|
||||
*
|
||||
* Description:
|
||||
* The pthread_cleanup_poplist() is function that will pop all clean-up
|
||||
* functions. This function is only called from within the pthread_exit()
|
||||
* The pthread_cleanup_popall() is an internal function that will pop and
|
||||
* execute all clean-up functions. This function is only called from
|
||||
* within the pthread_exit() and pthread_cancellation() logic
|
||||
*
|
||||
* Input Parameters:
|
||||
* cleanup - The array of struct pthread_cleanup_s to fetch callbacks
|
||||
* tcb - The TCB of the pthread that is exiting or being canceled.
|
||||
*
|
||||
* Returned Value:
|
||||
* The index to the next available entry at the top of the stack
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int pthread_cleanup_poplist(FAR struct pthread_cleanup_s *cleanup);
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
void pthread_cleanup_popall(void);
|
||||
#endif
|
||||
|
||||
#undef EXTERN
|
||||
#ifdef __cplusplus
|
||||
|
@ -690,17 +690,6 @@ struct tcb_s
|
||||
FAR struct pthread_mutex_s *mhead; /* List of mutexes held by thread */
|
||||
#endif
|
||||
|
||||
/* Clean-up stack *************************************************************/
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
/* tos - The index to the next available entry at the top of the stack.
|
||||
* stack - The pre-allocated clean-up stack memory.
|
||||
*/
|
||||
|
||||
uint8_t tos;
|
||||
struct pthread_cleanup_s stack[CONFIG_PTHREAD_CLEANUP_STACKSIZE];
|
||||
#endif
|
||||
|
||||
/* Pre-emption monitor support ************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_CRITMONITOR
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <nuttx/sched.h>
|
||||
#include <nuttx/lib/getopt.h>
|
||||
|
||||
/****************************************************************************
|
||||
@ -98,6 +99,16 @@ struct tls_info_s
|
||||
#if CONFIG_TLS_NELEM > 0
|
||||
uintptr_t tl_elem[CONFIG_TLS_NELEM]; /* TLS elements */
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
/* tos - The index to the next available entry at the top of the stack.
|
||||
* stack - The pre-allocated clean-up stack memory.
|
||||
*/
|
||||
|
||||
uint8_t tos;
|
||||
struct pthread_cleanup_s stack[CONFIG_PTHREAD_CLEANUP_STACKSIZE];
|
||||
#endif
|
||||
|
||||
int tl_errno; /* Per-thread error number */
|
||||
};
|
||||
|
||||
|
@ -327,11 +327,6 @@ SYSCALL_LOOKUP(telldir, 1)
|
||||
SYSCALL_LOOKUP(pthread_cond_clockwait, 4)
|
||||
SYSCALL_LOOKUP(pthread_kill, 2)
|
||||
SYSCALL_LOOKUP(pthread_sigmask, 3)
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
SYSCALL_LOOKUP(pthread_cleanup_push, 2)
|
||||
SYSCALL_LOOKUP(pthread_cleanup_pop, 1)
|
||||
SYSCALL_LOOKUP(pthread_cleanup_poplist, 1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The following are defined only if message queues are enabled */
|
||||
|
@ -61,6 +61,10 @@ ifeq ($(CONFIG_PTHREAD_SPINLOCKS),y)
|
||||
CSRCS += pthread_spinlock.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PTHREAD_CLEANUP),y)
|
||||
CSRCS += pthread_cleanup.c
|
||||
endif
|
||||
|
||||
endif # CONFIG_DISABLE_PTHREAD
|
||||
|
||||
# Add the pthread directory to the build
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* sched/pthread/pthread_cleanup.c
|
||||
* libs/libc/pthread/pthread_cleanup.c
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
@ -27,10 +27,11 @@
|
||||
#include <pthread.h>
|
||||
#include <sched.h>
|
||||
|
||||
#include <nuttx/arch.h>
|
||||
#include <nuttx/sched.h>
|
||||
|
||||
#include "sched/sched.h"
|
||||
#include "pthread/pthread.h"
|
||||
#include <nuttx/tls.h>
|
||||
#include <nuttx/pthread.h>
|
||||
#include <arch/tls.h>
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
|
||||
@ -39,7 +40,7 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: pthread_cleanup_pop_tcb
|
||||
* Name: pthread_cleanup_pop_tls
|
||||
*
|
||||
* Description:
|
||||
* The pthread_cleanup_pop_tcb() function will remove the routine at the
|
||||
@ -57,15 +58,15 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
static void pthread_cleanup_pop_tcb(FAR struct tcb_s *tcb, int execute)
|
||||
static void pthread_cleanup_pop_tls(FAR struct tls_info_s *tls, int execute)
|
||||
{
|
||||
if (tcb->tos > 0)
|
||||
if (tls->tos > 0)
|
||||
{
|
||||
unsigned int ndx;
|
||||
|
||||
/* Get the index to the last cleaner function pushed onto the stack */
|
||||
|
||||
ndx = tcb->tos - 1;
|
||||
ndx = tls->tos - 1;
|
||||
DEBUGASSERT(ndx >= 0 && ndx < CONFIG_PTHREAD_CLEANUP_STACKSIZE);
|
||||
|
||||
/* Should we execute the cleanup routine at the top of the stack? */
|
||||
@ -81,11 +82,11 @@ static void pthread_cleanup_pop_tcb(FAR struct tcb_s *tcb, int execute)
|
||||
* mode! See also on_exit() and atexit() callbacks.
|
||||
*/
|
||||
|
||||
cb = &tcb->stack[ndx];
|
||||
cb = &tls->stack[ndx];
|
||||
cb->pc_cleaner(cb->pc_arg);
|
||||
}
|
||||
|
||||
tcb->tos = ndx;
|
||||
tls->tos = ndx;
|
||||
}
|
||||
}
|
||||
|
||||
@ -123,9 +124,9 @@ static void pthread_cleanup_pop_tcb(FAR struct tcb_s *tcb, int execute)
|
||||
|
||||
void pthread_cleanup_pop(int execute)
|
||||
{
|
||||
FAR struct tcb_s *tcb = this_task();
|
||||
FAR struct tls_info_s *tls = up_tls_info();
|
||||
|
||||
DEBUGASSERT(tcb != NULL);
|
||||
DEBUGASSERT(tls != NULL);
|
||||
|
||||
/* sched_lock() should provide sufficient protection. We only need to
|
||||
* have this TCB stationary; the pthread cleanup stack should never be
|
||||
@ -133,20 +134,16 @@ void pthread_cleanup_pop(int execute)
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
pthread_cleanup_pop_tcb(tcb, execute);
|
||||
}
|
||||
|
||||
pthread_cleanup_pop_tls(tls, execute);
|
||||
sched_unlock();
|
||||
}
|
||||
|
||||
void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg)
|
||||
{
|
||||
FAR struct tcb_s *tcb = this_task();
|
||||
FAR struct tls_info_s *tls = up_tls_info();
|
||||
|
||||
DEBUGASSERT(tcb != NULL);
|
||||
DEBUGASSERT(tcb->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE);
|
||||
DEBUGASSERT(tls != NULL);
|
||||
DEBUGASSERT(tls->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE);
|
||||
|
||||
/* sched_lock() should provide sufficient protection. We only need to
|
||||
* have this TCB stationary; the pthread cleanup stack should never be
|
||||
@ -154,14 +151,13 @@ void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg)
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL &&
|
||||
tcb->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE)
|
||||
if (tls->tos < CONFIG_PTHREAD_CLEANUP_STACKSIZE)
|
||||
{
|
||||
unsigned int ndx = tcb->tos;
|
||||
unsigned int ndx = tls->tos;
|
||||
|
||||
tcb->tos++;
|
||||
tcb->stack[ndx].pc_cleaner = routine;
|
||||
tcb->stack[ndx].pc_arg = arg;
|
||||
tls->tos++;
|
||||
tls->stack[ndx].pc_cleaner = routine;
|
||||
tls->stack[ndx].pc_arg = arg;
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
@ -176,89 +172,26 @@ void pthread_cleanup_push(pthread_cleanup_t routine, FAR void *arg)
|
||||
* within the pthread_exit() and pthread_cancellation() logic
|
||||
*
|
||||
* Input Parameters:
|
||||
* tcb - The TCB of the pthread that is exiting or being canceled.
|
||||
* None
|
||||
*
|
||||
* Returned Value:
|
||||
* None
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
void pthread_cleanup_popall(FAR struct tcb_s *tcb)
|
||||
void pthread_cleanup_popall(void)
|
||||
{
|
||||
DEBUGASSERT(tcb != NULL);
|
||||
FAR struct tls_info_s *tls = up_tls_info();
|
||||
|
||||
/* Kernel threads do not support pthread APIs */
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_KERNEL)
|
||||
{
|
||||
/* Pop and execute each cleanup routine/
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
DEBUGASSERT(tls != NULL);
|
||||
|
||||
sched_lock();
|
||||
while (tcb->tos > 0)
|
||||
while (tls->tos > 0)
|
||||
{
|
||||
pthread_cleanup_pop_tcb(tcb, 1);
|
||||
pthread_cleanup_pop_tls(tls, 1);
|
||||
}
|
||||
|
||||
sched_unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* 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 */
|
@ -52,19 +52,7 @@
|
||||
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();
|
||||
pthread_cleanup_popall();
|
||||
#endif
|
||||
|
||||
nx_pthread_exit(exit_value);
|
||||
|
@ -38,10 +38,6 @@ ifeq ($(CONFIG_SMP),y)
|
||||
CSRCS += pthread_setaffinity.c pthread_getaffinity.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_PTHREAD_CLEANUP),y)
|
||||
CSRCS += pthread_cleanup.c
|
||||
endif
|
||||
|
||||
# Include pthread build support
|
||||
|
||||
DEPPATH += --dep-path pthread
|
||||
|
@ -81,10 +81,6 @@ struct task_group_s; /* Forward reference */
|
||||
int pthread_setup_scheduler(FAR struct pthread_tcb_s *tcb, int priority,
|
||||
start_t start, pthread_startroutine_t entry);
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
void pthread_cleanup_popall(FAR struct tcb_s *tcb);
|
||||
#endif
|
||||
|
||||
int pthread_completejoin(pid_t pid, FAR void *exit_value);
|
||||
void pthread_destroyjoin(FAR struct task_group_s *group,
|
||||
FAR struct join_s *pjoin);
|
||||
|
@ -85,19 +85,6 @@ int pthread_cancel(pthread_t thread)
|
||||
pthread_exit(PTHREAD_CANCELED);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
/* Perform any stack pthread clean-up callbacks.
|
||||
*
|
||||
* REVISIT: In this case, the clean-up callback will execute on the
|
||||
* thread of the caller of pthread cancel, not on the thread of
|
||||
* the thread-to-be-canceled. This is a problem when deferred
|
||||
* cancellation is not supported because, for example, the clean-up
|
||||
* function will be unable to unlock its own mutexes.
|
||||
*/
|
||||
|
||||
pthread_cleanup_popall(tcb);
|
||||
#endif
|
||||
|
||||
/* Complete pending join operations */
|
||||
|
||||
pthread_completejoin((pid_t)thread, PTHREAD_CANCELED);
|
||||
|
@ -87,12 +87,6 @@ void exit(int status)
|
||||
group_kill_children(tcb);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PTHREAD_CLEANUP
|
||||
/* Perform any stack pthread clean-up callbacks */
|
||||
|
||||
pthread_cleanup_popall(tcb);
|
||||
#endif
|
||||
|
||||
#if !defined(CONFIG_DISABLE_PTHREAD) && !defined(CONFIG_PTHREAD_MUTEX_UNSAFE)
|
||||
/* Recover any mutexes still held by the canceled thread */
|
||||
|
||||
|
@ -83,9 +83,6 @@
|
||||
"pread","unistd.h","","ssize_t","int","FAR void *","size_t","off_t"
|
||||
"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 *"
|
||||
|
Can't render this file because it has a wrong number of fields in line 2.
|
Loading…
Reference in New Issue
Block a user