You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by gn...@apache.org on 2020/05/04 13:20:12 UTC

[incubator-nuttx] 03/05: sched: add nx_wait, nx_waitid and nx_waitpid

This is an automated email from the ASF dual-hosted git repository.

gnutt pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git

commit de2a9d8a771ac4434d94a654e2b60c4fd0de19a1
Author: Xiang Xiao <xi...@xiaomi.com>
AuthorDate: Mon May 4 00:54:56 2020 +0800

    sched: add nx_wait, nx_waitid and nx_waitpid
    
    Signed-off-by: Xiang Xiao <xi...@xiaomi.com>
---
 include/nuttx/sched.h       |  10 ++
 sched/sched/sched_wait.c    |  11 +-
 sched/sched/sched_waitid.c  | 198 ++++++++++++-----------
 sched/sched/sched_waitpid.c | 374 ++++++++++++++++++++++----------------------
 4 files changed, 313 insertions(+), 280 deletions(-)

diff --git a/include/nuttx/sched.h b/include/nuttx/sched.h
index 8d07601..cc63e7c 100644
--- a/include/nuttx/sched.h
+++ b/include/nuttx/sched.h
@@ -1260,6 +1260,16 @@ int nxsched_setaffinity(pid_t pid, size_t cpusetsize,
 
 int sched_get_stackinfo(pid_t pid, FAR struct stackinfo_s *stackinfo);
 
+/********************************************************************************
+ * Name: nx_wait/nx_waitid/nx_waitpid
+ ********************************************************************************/
+
+#ifdef CONFIG_SCHED_WAITPID
+pid_t nx_wait(FAR int *stat_loc);
+int   nx_waitid(int idtype, id_t id, FAR siginfo_t *info, int options);
+pid_t nx_waitpid(pid_t pid, FAR int *stat_loc, int options);
+#endif
+
 #undef EXTERN
 #if defined(__cplusplus)
 }
diff --git a/sched/sched/sched_wait.c b/sched/sched/sched_wait.c
index 7dd9070..42e84f3 100644
--- a/sched/sched/sched_wait.c
+++ b/sched/sched/sched_wait.c
@@ -54,6 +54,15 @@
  ****************************************************************************/
 
 /****************************************************************************
+ * Name: nx_wait
+ ****************************************************************************/
+
+pid_t nx_wait(FAR int *stat_loc)
+{
+  return nx_waitpid((pid_t)-1, stat_loc, 0);
+}
+
+/****************************************************************************
  * Name: wait
  *
  * Description:
@@ -85,7 +94,7 @@ pid_t wait(FAR int *stat_loc)
    * trivial case.
    */
 
-  return waitpid((pid_t) - 1, stat_loc, 0);
+  return waitpid((pid_t)-1, stat_loc, 0);
 }
 
 #endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT */
diff --git a/sched/sched/sched_waitid.c b/sched/sched/sched_waitid.c
index a3431de..edabfee 100644
--- a/sched/sched/sched_waitid.c
+++ b/sched/sched/sched_waitid.c
@@ -93,69 +93,10 @@ static void exited_child(FAR struct tcb_s *rtcb,
  ****************************************************************************/
 
 /****************************************************************************
- * 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.
- *
+ * Name: nx_waitid
  ****************************************************************************/
 
-int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
+int nx_waitid(int idtype, id_t id, FAR siginfo_t *info, int options)
 {
   FAR struct tcb_s *rtcb = this_task();
   FAR struct tcb_s *ctcb;
@@ -164,8 +105,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
   bool retains;
 #endif
   sigset_t set;
-  int errcode;
-  int ret;
+  int ret = OK;
 
   /* MISSING LOGIC:   If WNOHANG is provided in the options, then this
    * function should returned immediately.  However, there is no mechanism
@@ -179,8 +119,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
 
   if (idtype != P_PID && idtype != P_ALL)
     {
-      set_errno(ENOSYS);
-      return ERROR;
+      return -ENOSYS;
     }
 
   /* None of the options are supported except for WEXITED (which must be
@@ -190,15 +129,10 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
 
   if (options != WEXITED)
     {
-      set_errno(ENOSYS);
-      return ERROR;
+      return -ENOSYS;
     }
 #endif
 
-  /* waitid() is a cancellation point */
-
-  enter_cancellation_point();
-
   /* Create a signal set that contains only SIGCHLD */
 
   sigemptyset(&set);
@@ -221,8 +155,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
     {
       /* There are no children */
 
-      errcode = ECHILD;
-      goto errout_with_errno;
+      ret = -ECHILD;
+      goto errout;
     }
   else if (idtype == P_PID)
     {
@@ -238,8 +172,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
       if (ctcb == NULL || ctcb->group->tg_ppid != rtcb->pid)
 #endif
         {
-          errcode = ECHILD;
-          goto errout_with_errno;
+          ret = -ECHILD;
+          goto errout;
         }
 
       /* Does this task retain child status? */
@@ -252,8 +186,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
             {
               /* This specific pid is not a child */
 
-              errcode = ECHILD;
-              goto errout_with_errno;
+              ret = -ECHILD;
+              goto errout;
             }
         }
     }
@@ -264,8 +198,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
     {
       /* There are no children */
 
-      errcode = ECHILD;
-      goto errout_with_errno;
+      ret = -ECHILD;
+      goto errout;
     }
   else if (idtype == P_PID)
     {
@@ -281,8 +215,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
       if (ctcb == NULL || ctcb->group->tg_ppid != rtcb->pid)
 #endif
         {
-          errcode = ECHILD;
-          goto errout_with_errno;
+          ret = -ECHILD;
+          goto errout;
         }
     }
 #endif
@@ -353,8 +287,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
                * to reported ECHILD than bogus status.
                */
 
-              errcode = ECHILD;
-              goto errout_with_errno;
+              ret = -ECHILD;
+              goto errout;
             }
         }
 #else
