summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregory Nutt <gnutt@nuttx.org>2013-04-18 16:15:20 -0600
committerGregory Nutt <gnutt@nuttx.org>2013-04-18 16:15:20 -0600
commit2d32b627f6f91e9f70ea20a481adf91dd8d27e99 (patch)
tree6ce126f0017af4d8cf269b433ca7087b655f7d11
parent032e040edbb467aa1137f8f7b3b9442579589ae1 (diff)
downloadnuttx-2d32b627f6f91e9f70ea20a481adf91dd8d27e99.tar.gz
nuttx-2d32b627f6f91e9f70ea20a481adf91dd8d27e99.tar.bz2
nuttx-2d32b627f6f91e9f70ea20a481adf91dd8d27e99.zip
_exit() should not call atexit() or on_exit() functions; Rename task_deletecurrent() to task_exit()
-rw-r--r--apps/ChangeLog.txt3
-rw-r--r--nuttx/ChangeLog13
-rw-r--r--nuttx/arch/8051/src/up_exit.c2
-rw-r--r--nuttx/arch/arm/src/common/up_exit.c2
-rw-r--r--nuttx/arch/avr/src/common/up_exit.c2
-rw-r--r--nuttx/arch/hc/src/common/up_exit.c2
-rw-r--r--nuttx/arch/mips/src/common/up_exit.c2
-rw-r--r--nuttx/arch/rgmp/src/nuttx.c2
-rw-r--r--nuttx/arch/sh/src/common/up_exit.c2
-rw-r--r--nuttx/arch/sim/src/up_exit.c2
-rw-r--r--nuttx/arch/x86/src/common/up_exit.c2
-rw-r--r--nuttx/arch/z16/src/common/up_exit.c2
-rw-r--r--nuttx/arch/z80/src/common/up_exit.c2
-rw-r--r--nuttx/sched/Makefile2
-rw-r--r--nuttx/sched/errno_getptr.c2
-rw-r--r--nuttx/sched/os_internal.h2
-rw-r--r--nuttx/sched/pthread_cancel.c1
-rw-r--r--nuttx/sched/task_delete.c2
-rw-r--r--nuttx/sched/task_exit.c (renamed from nuttx/sched/task_deletecurrent.c)141
-rw-r--r--nuttx/sched/task_exithook.c2
20 files changed, 164 insertions, 26 deletions
diff --git a/apps/ChangeLog.txt b/apps/ChangeLog.txt
index 96e3dbec8..e54f04075 100644
--- a/apps/ChangeLog.txt
+++ b/apps/ChangeLog.txt
@@ -526,3 +526,6 @@
6.27 2013-xx-xx Gregory Nutt <gnutt@nuttx.org>
* apps/system/ramtest: Add a simple memory test (2013-03-26).
+ * apps/examples/ostest: In the non-cancelable thread test, we need
+ to give the thread an opportunity to run and to set the non-
+ cancelable state.
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index 2576e97a8..bf74d92fe 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/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).
diff --git a/nuttx/arch/8051/src/up_exit.c b/nuttx/arch/8051/src/up_exit.c
index c96467bf9..31d8c99ab 100644
--- a/nuttx/arch/8051/src/up_exit.c
+++ b/nuttx/arch/8051/src/up_exit.c
@@ -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.
diff --git a/nuttx/arch/arm/src/common/up_exit.c b/nuttx/arch/arm/src/common/up_exit.c
index 76bf4e0dd..95a71f832 100644
--- a/nuttx/arch/arm/src/common/up_exit.c
+++ b/nuttx/arch/arm/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/avr/src/common/up_exit.c b/nuttx/arch/avr/src/common/up_exit.c
index 3b316123b..93ec7c487 100644
--- a/nuttx/arch/avr/src/common/up_exit.c
+++ b/nuttx/arch/avr/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/hc/src/common/up_exit.c b/nuttx/arch/hc/src/common/up_exit.c
index 9fad697f1..c71bbafd1 100644
--- a/nuttx/arch/hc/src/common/up_exit.c
+++ b/nuttx/arch/hc/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/mips/src/common/up_exit.c b/nuttx/arch/mips/src/common/up_exit.c
index a5746f8aa..8791fa40b 100644
--- a/nuttx/arch/mips/src/common/up_exit.c
+++ b/nuttx/arch/mips/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/rgmp/src/nuttx.c b/nuttx/arch/rgmp/src/nuttx.c
index da67ac214..a4f713be6 100644
--- a/nuttx/arch/rgmp/src/nuttx.c
+++ b/nuttx/arch/rgmp/src/nuttx.c
@@ -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.
diff --git a/nuttx/arch/sh/src/common/up_exit.c b/nuttx/arch/sh/src/common/up_exit.c
index 31c8e0404..e454d1b64 100644
--- a/nuttx/arch/sh/src/common/up_exit.c
+++ b/nuttx/arch/sh/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/sim/src/up_exit.c b/nuttx/arch/sim/src/up_exit.c
index 348c4a9e6..7d7d4d041 100644
--- a/nuttx/arch/sim/src/up_exit.c
+++ b/nuttx/arch/sim/src/up_exit.c
@@ -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.
diff --git a/nuttx/arch/x86/src/common/up_exit.c b/nuttx/arch/x86/src/common/up_exit.c
index 2aa21f352..9b0c0cbe1 100644
--- a/nuttx/arch/x86/src/common/up_exit.c
+++ b/nuttx/arch/x86/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/z16/src/common/up_exit.c b/nuttx/arch/z16/src/common/up_exit.c
index 59764484f..e4c6dcf9c 100644
--- a/nuttx/arch/z16/src/common/up_exit.c
+++ b/nuttx/arch/z16/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/arch/z80/src/common/up_exit.c b/nuttx/arch/z80/src/common/up_exit.c
index c738202a9..aa578f29e 100644
--- a/nuttx/arch/z80/src/common/up_exit.c
+++ b/nuttx/arch/z80/src/common/up_exit.c
@@ -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.
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index 0ee88bf8e..c711a35fa 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -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
diff --git a/nuttx/sched/errno_getptr.c b/nuttx/sched/errno_getptr.c
index 841cb837c..b233b18e4 100644
--- a/nuttx/sched/errno_getptr.c
+++ b/nuttx/sched/errno_getptr.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;
diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h
index 0b7236b28..bbfce9696 100644
--- a/nuttx/sched/os_internal.h
+++ b/nuttx/sched/os_internal.h
@@ -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
diff --git a/nuttx/sched/pthread_cancel.c b/nuttx/sched/pthread_cancel.c
index 6c114ba75..ec464ae15 100644
--- a/nuttx/sched/pthread_cancel.c
+++ b/nuttx/sched/pthread_cancel.c
@@ -147,4 +147,3 @@ int pthread_cancel(pthread_t thread)
return OK;
}
-
diff --git a/nuttx/sched/task_delete.c b/nuttx/sched/task_delete.c
index 1f51fc15d..64830154c 100644
--- a/nuttx/sched/task_delete.c
+++ b/nuttx/sched/task_delete.c
@@ -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()
diff --git a/nuttx/sched/task_deletecurrent.c b/nuttx/sched/task_exit.c
index d2fdaefd4..4414030cf 100644
--- a/nuttx/sched/task_deletecurrent.c
+++ b/nuttx/sched/task_exit.c
@@ -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>
@@ -70,19 +70,135 @@
****************************************************************************/
/****************************************************************************
+ * 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;
}
-
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 6372e628a..71cc13250 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -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)
*
****************************************************************************/