mirror of
https://github.com/apache/nuttx.git
synced 2026-05-31 23:40:19 +08:00
Fix some missing logic and inconsistencies in child status logic; Fix a bug introduced into sigaction()
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5560 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -7,7 +7,7 @@ standards, things that could be improved, and ideas for enhancements.
|
|||||||
nuttx/
|
nuttx/
|
||||||
|
|
||||||
(11) Task/Scheduler (sched/)
|
(11) Task/Scheduler (sched/)
|
||||||
(1) Memory Managment (mm/)
|
(2) Memory Managment (mm/)
|
||||||
(3) Signals (sched/, arch/)
|
(3) Signals (sched/, arch/)
|
||||||
(2) pthreads (sched/)
|
(2) pthreads (sched/)
|
||||||
(2) C++ Support
|
(2) C++ Support
|
||||||
@@ -278,6 +278,19 @@ o Memory Managment (mm/)
|
|||||||
Priority: Medium/Low, a good feature to prevent memory leaks but would
|
Priority: Medium/Low, a good feature to prevent memory leaks but would
|
||||||
have negative impact on memory usage and code size.
|
have negative impact on memory usage and code size.
|
||||||
|
|
||||||
|
Title: CONTAINER ALLOCATOR
|
||||||
|
Description: There are several places where the logic requires allocation of
|
||||||
|
a tiny structure that just contains pointers to other things or
|
||||||
|
small amounts of data that needs to be bundled together. There
|
||||||
|
are examples net/net_poll.c and numerous other places.
|
||||||
|
|
||||||
|
I am wondering if it would not be good create a pool of generic
|
||||||
|
containers (say void *[4]). There re-use these when we need
|
||||||
|
small containers. The code in sched/task_childstatus.c might
|
||||||
|
be generalized for this purpose.
|
||||||
|
Status: Open
|
||||||
|
Priority: Very low (I am not even sure that this is a good idea yet).
|
||||||
|
|
||||||
o Signals (sched/, arch/)
|
o Signals (sched/, arch/)
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
|||||||
+1
-3
@@ -367,8 +367,7 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup)
|
|||||||
|
|
||||||
if (psock->s_type != SOCK_STREAM)
|
if (psock->s_type != SOCK_STREAM)
|
||||||
{
|
{
|
||||||
ret = -ENOSYS;
|
return -ENOSYS;
|
||||||
goto errout;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -387,7 +386,6 @@ int psock_poll(FAR struct socket *psock, FAR struct pollfd *fds, bool setup)
|
|||||||
ret = net_pollteardown(psock, fds);
|
ret = net_pollteardown(psock, fds);
|
||||||
}
|
}
|
||||||
|
|
||||||
errout:
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -124,6 +124,13 @@ config PREALLOC_CHILDSTATUS
|
|||||||
sa.sa_flags = SA_NOCLDWAIT;
|
sa.sa_flags = SA_NOCLDWAIT;
|
||||||
int ret = sigaction(SIGCHLD, &sa, NULL);
|
int ret = sigaction(SIGCHLD, &sa, NULL);
|
||||||
|
|
||||||
|
config DEBUG_CHILDSTATUS
|
||||||
|
bool "Enable Child Status Debug Output"
|
||||||
|
default n
|
||||||
|
depends on SCHED_CHILD_STATUS && DEBUG
|
||||||
|
---help---
|
||||||
|
Very detailed... I am sure that you do not want this.
|
||||||
|
|
||||||
config JULIAN_TIME
|
config JULIAN_TIME
|
||||||
bool "Enables Julian time conversions"
|
bool "Enables Julian time conversions"
|
||||||
default n
|
default n
|
||||||
|
|||||||
@@ -274,6 +274,7 @@ void weak_function task_initialize(void);
|
|||||||
FAR struct child_status_s *task_allocchild(void);
|
FAR struct child_status_s *task_allocchild(void);
|
||||||
void task_freechild(FAR struct child_status_s *status);
|
void task_freechild(FAR struct child_status_s *status);
|
||||||
void task_addchild(FAR _TCB *tcb, FAR struct child_status_s *child);
|
void task_addchild(FAR _TCB *tcb, FAR struct child_status_s *child);
|
||||||
|
FAR struct child_status_s *task_exitchild(FAR _TCB *tcb);
|
||||||
FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid);
|
FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid);
|
||||||
FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid);
|
FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid);
|
||||||
void task_removechildren(FAR _TCB *tcb);
|
void task_removechildren(FAR _TCB *tcb);
|
||||||
|
|||||||
+102
-34
@@ -53,6 +53,36 @@
|
|||||||
* Private Functions
|
* Private Functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Name: exitted_child
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Handle the case where a child exitted properlay was we (apparently) lost
|
||||||
|
* the detch of child signal.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
|
static void exitted_child(FAR _TCB *rtcb, FAR struct child_status_s *child,
|
||||||
|
FAR siginfo_t *info)
|
||||||
|
{
|
||||||
|
/* The child has exited. Return the saved exit status (and some fudged
|
||||||
|
* information.
|
||||||
|
*/
|
||||||
|
|
||||||
|
info->si_signo = SIGCHLD;
|
||||||
|
info->si_code = CLD_EXITED;
|
||||||
|
info->si_value.sival_ptr = NULL;
|
||||||
|
info->si_pid = child->ch_pid;
|
||||||
|
info->si_status = child->ch_status;
|
||||||
|
|
||||||
|
/* Discard the child entry */
|
||||||
|
|
||||||
|
(void)task_removechild(rtcb, child->ch_pid);
|
||||||
|
task_freechild(child);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Public Functions
|
* Public Functions
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
@@ -120,9 +150,14 @@
|
|||||||
*
|
*
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options)
|
int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||||
{
|
{
|
||||||
FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
|
FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
|
||||||
|
FAR _TCB *ctcb;
|
||||||
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
|
FAR struct child_status_s *child;
|
||||||
|
bool retains;
|
||||||
|
#endif
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
int err;
|
int err;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -160,7 +195,11 @@ int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
if (rtcb->children == NULL)
|
/* Does this task retain child status? */
|
||||||
|
|
||||||
|
retains = ((rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0);
|
||||||
|
|
||||||
|
if (rtcb->children == NULL && retains)
|
||||||
{
|
{
|
||||||
/* There are no children */
|
/* There are no children */
|
||||||
|
|
||||||
@@ -169,13 +208,29 @@ int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options)
|
|||||||
}
|
}
|
||||||
else if (idtype == P_PID)
|
else if (idtype == P_PID)
|
||||||
{
|
{
|
||||||
if (task_findchild(rtcb, (pid_t)id) == NULL)
|
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||||
{
|
|
||||||
/* This specific pid is not a child */
|
|
||||||
|
|
||||||
|
ctcb = sched_gettcb((pid_t)id);
|
||||||
|
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||||
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
goto errout_with_errno;
|
goto errout_with_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Does this task retain child status? */
|
||||||
|
|
||||||
|
if (retains)
|
||||||
|
{
|
||||||
|
/* Check if this specific pid has allocated child status? */
|
||||||
|
|
||||||
|
if (task_findchild(rtcb, (pid_t)id) == NULL)
|
||||||
|
{
|
||||||
|
/* This specific pid is not a child */
|
||||||
|
|
||||||
|
err = ECHILD;
|
||||||
|
goto errout_with_errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (rtcb->nchildren == 0)
|
if (rtcb->nchildren == 0)
|
||||||
@@ -189,7 +244,7 @@ int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options)
|
|||||||
{
|
{
|
||||||
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||||
|
|
||||||
FAR _TCB *ctcb = sched_gettcb((pid_t)id);
|
ctcb = sched_gettcb((pid_t)id);
|
||||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||||
{
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
@@ -209,48 +264,61 @@ int waitid(idtype_t idtype, id_t id, siginfo_t *info, int options)
|
|||||||
* instead).
|
* instead).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DEBUGASSERT(rtcb->children);
|
DEBUGASSERT(!retains || rtcb->children);
|
||||||
if (rtcb->children == NULL)
|
if (idtype == P_ALL)
|
||||||
{
|
{
|
||||||
/* This should not happen. I am just wasting your FLASH. */
|
/* We are waiting for any child to exit */
|
||||||
|
|
||||||
err = ECHILD;
|
if (retains && (child = task_exitchild(rtcb)) != NULL)
|
||||||
goto errout_with_errno;
|
{
|
||||||
|
/* A child has exitted. Apparently we missed the signal.
|
||||||
|
* Return the exit status and break out of the loop.
|
||||||
|
*/
|
||||||
|
|
||||||
|
exitted_child(rtcb, child, info);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (idtype == P_PID)
|
|
||||||
{
|
|
||||||
FAR struct child_status_s *child;
|
|
||||||
|
|
||||||
/* We are waiting for a specific PID. Get the current status
|
/* We are waiting for a specific PID. Does this task retain child status? */
|
||||||
* of the child task.
|
|
||||||
*/
|
else if (retains)
|
||||||
|
{
|
||||||
|
/* Yes ... Get the current status of the child task. */
|
||||||
|
|
||||||
child = task_findchild(rtcb, (pid_t)id);
|
child = task_findchild(rtcb, (pid_t)id);
|
||||||
DEBUGASSERT(child);
|
DEBUGASSERT(child);
|
||||||
if (!child)
|
|
||||||
{
|
|
||||||
/* Yikes! The child status entry just disappeared! */
|
|
||||||
|
|
||||||
err = ECHILD;
|
|
||||||
goto errout_with_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Did the child exit? */
|
/* Did the child exit? */
|
||||||
|
|
||||||
if ((child->ch_flags & CHILD_FLAG_EXITED) != 0)
|
if ((child->ch_flags & CHILD_FLAG_EXITED) != 0)
|
||||||
{
|
{
|
||||||
/* The child has exited. Return the saved exit status */
|
/* The child has exited. Return the exit status and break out
|
||||||
|
* of the loop.
|
||||||
|
*/
|
||||||
|
|
||||||
info->si_signo = SIGCHLD;
|
exitted_child(rtcb, child, info);
|
||||||
info->si_code = CLD_EXITED;
|
break;
|
||||||
info->si_value.sival_ptr = NULL;
|
}
|
||||||
info->si_pid = (pid_t)id;
|
}
|
||||||
info->si_status = child->ch_status;
|
else
|
||||||
|
{
|
||||||
|
/* We can use kill() with signal number 0 to determine if that
|
||||||
|
* task is still alive.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Discard the child entry and break out of the loop */
|
ret = kill((pid_t)id, 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 than bogus status.
|
||||||
|
*/
|
||||||
|
|
||||||
(void)task_removechild(rtcb, (pid_t)id);
|
err = ECHILD;
|
||||||
task_freechild(child);
|
goto errout_with_errno;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
|
|||||||
+83
-49
@@ -185,7 +185,7 @@
|
|||||||
#ifndef CONFIG_SCHED_HAVE_PARENT
|
#ifndef CONFIG_SCHED_HAVE_PARENT
|
||||||
pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||||
{
|
{
|
||||||
_TCB *tcb;
|
_TCB *ctcb;
|
||||||
bool mystat;
|
bool mystat;
|
||||||
int err;
|
int err;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -208,8 +208,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
/* Get the TCB corresponding to this PID */
|
/* Get the TCB corresponding to this PID */
|
||||||
|
|
||||||
tcb = sched_gettcb(pid);
|
ctcb = sched_gettcb(pid);
|
||||||
if (!tcb)
|
if (!ctcb)
|
||||||
{
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
goto errout_with_errno;
|
goto errout_with_errno;
|
||||||
@@ -221,15 +221,15 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
* others?
|
* others?
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (stat_loc != NULL && tcb->stat_loc == NULL)
|
if (stat_loc != NULL && ctcb->stat_loc == NULL)
|
||||||
{
|
{
|
||||||
tcb->stat_loc = stat_loc;
|
ctcb->stat_loc = stat_loc;
|
||||||
mystat = true;
|
mystat = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Then wait for the task to exit */
|
/* Then wait for the task to exit */
|
||||||
|
|
||||||
ret = sem_wait(&tcb->exitsem);
|
ret = sem_wait(&ctcb->exitsem);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
/* Unlock pre-emption and return the ERROR (sem_wait has already set
|
/* Unlock pre-emption and return the ERROR (sem_wait has already set
|
||||||
@@ -239,7 +239,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
if (mystat)
|
if (mystat)
|
||||||
{
|
{
|
||||||
tcb->stat_loc = NULL;
|
ctcb->stat_loc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
goto errout;
|
goto errout;
|
||||||
@@ -274,8 +274,10 @@ errout:
|
|||||||
pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||||
{
|
{
|
||||||
FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
|
FAR _TCB *rtcb = (FAR _TCB *)g_readytorun.head;
|
||||||
|
FAR _TCB *ctcb;
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
FAR struct child_status_s *child;
|
FAR struct child_status_s *child;
|
||||||
|
bool retains;
|
||||||
#endif
|
#endif
|
||||||
FAR struct siginfo info;
|
FAR struct siginfo info;
|
||||||
sigset_t sigset;
|
sigset_t sigset;
|
||||||
@@ -303,27 +305,43 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
sched_lock();
|
sched_lock();
|
||||||
|
|
||||||
/* Verify that this task actually has children and that the the request
|
/* Verify that this task actually has children and that the requested PID
|
||||||
* TCB is actually a child of this task.
|
* is actually a child of this task.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
if (rtcb->children == NULL)
|
/* Does this task retain child status? */
|
||||||
{
|
|
||||||
/* There are no children */
|
|
||||||
|
|
||||||
|
retains = ((rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0);
|
||||||
|
|
||||||
|
if (rtcb->children == NULL && retains)
|
||||||
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
goto errout_with_errno;
|
goto errout_with_errno;
|
||||||
}
|
}
|
||||||
else if (pid != (pid_t)-1)
|
else if (pid != (pid_t)-1)
|
||||||
{
|
{
|
||||||
/* This specific pid is not a child */
|
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||||
|
|
||||||
if (task_findchild(rtcb, pid) == NULL)
|
ctcb = sched_gettcb(pid);
|
||||||
|
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||||
{
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
goto errout_with_errno;
|
goto errout_with_errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Does this task retain child status? */
|
||||||
|
|
||||||
|
if (retains)
|
||||||
|
{
|
||||||
|
/* Check if this specific pid has allocated child status? */
|
||||||
|
|
||||||
|
if (task_findchild(rtcb, pid) == NULL)
|
||||||
|
{
|
||||||
|
err = ECHILD;
|
||||||
|
goto errout_with_errno;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
if (rtcb->nchildren == 0)
|
if (rtcb->nchildren == 0)
|
||||||
@@ -337,7 +355,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
{
|
{
|
||||||
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||||
|
|
||||||
FAR _TCB *ctcb = sched_gettcb(pid);
|
ctcb = sched_gettcb(pid);
|
||||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||||
{
|
{
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
@@ -350,6 +368,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
/* Check if the task has already died. Signals are not queued in
|
/* Check if the task has already died. Signals are not queued in
|
||||||
* NuttX. So a possibility is that the child has died and we
|
* NuttX. So a possibility is that the child has died and we
|
||||||
* missed the death of child signal (we got some other signal
|
* missed the death of child signal (we got some other signal
|
||||||
@@ -362,39 +381,33 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
* chilren.
|
* chilren.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
DEBUGASSERT(!retains || rtcb->children);
|
||||||
DEBUGASSERT(rtcb->children);
|
if (retains && (child = task_exitchild(rtcb)) != NULL)
|
||||||
if (rtcb->children == NULL)
|
|
||||||
#else
|
|
||||||
if (rtcb->nchildren == 0)
|
|
||||||
#endif
|
|
||||||
{
|
{
|
||||||
/* There were one or more children when we started so they
|
/* A child has exitted. Apparently we missed the signal.
|
||||||
* must have exit'ed. There are just no bread crumbs left
|
* Return the saved exit status.
|
||||||
* behind to tell us the PID(s) of the existed children.
|
|
||||||
* Reporting ECHLD is about all we can do in this case.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
err = ECHILD;
|
/* The child has exited. Return the saved exit status */
|
||||||
goto errout_with_errno;
|
|
||||||
|
*stat_loc = child->ch_status;
|
||||||
|
|
||||||
|
/* Discard the child entry and break out of the loop */
|
||||||
|
|
||||||
|
(void)task_removechild(rtcb, child->ch_pid);
|
||||||
|
task_freechild(child);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
/* We are waiting for a specific PID. Does this task retain child status? */
|
||||||
|
|
||||||
|
else if (retains)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
/* Get the current status of the child task. */
|
||||||
/* We are waiting for a specific PID. Get the current status
|
|
||||||
* of the child task.
|
|
||||||
*/
|
|
||||||
|
|
||||||
child = task_findchild(rtcb, pid);
|
child = task_findchild(rtcb, pid);
|
||||||
DEBUGASSERT(child);
|
DEBUGASSERT(child);
|
||||||
if (!child)
|
|
||||||
{
|
|
||||||
/* Yikes! The child status entry just disappeared! */
|
|
||||||
|
|
||||||
err = ECHILD;
|
|
||||||
goto errout_with_errno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Did the child exit? */
|
/* Did the child exit? */
|
||||||
|
|
||||||
@@ -408,27 +421,48 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
|||||||
|
|
||||||
(void)task_removechild(rtcb, pid);
|
(void)task_removechild(rtcb, pid);
|
||||||
task_freechild(child);
|
task_freechild(child);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
#else
|
}
|
||||||
/* We are waiting for a specific PID. We can use kill() with
|
else
|
||||||
* signal number 0 to determine if that task is still alive.
|
{
|
||||||
|
/* We can use kill() with signal number 0 to determine if that
|
||||||
|
* task is still alive.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ret = kill(pid, 0);
|
ret = kill(pid, 0);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
/* It is no longer running. We know that the child task was
|
/* It is no longer running. We know that the child task
|
||||||
* running okay when we started, so we must have lost the
|
* was running okay when we started, so we must have lost
|
||||||
* signal. In this case, we know that the task exit'ed, but
|
* the signal. In this case, we know that the task exit'ed,
|
||||||
* we do not know its exit status. It would be better to
|
* but we do not know its exit status. It would be better
|
||||||
* reported ECHILD that bogus status.
|
* to reported ECHILD than bogus status.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
err = ECHILD;
|
err = ECHILD;
|
||||||
goto errout_with_errno;
|
goto errout_with_errno;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
/* 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 ||
|
||||||
|
(pid != (pid_t)-1 && (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;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Wait for any death-of-child signal */
|
/* Wait for any death-of-child signal */
|
||||||
|
|
||||||
|
|||||||
+14
-8
@@ -169,7 +169,6 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
|
|||||||
{
|
{
|
||||||
FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
|
FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
|
||||||
FAR sigactq_t *sigact;
|
FAR sigactq_t *sigact;
|
||||||
int ret;
|
|
||||||
|
|
||||||
/* Since sigactions can only be installed from the running thread of
|
/* Since sigactions can only be installed from the running thread of
|
||||||
* execution, no special precautions should be necessary.
|
* execution, no special precautions should be necessary.
|
||||||
@@ -251,24 +250,31 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
|
|||||||
|
|
||||||
if (act->sa_u._sa_handler == SIG_IGN)
|
if (act->sa_u._sa_handler == SIG_IGN)
|
||||||
{
|
{
|
||||||
/* If there is a old sigaction, remove it from sigactionq */
|
/* Do we still have a sigaction container from the previous setting? */
|
||||||
|
|
||||||
sq_rem((FAR sq_entry_t*)sigact, &rtcb->sigactionq);
|
if (sigact)
|
||||||
|
{
|
||||||
|
/* Yes.. Remove it from sigactionq */
|
||||||
|
|
||||||
/* And deallocate it */
|
sq_rem((FAR sq_entry_t*)sigact, &rtcb->sigactionq);
|
||||||
|
|
||||||
sig_releaseaction(sigact);
|
/* And deallocate it */
|
||||||
|
|
||||||
|
sig_releaseaction(sigact);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* A sigaction has been supplied */
|
/* A sigaction has been supplied */
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Check if a sigaction was found */
|
/* Do we still have a sigaction container from the previous setting?
|
||||||
|
* If so, then re-use for the new signal action.
|
||||||
|
*/
|
||||||
|
|
||||||
if (!sigact)
|
if (!sigact)
|
||||||
{
|
{
|
||||||
/* No sigaction was found, but one is needed. Allocate one. */
|
/* No.. Then we need to allocate one for the new action. */
|
||||||
|
|
||||||
sigact = sig_allocateaction();
|
sigact = sig_allocateaction();
|
||||||
|
|
||||||
@@ -294,7 +300,7 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
|
|||||||
COPY_SIGACTION(&sigact->act, act);
|
COPY_SIGACTION(&sigact->act, act);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
|
|||||||
@@ -297,6 +297,42 @@ FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************
|
||||||
|
* Name: task_exitchild
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
* Search for any child that has exitted.
|
||||||
|
*
|
||||||
|
* Parameters:
|
||||||
|
* tcb - The TCB of the parent task to containing the child status.
|
||||||
|
*
|
||||||
|
* Return Value:
|
||||||
|
* On success, a non-NULL pointer to a child status structure for the
|
||||||
|
* exited child. NULL is returned if not child has exited.
|
||||||
|
*
|
||||||
|
* Assumptions:
|
||||||
|
* Called during SIGCHLD processing in a safe context. No special precautions
|
||||||
|
* are required here.
|
||||||
|
*
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
FAR struct child_status_s *task_exitchild(FAR _TCB *tcb)
|
||||||
|
{
|
||||||
|
FAR struct child_status_s *child;
|
||||||
|
|
||||||
|
/* Find the status structure with the matching PID */
|
||||||
|
|
||||||
|
for (child = tcb->children; child; child = child->flink)
|
||||||
|
{
|
||||||
|
if ((child->ch_flags & CHILD_FLAG_EXITED) != 0)
|
||||||
|
{
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Name: task_removechild
|
* Name: task_removechild
|
||||||
*
|
*
|
||||||
|
|||||||
+21
-3
@@ -138,14 +138,32 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
|||||||
child = task_removechild(otcb, chpid);
|
child = task_removechild(otcb, chpid);
|
||||||
if (child)
|
if (child)
|
||||||
{
|
{
|
||||||
/* Add the child status entry to the new parent TCB */
|
/* Has the new parent supressed child exit status? */
|
||||||
|
|
||||||
|
if ((ptcb->flags && TCB_FLAG_NOCLDWAIT) == 0)
|
||||||
|
{
|
||||||
|
/* No.. Add the child status entry to the new parent TCB */
|
||||||
|
|
||||||
|
task_addchild(ptcb, child);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Yes.. Discard the child status entry */
|
||||||
|
|
||||||
|
task_freechild(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Either case is a success */
|
||||||
|
|
||||||
task_addchild(ptcb, child);
|
|
||||||
ret = OK;
|
ret = OK;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = -ENOENT;
|
/* This would not be an error if the original parent has
|
||||||
|
* suppressed child exit status.
|
||||||
|
*/
|
||||||
|
|
||||||
|
ret = ((otcb->flags && TCB_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
DEBUGASSERT(otcb->nchildren > 0);
|
DEBUGASSERT(otcb->nchildren > 0);
|
||||||
|
|||||||
+17
-10
@@ -150,7 +150,8 @@ static int task_assignpid(FAR _TCB *tcb)
|
|||||||
* Name: task_saveparent
|
* Name: task_saveparent
|
||||||
*
|
*
|
||||||
* Description:
|
* Description:
|
||||||
* Save the task ID of the parent task in the child task's TCB.
|
* Save the task ID of the parent task in the child task's TCB and allocate
|
||||||
|
* a child status structure to catch the child task's exit status.
|
||||||
*
|
*
|
||||||
* Parameters:
|
* Parameters:
|
||||||
* tcb - The TCB of the new, child task.
|
* tcb - The TCB of the new, child task.
|
||||||
@@ -177,11 +178,15 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
|
|||||||
|
|
||||||
tcb->parent = rtcb->pid;
|
tcb->parent = rtcb->pid;
|
||||||
|
|
||||||
/* Exit status only needs to be retained for the case of tasks, however */
|
|
||||||
|
|
||||||
if (ttype == TCB_FLAG_TTYPE_TASK)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||||
|
/* Exit status only needs to be retained for the case of tasks, however.
|
||||||
|
* Tasks can also suppress retention of their child status by applying
|
||||||
|
* the SA_NOCLDWAIT flag with sigaction()/
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (ttype == TCB_FLAG_TTYPE_TASK &&
|
||||||
|
(rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0)
|
||||||
|
{
|
||||||
FAR struct child_status_s *child;
|
FAR struct child_status_s *child;
|
||||||
|
|
||||||
/* Make sure that there is not already a structure for this PID in the
|
/* Make sure that there is not already a structure for this PID in the
|
||||||
@@ -212,11 +217,11 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
|
|||||||
|
|
||||||
task_addchild(rtcb, child);
|
task_addchild(rtcb, child);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
DEBUGASSERT(rtcb->nchildren < UINT16_MAX);
|
|
||||||
rtcb->nchildren++;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
DEBUGASSERT(rtcb->nchildren < UINT16_MAX);
|
||||||
|
rtcb->nchildren++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
# define task_saveparent(tcb,ttype)
|
# define task_saveparent(tcb,ttype)
|
||||||
@@ -318,7 +323,9 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start, main_t main,
|
|||||||
tcb->flags &= ~TCB_FLAG_TTYPE_MASK;
|
tcb->flags &= ~TCB_FLAG_TTYPE_MASK;
|
||||||
tcb->flags |= ttype;
|
tcb->flags |= ttype;
|
||||||
|
|
||||||
/* Save the task ID of the parent task in the TCB */
|
/* Save the task ID of the parent task in the TCB and allocate
|
||||||
|
* a child status structure.
|
||||||
|
*/
|
||||||
|
|
||||||
task_saveparent(tcb, ttype);
|
task_saveparent(tcb, ttype);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user