@@ -372,8 +306,8 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
            * Let's return ECHILD.. that is at least informative.
            */
 
-          errcode = ECHILD;
-          goto errout_with_errno;
+          ret = -ECHILD;
+          goto errout;
         }
 #endif
 
@@ -382,8 +316,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
       ret = nxsig_waitinfo(&set, info);
       if (ret < 0)
         {
-          errcode = -ret;
-          goto errout_with_errno;
+          goto errout;
         }
 
       /* Make there this was SIGCHLD */
@@ -417,22 +350,97 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
 
           else /* if (idtype == P_PGID) */
             {
-              errcode = ENOSYS;
-              goto errout_with_errno;
+              ret = -ENOSYS;
+              goto errout;
             }
         }
     }
 
-  leave_cancellation_point();
+errout:
   sched_unlock();
-  return OK;
+  return ret;
+}
+
+/****************************************************************************
+ * 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.
+ *
+ ****************************************************************************/
 
-errout_with_errno:
-  set_errno(errcode);
+int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
+{
+  int ret;
+
+  /* waitid() is a cancellation point */
+
+  enter_cancellation_point();
+
+  ret = nx_waitid(idtype, id, info, options);
+  if (ret < 0)
+    {
+      set_errno(-ret);
+      ret = ERROR;
+    }
 
   leave_cancellation_point();
-  sched_unlock();
-  return ERROR;
+  return ret;
 }
 
 #endif /* CONFIG_SCHED_WAITPID && CONFIG_SCHED_HAVE_PARENT */
