Add logic to retain child task exit status if so configured

git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5553 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo
2013-01-23 22:23:46 +00:00
parent f86f863834
commit 340a72b7cd
23 changed files with 846 additions and 223 deletions
+78 -47
View File
@@ -39,24 +39,44 @@
#include <nuttx/config.h>
#include <sched.h>
#include <errno.h>
#include <debug.h>
#include "os_internal.h"
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
/*****************************************************************************
* Pre-processor Definitions
*****************************************************************************/
/* Note that there cannot be more that CONFIG_MAX_TASKS tasks in total.
* However, the number of child status structures may need to be significantly
* larger because this number includes the maximum number of tasks that are
* running PLUS the number of tasks that have exit'ed without having their
* exit status reaped (via wait(), waitid(), or waitpid()).
*
* Obviously, if tasks spawn children indefinitely and never have the exit
* status reaped, then you have a memory leak!
*/
#if !defined(CONFIG_PREALLOC_CHILDSTATUS) || CONFIG_PREALLOC_CHILDSTATUS == 0
# undef CONFIG_PREALLOC_CHILDSTATUS
# define CONFIG_PREALLOC_CHILDSTATUS (2*CONFIG_MAX_TASKS)
#endif
#ifndef CONFIG_DEBUG
# undef CONFIG_DEBUG_CHILDSTATUS
#endif
/*****************************************************************************
* Private Types
*****************************************************************************/
/* Globals are maintained in a structure to minimize name collisions. Note
* that there cannot be more that CONFIG_MAX_TASKS tasks in total. So using
* CONFIG_MAX_TASKS should be sufficient (at least one task, the IDLE thread,
* will have no parent).
*/
/* Globals are maintained in a structure to minimize name collisions. */
struct child_pool_s
{
struct child_status_s alloc[CONFIG_MAX_TASKS];
struct child_status_s alloc[CONFIG_PREALLOC_CHILDSTATUS];
FAR struct child_status_s *freelist;
};
@@ -70,6 +90,40 @@ static struct child_pool_s g_child_pool;
* Private Functions
*****************************************************************************/
/*****************************************************************************
* Name: task_dumpchildren
*
* Description:
* Dump all of the children when the part TCB list is modified.
*
* Parameters:
* tcb - The parent TCB.
*
* Return Value:
* None.
*
* Assumptions:
* Called early in initialization. No special precautions are required.
*
*****************************************************************************/
#ifdef CONFIG_DEBUG_CHILDSTATUS
static void task_dumpchildren(FAR _TCB *tcb, FAR const char *msg)
{
FAR struct child_status_s *child;
int i;
dbg("Parent TCB=%p: %s\n", tcb, msg);
for (i = 0, child = tcb->children; child; i++, child = child->flink)
{
dbg(" %d. ch_flags=%02x ch_pid=%d ch_status=%d\n",
i, child->ch_flags, child->ch_pid, child->ch_status);
}
}
#else
# task_dumpchildren(t,m)
#endif
/*****************************************************************************
* Public Functions
*****************************************************************************/
@@ -88,7 +142,7 @@ static struct child_pool_s g_child_pool;
* None.
*
* Assumptions:
* Called early in initializatin. No special precautions are required.
* Called early in initialization. No special precautions are required.
*
*****************************************************************************/
@@ -102,11 +156,11 @@ void task_initialize(void)
prev = &g_child_pool.alloc[0];
g_child_pool.freelist = prev;
for (i = 0; i < CONFIG_MAX_TASKS; i++)
for (i = 0; i < CONFIG_PREALLOC_CHILDSTATUS; i++)
{
curr = &g_child_pool.alloc[i]
curr = &g_child_pool.alloc[i];
prev->flink = curr;
prev = curr;
prev = curr;
}
}
@@ -140,7 +194,7 @@ FAR struct child_status_s *task_allocchild(void)
if (ret)
{
g_child_pool.freelist = ret->flink;
ret->flink = NULL;
ret->flink = NULL;
}
return ret;
@@ -170,7 +224,7 @@ void task_freechild(FAR struct child_status_s *child)
if (child)
{
child->flink = g_child_pool.freelist;
child->flink = g_child_pool.freelist;
g_child_pool.freelist = child;
}
}
@@ -179,18 +233,14 @@ void task_freechild(FAR struct child_status_s *child)
* Name: task_addchild
*
* Description:
* Find a child status structure in the given TCB.
* Add a child status structure in the given TCB.
*
* Parameters:
* tcb - The TCB of the parent task to containing the child status.
* pid - The ID of the child to create
* status - Child exit status (should be zero)
* flags - Child flags (see CHILD_FLAGS_* defininitions)
* child - The structure to be added
*
* Return Value:
* On success, a non-NULL pointer to a child status structure. NULL is
* returned if (1) there are no free status structures, or (2) an entry
* with this PID already exists.
* N
*
* Assumptions:
* Called during task creation processing in a safe context. No special
@@ -198,37 +248,14 @@ void task_freechild(FAR struct child_status_s *child)
*
*****************************************************************************/
FAR struct child_status_s *task_addchild(FAR _TCB *tcb, pid_t pid, int status,
uint8_t flags)
void task_addchild(FAR _TCB *tcb, FAR struct child_status_s *child)
{
FAR struct child_status_s *child;
/* Add the entry into the TCB list of children */
/* Make sure that there is not already a structure for this PID */
child->flink = tcb->children;
tcb->children = child;
child = task_findchild(tcb, pid);
if (child)
{
return NULL;
}
/* Allocate a new status structure */
child = task_allocchild(void);
if (child)
{
/* Initialize the structure */
child->ch_flags = flags;
child->ch_pid = pid;
child->ch_status = status;
/* Add the entry into the TCB list of children */
status->flink = tcb->children;
tcb->childen = status;
}
return child;
task_dumpchildren(tcb, "task_addchild");
}
/*****************************************************************************
@@ -325,6 +352,7 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
}
curr->flink = NULL;
task_dumpchildren(tcb, "task_removechild");
}
return curr;
@@ -360,6 +388,9 @@ void task_removechildren(FAR _TCB *tcb)
next = curr->flink;
task_freechild(curr);
}
tcb->children = NULL;
task_dumpchildren(tcb, "task_removechildren");
}
#endif /* CONFIG_SCHED_HAVE_PARENT && CONFIG_SCHED_CHILD_STATUS */