diff options
author | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-13 18:53:00 +0000 |
---|---|---|
committer | patacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3> | 2013-01-13 18:53:00 +0000 |
commit | 0191f2d9e4a4c9857ee37655dd3da523cf74a48a (patch) | |
tree | df530299e0171e8a86a2709ed4f19a1468efda4e /nuttx | |
parent | 0d8a269d4bbb18fa509e642ae2eaec8a8c80a1c3 (diff) | |
download | px4-nuttx-0191f2d9e4a4c9857ee37655dd3da523cf74a48a.tar.gz px4-nuttx-0191f2d9e4a4c9857ee37655dd3da523cf74a48a.tar.bz2 px4-nuttx-0191f2d9e4a4c9857ee37655dd3da523cf74a48a.zip |
Use SIGCHLD with waitpid(); implemented wait() and waitid()
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5515 42af7a65-404d-4744-a932-0658087f49c3
Diffstat (limited to 'nuttx')
-rw-r--r-- | nuttx/ChangeLog | 7 | ||||
-rw-r--r-- | nuttx/Documentation/NuttX.html | 8 | ||||
-rw-r--r-- | nuttx/Documentation/NuttxPortingGuide.html | 10 | ||||
-rw-r--r-- | nuttx/Documentation/NuttxUserGuide.html | 181 | ||||
-rw-r--r-- | nuttx/TODO | 13 | ||||
-rw-r--r-- | nuttx/configs/README.txt | 16 | ||||
-rw-r--r-- | nuttx/configs/sim/ostest/defconfig | 2 | ||||
-rw-r--r-- | nuttx/include/nuttx/sched.h | 5 | ||||
-rw-r--r-- | nuttx/include/sys/types.h | 4 | ||||
-rw-r--r-- | nuttx/include/sys/wait.h | 10 | ||||
-rw-r--r-- | nuttx/sched/Kconfig | 14 | ||||
-rw-r--r-- | nuttx/sched/Makefile | 5 | ||||
-rw-r--r-- | nuttx/sched/os_internal.h | 6 | ||||
-rw-r--r-- | nuttx/sched/sched_wait.c | 90 | ||||
-rw-r--r-- | nuttx/sched/sched_waitid.c | 256 | ||||
-rw-r--r-- | nuttx/sched/sched_waitpid.c | 192 | ||||
-rw-r--r-- | nuttx/sched/task_exithook.c | 24 | ||||
-rw-r--r-- | nuttx/sched/task_setup.c | 3 |
18 files changed, 771 insertions, 75 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 7deb9fa94..e8d4f7309 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -3922,3 +3922,10 @@ which decrements the lockcount on the wrong TCB. The failure case that I saw was that pre-emption got disabled in the IDLE thread, locking up the whole system. + * sched/sched_waitpid.c: Use SIGCHLD instead of a semaphore. This + is a much more spec-compliant implemenation. However, there are + some issues with overruning signals because NuttX does not support + queueing of signals (POSIX does not require it). I think it may + need to. + * sched/sched_waitid.c and sched_wait.c: Add support for waitid() + and wait(). See issues with waitpid() above. diff --git a/nuttx/Documentation/NuttX.html b/nuttx/Documentation/NuttX.html index f6e9a41ba..22651de79 100644 --- a/nuttx/Documentation/NuttX.html +++ b/nuttx/Documentation/NuttX.html @@ -286,7 +286,7 @@ <p> <li> Easily extensible to new processor architectures, SoC architecture, or board architectures. - A <a href="NuttXPortingGuide.html">Porting Guide</a> is available. + A <a href="NuttxPortingGuide.html">Porting Guide</a> is available. </li> </p> </tr> @@ -536,7 +536,7 @@ <td><br></td> <td> <p> - <li><a href="NuttXPortingGuide.html#pwrmgmt">Power management</a> sub-system.</li> + <li><a href="NuttxPortingGuide.html#pwrmgmt">Power management</a> sub-system.</li> </p> </td> </tr> @@ -1009,7 +1009,7 @@ This configuration file contains a long list of settings that control what is built into NuttX and what is not. There are hundreds of such settings - (see the <a href="NuttXPortingGuide.html#apndxconfigs">NuttX Porting Guide</a> + (see the <a href="NuttxPortingGuide.html#apndxconfigs">NuttX Porting Guide</a> for a partial list that excludes platform specific settings). These many, many configuration options allow NuttX to be highly tuned to meet size requirements. @@ -3837,7 +3837,7 @@ pascal-3.0 2011-05-15 Gregory Nutt <gnutt@nuttx.org> </tr> <tr> <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> - <td><a href="NuttXPortingGuide.html">Porting Guide</a></td> + <td><a href="NuttxPortingGuide.html">Porting Guide</a></td> </tr> <tr> <td valign="top" width="22"><img height="20" width="20" src="favicon.ico"></td> diff --git a/nuttx/Documentation/NuttxPortingGuide.html b/nuttx/Documentation/NuttxPortingGuide.html index 0b67eddb7..fec7106b0 100644 --- a/nuttx/Documentation/NuttxPortingGuide.html +++ b/nuttx/Documentation/NuttxPortingGuide.html @@ -12,7 +12,7 @@ <h1><big><font color="#3c34ec"> <i>NuttX RTOS Porting Guide</i> </font></big></h1> - <p>Last Updated: January 12, 2013</p> + <p>Last Updated: January 13, 2013</p> </td> </tr> </table> @@ -4482,7 +4482,8 @@ build </li> <li> <code>CONFIG_SCHED_HAVE_PARENT</code>: Remember the ID of the parent thread when a new child thread is created. - This support enables a few minor features (such as <code>SIGCHLD</code>) and slightly increases the size of the Task Control Block (TCB) of every task to hold the ID of the parent thread. + This support enables some additional features (such as <code>SIGCHLD</code>) and modifies the behavior of other interfaces. + For example, it makes <code>waitpid()</code> more standards complete by restricting the waited-for tasks to the children of the caller. Default: disabled. </li> <li> @@ -4601,10 +4602,11 @@ build <code>CONFIG_SCHED_LPWORKPERIOD</code>: How often the lower priority worker thread checks for work in units of microseconds. Default: 50*1000 (50 MS). </li> <li> - <code>CONFIG_SCHED_LPWORKSTACKSIZE - The stack size allocated for the lower priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE. + <code>CONFIG_SCHED_LPWORKSTACKSIZE</code>: The stack size allocated for the lower priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE. </li> <li> - <code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> API + <code>CONFIG_SCHED_WAITPID</code>: Enables the <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> interface in a default, non-standard mode (non-standard in the sense that the waited for PID need not be child of the caller). + If <code>SCHED_HAVE_PARENT</code> is also defined, then this setting will modify the behavior or <a href="NuttxUserGuide.html#waitpid"><code>waitpid()</code><a> (making more spec compliant) and will enable the <a href="NuttxUserGuide.html#waitid"><code>waitid()</code><a> and <a href="NuttxUserGuide.html#wait"><code>waitp()</code><a> interfaces as well. </li> <li> <code>CONFIG_SCHED_ATEXIT</code>: Enables the <a href="NuttxUserGuide.html#atexit">atexit()</code><a> API diff --git a/nuttx/Documentation/NuttxUserGuide.html b/nuttx/Documentation/NuttxUserGuide.html index c6eabd29a..3cfb63f11 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: January 11, 2013</p> + <p>Last Updated: January 13, 2013</p> </td> </tr> </table> @@ -1776,8 +1776,10 @@ priority of the calling task is returned. <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> + <li><a href="#waitid">2.3.5 waitid</a></li> + <li><a href="#wait">2.3.6 wait</a></li> + <li><a href="#atexit">2.3.7 atexit</a></li> + <li><a href="#onexit">2.3.8 on_exit</a></li> </ul> <H3><a name="schedlock">2.3.1 sched_lock</a></H3> @@ -1886,10 +1888,12 @@ on this thread of execution. <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>). + 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 incomplete (but usable). + If <code>CONFIG_SCHED_HAVE_PARENT</code> is defined, <code>waitpid()</code> will be a little more compliant to specifications. + Without <code>CONFIG_SCHED_HAVE_PARENT</code>, <code>waitpid()</code> simply supports waiting for any task to complete execution. + With <code>CONFIG_SCHED_HAVE_PARENT</code>, <code>waitpid()</code> will use <code>SIGCHLD</code> and can, therefore, wait for any child of the parent to complete. + The implementation is incomplete in either case, however: NuttX does not support any concept of process groups. 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> @@ -2038,7 +2042,158 @@ on this thread of execution. 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> +<h3><a name="waitid">2.3.5 waitid</a></li></h3> +<p> +<b>Function Prototype:</b> +<pre> + #include <sys/wait.h> + #ifdef CONFIG_SCHED_HAVE_PARENT + int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options); + #endif +</pre> +<p> + <b>Description:</b> +</p> +<blockquote><small> + The following discussion is a general description of the <code>waitid()</code> interface. + However, as of this writing, the implementation of <code>waitid()</code> is incomplete (but usable). + If <code>CONFIG_SCHED_HAVE_PARENT</code> is defined, <code>waitid()</code> will be a little more compliant to specifications. + <code>waitpid()</code> simply supports waiting a specific child task (<code>P_PID</code> or for any child task <code>P_ALL</code> to complete execution. + <code>SIGCHLD</code> is used. + The implementation is incomplete in either case, however: NuttX does not support any concept of process groups. + 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>waitid()</code> function suspends the calling thread until one child of the process containing the calling thread changes state. + It records the current state of a child in the structure pointed to by <code>info</code>. + If a child process changed state prior to the call to <code>waitid()</code>, <code>waitid()</code> returns immediately. + If more than one thread is suspended in <code>wait()</code> or <code>waitpid()</code> waiting termination of the same process, exactly one thread will return the process status at the time of the target process termination +</p> +<p> + The <code>idtype</code> and <code>id</code> arguments are used to specify which children <code>waitid()</code> will wait for. +</p> +<p> +<ul> + <li> + If <code>idtype</code> is P_PID, <code>waitid()</code> will wait for the child with a process ID equal to (pid_t)<code>id</code>. + </li> + <li> + If <code>idtype</code> is P_PGID, <code>waitid()</code> will wait for any child with a process group ID equal to (pid_t)<code>id</code>. + </li> + <li> + If <code>idtype</code> is P_ALL, <code>waitid()</code> will wait for any children and <code>id</code> is ignored. +</ul> +<p> + The <code>options</code> argument is used to specify which state changes <code>waitid()</code> will will wait for. + It is formed by OR-ing together one or more of the following flags: +</p> +<ul> + <li> + <code>WEXITED</code>: + Wait for processes that have exited. + </li> + <li> + <code>WSTOPPED</code>: + Status will be returned for any child that has stopped upon receipt of a signal. + </li> + <li> + <code>WCONTINUES</code>: + Status will be returned for any child that was stopped and has been continued. + </li> + <li> + <code>WNOHANG</code>: + Return immediately if there are no children to wait for. + </li> + <li> + <code>WNOWAIT</code>: + Keep the process whose status is returned in <code>info</code> in a waitable state. + This will not affect the state of the process; + the process may be waited for again after this call completes. + </li> +</ul> + The <code>info</code> argument must point to a <code>siginfo_t</code> structure. + If <code>waitid()</code> returns because a child process was found that satisfied the conditions indicated by the arguments <code>idtype</code> and options, then the structure pointed to by <code>info</code> will be filled in by the system with the status of the process. + The <code>si_signo</code> member will always be equal to <code>SIGCHLD</code>. +</p> +<p> + <b>Input Parameters:</b> + See the description above. +</p> +<p> + <b>Returned Value:</b> + If <code>waitid()</code> returns due to the change of state of one of its children, 0 is returned. + Otherwise, -1 is returned and <code>errno</code> is set to indicate the error. +</p> +<p> + The <code>waitid()</code> function will fail if: +</p> +<ul> + <li> + <code>ECHILD</code>: + </li> + The calling process has no existing unwaited-for child processes. + <li> + <code>EINTR</code>: + </li> + The <code>waitid()</code> function was interrupted by a signal. + <li> + <code>EINVAL</code>: + An invalid value was specified for <code>options</code>, or <code>idtype</code> and <code>id</code> specify an invalid set of processes. + </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 in the description above). +</p> + +<h3><a name="wait">2.3.6 wait</a></li></h3> +<p> +<b>Function Prototype:</b> +<pre> + #include <sys/wait.h> + #ifdef CONFIG_SCHED_HAVE_PARENT + pid_t wait(FAR int *stat_loc); + #endif +</pre> +<p> + <b>Description:</b> +</p> +<blockquote><small> + The following discussion is a general description of the <code>wait()</code> interface. + However, as of this writing, the implementation of <code>wait()</code> is incomplete (but usable). + <code>wait()</code> is based on <a href="#waitpid"><code>waitpaid()</code></a>. + See the description of <a href="#waitpid"><code>waitpaid()</code></a> for further information. +</small></blockquote> +<p> + The <code>wait()</code> function will suspend execution of the calling thread until status information for one of its terminated child processes 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>wait()</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>wait()</code>, return will be immediate. +</p> +<p> + The <code>waitpid()</code> function will behave identically to <code>wait()</code>, if its <code>pid</code> argument is (pid_t)-1 and the options argument is 0. + Otherwise, its behavior will be modified by the values of the <code>pid</code> and <code>options</code> arguments. +</p> +<p> + <b>Input Parameters:</b> +</p> +<ul> + <li><code>stat_loc</code>. The location to return the exit status</li> +</ul> +<p> + <b>Returned Value:</b> + See the values returned by <a href="#waitpid"><code>waitpaid()</code></a>. +</p> +<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 in the description <a href="#waitpid"><code>waitpaid()</code></a>). +</p> + +<h3><a name="atexit">2.3.7 atexit</a></h3> <p> <b>Function Prototype:</b> @@ -2077,7 +2232,7 @@ on this thread of execution. <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> +<H3><a name="onexit">2.3.8 on_exit</a></H3> <p> <b>Function Prototype:</b> @@ -9023,9 +9178,9 @@ notify a task when a message is available on a queue. <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="#posix_spawn">posix_spawn</a></li> </td> <td valign="top" width="33%"> - <li><a href="#posix_spawn">posix_spawn</a></li> <li><a href="#posix_spawn_file_actions_addclose">posix_spawn_file_actions_addclose</a></li> <li><a href="#posix_spawn_file_actions_adddup2">posix_spawn_file_actions_adddup2</a></li> <li><a href="#posix_spawn_file_actions_addopen">posix_spawn_file_actions_addopen</a></li> @@ -9107,10 +9262,10 @@ notify a task when a message is available on a queue. <li><a href="#recv">recv</a></li> <li><a href="#recvfrom">recvfrom</a></li> <li><a href="#standardio">rename</a></li> -</td> -<td valign="top"> <li><a href="#standardio">rmdir</a></li> <li><a href="#dirdirentops">rewinddir</a></li> +</td> +<td valign="top"> <li><a href="#mmapxip">ROM disk driver</a></li> <li><a href="#mmapxip">ROMFS</a></li> <li><a href="#schedgetparam">sched_getparam</a></li> @@ -9183,6 +9338,8 @@ 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="#wait">wait</a></li> + <li><a href="#waitid">waitid</a></li> <li><a href="#waitpid">waitpid</a> <li><a href="#Watchdogs">Watchdog Timer Interfaces</a> <li><a href="#wdcancel">wd_cancel</a></li> diff --git a/nuttx/TODO b/nuttx/TODO index 92b7ab4f5..88324c06b 100644 --- a/nuttx/TODO +++ b/nuttx/TODO @@ -6,7 +6,7 @@ standards, things that could be improved, and ideas for enhancements. nuttx/ - (11) Task/Scheduler (sched/) + (10) Task/Scheduler (sched/) (1) Memory Managment (mm/) (2) Signals (sched/, arch/) (2) pthreads (sched/) @@ -58,17 +58,6 @@ o Task/Scheduler (sched/) Status: Closed. No, this behavior will not be implemented. Priority: Medium, required for good emulation of process/pthread model. - Title: WAIT.H - Description: Implement sys/wait.h and functions. Consider implementing wait, - waitpid, waitid. At present, a parent has no information about - child tasks. - - Update: A simple but usable version of waitpid() has been included. - This version is not compliant with all specifications and can be - enabled with CONFIG_SCHED_WAITPID. - Status: Open, however no further work is planned. - Priority: Low - Title: MISSING ERRNO SETTINGS Description: Several APIs do not set errno. Need to review all APIs. Update: These are being fixed as they are encountered. There is diff --git a/nuttx/configs/README.txt b/nuttx/configs/README.txt index 2724cf5a3..4800f02ee 100644 --- a/nuttx/configs/README.txt +++ b/nuttx/configs/README.txt @@ -335,10 +335,11 @@ defconfig -- This is a configuration file similar to the Linux task name to save in the TCB. Useful if scheduler instrumentation is selected. Set to zero to disable. CONFIG_SCHED_HAVE_PARENT - Remember the ID of the parent thread - when a new child thread is created. This support enables a - few minor features (such as SIGCHLD) and slightly increases - the size of the Task Control Block (TCB) of every task to hold - the ID of the parent thread. Default: disabled. + when a new child thread is created. This support enables some + additional features (such as SIGCHLD) and modifies the behavior + of other interfaces. For example, it makes waitpid() more + standards complete by restricting the waited-for tasks to the + children of the caller. Default: disabled. CONFIG_START_YEAR, CONFIG_START_MONTH, CONFIG_START_DAY - Used to initialize the internal time logic. CONFIG_GREGORIAN_TIME - Enables Gregorian time conversions. @@ -417,7 +418,12 @@ defconfig -- This is a configuration file similar to the Linux checks for work in units of microseconds. Default: 50*1000 (50 MS). CONFIG_SCHED_LPWORKSTACKSIZE - The stack size allocated for the lower priority worker thread. Default: CONFIG_IDLETHREAD_STACKSIZE. - CONFIG_SCHED_WAITPID - Enables the waitpid() API + CONFIG_SCHED_WAITPID - Enables the waitpid() interface in a default, + non-standard mode (non-standard in the sense that the waited for + PID need not be child of the caller). If SCHED_HAVE_PARENT is + also defined, then this setting will modify the behavior or + waitpid() (making more spec compliant) and will enable the + waitid() and wait() interfaces as well. CONFIG_SCHED_ATEXIT - Enables the atexit() API CONFIG_SCHED_ATEXIT_MAX - By default if CONFIG_SCHED_ATEXIT is selected, only a single atexit() function is supported. That number diff --git a/nuttx/configs/sim/ostest/defconfig b/nuttx/configs/sim/ostest/defconfig index 5cea9a6d4..c8d5c501d 100644 --- a/nuttx/configs/sim/ostest/defconfig +++ b/nuttx/configs/sim/ostest/defconfig @@ -143,7 +143,7 @@ CONFIG_MUTEX_TYPES=y # CONFIG_FDCLONE_STDIO is not set CONFIG_SDCLONE_DISABLE=y # CONFIG_SCHED_WORKQUEUE is not set -# CONFIG_SCHED_WAITPID is not set +CONFIG_SCHED_WAITPID=y # CONFIG_SCHED_ATEXIT is not set # CONFIG_SCHED_ONEXIT is not set CONFIG_USER_ENTRYPOINT="ostest_main" diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h index 6c67e1500..b2ec1cee4 100644 --- a/nuttx/include/nuttx/sched.h +++ b/nuttx/include/nuttx/sched.h @@ -1,7 +1,7 @@ /******************************************************************************** * include/nuttx/sched.h * - * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -204,6 +204,7 @@ struct _TCB pid_t pid; /* This is the ID of the thread */ #ifdef CONFIG_SCHED_HAVE_PARENT pid_t parent; /* This is the ID of the parent thread */ + uint16_t nchildren; /* This is the number active children */ #endif start_t start; /* Thread start function */ entry_t entry; /* Entry Point into the thread */ @@ -226,7 +227,7 @@ struct _TCB # endif #endif -#ifdef CONFIG_SCHED_WAITPID +#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) sem_t exitsem; /* Support for waitpid */ int *stat_loc; /* Location to return exit status */ #endif diff --git a/nuttx/include/sys/types.h b/nuttx/include/sys/types.h index 2ae69d4a7..95feee72e 100644 --- a/nuttx/include/sys/types.h +++ b/nuttx/include/sys/types.h @@ -154,7 +154,9 @@ typedef uint16_t dev_t; typedef uint16_t ino_t; -/* pid_t is used for process IDs and process group IDs */ +/* pid_t is used for process IDs and process group IDs. It must be signed because + * negative PID values are used to represent invalid PIDs. + */ typedef int pid_t; diff --git a/nuttx/include/sys/wait.h b/nuttx/include/sys/wait.h index 6af1e971e..2476adef9 100644 --- a/nuttx/include/sys/wait.h +++ b/nuttx/include/sys/wait.h @@ -1,7 +1,7 @@ /**************************************************************************** * include/sys/wait.h * - * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * Copyright (C) 2011, 2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -66,7 +66,7 @@ #define WTERMSIG(s) (false) /* Return signal number that caused process to terminate */ /* The following symbolic constants are possible values for the options - * argument to waitpi(1) (1) and/or waitid() (2), + * argument to waitpid() (1) and/or waitid() (2), */ #define WCONTINUED (1 << 0) /* Status for child that has been continued (1)(2) */ @@ -104,9 +104,9 @@ extern "C" { #define EXTERN extern #endif -EXTERN pid_t wait(int *stat_loc); -EXTERN int waitid(idtype_t idtype, id_t id, siginfo_t *siginfo, int options); -EXTERN pid_t waitpid(pid_t pid, int *stat_loc, int options); +EXTERN pid_t wait(FAR int *stat_loc); +EXTERN int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options); +EXTERN pid_t waitpid(pid_t pid, FAR int *stat_loc, int options); #undef EXTERN #if defined(__cplusplus) diff --git a/nuttx/sched/Kconfig b/nuttx/sched/Kconfig index 69621a1fa..6d53a03aa 100644 --- a/nuttx/sched/Kconfig +++ b/nuttx/sched/Kconfig @@ -43,9 +43,10 @@ config SCHED_HAVE_PARENT default n ---help--- Remember the ID of the parent thread when a new child thread is - created. This support enables a few minor features (such as - SIGCHLD) and slightly increases the size of the Task Control Block - (TCB) of every task to hold the ID of the parent thread. Default: + created. This support enables some additional features (such as + SIGCHLD) and modifies the behavior of other interfaces. For + example, it makes waitpid() more standards complete by restricting + the waited-for tasks to the children of the caller. Default: disabled. config JULIAN_TIME @@ -206,7 +207,12 @@ config SCHED_WAITPID bool "Enable waitpid() API" default n ---help--- - Enables the waitpid() API + Enables the waitpid() interface in a default, non-standard mode + (non-standard in the sense that the waited for PID need not be child + of the caller). If SCHED_HAVE_PARENT is also defined, then this + setting will modify the behavior or waitpid() (making more spec + compliant) and will enable the waitid() and wait() interfaces as + well. config SCHED_ATEXIT bool "Enable atexit() API" diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile index 23d1e9938..3d6b58bac 100644 --- a/nuttx/sched/Makefile +++ b/nuttx/sched/Makefile @@ -1,7 +1,7 @@ ############################################################################ # sched/Makefile # -# Copyright (C) 2007-2012 Gregory Nutt. All rights reserved. +# Copyright (C) 2007-2013 Gregory Nutt. All rights reserved. # Author: Gregory Nutt <gnutt@nuttx.org> # # Redistribution and use in source and binary forms, with or without @@ -69,6 +69,9 @@ endif ifeq ($(CONFIG_SCHED_WAITPID),y) SCHED_SRCS += sched_waitpid.c +ifeq ($(CONFIG_SCHED_HAVE_PARENT),y) +SCHED_SRCS += sched_waitid.c sched_wait.c +endif endif ENV_SRCS = env_getenvironptr.c env_dup.c env_share.c env_release.c \ diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h index 13b8083cf..32d9fb4ac 100644 --- a/nuttx/sched/os_internal.h +++ b/nuttx/sched/os_internal.h @@ -83,10 +83,10 @@ enum os_crash_codes_e OSERR_BADREPRIORITIZESTATE /* Attempt to reprioritize in bad state or priority */ }; -/* Special task IDS */ +/* Special task IDS. Any negative PID is invalid. */ -#define NULL_TASK_PROCESS_ID 0 -#define INVALID_PROCESS_ID 0 +#define NULL_TASK_PROCESS_ID (pid_t)0 +#define INVALID_PROCESS_ID (pid_t)-1 /* Although task IDs can take the (positive, non-zero) * range of pid_t, the number of tasks that will be supported diff --git a/nuttx/sched/sched_wait.c b/nuttx/sched/sched_wait.c new file mode 100644 index 000000000..813d4f842 --- /dev/null +++ b/nuttx/sched/sched_wait.c @@ -0,0 +1,90 @@ +/***************************************************************************** + * sched/sched_wait.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> + +#include <nuttx/sched.h> + +#include "os_internal.h" + +#if defined(CONFIG_SCHED_WAITPID) && defined(CONFIG_SCHED_HAVE_PARENT) + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: wait + * + * Description: + * The wait() function will suspend execution of the calling thread until + * status information for one of its terminated child processes 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 wait() or waitpid() 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 wait(), return will be immediate. + * + * The waitpid() function will behave identically to wait(), if the pid + * argument is (pid_t)-1 and the options argument is 0. Otherwise, its + * behaviour will be modified by the values of the pid and options arguments. + * + * Input Parameters: + * stat_loc - The location to return the exit status + * + * Returned Value: + * See waitpid(); + * + *****************************************************************************/ + +pid_t wait(FAR int *stat_loc) +{ + return waitpid((pid_t)-1, stat_loc, 0); +} + +#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT*/ diff --git a/nuttx/sched/sched_waitid.c b/nuttx/sched/sched_waitid.c new file mode 100644 index 000000000..eabc69afe --- /dev/null +++ b/nuttx/sched/sched_waitid.c @@ -0,0 +1,256 @@ +/***************************************************************************** + * sched/sched_waitid.c + * + * Copyright (C) 2013 Gregory Nutt. All rights reserved. + * Author: Gregory Nutt <gnutt@nuttx.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Neither the name NuttX nor the names of its contributors may be + * used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS + * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN + * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + *****************************************************************************/ + +/***************************************************************************** + * Included Files + *****************************************************************************/ + +#include <nuttx/config.h> + +#include <sys/wait.h> +#include <signal.h> +#include <errno.h> + +#include <nuttx/sched.h> + +#include "os_internal.h" + +#if defined(CONFIG_SCHED_WAITPID) && defined(CONFIG_SCHED_HAVE_PARENT) + +/***************************************************************************** + * Private Functions + *****************************************************************************/ + +/***************************************************************************** + * Public Functions + *****************************************************************************/ + +/***************************************************************************** + * Name: waitid + * + * Description: + * The waitid() function suspends the calling thread until one child of + * the process containing the calling thread changes state. It records the + * current state of a child in the structure pointed to by 'info'. If a + * child process changed state prior to the call to waitid(), waitid() + * returns immediately. If more than one thread is suspended in wait() or + * waitpid() waiting termination of the same process, exactly one thread + * will return the process status at the time of the target process + * termination + * + * The idtype and id arguments are used to specify which children waitid() + * will wait for. + * + * If idtype is P_PID, waitid() will wait for the child with a process + * ID equal to (pid_t)id. + * + * If idtype is P_PGID, waitid() will wait for any child with a process + * group ID equal to (pid_t)id. + * + * If idtype is P_ALL, waitid() will wait for any children and id is + * ignored. + * + * The options argument is used to specify which state changes waitid() + * will will wait for. It is formed by OR-ing together one or more of the + * following flags: + * + * WEXITED - Wait for processes that have exited. + * WSTOPPED - Status will be returned for any child that has stopped + * upon receipt of a signal. + * WCONTINUED - Status will be returned for any child that was stopped + * and has been continued. + * WNOHANG - Return immediately if there are no children to wait for. + * WNOWAIT - Keep the process whose status is returned in 'info' in a + * waitable state. This will not affect the state of the process; the + * process may be waited for again after this call completes. + * + * The 'info' argument must point to a siginfo_t structure. If waitid() + * returns because a child process was found that satisfied the conditions + * indicated by the arguments idtype and options, then the structure pointed + * to by 'info' will be filled in by the system with the status of the + * process. The si_signo member will always be equal to SIGCHLD. + * + * Input Parameters: + * See description. + * + * Returned Value: + * If waitid() returns due to the change of state of one of its children, + * 0 is returned. Otherwise, -1 is returned and errno is set to indicate + * the error. + * + * The waitid() function will fail if: + * + * ECHILD - The calling process has no existing unwaited-for child + * processes. + * EINTR - The waitid() function was interrupted by a signal. + * EINVAL - An invalid value was specified for options, or idtype and id + * specify an invalid set of processes. + * + *****************************************************************************/ + +int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options) +{ + FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head; + sigset_t sigset; + int err; + int ret; + + /* MISSING LOGIC: If WNOHANG is provided in the options, then this function + * should returned immediately. However, there is no mechanism available now + * know if the thread has child: The children remember their parents (if + * CONFIG_SCHED_HAVE_PARENT) but the parents do not remember their children. + */ + + /* None of the options are supported except for WEXITED (which must be + * provided. Currently SIGCHILD always reports CLD_EXITED so we cannot + * distinguish any other events. + */ + +#ifdef CONFIG_DEBUG + if (options != WEXITED) + { + set_errno(ENOSYS); + return ERROR; + } +#endif + + /* Create a signal set that contains only SIGCHLD */ + + (void)sigemptyset(&sigset); + (void)sigaddset(&sigset, SIGCHLD); + + /* Disable pre-emption so that nothing changes while the loop executes */ + + sched_lock(); + + /* Verify that this task actually has children and that the the requeste + * TCB is actually a child of this task. + */ + + if (rtcb->nchildren == 0) + { + err = ECHILD; + goto errout_with_errno; + } + else if (idtype == P_PID) + { + /* Get the TCB corresponding to this PID and make sure it is our child. */ + + FAR _TCB *ctcb = sched_gettcb((pid_t)id); + if (!ctcb || ctcb->parent != rtcb->pid) + { + err = ECHILD; + goto errout_with_errno; + } + } + + /* Loop until the child that we are waiting for dies */ + + for (;;) + { + /* Check if the task has already died. Signals are not queued in + * NuttX. So a possibility is that the child has died and we + * missed the death of child signal (we got some other signal + * instead). + */ + + if (rtcb->nchildren == 0 || + (idtype == P_PID && (ret = kill((pid_t)id, 0)) < 0)) + { + /* We know that the child task was running okay we stared, + * so we must have lost the signal. What can we do? + * Let's claim we were interrupted by a signal. + */ + + err = EINTR; + goto errout_with_errno; + } + + /* Wait for any death-of-child signal */ + + ret = sigwaitinfo(&sigset, info); + if (ret < 0) + { + goto errout; + } + + /* Make there this was SIGCHLD */ + + if (info->si_signo == SIGCHLD) + { + /* Yes.. Are we waiting for the death of a specific child? */ + + if (idtype == P_PID) + { + /* Was this the death of the thread we were waiting for? */ + + if (info->si_pid == (pid_t)id) + { + /* Yes... return success */ + + break; + } + } + + /* Are we waiting for any child to change state? */ + + else if (idtype == P_ALL) + { + /* Return success */ + + break; + } + + /* Other ID types are not supported */ + + else /* if (idtype == P_PGID) */ + { + set_errno(ENOSYS); + goto errout; + } + } + } + + sched_unlock(); + return OK; + +errout_with_errno: + set_errno(err); +errout: + sched_unlock(); + return ERROR; +} + +#endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT*/ diff --git a/nuttx/sched/sched_waitpid.c b/nuttx/sched/sched_waitpid.c index 692ef6410..dc715b2e9 100644 --- a/nuttx/sched/sched_waitpid.c +++ b/nuttx/sched/sched_waitpid.c @@ -1,7 +1,7 @@ /***************************************************************************** * sched/sched_waitpid.c * - * Copyright (C) 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2011-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -41,13 +41,14 @@ #include <sys/wait.h> #include <semaphore.h> +#include <signal.h> #include <errno.h> #include <nuttx/sched.h> #include "os_internal.h" -#ifdef CONFIG_SCHED_WAITPID /* Experimental */ +#ifdef CONFIG_SCHED_WAITPID /***************************************************************************** * Private Functions @@ -58,7 +59,7 @@ *****************************************************************************/ /***************************************************************************** - * Name: sched_waitpid + * Name: waitpid * * Description: * @@ -172,10 +173,16 @@ * *****************************************************************************/ -/***************************************************************************/ -/* NOTE: This is a partially functional, experimental version of waitpid() */ -/***************************************************************************/ +/*************************************************************************** + * NOTE: This is a partially functional, experimental version of waitpid() + * + * If there is no SIGCHLD signal supported (CONFIG_SCHED_HAVE_PARENT not + * defined), then waitpid() is still available, but does not obey the + * restriction that the pid be a child of the caller. + * + ***************************************************************************/ +#ifndef CONFIG_SCHED_HAVE_PARENT pid_t waitpid(pid_t pid, int *stat_loc, int options) { _TCB *tcb; @@ -183,9 +190,24 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options) int err; int ret; + DEBUGASSERT(stat_loc); + + /* None of the options are supported */ + +#ifdef CONFIG_DEBUG + if (options != 0) + { + set_errno(ENOSYS); + return ERROR; + } +#endif + /* Disable pre-emption so that nothing changes in the following tests */ sched_lock(); + + /* Get the TCB corresponding to this PID */ + tcb = sched_gettcb(pid); if (!tcb) { @@ -193,16 +215,6 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options) goto errout_with_errno; } - /* None of the options are supported */ - -#ifdef CONFIG_DEBUG - if (options != 0) - { - err = ENOSYS; - goto errout_with_errno; - } -#endif - /* "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 @@ -245,4 +257,152 @@ errout: return ERROR; } +/*************************************************************************** + * + * If CONFIG_SCHED_HAVE_PARENT is defined, then waitpid will use the SIGHCLD + * signal. It can also handle the pid == (pid_t)-1 arguement. This is + * slightly more spec-compliant. + * + * But then I have to be concerned about the fact that NuttX does not queue + * signals. This means that a flurry of signals can cause signals to be + * lost (or to have the data in the struct siginfo to be overwritten by + * the next signal). + * + ***************************************************************************/ + +#else +pid_t waitpid(pid_t pid, int *stat_loc, int options) +{ + FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head; + FAR struct siginfo info; + sigset_t sigset; + int err; + int ret; + + DEBUGASSERT(stat_loc); + + /* None of the options are supported */ + +#ifdef CONFIG_DEBUG + if (options != 0) + { + set_errno(ENOSYS); + return ERROR; + } +#endif + + /* Create a signal set that contains only SIGCHLD */ + + (void)sigemptyset(&sigset); + (void)sigaddset(&sigset, SIGCHLD); + + /* Disable pre-emption so that nothing changes while the loop executes */ + + sched_lock(); + + /* Verify that this task actually has children and that the the requeste + * TCB is actually a child of this task. + */ + + if (rtcb->nchildren == 0) + { + err = ECHILD; + goto errout_with_errno; + } + else if (pid != (pid_t)-1) + { + /* Get the TCB corresponding to this PID and make sure it is our child. */ + + FAR _TCB *ctcb = sched_gettcb(pid); + if (!ctcb || ctcb->parent != rtcb->pid) + { + err = ECHILD; + goto errout_with_errno; + } + } + + /* Loop until the child that we are waiting for dies */ + + for (;;) + { + /* Check if the task has already died. Signals are not queued in + * NuttX. So a possibility is that the child has died and we + * missed the death of child signal (we got some other signal + * instead). + */ + + if (pid == (pid_t)-1) + { + /* We are waiting for any child, check if there are still + * chilren. + */ + + if (rtcb->nchildren == 0) + { + /* There were one or more children when we started so they + * must have exit'ed. There are just no bread crumbs left + * behind to tell us the PID(s) of the existed children. + * Reporting ECHLD is about all we can do in this case. + */ + + err = ECHILD; + goto errout_with_errno; + } + } + else + { + /* We are waiting for a specific PID. We can use kill() with + * signal number 0 to determine if that task is still alive. + */ + + ret = kill(pid, 0); + if (ret < 0) + { + /* It is no longer running. We know that the child task was + * running okay when we started, so we must have lost the + * signal. In this case, we know that the task exit'ed, but + * we do not know its exit status. It would be better to + * reported ECHILD that bogus status. + */ + + err = ECHILD; + goto errout_with_errno; + } + } + + /* Wait for any death-of-child signal */ + + ret = sigwaitinfo(&sigset, &info); + if (ret < 0) + { + goto errout_with_lock; + } + + /* Was this the death of the thread we were waiting for? In the of + * pid == (pid_t)-1, we are waiting for any child thread. + */ + + if (info.si_signo == SIGCHLD && + (pid == (pid_t)-1 || info.si_pid == pid)) + { + /* Yes... return the status and PID (in the event it was -1) */ + + *stat_loc = info.si_status; + pid = info.si_pid; + break; + } + } + + sched_unlock(); + return (int)pid; + +errout_with_errno: + set_errno(err); + +errout_with_lock: + sched_unlock(); + return ERROR; +} +#endif /* CONFIG_SCHED_HAVE_PARENT */ + #endif /* CONFIG_SCHED_WAITPID */ diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c index 9ce2e5899..1106f2885 100644 --- a/nuttx/sched/task_exithook.c +++ b/nuttx/sched/task_exithook.c @@ -217,6 +217,20 @@ static inline void task_sigchild(FAR _TCB *tcb, int status) return; } + /* Decrement the number of children from this parent */ + + DEBUGASSERT(ptcb->nchildren > 0); + ptcb->nchildren--; + + /* Set the parent to an impossible PID. We do this because under certain + * conditions, task_exithook() can be called multiple times. If this + * function is called again, sched_gettcb() will fail on the invalid + * parent PID above, nchildren will be decremented once and all will be + * well. + */ + + tcb->parent = INVALID_PROCESS_ID; + /* Create the siginfo structure. We don't actually know the cause. That * is a bug. Let's just say that the child task just exit-ted for now. */ @@ -246,7 +260,7 @@ static inline void task_sigchild(FAR _TCB *tcb, int status) * ****************************************************************************/ -#ifdef CONFIG_SCHED_WAITPID +#if defined(CONFIG_SCHED_WAITPID) && !defined(CONFIG_SCHED_HAVE_PARENT) static inline void task_exitwakeup(FAR _TCB *tcb, int status) { /* Wakeup any tasks waiting for this task to exit */ @@ -310,14 +324,14 @@ void task_exithook(FAR _TCB *tcb, int status) task_atexit(tcb); - /* Send SIGCHLD to the parent of the exiting task */ - - task_sigchild(tcb, status); - /* Call any registered on_exit function(s) */ task_onexit(tcb, status); + /* Send SIGCHLD to the parent of the exit-ing task */ + + task_sigchild(tcb, status); + /* Wakeup any tasks waiting for this task to exit */ task_exitwakeup(tcb, status); diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c index c5dd8ca3a..92897f0ae 100644 --- a/nuttx/sched/task_setup.c +++ b/nuttx/sched/task_setup.c @@ -168,7 +168,10 @@ static int task_assignpid(FAR _TCB *tcb) static inline void task_saveparent(FAR _TCB *tcb) { FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; + + DEBUGASSERT(rtcb->nchildren < UINT16_MAX); tcb->parent = rtcb->pid; + rtcb->nchildren++; } #else # define task_saveparent(tcb) |