diff --git a/sched/sched/sched_waitpid.c b/sched/sched/sched_waitpid.c
index 8ff5244..45527be 100644
--- a/sched/sched/sched_waitpid.c
+++ b/sched/sched/sched_waitpid.c
@@ -59,144 +59,19 @@
  ****************************************************************************/
 
 /****************************************************************************
- * Name: waitpid
- *
- * Description:
- *   The waitpid() functions will obtain status information pertaining to one
- *   of the caller's child processes. The waitpid() 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 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 waitpid(), return will be immediate.
- *
- *   The pid argument specifies a set of child processes for which status is
- *   requested. The waitpid() function will only return the status of a child
- *   process from this set:
- *
- *   - If pid is equal to (pid_t)-1, status is requested for any child
- *     process. In this respect, waitpid() is then equivalent to wait().
- *   - If pid is greater than 0, it specifies the process ID of a single
- *     child process for which status is requested.
- *   - If pid is 0, status is requested for any child process whose process
- *     group ID is equal to that of the calling process.
- *   - If pid is less than (pid_t)-1, status is requested for any child
- *     process whose process group ID is equal to the absolute value of pid.
- *
- *   The options argument is constructed from the bitwise-inclusive OR of
- *   zero or more of the following flags, defined in the <sys/wait.h> header:
- *
- *   WCONTINUED - The waitpid() 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.
- *   WNOHANG - The waitpid() function will not suspend execution of the
- *    calling thread if status is not immediately available for one of the
- *    child processes specified by pid.
- *   WUNTRACED - The status of any child processes specified by pid that are
- *    stopped, and whose status has not yet been reported since they stopped,
- *    will also be reported to the requesting process.
- *
- *   If the calling process has SA_NOCLDWAIT set or has SIGCHLD set to
- *   SIG_IGN, 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 waitpid() will fail and set errno to ECHILD.
- *
- *   If waitpid() 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
- *   stat_loc. The value stored at the location pointed to by stat_loc will
- *   be 0 if and only if the status returned is from a terminated child
- *   process that terminated by one of the following means:
- *
- *   1. The process returned 0 from main().
- *   2. The process called _exit() or exit() with a status argument of 0.
- *   3. The process was terminated because the last thread in the process
- *      terminated.
- *
- *   Regardless of its value, this information may be interpreted using the
- *   following macros, which are defined in <sys/wait.h> and evaluate to
- *   integral expressions; the stat_val argument is the integer value pointed
- *   to by stat_loc.
- *
- *   WIFEXITED(stat_val) - Evaluates to a non-zero value if status was
- *     returned for a child process that terminated normally.
- *   WEXITSTATUS(stat_val) - If the value of WIFEXITED(stat_val) is non-zero,
- *     this macro evaluates to the low-order 8 bits of the status argument
- *     that the child process passed to _exit() or exit(), or the value the
- *     child process returned from main().
- *   WIFSIGNALED(stat_val) - 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>).
- *   WTERMSIG(stat_val)  - If the value of WIFSIGNALED(stat_val) is non-zero,
- *     this macro evaluates to the number of the signal that caused the
- *     termination of the child process.
- *   WIFSTOPPED(stat_val) - Evaluates to a non-zero value if status was
- *     returned for a child process that is currently stopped.
- *   WSTOPSIG(stat_val) - If the value of WIFSTOPPED(stat_val) is non-zero,
- *     this macro evaluates to the number of the signal that caused the child
- *     process to stop.
- *   WIFCONTINUED(stat_val) - Evaluates to a non-zero value if status was
- *    returned for a child process that has continued from a job control
- *    stop.
- *
- * Input Parameters:
- *   pid - The task ID of the thread to waid for
- *   stat_loc - The location to return the exit status
- *   options - ignored
- *
- * Returned Value:
- *   If waitpid() 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.
- *
- *   If waitpid() returns due to the delivery of a signal to the calling
- *   process, -1 will be returned and errno set to EINTR.
- *
- *   If waitpid() 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.
- *
- *   Otherwise, (pid_t)-1 will be returned, and errno set to indicate the
- *   error:
- *
- *   ECHILD - The process specified by pid does not exist or is not a child
- *            of the calling process, or the process group specified by pid
- *            does not exist does not have any member process that is a child
- *            of the calling process.
- *   EINTR - The function was interrupted by a signal. The value of the
- *           location pointed to by stat_loc is undefined.
- *   EINVAL - The options argument is not valid.
- *
- * Assumptions:
- *
- * Compatibility
- *   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.
- *
+ * Name: nx_waitpid
  ****************************************************************************/
 
 #ifndef CONFIG_SCHED_HAVE_PARENT
-pid_t waitpid(pid_t pid, int *stat_loc, int options)
+pid_t nx_waitpid(pid_t pid, int *stat_loc, int options)
 {
   FAR struct tcb_s *ctcb;
   FAR struct task_group_s *group;
   bool mystat = false;
-  int errcode;
   int ret;
 
   DEBUGASSERT(stat_loc);
 
-  /* waitpid() is a cancellation point */
-
-  enter_cancellation_point();
-
   /* Disable pre-emption so that nothing changes in the following tests */
 
   sched_lock();
@@ -206,8 +81,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
   ctcb = sched_gettcb(pid);
   if (ctcb == NULL)
     {
-      errcode = ECHILD;
-      goto errout_with_errno;
+      ret = -ECHILD;
+      goto errout;
     }
 
   /* Then the task group corresponding to this PID */
@@ -249,50 +124,46 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
       /* Don't wait if status is not available */
 
       ret = nxsem_trywait(&group->tg_exitsem);
-      group_delwaiter(group);
-
-      if (ret < 0)
-        {
-          pid = 0;
-        }
     }
   else
     {
       /* Wait if necessary for status to become available */
 
       ret = nxsem_wait(&group->tg_exitsem);
-      group_delwaiter(group);
+    }
 
