accept
+ atexit
bind
BIOC_XIPBASE
chdir
@@ -7903,12 +8158,13 @@ notify a task when a message is available on a queue.
mq_unlink
mmap
Network Interfaces
+ on_exit
open
opendir
- OS Interfaces
- pipe
|
+ OS Interfaces
+ pipe
poll
poll.h
printf
@@ -7982,9 +8238,9 @@ notify a task when a message is available on a queue.
ROMFS
sched_getparam
sched_get_priority_max
- sched_get_priority_min
|
+ sched_get_priority_min
sched_get_rr_interval
sched_lockcount
sched_lock
@@ -8035,8 +8291,8 @@ notify a task when a message is available on a queue.
task_delete
task_init
task_restart
+ Task Control Interfaces
Task Scheduling Interfaces
- Task Switching Interfaces
telldir
timer_create
timer_delete
@@ -8051,6 +8307,7 @@ notify a task when a message is available on a queue.
vfprintf
vprintf
vsprintf
+ waitpid
Watchdog Timer Interfaces
wd_cancel
wd_create
diff --git a/TODO b/TODO
index 33d48027d7..d3de88df42 100644
--- a/TODO
+++ b/TODO
@@ -1,4 +1,4 @@
-NuttX TODO List (Last updated June 20, 2012)
+NuttX TODO List (Last updated August 1, 2012)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This file summarizes known NuttX bugs, limitations, inconsistencies with
@@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements.
nuttx/
- (6) Task/Scheduler (sched/)
+ (5) Task/Scheduler (sched/)
(1) On-demand paging (sched/)
(1) Memory Managment (mm/)
(2) Signals (sched/, arch/)
@@ -58,14 +58,6 @@ o Task/Scheduler (sched/)
Status: Open
Priority: Medium, required for good emulation of process/pthread model.
- Title: MULTIPLE ATEXIT() FUNCTIONS
- Description: atexit() supports registration of only single function called on
- exit(). It should support multiple functions registered by atexit()
- or onexit() and these should be called in reverse order of
- registration when the task exits.
- Status: Open
- Priority: Low
-
Title: MMAN.H
Description: Implement sys/mman.h and functions
Status: Open
diff --git a/arch/arm/src/lpc17xx/lpc17_lowputc.c b/arch/arm/src/lpc17xx/lpc17_lowputc.c
index 1ea68287bc..ba90c1ff6a 100644
--- a/arch/arm/src/lpc17xx/lpc17_lowputc.c
+++ b/arch/arm/src/lpc17xx/lpc17_lowputc.c
@@ -141,9 +141,11 @@
*
* PCLK = CCLK / divisor
*
- * Ignoring the fractional divider for now.
+ * Ignoring the fractional divider for now. (If you want to extend this driver
+ * to support the fractional divider, see lpc43xx_uart.c. The LPC43xx uses
+ * the same peripheral and that logic could easily leveraged here).
*
- * Check divisor == 1. This works if the upper limit is met
+ * Check divisor == 1. This works if the upper limit is met:
*
* DL < 0xffff, or
* PCLK / BAUD / 16 < 0xffff, or
diff --git a/arch/arm/src/lpc17xx/lpc17_serial.c b/arch/arm/src/lpc17xx/lpc17_serial.c
index ced1c5d665..5ea6348e08 100644
--- a/arch/arm/src/lpc17xx/lpc17_serial.c
+++ b/arch/arm/src/lpc17xx/lpc17_serial.c
@@ -791,7 +791,9 @@ static inline void lpc17_uart3config(uint32_t clkdiv)
* BAUD = PCLK / (16 * DL), or
* DL = PCLK / BAUD / 16
*
- * Ignoring the fractional divider for now.
+ * Ignoring the fractional divider for now. (If you want to extend this driver
+ * to support the fractional divider, see lpc43xx_uart.c. The LPC43xx uses
+ * the same peripheral and that logic could easily leveraged here).
*
************************************************************************************/
diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 90e54706d1..241af6210c 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -188,18 +188,32 @@ struct _TCB
pid_t pid; /* This is the ID of the thread */
start_t start; /* Thread start function */
entry_t entry; /* Entry Point into the thread */
+
#ifdef CONFIG_SCHED_ATEXIT
- atexitfunc_t atexitfunc; /* Called if exit is called. */
+# if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
+ atexitfunc_t atexitfunc[CONFIG_SCHED_ATEXIT_MAX];
+# else
+ atexitfunc_t atexitfunc; /* Called when exit is called. */
+# endif
#endif
+
#ifdef CONFIG_SCHED_ONEXIT
- onexitfunc_t onexitfunc; /* Called if exit is called. */
+# if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
+ onexitfunc_t onexitfunc[CONFIG_SCHED_ONEXIT_MAX];
+ FAR void *onexitarg[CONFIG_SCHED_ONEXIT_MAX];
+# else
+ onexitfunc_t onexitfunc; /* Called when exit is called. */
FAR void *onexitarg; /* The argument passed to the function */
+# endif
#endif
-#ifdef CONFIG_SCHED_WAITPID /* Experimental */
+
+#ifdef CONFIG_SCHED_WAITPID
sem_t exitsem; /* Support for waitpid */
int *stat_loc; /* Location to return exit status */
#endif
+
uint8_t sched_priority; /* Current priority of the thread */
+
#ifdef CONFIG_PRIORITY_INHERITANCE
# if CONFIG_SEM_NNESTPRIO > 0
uint8_t npend_reprio; /* Number of nested reprioritizations */
@@ -207,12 +221,15 @@ struct _TCB
# endif
uint8_t base_priority; /* "Normal" priority of the thread */
#endif
+
uint8_t task_state; /* Current state of the thread */
uint16_t flags; /* Misc. general status flags */
int16_t lockcount; /* 0=preemptable (not-locked) */
+
#ifndef CONFIG_DISABLE_PTHREAD
FAR void *joininfo; /* Detach-able info to support join */
#endif
+
#if CONFIG_RR_INTERVAL > 0
int timeslice; /* RR timeslice interval remaining */
#endif
@@ -221,6 +238,7 @@ struct _TCB
uint8_t init_priority; /* Initial priority of the task */
char *argv[CONFIG_MAX_TASK_ARGS+1]; /* Name+start-up parameters */
+
#ifndef CONFIG_DISABLE_ENVIRON
FAR environ_t *envp; /* Environment variables */
#endif
diff --git a/include/sys/syscall.h b/include/sys/syscall.h
index 96650eaea9..57545beb7d 100644
--- a/include/sys/syscall.h
+++ b/include/sys/syscall.h
@@ -97,9 +97,16 @@
#ifdef CONFIG_SCHED_ATEXIT
# define SYS_atexit __SYS_atexit
-# define __SYS_waitpaid (__SYS_atexit+1)
+# define __SYS_onexit (__SYS_atexit+1)
#else
-# define __SYS_waitpaid __SYS_atexit
+# define __SYS_onexit __SYS_atexit
+#endif
+
+#ifdef CONFIG_SCHED_ONEXIT
+# define SYS_onexit __SYS_onexit
+# define __SYS_waitpaid (__SYS_onexit+1)
+#else
+# define __SYS_waitpaid __SYS_onexit
#endif
#ifdef CONFIG_SCHED_WAITPID
diff --git a/sched/atexit.c b/sched/atexit.c
index 2c9b89d929..f7d81bec20 100644
--- a/sched/atexit.c
+++ b/sched/atexit.c
@@ -1,4 +1,4 @@
-/************************************************************************
+/****************************************************************************
* sched/atexit.c
*
* Copyright (C) 2007, 2009, 2011-2012 Gregory Nutt. All rights reserved.
@@ -31,11 +31,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Included Files
- ************************************************************************/
+ ****************************************************************************/
#include
@@ -51,50 +51,95 @@
#ifdef CONFIG_SCHED_ATEXIT
-/************************************************************************
+/****************************************************************************
* Pre-processor Definitions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Type Declarations
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Global Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Function Prototypes
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Public Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Name: atexit
*
* Description:
* Registers a function to be called at program exit.
+ * The atexit() function registers the given function to be called
+ * at normal process termination, whether via exit or via return from
+ * the program's main().
+ *
+ * NOTE: CONFIG_SCHED_ATEXIT must be defined to enable this function
+ *
+ * Limitiations in the current implementation:
+ *
+ * 1. Only a single atexit function can be registered unless
+ * CONFIG_SCHED_ATEXIT_MAX defines a larger number.
+ * 2. atexit functions are not inherited when a new task is
+ * created.
*
* Parameters:
- * func
+ * func - A pointer to the function to be called when the task exits.
*
* Return Value:
* Zero on success. Non-zero on failure.
*
- ************************************************************************/
+ ****************************************************************************/
int atexit(void (*func)(void))
{
+#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
+ _TCB *tcb = (_TCB*)g_readytorun.head;
+ int index;
+ int ret = ERROR;
+
+ /* The following must be atomic */
+
+ if (func)
+ {
+ sched_lock();
+
+ /* Search for the first available slot. atexit() functions are registered
+ * from lower to higher arry indices; they must be called in the reverse
+ * order of registration when task exists, i.e., from higher to lower
+ * indices.
+ */
+
+ available = -1;
+ for (index = 0; index < CONFIG_SCHED_ATEXIT_MAX; index++)
+ {
+ if (!tcb->atexitfunc[index])
+ {
+ tcb->atexitfunc[index] = func;
+ ret = OK;
+ break;
+ }
+ }
+
+ sched_unlock();
+ }
+
+ return ret;
+#else
_TCB *tcb = (_TCB*)g_readytorun.head;
int ret = ERROR;
@@ -109,6 +154,7 @@ int atexit(void (*func)(void))
sched_unlock();
return ret;
+#endif
}
#endif /* CONFIG_SCHED_ATEXIT */
diff --git a/sched/on_exit.c b/sched/on_exit.c
index 8c08026fd2..5b8be5cd10 100644
--- a/sched/on_exit.c
+++ b/sched/on_exit.c
@@ -1,4 +1,4 @@
-/************************************************************************
+/****************************************************************************
* sched/on_exit.c
*
* Copyright (C) 2012 Gregory Nutt. All rights reserved.
@@ -31,11 +31,11 @@
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Included Files
- ************************************************************************/
+ ****************************************************************************/
#include
@@ -51,36 +51,36 @@
#ifdef CONFIG_SCHED_ONEXIT
-/************************************************************************
+/****************************************************************************
* Pre-processor Definitions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Type Declarations
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Global Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Variables
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Function Prototypes
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Private Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
+/****************************************************************************
* Public Functions
- ************************************************************************/
+ ****************************************************************************/
-/************************************************************************
- * Name: atexit
+/****************************************************************************
+ * Name: on_exit
*
* Description:
* Registers a function to be called at program exit.
@@ -89,22 +89,65 @@
* the program's main(). The function is passed the status argument
* given to the last call to exit and the arg argument from on_exit().
*
+ * NOTE 1: This function comes from SunOS 4, but is also present in
+ * libc4, libc5 and glibc. It no longer occurs in Solaris (SunOS 5).
+ * Avoid this function, and use the standard atexit() instead.
+ *
+ * NOTE 2: CONFIG_SCHED_ONEXIT must be defined to enable this function
+ *
* Limitiations in the current implementation:
*
- * 1. Only a single on_exit function can be registered.
+ * 1. Only a single on_exit function can be registered unless
+ * CONFIG_SCHED_ONEXIT_MAX defines a larger number.
* 2. on_exit functions are not inherited when a new task is
* created.
*
* Parameters:
- * func
+ * func - A pointer to the function to be called when the task exits.
+ * arg - An argument that will be provided to the on_exit() function when
+ * the task exits.
*
* Return Value:
* Zero on success. Non-zero on failure.
*
- ************************************************************************/
+ ****************************************************************************/
int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
{
+#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
+ _TCB *tcb = (_TCB*)g_readytorun.head;
+ int index;
+ int ret = ERROR;
+
+ /* The following must be atomic */
+
+ if (func)
+ {
+ sched_lock();
+
+ /* Search for the first available slot. on_exit() functions are registered
+ * from lower to higher arry indices; they must be called in the reverse
+ * order of registration when task exists, i.e., from higher to lower
+ * indices.
+ */
+
+ available = -1;
+ for (index = 0; index < CONFIG_SCHED_ONEXIT_MAX; index++)
+ {
+ if (!tcb->onexitfunc[index])
+ {
+ tcb->onexitfunc[index] = func;
+ tcb->onexitarg[index] = arg;
+ ret = OK;
+ break;
+ }
+ }
+
+ sched_unlock();
+ }
+
+ return ret;
+#else
_TCB *tcb = (_TCB*)g_readytorun.head;
int ret = ERROR;
@@ -120,8 +163,9 @@ int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg)
sched_unlock();
return ret;
+#endif
}
-#endif /* CONFIG_SCHED_ATEXIT */
+#endif /* CONFIG_SCHED_ONEXIT */
diff --git a/sched/task_exithook.c b/sched/task_exithook.c
index 8fa3bde054..63dc28aa05 100644
--- a/sched/task_exithook.c
+++ b/sched/task_exithook.c
@@ -73,6 +73,153 @@
* Private Functions
****************************************************************************/
+/****************************************************************************
+ * Name: task_atexit
+ *
+ * Description:
+ * Call any registerd atexit function(s)
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_ATEXIT
+static inline void task_atexit(FAR _TCB *tcb)
+{
+#if defined(CONFIG_SCHED_ATEXIT_MAX) && CONFIG_SCHED_ATEXIT_MAX > 1
+ int index;
+
+ /* Call each atexit function in reverse order of registration atexit()
+ * functions are registered from lower to higher arry indices; they must
+ * be called in the reverse order of registration when task exists, i.e.,
+ * from higher to lower indices.
+ */
+
+ for (index = CONFIG_SCHED_ATEXIT_MAX-1; index >= 0; index--)
+ {
+ if (tcb->atexitfunc[index])
+ {
+ /* Call the atexit function */
+
+ (*tcb->atexitfunc[index])();
+
+ /* Nullify the atexit function. task_exithook may be called more then
+ * once in most task exit scenarios. Nullifying the atext function
+ * pointer will assure that the callback is performed only once.
+ */
+
+ tcb->atexitfunc[index] = NULL;
+ }
+ }
+
+#else
+ if (tcb->atexitfunc)
+ {
+ /* Call the atexit function */
+
+ (*tcb->atexitfunc)();
+
+ /* Nullify the atexit function. task_exithook may be called more then
+ * once in most task exit scenarios. Nullifying the atext function
+ * pointer will assure that the callback is performed only once.
+ */
+
+ tcb->atexitfunc = NULL;
+ }
+#endif
+#else
+# define task_atexit(tcb)
+#endif
+
+/****************************************************************************
+ * Name: task_onexit
+ *
+ * Description:
+ * Call any registerd on)exit function(s)
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_ONEXIT
+static inline void task_onexit(FAR _TCB *tcb, int status)
+{
+#if defined(CONFIG_SCHED_ONEXIT_MAX) && CONFIG_SCHED_ONEXIT_MAX > 1
+ int index;
+
+ /* Call each on_exit function in reverse order of registration. on_exit()
+ * functions are registered from lower to higher arry indices; they must
+ * be called in the reverse order of registration when task exists, i.e.,
+ * from higher to lower indices.
+ */
+
+ for (index = CONFIG_SCHED_ONEXIT_MAX-1; index >= 0; index--)
+ {
+ if (tcb->onexitfunc[index])
+ {
+ /* Call the on_exit function */
+
+ (*tcb->onexitfunc[index])(status, tcb->onexitarg[index]);
+
+ /* Nullify the on_exit function. task_exithook may be called more then
+ * once in most task exit scenarios. Nullifying the atext function
+ * pointer will assure that the callback is performed only once.
+ */
+
+ tcb->onexitfunc[index] = NULL;
+ }
+ }
+#else
+ if (tcb->onexitfunc)
+ {
+ /* Call the on_exit function */
+
+ (*tcb->onexitfunc)(status, tcb->onexitarg);
+
+ /* Nullify the on_exit function. task_exithook may be called more then
+ * once in most task exit scenarios. Nullifying the on_exit function
+ * pointer will assure that the callback is performed only once.
+ */
+
+ tcb->onexitfunc = NULL;
+ }
+#endif
+#else
+# define task_onexit(tcb,status)
+#endif
+
+/****************************************************************************
+ * Name: task_exitwakeup
+ *
+ * Description:
+ * Wakeup any tasks waiting for this task to exit
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_WAITPID
+static inline void task_exitwakeup(FAR _TCB *tcb, int status)
+{
+ /* Wakeup any tasks waiting for this task to exit */
+
+ while (tcb->exitsem.semcount < 0)
+ {
+ /* "If more than one thread is suspended in waitpid() awaiting
+ * termination of the same process, exactly one thread will return
+ * the process status at the time of the target process termination."
+ * Hmmm.. what do we return to the others?
+ */
+
+ if (tcb->stat_loc)
+ {
+ *tcb->stat_loc = status << 8;
+ tcb->stat_loc = NULL;
+ }
+
+ /* Wake up the thread */
+
+ sem_post(&tcb->exitsem);
+ }
+}
+#else
+# define task_exitwakeup(tcb, status)
+#endif
+
/****************************************************************************
* Public Functions
****************************************************************************/
@@ -102,65 +249,21 @@
void task_exithook(FAR _TCB *tcb, int status)
{
- /* If an exit function was registered, call it now before we do any un-
- * initialized. NOTE: In the case of task_delete(), the exit function
+ /* If exit function(s) were registered, call them now before we do any un-
+ * initialization. NOTE: In the case of task_delete(), the exit function
* will *not* be called on the thread execution of the task being deleted!
*/
-#ifdef CONFIG_SCHED_ATEXIT
- if (tcb->atexitfunc)
- {
- /* Call the atexit function */
+ task_atexit(tcb);
- (*tcb->atexitfunc)();
+ /* Call any registered on_exit function(s) */
- /* Nullify the atexit function. task_exithook may be called more then
- * once in most task exit scenarios. Nullifying the atext function
- * pointer will assure that the callback is performed only once.
- */
-
- tcb->atexitfunc = NULL;
- }
-#endif
-
-#ifdef CONFIG_SCHED_ONEXIT
- if (tcb->onexitfunc)
- {
- /* Call the on_exit function */
-
- (*tcb->onexitfunc)(status, tcb->onexitarg);
-
- /* Nullify the on_exit function. task_exithook may be called more then
- * once in most task exit scenarios. Nullifying the on_exit function
- * pointer will assure that the callback is performed only once.
- */
-
- tcb->onexitfunc = NULL;
- }
-#endif
+ task_onexit(tcb, status);
/* Wakeup any tasks waiting for this task to exit */
-#ifdef CONFIG_SCHED_WAITPID /* Experimental */
- while (tcb->exitsem.semcount < 0)
- {
- /* "If more than one thread is suspended in waitpid() awaiting
- * termination of the same process, exactly one thread will return
- * the process status at the time of the target process termination."
- * Hmmm.. what do we return to the others?
- */
+ task_exitwakeup(tcb, status);
- if (tcb->stat_loc)
- {
- *tcb->stat_loc = status << 8;
- tcb->stat_loc = NULL;
- }
-
- /* Wake up the thread */
-
- sem_post(&tcb->exitsem);
- }
-#endif
/* Flush all streams (File descriptors will be closed when
* the TCB is deallocated).
*/
diff --git a/syscall/stub_lookup.h b/syscall/stub_lookup.h
index 4f75c16962..9b4a928144 100644
--- a/syscall/stub_lookup.h
+++ b/syscall/stub_lookup.h
@@ -76,6 +76,10 @@ STUB_LOOKUP(3, STUB_up_assert_code) /* SYS_up_assert_code */
STUB_LOOKUP(1, STUB_atexit) /* SYS_atexit */
#endif
+#ifdef CONFIG_SCHED_ONEXIT
+ STUB_LOOKUP(2, STUB_onexit) /* SYS_onexit */
+#endif
+
#ifdef CONFIG_SCHED_WAITPID
STUB_LOOKUP(3, STUB_waitpid) /* SYS_waitpid */
#endif
diff --git a/syscall/syscall.csv b/syscall/syscall.csv
index b323eb95f4..22b45df9da 100644
--- a/syscall/syscall.csv
+++ b/syscall/syscall.csv
@@ -36,6 +36,7 @@
"mq_timedreceive","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","ssize_t","mqd_t","void*","size_t","int*","const struct timespec*"
"mq_timedsend","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","mqd_t","const char*","size_t","int","const struct timespec*"
"mq_unlink","mqueue.h","!defined(CONFIG_DISABLE_MQUEUE)","int","const char*"
+"on_exit","stdlib.h","defined(CONFIG_SCHED_ONEXIT)","int","CODE void (*func)(int, FAR void *)","FAR void *"
"open","fcntl.h","CONFIG_NFILE_DESCRIPTORS > 0","int","const char*","int","..."
"opendir","dirent.h","CONFIG_NFILE_DESCRIPTORS > 0","FAR DIR*","FAR const char*"
"pipe","unistd.h","CONFIG_NFILE_DESCRIPTORS > 0","int","int [2]|int*"
|