_exit() should not call atexit() or on_exit() functions; Rename task_deletecurrent() to task_exit()
This commit is contained in:
parent
7be1a9622a
commit
5187631e30
13
ChangeLog
13
ChangeLog
@ -4563,3 +4563,16 @@
|
||||
occur when SVC instructions are executed (2013-4-16).
|
||||
* configs/stm3240g-eval/ostest: Converted to use the kconfig-frontends
|
||||
tools (2013-4-17).
|
||||
* sched/task_exithook.c: Don't flush the streams until the
|
||||
final thread of the group exits. Flushing may cause the
|
||||
thread to get suspended at a bad time and other threads in the
|
||||
group may run while the exiting thread is in an unhealthy state.
|
||||
This can cause crashes under certain circumstance. This is a
|
||||
critical bugfix (2013-4-18).
|
||||
* drivers/mtd/ramtron.c: Extended to support the FM25V01 device.
|
||||
Contributed by Lorenz Meier (2013-4-18).
|
||||
* sched/task_deletecurrent.c and task_exit.c, arch/*/up_exit.c:
|
||||
Renamed task_deletecurrent() and task_exit() since it really
|
||||
handles the architecture independent part of _exit(). _exit()
|
||||
is used internally, but if it is called from the user, it should
|
||||
unregister any atexit() or on_exit() functions (2013-4-18).
|
||||
|
@ -89,7 +89,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -153,7 +153,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -153,7 +153,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -153,7 +153,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -155,7 +155,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -422,7 +422,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -154,7 +154,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -82,7 +82,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -153,7 +153,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -155,7 +155,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -156,7 +156,7 @@ void _exit(int status)
|
||||
|
||||
/* Destroy the task at the head of the ready to run list. */
|
||||
|
||||
(void)task_deletecurrent();
|
||||
(void)task_exit();
|
||||
|
||||
/* Now, perform the context switch to the new ready-to-run task at the
|
||||
* head of the list.
|
||||
|
@ -43,7 +43,7 @@ MISC_SRCS += sched_garbage.c sched_getfiles.c sched_getsockets.c sched_getstream
|
||||
|
||||
TSK_SRCS = prctl.c exit.c getpid.c
|
||||
TSK_SRCS += task_create.c task_init.c task_setup.c task_activate.c task_start.c
|
||||
TSK_SRCS += task_delete.c task_deletecurrent.c task_exithook.c task_recover.c
|
||||
TSK_SRCS += task_delete.c task_exit.c task_exithook.c task_recover.c
|
||||
TSK_SRCS += task_restart.c task_spawn.c task_spawnparms.c
|
||||
TSK_SRCS += sched_addreadytorun.c sched_removereadytorun.c sched_addprioritized.c
|
||||
TSK_SRCS += sched_mergepending.c sched_addblocked.c sched_removeblocked.c
|
||||
|
@ -88,7 +88,7 @@ FAR int *get_errno_ptr(void)
|
||||
/* We were called from the normal tasking context. Verify that the
|
||||
* task at the head of the ready-to-run list is actually running. It
|
||||
* may not be running during very brief times during context switching
|
||||
* logic (see, for example, task_deletecurrent.c).
|
||||
* logic (see, for example, task_exit.c).
|
||||
*/
|
||||
|
||||
FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
|
@ -264,8 +264,8 @@ void task_start(void);
|
||||
int task_schedsetup(FAR struct task_tcb_s *tcb, int priority, start_t start,
|
||||
main_t main, uint8_t ttype);
|
||||
int task_argsetup(FAR struct task_tcb_s *tcb, FAR const char *name, FAR char * const argv[]);
|
||||
int task_exit(void);
|
||||
void task_exithook(FAR struct tcb_s *tcb, int status);
|
||||
int task_deletecurrent(void);
|
||||
void task_recover(FAR struct tcb_s *tcb);
|
||||
|
||||
#ifndef CONFIG_CUSTOM_STACK
|
||||
|
@ -147,4 +147,3 @@ int pthread_cancel(pthread_t thread)
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,7 +93,7 @@
|
||||
*
|
||||
* - pthread_exit(). Calls exit()
|
||||
* - exit(). Calls _exit()
|
||||
* - _exit(). Calls task_deletecurrent() making the currently running task
|
||||
* - _exit(). Calls task_exit() making the currently running task
|
||||
* non-running then calls task_delete() to terminate the non-running
|
||||
* task.
|
||||
* - task_delete()
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* sched/task_deletecurrent.c
|
||||
* sched/task_exit.c
|
||||
*
|
||||
* Copyright (C) 2008-2009, 2012-2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
@ -69,20 +69,136 @@
|
||||
* Private Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: task_cancel_atexit
|
||||
*
|
||||
* Description:
|
||||
* Cncel any registerd atexit function(s)
|
||||
*
|
||||
* This function is called from task_exit() which implements the processor-
|
||||
* independent part of _exit(). _exit() is, in turn, used to implement
|
||||
* the bottom half of exit() and pthread_exit(). These cases are
|
||||
* distinguished as follows:
|
||||
*
|
||||
* 1) _exit() should be called by user logic only from tasks. In this
|
||||
* case, atexit() calls will be canceled by this function.
|
||||
* 2) If the user calls exit(), the exit() function will call task_exithook()
|
||||
* which will process all pending atexit() call. In that case, this
|
||||
* function will have no effect.
|
||||
* 3) If the user called pthread_exit(), the logic in this function will
|
||||
* do nothing. Only a task can legitimately called _exit(). atexit
|
||||
* calls will not be cleared. task_exithook() will be called later (from
|
||||
* task_delete()) and if this is the final thread of the group, any
|
||||
* registered atexit() calls will be performed.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#if defined(CONFIG_SCHED_ATEXIT) && !defined(CONFIG_SCHED_ONEXIT)
|
||||
static inline void task_cancel_atexit(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
DEBUGASSERT(group);
|
||||
|
||||
/* This behavior applies only to tasks that _exit() */
|
||||
|
||||
#ifndef CONFIG_DISABLE_PTHREAD
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
|
||||
int index;
|
||||
|
||||
/* Nullify each atexit function pointer */
|
||||
|
||||
for (index = 0; index < CONFIG_SCHED_ATEXIT_MAX; index++)
|
||||
{
|
||||
group->tg_atexitfunc[index] = NULL;
|
||||
}
|
||||
#else
|
||||
/* Nullify the atexit function to prevent its reuse. */
|
||||
|
||||
group->tg_atexitfunc = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define task_cancel_atexit(tcb)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Name: task_cancel_onexit
|
||||
*
|
||||
* Description:
|
||||
* Cancel any registerd on)exit function(s).
|
||||
*
|
||||
* This function is called from task_exit() which implements the processor-
|
||||
* independent part of _exit(). _exit() is, in turn, used to implement
|
||||
* the bottom half of exit() and pthread_exit(). These cases are
|
||||
* distinguished as follows:
|
||||
*
|
||||
* 1) _exit() should be called by user logic only from tasks. In this
|
||||
* case, on_exit() calls will be canceled by this function.
|
||||
* 2) If the user calls exit(), the exit() function will call task_exithook()
|
||||
* which will process all pending on_exit() call. In that case, this
|
||||
* function will have no effect.
|
||||
* 3) If the user called pthread_exit(), the logic in this function will
|
||||
* do nothing. Only a task can legitimately called _exit(). on_exit
|
||||
* calls will not be cleared. task_exithook() will be called later (from
|
||||
* task_delete()) and if this is the final thread of the group, any
|
||||
* registered on_exit() calls will be performed.
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_ONEXIT
|
||||
static inline void task_cancel_onexit(FAR struct tcb_s *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
DEBUGASSERT(group);
|
||||
|
||||
/* This behavior applies only to tasks that _exit() */
|
||||
|
||||
#ifndef CONFIG_DISABLE_PTHREAD
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
|
||||
#endif
|
||||
{
|
||||
#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
|
||||
int index;
|
||||
|
||||
/* Nullify each atexit function pointer */
|
||||
|
||||
for (index = 0; index < CONFIG_SCHED_ONEXIT_MAX; index++)
|
||||
{
|
||||
group->tg_onexitfunc[index] = NULL;
|
||||
}
|
||||
#else
|
||||
group->tg_onexitfunc = NULL;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define task_cancel_onexit(tcb)
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Functions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: task_delete
|
||||
* Name: task_exit
|
||||
*
|
||||
* Description:
|
||||
* This is a part of the logic used to implement _exit(). The full
|
||||
* implementation of _exit() is architecture-dependent. The _exit()
|
||||
* function also implements the bottom half of exit() and pthread_exit().
|
||||
*
|
||||
* This function causes the currently running task (i.e., the task at the
|
||||
* head of the ready-to-run list) to cease to exist. This is a part of
|
||||
* the logic used to implement _exit(). The full implementation of _exit()
|
||||
* is architecture-dependent. This function should never be called from
|
||||
* normal user code, but only from the architecture-specific implementation
|
||||
* of exit.
|
||||
* head of the ready-to-run list) to cease to exist. This function should
|
||||
* never be called from normal user code, but only from the architecture-
|
||||
* specific implementation of exit.
|
||||
*
|
||||
* Threads/tasks could also be terminated via pthread_cancel, task_delete(),
|
||||
* and task_restart(). In the last two cases, the task will be terminated
|
||||
* as though exit() were called.
|
||||
*
|
||||
* Inputs:
|
||||
* None
|
||||
@ -95,7 +211,7 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int task_deletecurrent(void)
|
||||
int task_exit(void)
|
||||
{
|
||||
FAR struct tcb_s *dtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
FAR struct tcb_s *rtcb;
|
||||
@ -111,6 +227,14 @@ int task_deletecurrent(void)
|
||||
(void)sched_removereadytorun(dtcb);
|
||||
rtcb = (FAR struct tcb_s*)g_readytorun.head;
|
||||
|
||||
/* Cancel any pending atexit() or on_exit() calls. These are not performed
|
||||
* when performing _exit(). Different implementations of _exit() may or may
|
||||
* not* flush buffered I/O. This implemenation *will* flush buffered I/O.
|
||||
*/
|
||||
|
||||
task_cancel_atexit(rtcb);
|
||||
task_cancel_onexit(rtcb);
|
||||
|
||||
/* We are now in a bad state -- the head of the ready to run task list
|
||||
* does not correspond to the thread that is running. Disabling pre-
|
||||
* emption on this TCB and marking the new ready-to-run task as not
|
||||
@ -149,4 +273,3 @@ int task_deletecurrent(void)
|
||||
rtcb->lockcount--;
|
||||
return OK;
|
||||
}
|
||||
|
@ -140,7 +140,7 @@ static inline void task_atexit(FAR struct tcb_s *tcb)
|
||||
* Name: task_onexit
|
||||
*
|
||||
* Description:
|
||||
* Call any registerd on)exit function(s)
|
||||
* Call any registerd on_exit function(s)
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user