-      if (ret < 0)
-        {
-          /* Unlock pre-emption and return the ERROR (nxsem_wait has already
-           * set the errno).  Handle the awkward case of whether or not we
-           * need to nullify the stat_loc value.
-           */
+  group_delwaiter(group);
 
-          if (mystat)
-            {
-              group->tg_statloc   = NULL;
-              group->tg_waitflags = 0;
-            }
+  if (ret < 0)
+    {
+      /* Handle the awkward case of whether or not we
+       * need to nullify the stat_loc value.
+       */
+
+      if (mystat)
+        {
+          group->tg_statloc   = NULL;
+          group->tg_waitflags = 0;
+        }
 
-          errcode = -ret;
-          goto errout_with_errno;
+      if ((options & WNOHANG) != 0)
+        {
+          pid = 0;
+        }
+      else
+        {
+          goto errout;
         }
     }
 
   /* On success, return the PID */
 
-  leave_cancellation_point();
   sched_unlock();
   return pid;
 
-errout_with_errno:
-  set_errno(errcode);
-
-  leave_cancellation_point();
+errout:
   sched_unlock();
-  return ERROR;
+  return ret;
 }
 
 /****************************************************************************
@@ -309,7 +180,7 @@ errout_with_errno:
  ****************************************************************************/
 
 #else
-pid_t waitpid(pid_t pid, int *stat_loc, int options)
+pid_t nx_waitpid(pid_t pid, int *stat_loc, int options)
 {
   FAR struct tcb_s *rtcb = this_task();
   FAR struct tcb_s *ctcb;
@@ -319,15 +190,10 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 #endif
   FAR struct siginfo info;
   sigset_t set;
-  int errcode;
   int ret;
 
   DEBUGASSERT(stat_loc);
 
-  /* waitpid() is a cancellation point */
-
-  enter_cancellation_point();
-
   /* Create a signal set that contains only SIGCHLD */
 
   sigemptyset(&set);
@@ -348,8 +214,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 
   if (rtcb->group->tg_children == NULL && retains)
     {
-      errcode = ECHILD;
-      goto errout_with_errno;
+      ret = -ECHILD;
+      goto errout;
     }
   else if (pid != (pid_t)-1)
     {
@@ -368,8 +234,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
           if (ctcb->group->tg_ppid != rtcb->pid)
 #endif
             {
-              errcode = ECHILD;
-              goto errout_with_errno;
+              ret = -ECHILD;
+              goto errout;
             }
         }
 
@@ -383,8 +249,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
 
           if (group_findchild(rtcb->group, pid) == NULL)
             {
-              errcode = ECHILD;
-              goto errout_with_errno;
+              ret = -ECHILD;
+              goto errout;
             }
         }
     }
@@ -395,8 +261,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
     {
       /* There are no children */
 
-      errcode = ECHILD;
-      goto errout_with_errno;
+      ret = -ECHILD;
+      goto errout;
     }
   else if (pid != (pid_t)-1)
     {
@@ -412,8 +278,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
       if (ctcb == NULL || ctcb->group->tg_ppid != rtcb->pid)
 #endif
         {
-          errcode = ECHILD;
-          goto errout_with_errno;
+          ret = -ECHILD;
+          goto errout;
         }
     }
 
@@ -497,8 +363,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
                * to reported ECHILD than bogus status.
                */
 
-              errcode = ECHILD;
-              goto errout_with_errno;
+              ret = -ECHILD;
+              goto errout;
             }
         }
 
@@ -518,8 +384,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
            * Let's return ECHILD.. that is at least informative.
            */
 
-          errcode = ECHILD;
-          goto errout_with_errno;
+          ret = -ECHILD;
+          goto errout;
         }
 
 #endif /* CONFIG_SCHED_CHILD_STATUS */
@@ -529,8 +395,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
       ret = nxsig_waitinfo(&set, &info);
       if (ret < 0)
         {
-          errcode = -ret;
-          goto errout_with_errno;
+          goto errout;
         }
 
       /* Was this the death of the thread we were waiting for? In the of
@@ -567,17 +432,158 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
         }
     }
 
-  leave_cancellation_point();
   sched_unlock();
-  return (int)pid;
-
-errout_with_errno:
-  set_errno(errcode);
+  return pid;
 
-  leave_cancellation_point();
+errout:
   sched_unlock();
-  return ERROR;
+  return ret;
 }
 #endif /* CONFIG_SCHED_HAVE_PARENT */
 
