diff options
author | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-08-01 17:47:54 +0000 |
---|---|---|
committer | patacongo <patacongo@7fd9a85b-ad96-42d3-883c-3090e2eb8679> | 2012-08-01 17:47:54 +0000 |
commit | 20324504d5997b2ddad85ec3bfa91544c09edd2a (patch) | |
tree | 9226c125b2583f72f45393934b2571f2600fee49 /nuttx | |
parent | 8a4cf655d73899d4a6bac46c2ef762e0e9344ede (diff) | |
download | px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.tar.gz px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.tar.bz2 px4-firmware-20324504d5997b2ddad85ec3bfa91544c09edd2a.zip |
atexit() and on_exit() may now be configured to support multiple exit callbacks
git-svn-id: https://nuttx.svn.sourceforge.net/svnroot/nuttx/trunk@4995 7fd9a85b-ad96-42d3-883c-3090e2eb8679
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/ChangeLog | 3 | ||||
-rw-r--r-- | nuttx/Documentation/NuttxPortingGuide.html | 18 | ||||
-rw-r--r-- | nuttx/Documentation/NuttxUserGuide.html | 271 | ||||
-rw-r--r-- | nuttx/TODO | 12 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lpc17xx/lpc17_lowputc.c | 6 | ||||
-rw-r--r-- | nuttx/arch/arm/src/lpc17xx/lpc17_serial.c | 4 | ||||
-rw-r--r-- | nuttx/include/nuttx/sched.h | 24 | ||||
-rw-r--r-- | nuttx/include/sys/syscall.h | 11 | ||||
-rw-r--r-- | nuttx/sched/atexit.c | 88 | ||||
-rw-r--r-- | nuttx/sched/on_exit.c | 92 | ||||
-rw-r--r-- | nuttx/sched/task_exithook.c | 159 | ||||
-rw-r--r-- | nuttx/syscall/stub_lookup.h | 4 | ||||
-rw-r--r-- | nuttx/syscall/syscall.csv | 1 |
13 files changed, 595 insertions, 98 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 3684728eb..3dc1dc527 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3096,4 +3096,7 @@ * arch/*/src/*_serial.c: Fix ioctl method return values. Theses methods should return a negated errno value; they should not set the errno variable. + * sched/on_exit.c, sched/task_exithook.c, and include/nuttx/sched.c: Add + support for multiple registered on_exit() functions if CONFIG_SCHED_ONEXIT_MAX + is defined. diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index d3689da49..c4a6c90a7 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -4063,6 +4063,24 @@ build <code>CONFIG_SIG_SIGWORK</code>: The signal number that will be used to wake-up the worker thread. Default: 4 </li> + + <li> + <code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> API + </li> + <li> + <code>CONFIG_SCHED_ATEXIT</code>: Enables the <a href="NuttxUserGuide.html#atexit">atexit()</code><a> API + </li> + <li> + <code>CONFIG_SCHED_ATEXIT_MAX</code>: By default if <code>CONFIG_SCHED_ATEXIT</code> is selected, only a single <code>atexit()</code> function is supported. + That number can be increased by defined this setting to the number that you require. + </li> + <li> + <code>CONFIG_SCHED_ONEXIT</code>: Enables the <a href="NuttxUserGuide.html#onexit">on_exit()</code><a> API + </li> + <li> + <code>CONFIG_SCHED_ONEXIT_MAX</code>: By default if <code>CONFIG_SCHED_ONEXIT</code> is selected, only a single <code>on_exit()</code> function is supported. + That number can be increased by defined this setting to the number that you require. + </li> </ul> <p> diff --git a/nuttx/Documentation/NuttxUserGuide.html b/nuttx/Documentation/NuttxUserGuide.html index 9d3af1c27..457347727 100644 --- a/nuttx/Documentation/NuttxUserGuide.html +++ b/nuttx/Documentation/NuttxUserGuide.html @@ -13,7 +13,7 @@ <h1><big><font color="#3c34ec"><i>NuttX Operating System<p>User's Manual</i></font></big></h1> <p><small>by</small></p> <p>Gregory Nutt<p> - <p>Last Updated: March 23, 2012</p> + <p>Last Updated: August 1, 2012</p> </td> </tr> </table> @@ -54,7 +54,7 @@ <ul> <li>Paragraph 2.1 <a href="#Task_Control">Task Control Interfaces</a></li> <li>Paragraph 2.2 <a href="#Task_Schedule">Task Scheduling Interfaces</a></li> - <li>Paragraph 2.3 <a href="#Task_Switch">Task Switching Interfaces</a></li> + <li>Paragraph 2.3 <a href="#Task_Switch">Task Control Interfaces</a></li> <li>Paragraph 2.4 <a href="#Message_Queue">Named Message Queue Interfaces</a></li> <li>Paragraph 2.5 <a href="#Semaphores">Counting Semaphore Interfaces</a></li> <li>Paragraph 2.6 <a href="#Watchdogs">Watchdog Timer Interfaces</a></li> @@ -963,16 +963,23 @@ priority of the calling task is returned. <table width ="100%"> <tr bgcolor="#e4e4e4"> <td> - <a name="Task_Switch"><h2>2.3 Task Switching Interfaces</h2></a> + <a name="Task_Switch"><h2>2.3 Task Control Interfaces</h2></a> </td> </tr> </table> +<p>Scheduler locking interfaces</p> <ul> <li><a href="#schedlock">2.3.1 sched_lock</a></li> <li><a href="#schedunlock">2.3.2 sched_unlock</a></li> <li><a href="#schedlockcount">2.3.3 sched_lockcount</a></li> </ul> +<p>Task synchronization interfaces</p> +<ul> + <li><a href="#waitpid">2.3.4 waitpid</a></li> + <li><a href="#atexit">2.3.5 atexit</a></li> + <li><a href="#onexit">2.3.6 on_exit</a></li> +</ul> <H3><a name="schedlock">2.3.1 sched_lock</a></H3> @@ -1067,6 +1074,253 @@ on this thread of execution. <b> POSIX Compatibility:</b> None. </p> +<H3><a name="waitpid">2.3.4 waitpid</a></H3> + +<p> +<b>Function Prototype:</b> +<pre> + #include <sys/wait.h> + ipid_t waitpid(pid_t pid, int *stat_loc, int options); +</pre> + +<p> + <b>Description:</b> +</p> +<blockquote><small> + The following discussion is a general description of the <code>waitpid(</code>) interface. + However, as of this writing, the implementation of <code>waitpid()</code> is fragmentary (but usable). + It simply supports waiting for any task to complete execution. + NuttX does not support any concept of parent/child processes or of process groups nor signals related to child processes (<code>SIGCHLD</code>). + Nor does NuttX retain the status of exited tasks so if <code>waitpid()</code> is called after a task has exited, then no status will be available. + The options argument is currently ignored. +</small></blockquote> +<p> + The <code>waitpid()</code> functions will obtain status information pertaining to one of the caller's child processes. + The <code>waitpid()</code> function will suspend execution of the calling thread until status information for one of the terminated child processes of the calling process is available, or until delivery of a signal whose action is either to execute a signal-catching function or to terminate the process. + If more than one thread is suspended in <code>waitpid()</code> awaiting termination of the same process, exactly one thread will return the process status at the time of the target process termination. + If status information is available prior to the call to <code>waitpid()</code>, return will be immediate. +</p> +<p> + <b>NOTE</b>: + Because <code>waitpid()</code> is not fully POSIX compliant, it must be specifically enabled by setting <code>CONFIG_SCHED_WAITPID</code> in the NuttX configuration file. +</p> +<p> + <b>Input Parameters:</b> +</p> +<ul> +<li><code>pid</code>. The task ID of the thread to waid for</li> +<li><code>stat_loc</code>. The location to return the exit status</li> +<li><code>options</code>. ignored</li> +</ul> +<p> + The <code>pid</code> argument specifies a set of child processes for which status is requested. + The <code>waitpid()</code> function will only return the status of a child process from this set: +</p> +<ul> + <li> + If <code>pid</code> is equal to <code>(pid_t)-1</code>), status is requested for any child process. + In this respect, <code>waitpid()</code> is then equivalent to <code>wait()</code>. + </li> + <li> + If <code>pid</code> is greater than 0, it specifies the process ID of a single child process for which status is requested. + </li> + <li> + If <code>pid</code> is 0, status is requested for any child process whose process group ID is equal to that of the calling process. + </li> + <li> + If <code>pid</code> is less than <code>(pid_t)-1</code>), status is requested for any child process whose process group ID is equal to the absolute value of pid. + </li> +</ul> +<p> + The <code>options</code> argument is constructed from the bitwise-inclusive OR of zero or more of the following flags, + defined in the <code><sys/wait.h></code> header: +</p> +<ul> + <li> + <code>WCONTINUED</code>. + The <code>waitpid()</code> function will report the status of any continued child process specified by pid whose status has not been reported since it continued from a job control stop. + </li> + <li> + <code>WNOHANG</code>. + The <code>waitpid()</code> function will not suspend execution of the calling thread if status is not immediately available for one of the child processes specified by <code>pid</code>. + </li> + <li> + <code>WUNTRACED</code>. + The status of any child processes specified by <code>pid</code> that are stopped, and whose status has not yet been reported since they stopped, will also be reported to the requesting process. + </li> +</ul> +<p> + If the calling process has <code>SA_NOCLDWAIT</code> set or has <code>SIGCHLD</code> set to <code>SIG_IGN</code>, and the process has no unwaited-for children that were transformed into zombie processes, the calling thread will block until all of the children of the process containing the calling thread terminate, and <code>waitpid()</code> will fail and set errno to <code>ECHILD</code>. +</p> +<p> + If <code>waitpid()</code> returns because the status of a child process is available, these functions will return a value equal to the process ID of the child process. + In this case, if the value of the argument stat_loc is not a null pointer, information will be stored in the location pointed to by <code>stat_loc</code>. + The value stored at the location pointed to by <code>stat_loc</code> will be 0 if and only if the status returned is from a terminated child process that terminated by one of the following means: +</p> +<ol> + <li> + The process returned 0 from <code>main()</code>. + </li> + <li> + The process called <code>_exit()</code> or <code>exit()</code> with a status argument of 0. + </li> + <li> + The process was terminated because the last thread in the process terminated. + </li> +</ol> +<p> + Regardless of its value, this information may be interpreted using the following macros, which are defined in <code><sys/wait.h></code> and evaluate to integral expressions; the <code>stat_val</code> argument is the integer value pointed to by <code>stat_loc</code>. +</p> +<ul> + <li> + <code>WIFEXITED(stat_val)</code>. + Evaluates to a non-zero value if status was returned for a child process that terminated normally. + </li> + <li> + <code>WEXITSTATUS(stat_val)</code>. + If the value of <code>WIFEXITED(stat_val)</code> is non-zero, this macro evaluates to the low-order 8 bits of the status argument that the child process passed to <code>_exit()</code> or <code>exit()</code>, or the value the child process returned from <code>main()</code>. + </li> + <li> + <code>WIFSIGNALED(stat_val)</code>. + Evaluates to a non-zero value if status was returned for a child process that terminated due to the receipt of a signal that was not caught (see >signal.h<). + </li> + <li> + <code>WTERMSIG(stat_val)</code>. + If the value of <code>WIFSIGNALED(stat_val)</code> is non-zero, this macro evaluates to the number of the signal that caused the termination of the child process. + </li> + <li> + <code>WIFSTOPPED(stat_val)</code>. + Evaluates to a non-zero value if status was returned for a child process that is currently stopped. + </li> + <li> + <code>WSTOPSIG(stat_val)</code>. + If the value of <code>WIFSTOPPED(stat_val)</code> is non-zero, this macro evaluates to the number of the signal that caused the child process to stop. + </li> + <li> + <code>WIFCONTINUED(stat_val)</code>. + Evaluates to a non-zero value if status was returned for a child process that has continued from a job control stop. + </li> +</ul> +<p> + <b>Returned Values:</b> +</p> +<p> + If <code>waitpid()</code> returns because the status of a child process is available, it will return a value equal to the process ID of the child process for which status is reported. +</p> +<p> + If <code>waitpid()</code> returns due to the delivery of a signal to the calling process, -1 will be returned and <code>errno</code> set to <code>EINTR</code>. +</p> +<p> + If <code>waitpid()</code> was invoked with WNOHANG set in options, it has at least one child process specified by pid for which status is not available, and status is not available for any process specified by pid, 0 is returned. +</p> +<p> + Otherwise, <code>(pid_t)-1</code< will be returned, and <code>errno</code> set to indicate the error: +</p> +<ul> + <li> + <code>ECHILD</code>. + The process specified by <code>pid</code> does not exist or is not a child of the calling process, or the process group specified by <code>pid</code> does not exist or does not have any member process that is a child of the calling process. + </li> + <li> + <code>EINTR</code>. + The function was interrupted by a signal. + The value of the location pointed to by <code>stat_loc</code> is undefined. + </li> + <li> + <code>EINVAL</code>. + The <code>options</code> argument is not valid. + </li> +</ul> + +<p> + <b>Assumptions/Limitations:</b> +<p> + <b>POSIX Compatibility:</b> + Comparable to the POSIX interface of the same name, but the implementation is incomplete (as detailed above). +</P> + +<H3><a name="atexit">2.3.5 atexit</a></H3> + +<p> +<b>Function Prototype:</b> +<pre> + #include <stdlib.h> + int atexit(void (*func)(void)); +</pre> +<p> + <b>Description:</b> + Registers a function to be called at program exit. + The <code>atexit()</code> function registers the given function to be called at normal process termination, whether via <code>exit()</code> or via return from the program's <code>main()</code>. +</p> +<p> + <b>NOTE</b>: <code>CONFIG_SCHED_ATEXIT</code> must be defined to enable this function. +</p> +<p> + <b>Input Parameters:</b> +</p> +<ul> +<li><i>func</i>. A pointer to the function to be called when the task exits.</li> +</ul> +<p> + <b>Returned Values:</b> + On success, <code>atexit()</code> returns OK (0). + On error, ERROR (-1) is returned, and <a href="#ErrnoAccess"><code>errno</code></a> is set to indicate the cause of the failure. +</p> + +<p> + <b>Assumptions/Limitations:</b> +<p> + <b>POSIX Compatibility:</b> Comparable to the ISO C interface of the same name. + Limitiations in the current implementation: +</p> +<ol> + <li>Only a single <code>atexit</code> function can be registered unless <code>CONFIG_SCHED_ATEXIT_MAX</code> defines a larger number.</li> + <li><code>atexit()</code> functions are not inherited when a new task is created.</li> +</ol> + +<H3><a name="onexit">2.3.6 on_exit</a></H3> + +<p> +<b>Function Prototype:</b> +<pre> + #include <stdlib.h> + int on_exit(CODE void (*func)(int, FAR void *), FAR void *arg) +</pre> +<p> + <b>Description:</b> + Registers a function to be called at program exit. + The <code>on_exit()</code> function registers the given function to be called at normal process termination, whether via <code>exit()</code> or via return from the program's <code>main()</code>. + The function is passed the status argument given to the last call to <code>exit()</code> and the <code>arg</code> argument from <code>on_exit()</code>. +</p> +<p> + <b>NOTE</b>: <code>CONFIG_SCHED_ONEXIT</code> must be defined to enable this function +</p> +<p> + <b>Input Parameters:</b> +</p> +<ul> +<li><i>func</i>. A pointer to the function to be called when the task exits.</li> +<li><i>arg</i>. An argument that will be provided to the <code>on_exit()</code> function when the task exits.</li> +</ul> +<p> + <b>Returned Values:</b> + On success, <code>on_exit()</code> returns OK (0). + On error, ERROR (-1) is returned, and <a href="#ErrnoAccess"><code>errno</code></a> is set to indicate the cause of the failure. +</p> + +<p> + <b>Assumptions/Limitations:</b> +<p> + <b>POSIX Compatibility:</b> + 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 <code>atexit()</code> instead. +</p> +<ol> + <li>Only a single <code>on_exit</code> function can be registered unless <code>CONFIG_SCHED_ONEXIT_MAX</code> defines a larger number.</li> + <li><code>on_exit()</code> functions are not inherited when a new task is created.</li> +</ol> + <table width ="100%"> <tr bgcolor="#e4e4e4"> <td> @@ -7833,6 +8087,7 @@ notify a task when a message is available on a queue. <tr> <td valign="top" width="34%"> <li><a href="#accept">accept</a></li> + <li><a href="#atexit">atexit</a> <li><a href="#bind">bind</a></li> <li><a href="#mmapxip">BIOC_XIPBASE</a></li> <li><a href="#dirunistdops">chdir</a></li> @@ -7903,12 +8158,13 @@ notify a task when a message is available on a queue. <li><a href="#mqunlink">mq_unlink</a></li> <li><a href="#mmap">mmap</a></li> <li><a href="#Network">Network Interfaces</a></li> + <li><a href="#onexit">on_exit</a> <li><a href="#drvrfcntlops">open</a></li> <li><a href="#dirdirentops">opendir</a></li> - <li><a href="#OS_Interfaces">OS Interfaces</a></li> - <li><a href="#pipe">pipe</a></li> </td> <td valign="top" width="33%"> + <li><a href="#OS_Interfaces">OS Interfaces</a></li> + <li><a href="#pipe">pipe</a></li> <li><a href="#poll">poll</a></li> <li><a href="#drvrpollops">poll.h</a></li> <li><a href="#standardio">printf</a></li> @@ -7982,9 +8238,9 @@ notify a task when a message is available on a queue. <li><a href="#mmapxip">ROMFS</a></li> <li><a href="#schedgetparam">sched_getparam</a></li> <li><a href="#schedgetprioritymax">sched_get_priority_max</a></li> - <li><a href="#schedgetprioritymin">sched_get_priority_min</a></li> </td> <td valign="top"> + <li><a href="#schedgetprioritymin">sched_get_priority_min</a></li> <li><a href="#schedgetrrinterval">sched_get_rr_interval</a></li> <li><a href="#schedlockcount">sched_lockcount</a></li> <li><a href="#schedlock">sched_lock</a></li> @@ -8035,8 +8291,8 @@ notify a task when a message is available on a queue. <li><a href="#taskdelete">task_delete</a></li> <li><a href="#taskinit">task_init</a></li> <li><a href="#taskrestart">task_restart</a></li> + <li><a href="#Task_Switch">Task Control Interfaces</a> <li><a href="#Task_Schedule">Task Scheduling Interfaces</a> - <li><a href="#Task_Switch">Task Switching Interfaces</a> <li><a href="#dirdirentops">telldir</a></li> <li><a href="#timercreate">timer_create</a></li> <li><a href="#timerdelete">timer_delete</a></li> @@ -8051,6 +8307,7 @@ notify a task when a message is available on a queue. <li><a href="#standardio">vfprintf</a></li> <li><a href="#standardio">vprintf</a></li> <li><a href="#standardio">vsprintf</a></li> + <li><a href="#waitpid">waitpid</a> <li><a href="#Watchdogs">Watchdog Timer Interfaces</a> <li><a href="#wdcancel">wd_cancel</a></li> <li><a href="#wdcreate">wd_create</a></li> diff --git a/nuttx/TODO b/nuttx/TODO index 33d48027d..d3de88df4 100644 --- a/nuttx/TODO +++ b/nuttx/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/nuttx/arch/arm/src/lpc17xx/lpc17_lowputc.c b/nuttx/arch/arm/src/lpc17xx/lpc17_lowputc.c index 1ea68287b..ba90c1ff6 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_lowputc.c +++ b/nuttx/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/nuttx/arch/arm/src/lpc17xx/lpc17_serial.c b/nuttx/arch/arm/src/lpc17xx/lpc17_serial.c index ced1c5d66..5ea6348e0 100644 --- a/nuttx/arch/arm/src/lpc17xx/lpc17_serial.c +++ b/nuttx/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/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h index 90e54706d..241af6210 100644 --- a/nuttx/include/nuttx/sched.h +++ b/nuttx/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/nuttx/include/sys/syscall.h b/nuttx/include/sys/syscall.h index 96650eaea..57545beb7 100644 --- a/nuttx/include/sys/syscall.h +++ b/nuttx/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/nuttx/sched/atexit.c b/nuttx/sched/atexit.c index 2c9b89d92..f7d81bec2 100644 --- a/nuttx/sched/atexit.c +++ b/nuttx/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 <nuttx/config.h> @@ -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/nuttx/sched/on_exit.c b/nuttx/sched/on_exit.c index 8c08026fd..5b8be5cd1 100644 --- a/nuttx/sched/on_exit.c +++ b/nuttx/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 <nuttx/config.h> @@ -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/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c index 8fa3bde05..63dc28aa0 100644 --- a/nuttx/sched/task_exithook.c +++ b/nuttx/sched/task_exithook.c @@ -74,40 +74,43 @@ ****************************************************************************/ /**************************************************************************** - * Public Functions - ****************************************************************************/ - -/**************************************************************************** - * Name: task_hook + * Name: task_atexit * * Description: - * This function implements some of the internal logic of exit() and - * task_delete(). This function performs some cleanup and other actions - * required when a task exists: - * - * - All open streams are flushed and closed. - * - All functions registered with atexit() and on_exit() are called, in - * the reverse order of their registration. - * - * When called from exit(), the tcb still resides at the head of the ready- - * to-run list. The following logic is safe because we will not be - * returning from the exit() call. - * - * When called from task_delete() we are operating on a different thread; - * on the thread that called task_delete(). In this case, task_delete - * will have already removed the tcb from the ready-to-run list to prevent - * any further action on this task. + * Call any registerd atexit function(s) * ****************************************************************************/ - -void task_exithook(FAR _TCB *tcb, int status) + +#ifdef CONFIG_SCHED_ATEXIT +static inline void task_atexit(FAR _TCB *tcb) { - /* 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 - * will *not* be called on the thread execution of the task being deleted! +#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. */ -#ifdef CONFIG_SCHED_ATEXIT + 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 */ @@ -122,8 +125,47 @@ void task_exithook(FAR _TCB *tcb, int status) 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 */ @@ -138,10 +180,23 @@ void task_exithook(FAR _TCB *tcb, int status) 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 */ -#ifdef CONFIG_SCHED_WAITPID /* Experimental */ while (tcb->exitsem.semcount < 0) { /* "If more than one thread is suspended in waitpid() awaiting @@ -160,7 +215,55 @@ void task_exithook(FAR _TCB *tcb, int status) sem_post(&tcb->exitsem); } +} +#else +# define task_exitwakeup(tcb, status) #endif + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: task_hook + * + * Description: + * This function implements some of the internal logic of exit() and + * task_delete(). This function performs some cleanup and other actions + * required when a task exists: + * + * - All open streams are flushed and closed. + * - All functions registered with atexit() and on_exit() are called, in + * the reverse order of their registration. + * + * When called from exit(), the tcb still resides at the head of the ready- + * to-run list. The following logic is safe because we will not be + * returning from the exit() call. + * + * When called from task_delete() we are operating on a different thread; + * on the thread that called task_delete(). In this case, task_delete + * will have already removed the tcb from the ready-to-run list to prevent + * any further action on this task. + * + ****************************************************************************/ + +void task_exithook(FAR _TCB *tcb, int status) +{ + /* 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! + */ + + task_atexit(tcb); + + /* Call any registered on_exit function(s) */ + + task_onexit(tcb, status); + + /* Wakeup any tasks waiting for this task to exit */ + + task_exitwakeup(tcb, status); + /* Flush all streams (File descriptors will be closed when * the TCB is deallocated). */ diff --git a/nuttx/syscall/stub_lookup.h b/nuttx/syscall/stub_lookup.h index 4f75c1696..9b4a92814 100644 --- a/nuttx/syscall/stub_lookup.h +++ b/nuttx/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/nuttx/syscall/syscall.csv b/nuttx/syscall/syscall.csv index b323eb95f..22b45df9d 100644 --- a/nuttx/syscall/syscall.csv +++ b/nuttx/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*" |