+/****************************************************************************
+ * Name: waitpid
+ *
+ * Description:
+ *   The waitpid() functions will obtain status information pertaining to one
+ *   of the caller's child processes. The waitpid() 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 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 waitpid(), return will be immediate.
+ *
+ *   The pid argument specifies a set of child processes for which status is
+ *   requested. The waitpid() function will only return the status of a child
+ *   process from this set:
+ *
+ *   - If pid is equal to (pid_t)-1, status is requested for any child
+ *     process. In this respect, waitpid() is then equivalent to wait().
+ *   - If pid is greater than 0, it specifies the process ID of a single
+ *     child process for which status is requested.
+ *   - If pid is 0, status is requested for any child process whose process
+ *     group ID is equal to that of the calling process.
+ *   - If pid is less than (pid_t)-1, status is requested for any child
+ *     process whose process group ID is equal to the absolute value of pid.
+ *
+ *   The options argument is constructed from the bitwise-inclusive OR of
+ *   zero or more of the following flags, defined in the <sys/wait.h> header:
+ *
+ *   WCONTINUED - The waitpid() 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.
+ *   WNOHANG - The waitpid() function will not suspend execution of the
+ *    calling thread if status is not immediately available for one of the
+ *    child processes specified by pid.
+ *   WUNTRACED - The status of any child processes specified by pid that are
+ *    stopped, and whose status has not yet been reported since they stopped,
+ *    will also be reported to the requesting process.
+ *
+ *   If the calling process has SA_NOCLDWAIT set or has SIGCHLD set to
+ *   SIG_IGN, 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 waitpid() will fail and set errno to ECHILD.
+ *
+ *   If waitpid() 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
+ *   stat_loc. The value stored at the location pointed to by stat_loc will
+ *   be 0 if and only if the status returned is from a terminated child
+ *   process that terminated by one of the following means:
+ *
+ *   1. The process returned 0 from main().
+ *   2. The process called _exit() or exit() with a status argument of 0.
+ *   3. The process was terminated because the last thread in the process
+ *      terminated.
+ *
+ *   Regardless of its value, this information may be interpreted using the
+ *   following macros, which are defined in <sys/wait.h> and evaluate to
+ *   integral expressions; the stat_val argument is the integer value pointed
+ *   to by stat_loc.
+ *
+ *   WIFEXITED(stat_val) - Evaluates to a non-zero value if status was
+ *     returned for a child process that terminated normally.
+ *   WEXITSTATUS(stat_val) - If the value of WIFEXITED(stat_val) is non-zero,
+ *     this macro evaluates to the low-order 8 bits of the status argument
+ *     that the child process passed to _exit() or exit(), or the value the
+ *     child process returned from main().
+ *   WIFSIGNALED(stat_val) - 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>).
+ *   WTERMSIG(stat_val)  - If the value of WIFSIGNALED(stat_val) is non-zero,
+ *     this macro evaluates to the number of the signal that caused the
+ *     termination of the child process.
+ *   WIFSTOPPED(stat_val) - Evaluates to a non-zero value if status was
+ *     returned for a child process that is currently stopped.
+ *   WSTOPSIG(stat_val) - If the value of WIFSTOPPED(stat_val) is non-zero,
+ *     this macro evaluates to the number of the signal that caused the child
+ *     process to stop.
+ *   WIFCONTINUED(stat_val) - Evaluates to a non-zero value if status was
+ *    returned for a child process that has continued from a job control
+ *    stop.
+ *
+ * Input Parameters:
+ *   pid - The task ID of the thread to waid for
+ *   stat_loc - The location to return the exit status
+ *   options - ignored
+ *
+ * Returned Value:
+ *   If waitpid() 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.
+ *
+ *   If waitpid() returns due to the delivery of a signal to the calling
+ *   process, -1 will be returned and errno set to EINTR.
+ *
+ *   If waitpid() 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.
+ *
+ *   Otherwise, (pid_t)-1 will be returned, and errno set to indicate the
+ *   error:
+ *
+ *   ECHILD - The process specified by pid does not exist or is not a child
+ *            of the calling process, or the process group specified by pid
+ *            does not exist does not have any member process that is a child
+ *            of the calling process.
+ *   EINTR - The function was interrupted by a signal. The value of the
+ *           location pointed to by stat_loc is undefined.
+ *   EINVAL - The options argument is not valid.
+ *
+ * Assumptions:
+ *
+ * Compatibility
+ *   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.
+ *
+ ****************************************************************************/
+
+pid_t waitpid(pid_t pid, int *stat_loc, int options)
+{
+  pid_t ret;
+
+  /* waitpid() is a cancellation point */
+
+  enter_cancellation_point();
+
+  /* Let nx_waitpid() do the work. */
+
+  ret = nx_waitpid(pid, stat_loc, options);
+  if (ret < 0)
+    {
+      set_errno(-ret);
+      ret = ERROR;
+    }
+
+  leave_cancellation_point();
+  return ret;
+}
+
 #endif /* CONFIG_SCHED_WAITPID */