Don't keep the parent task's task ID in the child task's TCB. Instead, keep the parent task group IN the child task's task group.
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5566 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
parent
0cefbf4762
commit
fc8136d5d3
@ -4031,4 +4031,6 @@
|
||||
members for the parent task group.
|
||||
* include/nuttx/sched.h and sched/env_*.c: Move environment
|
||||
variables into task group structure.
|
||||
|
||||
* sched/: Lots of file changed. Don't keep the parent task's
|
||||
task ID in the child task's TCB. Instead, keep the parent
|
||||
task group IN the child task's task group.
|
||||
|
@ -95,6 +95,7 @@
|
||||
#define TCB_FLAG_NONCANCELABLE (1 << 2) /* Bit 2: Pthread is non-cancelable */
|
||||
#define TCB_FLAG_CANCEL_PENDING (1 << 3) /* Bit 3: Pthread cancel is pending */
|
||||
#define TCB_FLAG_ROUND_ROBIN (1 << 4) /* Bit 4: Round robin sched enabled */
|
||||
#define TCB_FLAG_EXIT_PROCESSING (1 << 5) /* Bit 5: Exitting */
|
||||
|
||||
/* Values for struct task_group tg_flags */
|
||||
|
||||
@ -253,6 +254,11 @@ struct dspace_s
|
||||
#ifdef HAVE_TASK_GROUP
|
||||
struct task_group_s
|
||||
{
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
struct task_group_s *flink; /* Supports a singly linked list */
|
||||
gid_t tg_gid; /* The ID of this task group */
|
||||
gid_t tg_pgid; /* The ID of the parent task group */
|
||||
#endif
|
||||
uint8_t tg_flags; /* See GROUP_FLAG_* definitions */
|
||||
|
||||
/* Group membership ***********************************************************/
|
||||
@ -311,12 +317,16 @@ struct _TCB
|
||||
/* Task Management Fields *****************************************************/
|
||||
|
||||
pid_t pid; /* This is the ID of the thread */
|
||||
|
||||
#ifdef CONFIG_SCHED_HAVE_PARENT /* Support parent-child relationship */
|
||||
pid_t parent; /* This is the ID of the parent thread */
|
||||
#ifndef HAVE_GROUP_MEMBERS /* Don't know pids of group members */
|
||||
pid_t ppid; /* This is the ID of the parent thread */
|
||||
#ifndef CONFIG_SCHED_CHILD_STATUS /* Retain child thread status */
|
||||
uint16_t nchildren; /* This is the number active children */
|
||||
#endif
|
||||
#endif
|
||||
#endif /* CONFIG_SCHED_HAVE_PARENT */
|
||||
|
||||
start_t start; /* Thread start function */
|
||||
entry_t entry; /* Entry Point into the thread */
|
||||
|
||||
|
@ -73,13 +73,6 @@ ifeq ($(CONFIG_PRIORITY_INHERITANCE),y)
|
||||
SCHED_SRCS += sched_reprioritize.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_HAVE_PARENT),y)
|
||||
SCHED_SRCS += task_reparent.c
|
||||
ifeq ($(CONFIG_SCHED_CHILD_STATUS),y)
|
||||
SCHED_SRCS += task_childstatus.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_SCHED_WAITPID),y)
|
||||
SCHED_SRCS += sched_waitpid.c
|
||||
ifeq ($(CONFIG_SCHED_HAVE_PARENT),y)
|
||||
@ -87,7 +80,14 @@ SCHED_SRCS += sched_waitid.c sched_wait.c
|
||||
endif
|
||||
endif
|
||||
|
||||
GRP_SRCS = group_create.c group_join.c group_leave.c
|
||||
GRP_SRCS = group_create.c group_join.c group_leave.c group_find.c
|
||||
|
||||
ifeq ($(CONFIG_SCHED_HAVE_PARENT),y)
|
||||
GRP_SRCS += task_reparent.c
|
||||
ifeq ($(CONFIG_SCHED_CHILD_STATUS),y)
|
||||
GRP_SRCS += group_childstatus.c
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(CONFIG_DISABLE_SIGNALS),y)
|
||||
GRP_SRCS += group_signal.c
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* sched/task_childstatus.c
|
||||
* sched/group_childstatus.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
@ -92,13 +92,13 @@ static struct child_pool_s g_child_pool;
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_dumpchildren
|
||||
* Name: group_dumpchildren
|
||||
*
|
||||
* Description:
|
||||
* Dump all of the children when the part TCB list is modified.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The parent TCB.
|
||||
* group - The task group containing the child status.
|
||||
*
|
||||
* Return Value:
|
||||
* None.
|
||||
@ -109,13 +109,13 @@ static struct child_pool_s g_child_pool;
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_DEBUG_CHILDSTATUS
|
||||
static void task_dumpchildren(FAR _TCB *tcb, FAR const char *msg)
|
||||
static void group_dumpchildren(FAR struct task_group_s *group,
|
||||
FAR const char *msg)
|
||||
{
|
||||
FAR struct child_status_s *child;
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
int i;
|
||||
|
||||
dbg("Parent TCB=%p group=%p: %s\n", tcb, group, msg);
|
||||
dbg("Task group=%p: %s\n", group, msg);
|
||||
for (i = 0, child = group->tg_children; child; i++, child = child->flink)
|
||||
{
|
||||
dbg(" %d. ch_flags=%02x ch_pid=%d ch_status=%d\n",
|
||||
@ -123,7 +123,7 @@ static void task_dumpchildren(FAR _TCB *tcb, FAR const char *msg)
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define task_dumpchildren(t,m)
|
||||
# define group_dumpchildren(t,m)
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
@ -167,7 +167,7 @@ void task_initialize(void)
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_allocchild
|
||||
* Name: group_allocchild
|
||||
*
|
||||
* Description:
|
||||
* Allocate a child status structure by removing the next entry from a
|
||||
@ -186,7 +186,7 @@ void task_initialize(void)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
FAR struct child_status_s *task_allocchild(void)
|
||||
FAR struct child_status_s *group_allocchild(void)
|
||||
{
|
||||
FAR struct child_status_s *ret;
|
||||
|
||||
@ -203,7 +203,7 @@ FAR struct child_status_s *task_allocchild(void)
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_freechild
|
||||
* Name: group_freechild
|
||||
*
|
||||
* Description:
|
||||
* Release a child status structure by returning it to a free list.
|
||||
@ -220,7 +220,7 @@ FAR struct child_status_s *task_allocchild(void)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void task_freechild(FAR struct child_status_s *child)
|
||||
void group_freechild(FAR struct child_status_s *child)
|
||||
{
|
||||
/* Return the child status structure to the free list */
|
||||
|
||||
@ -232,13 +232,13 @@ void task_freechild(FAR struct child_status_s *child)
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_addchild
|
||||
* Name: group_addchild
|
||||
*
|
||||
* Description:
|
||||
* Add a child status structure in the given TCB.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the parent task to containing the child status.
|
||||
* group - The task group for the child status.
|
||||
* child - The structure to be added
|
||||
*
|
||||
* Return Value:
|
||||
@ -250,28 +250,27 @@ void task_freechild(FAR struct child_status_s *child)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void task_addchild(FAR _TCB *tcb, FAR struct child_status_s *child)
|
||||
void group_addchild(FAR struct task_group_s *group,
|
||||
FAR struct child_status_s *child)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
|
||||
/* Add the entry into the TCB list of children */
|
||||
|
||||
child->flink = group->tg_children;
|
||||
group->tg_children = child;
|
||||
|
||||
task_dumpchildren(tcb, "task_addchild");
|
||||
group_dumpchildren(group, "group_addchild");
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_findchild
|
||||
* Name: group_findchild
|
||||
*
|
||||
* Description:
|
||||
* Find a child status structure in the given TCB. A reference to the
|
||||
* child structure is returned, but the child remains the the TCB's list
|
||||
* of children.
|
||||
* Find a child status structure in the given task group. A reference to
|
||||
* the child structure is returned, but the child remains the the group's
|
||||
* list of children.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the parent task to containing the child status.
|
||||
* group - The ID of the parent task group to containing the child status.
|
||||
* pid - The ID of the child to find.
|
||||
*
|
||||
* Return Value:
|
||||
@ -284,11 +283,13 @@ void task_addchild(FAR _TCB *tcb, FAR struct child_status_s *child)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid)
|
||||
FAR struct child_status_s *group_findchild(FAR struct task_group_s *group,
|
||||
pid_t pid)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
FAR struct child_status_s *child;
|
||||
|
||||
DEBUGASSERT(group);
|
||||
|
||||
/* Find the status structure with the matching PID */
|
||||
|
||||
for (child = group->tg_children; child; child = child->flink)
|
||||
@ -303,7 +304,7 @@ FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid)
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_exitchild
|
||||
* Name: group_exitchild
|
||||
*
|
||||
* Description:
|
||||
* Search for any child that has exitted.
|
||||
@ -321,9 +322,8 @@ FAR struct child_status_s *task_findchild(FAR _TCB *tcb, pid_t pid)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
FAR struct child_status_s *task_exitchild(FAR _TCB *tcb)
|
||||
FAR struct child_status_s *group_exitchild(FAR struct task_group_s *group)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
FAR struct child_status_s *child;
|
||||
|
||||
/* Find the status structure of any child task that has exitted. */
|
||||
@ -340,15 +340,15 @@ FAR struct child_status_s *task_exitchild(FAR _TCB *tcb)
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_removechild
|
||||
* Name: group_removechild
|
||||
*
|
||||
* Description:
|
||||
* Remove one child structure from the TCB. The child is removed, but is
|
||||
* not yet freed. task_freechild must be called in order to free the child
|
||||
* status structure.
|
||||
* Remove one child structure from a task group. The child is removed, but
|
||||
* is not yet freed. group_freechild must be called in order to free the
|
||||
* child status structure.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the parent task to containing the child status.
|
||||
* group - The task group containing the child status.
|
||||
* pid - The ID of the child to find.
|
||||
*
|
||||
* Return Value:
|
||||
@ -361,13 +361,15 @@ FAR struct child_status_s *task_exitchild(FAR _TCB *tcb)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
|
||||
FAR struct child_status_s *group_removechild(FAR struct task_group_s *group,
|
||||
pid_t pid)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
FAR struct child_status_s *curr;
|
||||
FAR struct child_status_s *prev;
|
||||
|
||||
/* Find the status structure with the matching PID */
|
||||
DEBUGASSERT(group);
|
||||
|
||||
/* Find the status structure with the matching PID */
|
||||
|
||||
for (prev = NULL, curr = group->tg_children;
|
||||
curr;
|
||||
@ -379,7 +381,7 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
|
||||
}
|
||||
}
|
||||
|
||||
/* Did we find it? If so, remove it from the TCB. */
|
||||
/* Did we find it? If so, remove it from the group. */
|
||||
|
||||
if (curr)
|
||||
{
|
||||
@ -395,20 +397,20 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
|
||||
}
|
||||
|
||||
curr->flink = NULL;
|
||||
task_dumpchildren(tcb, "task_removechild");
|
||||
group_dumpchildren(group, "group_removechild");
|
||||
}
|
||||
|
||||
return curr;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: task_removechildren
|
||||
* Name: group_removechildren
|
||||
*
|
||||
* Description:
|
||||
* Remove and free all child structure from the TCB.
|
||||
* Remove and free all child structure from the task group.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The TCB of the parent task to containing the child status.
|
||||
* group - The task group containing the child status.
|
||||
*
|
||||
* Return Value:
|
||||
* None.
|
||||
@ -419,9 +421,8 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
void task_removechildren(FAR _TCB *tcb)
|
||||
void group_removechildren(FAR struct task_group_s *group)
|
||||
{
|
||||
FAR struct task_group_s *group = tcb->group;
|
||||
FAR struct child_status_s *curr;
|
||||
FAR struct child_status_s *next;
|
||||
|
||||
@ -430,11 +431,11 @@ void task_removechildren(FAR _TCB *tcb)
|
||||
for (curr = group->tg_children; curr; curr = next)
|
||||
{
|
||||
next = curr->flink;
|
||||
task_freechild(curr);
|
||||
group_freechild(curr);
|
||||
}
|
||||
|
||||
group->tg_children = NULL;
|
||||
task_dumpchildren(tcb, "task_removechildren");
|
||||
group_dumpchildren(group, "group_removechildren");
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SCHED_HAVE_PARENT && CONFIG_SCHED_CHILD_STATUS */
|
@ -1,5 +1,5 @@
|
||||
/*****************************************************************************
|
||||
* sched/group_allocate.c
|
||||
* sched/group_create.c
|
||||
*
|
||||
* Copyright (C) 2013 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <gnutt@nuttx.org>
|
||||
@ -65,11 +65,87 @@
|
||||
/*****************************************************************************
|
||||
* Private Data
|
||||
*****************************************************************************/
|
||||
/* This is counter that is used to generate unique task group IDs */
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
static gid_t g_gidcounter;
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Data
|
||||
*****************************************************************************/
|
||||
/* This is the head of a list of all group members */
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
FAR struct task_group_s *g_grouphead;
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Private Functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_assigngid
|
||||
*
|
||||
* Description:
|
||||
* Create a unique group ID.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The tcb in need of the task group.
|
||||
*
|
||||
* Return Value:
|
||||
* None
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during task creation in a safe context. No special precautions
|
||||
* are required here.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
void group_assigngid(FAR struct task_group_s *group)
|
||||
{
|
||||
irqstate_t flags;
|
||||
gid_t gid;
|
||||
|
||||
/* Pre-emption should already be enabled, but lets be paranoid careful */
|
||||
|
||||
sched_lock();
|
||||
|
||||
/* Loop until we create a unique ID */
|
||||
|
||||
for (;;)
|
||||
{
|
||||
/* Increment the ID counter. This is global data so be extra paraoid. */
|
||||
|
||||
flags = irqsave();
|
||||
gid = ++g_gidcounter;
|
||||
|
||||
/* Check for overflow */
|
||||
|
||||
if (gid <= 0)
|
||||
{
|
||||
g_gidcounter = 1;
|
||||
irqrestore(flags);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Does a task group with this ID already exist? */
|
||||
|
||||
irqrestore(flags);
|
||||
if (group_find(gid) == NULL)
|
||||
{
|
||||
/* Now assign this ID to the group and return */
|
||||
|
||||
group->tg_gid = gid;
|
||||
sched_unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Functions
|
||||
*****************************************************************************/
|
||||
@ -112,6 +188,14 @@ int group_allocate(FAR _TCB *tcb)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Assign the group a unique ID. If g_gidcounter were to wrap before we
|
||||
* finish with task creation, that would be a problem.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
group_assigngid(tcb->group);
|
||||
#endif
|
||||
|
||||
/* Duplicate the parent tasks envionment */
|
||||
|
||||
ret = env_dup(tcb);
|
||||
@ -149,6 +233,9 @@ int group_allocate(FAR _TCB *tcb)
|
||||
int group_initialize(FAR _TCB *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group;
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
irqstate_t flags;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(tcb && tcb->group);
|
||||
group = tcb->group;
|
||||
@ -172,9 +259,17 @@ int group_initialize(FAR _TCB *tcb)
|
||||
*/
|
||||
|
||||
group->tg_mxmembers = GROUP_INITIAL_MEMBERS; /* Number of members in allocation */
|
||||
|
||||
/* Add the initialized entry to the list of groups */
|
||||
|
||||
flags = irqsave();
|
||||
group->flink = g_grouphead;
|
||||
g_grouphead = group;
|
||||
irqrestore(flags);
|
||||
|
||||
#endif
|
||||
|
||||
group->tg_nmembers = 1; /* Number of members in the group */
|
||||
group->tg_nmembers = 1; /* Number of members in the group */
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
125
sched/group_find.c
Normal file
125
sched/group_find.c
Normal file
@ -0,0 +1,125 @@
|
||||
/*****************************************************************************
|
||||
* sched/group_find.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 <sched.h>
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/kmalloc.h>
|
||||
|
||||
#include "group_internal.h"
|
||||
#include "env_internal.h"
|
||||
|
||||
#ifdef HAVE_TASK_GROUP
|
||||
|
||||
/*****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private Types
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private Data
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Data
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Private Functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_find
|
||||
*
|
||||
* Description:
|
||||
* Given a group ID, find the group task structure with that ID. IDs are
|
||||
* used instead of pointers to group structures. This is done because a
|
||||
* group can disappear at any time leaving a stale pointer; an ID is cleaner
|
||||
* because if the group disappears, this function will fail gracefully.
|
||||
*
|
||||
* Parameters:
|
||||
* gid - The group ID to find.
|
||||
*
|
||||
* Return Value:
|
||||
* On success, a pointer to the group task structure is returned. This
|
||||
* function can fail only if there is no group that corresponds to the
|
||||
* groupd ID.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during when signally tasks in a safe context. No special
|
||||
* precautions should be required here. However, extra care is taken when
|
||||
* accessing the global g_grouphead list.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
FAR struct task_group_s *group_find(gid_t gid)
|
||||
{
|
||||
FAR struct task_group_s *group;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Find the status structure with the matching PID */
|
||||
|
||||
flags = irqsave();
|
||||
for (group = g_grouphead; group; group = group->flink)
|
||||
{
|
||||
if (group->tg_gid == gid)
|
||||
{
|
||||
irqrestore(flags);
|
||||
return group;
|
||||
}
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* HAVE_TASK_GROUP */
|
@ -52,37 +52,62 @@
|
||||
/****************************************************************************
|
||||
* Pre-processor Definitions
|
||||
****************************************************************************/
|
||||
/* Any negative GID is invalid. */
|
||||
|
||||
#define INVALID_GROUP_ID (pid_t)-1
|
||||
#define IS_INVALID_GID(gid) ((int)(gid) < 0)
|
||||
|
||||
/****************************************************************************
|
||||
* Public Type Definitions
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Global Variables
|
||||
* Public Data
|
||||
****************************************************************************/
|
||||
/* This is the head of a list of all group members */
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
extern FAR struct task_group_s *g_grouphead;
|
||||
#endif
|
||||
|
||||
/****************************************************************************
|
||||
* Public Function Prototypes
|
||||
****************************************************************************/
|
||||
/* Task group data structure management */
|
||||
|
||||
#ifdef HAVE_TASK_GROUP
|
||||
int group_allocate(FAR _TCB *tcb);
|
||||
int group_initialize(FAR _TCB *tcb);
|
||||
int group_bind(FAR _TCB *tcb);
|
||||
int group_join(FAR _TCB *tcb);
|
||||
int group_allocate(FAR _TCB *tcb);
|
||||
int group_initialize(FAR _TCB *tcb);
|
||||
int group_bind(FAR _TCB *tcb);
|
||||
int group_join(FAR _TCB *tcb);
|
||||
void group_leave(FAR _TCB *tcb);
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
int group_signal(FAR _TCB *tcb, FAR siginfo_t *info);
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
FAR struct task_group_s *group_find(gid_t gid);
|
||||
int group_addmember(FAR struct task_group_s *group, pid_t pid);
|
||||
int group_removemember(FAR struct task_group_s *group, pid_t pid);
|
||||
#else
|
||||
# define group_signal(tcb,info) (0)
|
||||
# define group_find(gid) (NULL)
|
||||
# define group_addmember(group,pid) (0)
|
||||
# define group_removemember(group,pid) (1)
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
int group_signal(FAR struct task_group_s *group, FAR siginfo_t *info);
|
||||
#else
|
||||
# define group_allocate(tcb) (0)
|
||||
# define group_initialize(tcb) (0)
|
||||
# define group_bind(tcb) (0)
|
||||
# define group_join(tcb) (0)
|
||||
# define group_leave(tcb)
|
||||
# define group_signal(tcb,info) (0)
|
||||
# define group_signal(tcb,info) (0)
|
||||
#endif
|
||||
|
||||
#else
|
||||
# define group_allocate(tcb) (0)
|
||||
# define group_initialize(tcb) (0)
|
||||
# define group_bind(tcb) (0)
|
||||
# define group_join(tcb) (0)
|
||||
# define group_leave(tcb)
|
||||
# define group_find(gid) (NULL)
|
||||
# define group_addmember(group,pid) (0)
|
||||
# define group_removemember(group,pid) (1)
|
||||
# define group_signal(tcb,info) (0)
|
||||
#endif /* HAVE_TASK_GROUP */
|
||||
|
||||
/* Parent/child data management */
|
||||
@ -91,14 +116,18 @@ int group_signal(FAR _TCB *tcb, FAR siginfo_t *info);
|
||||
int task_reparent(pid_t ppid, pid_t chpid);
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
FAR struct child_status_s *task_allocchild(void);
|
||||
void task_freechild(FAR struct child_status_s *status);
|
||||
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_removechild(FAR _TCB *tcb, pid_t pid);
|
||||
void task_removechildren(FAR _TCB *tcb);
|
||||
#endif
|
||||
FAR struct child_status_s *group_allocchild(void);
|
||||
void group_freechild(FAR struct child_status_s *status);
|
||||
void group_addchild(FAR struct task_group_s *group,
|
||||
FAR struct child_status_s *child);
|
||||
FAR struct child_status_s *group_exitchild(FAR struct task_group_s *group);
|
||||
FAR struct child_status_s *group_findchild(FAR struct task_group_s *group,
|
||||
pid_t pid);
|
||||
FAR struct child_status_s *group_removechild(FAR struct task_group_s *group,
|
||||
pid_t pid);
|
||||
void group_removechildren(FAR struct task_group_s *group);
|
||||
|
||||
#endif /* CONFIG_SCHED_CHILD_STATUS */
|
||||
#endif /* CONFIG_SCHED_HAVE_PARENT */
|
||||
|
||||
#endif /* __SCHED_GROUP_INERNAL_H */
|
||||
|
@ -139,6 +139,9 @@ int group_bind(FAR _TCB *tcb)
|
||||
int group_join(FAR _TCB *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group;
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
int ret;
|
||||
#endif
|
||||
|
||||
DEBUGASSERT(tcb && tcb->group &&
|
||||
tcb->group->tg_nmembers < UINT8_MAX);
|
||||
@ -146,8 +149,45 @@ int group_join(FAR _TCB *tcb)
|
||||
/* Get the group from the TCB */
|
||||
|
||||
group = tcb->group;
|
||||
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
/* Add the member to the group */
|
||||
|
||||
ret = group_addmember(group, tcb->pid);
|
||||
if (ret < 0)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
group->tg_nmembers++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_addmember
|
||||
*
|
||||
* Description:
|
||||
* Add a new member to a group.
|
||||
*
|
||||
* Parameters:
|
||||
* group - The task group to add the new member
|
||||
* pid - The new member
|
||||
*
|
||||
* Return Value:
|
||||
* 0 (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during thread creation and during reparenting in a safe context.
|
||||
* No special precautions are required here.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
int group_addmember(FAR struct task_group_s *group, pid_t pid)
|
||||
{
|
||||
DEBUGASSERT(group && group->tg_nmembers < UINT8_MAX);
|
||||
|
||||
/* Will we need to extend the size of the array of groups? */
|
||||
|
||||
if (group->tg_nmembers >= group->tg_mxmembers)
|
||||
@ -179,11 +219,9 @@ int group_join(FAR _TCB *tcb)
|
||||
|
||||
/* Assign this new pid to the group. */
|
||||
|
||||
group->tg_members[group->tg_nmembers] = tcb->pid;
|
||||
#endif
|
||||
|
||||
group->tg_nmembers++;
|
||||
group->tg_members[group->tg_nmembers] = pid;
|
||||
return OK;
|
||||
}
|
||||
#endif /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
#endif /* HAVE_TASK_GROUP */
|
||||
|
@ -65,6 +65,65 @@
|
||||
* Private Functions
|
||||
*****************************************************************************/
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_remove
|
||||
*
|
||||
* Description:
|
||||
* Remove a group from the list of groups.
|
||||
*
|
||||
* Parameters:
|
||||
* group - The group to be removed.
|
||||
*
|
||||
* Return Value:
|
||||
* None.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during task deletion in a safe context. No special precautions
|
||||
* are required here.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
void group_remove(FAR struct task_group_s *group)
|
||||
{
|
||||
FAR struct task_group_s *curr;
|
||||
FAR struct task_group_s *prev;
|
||||
irqstate_t flags;
|
||||
|
||||
/* Let's be especially careful while access the global task group list.
|
||||
* This is probably un-necessary.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
/* Find the task group structure */
|
||||
|
||||
for (prev = NULL, curr = g_grouphead;
|
||||
curr && curr != group;
|
||||
prev = curr, curr = curr->flink);
|
||||
|
||||
/* Did we find it? If so, remove it from the list. */
|
||||
|
||||
if (curr)
|
||||
{
|
||||
/* Do we remove it from mid-list? Or from the head of the list? */
|
||||
|
||||
if (prev)
|
||||
{
|
||||
prev->flink = curr->flink;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_grouphead = curr->flink;
|
||||
}
|
||||
|
||||
curr->flink = NULL;
|
||||
}
|
||||
|
||||
irqrestore(flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
* Public Functions
|
||||
*****************************************************************************/
|
||||
@ -90,6 +149,8 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
|
||||
void group_leave(FAR _TCB *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group;
|
||||
@ -101,64 +162,57 @@ void group_leave(FAR _TCB *tcb)
|
||||
group = tcb->group;
|
||||
if (group)
|
||||
{
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
int i;
|
||||
/* Remove the member from group */
|
||||
|
||||
/* Find the member in the array of members and remove it */
|
||||
int ret = group_removemember(group, tcb->pid);
|
||||
DEBUGASSERT(ret >= 0);
|
||||
|
||||
for (i = 0; i < group->tg_nmembers; i++)
|
||||
/* Is the group now empty? */
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
/* Does this member have the matching pid */
|
||||
|
||||
if (group->tg_members[i] == tcb->pid)
|
||||
{
|
||||
/* Yes.. break out of the loop. We don't do the actual
|
||||
* removal here, instead we re-test i and do the adjustments
|
||||
* outside of the loop. We do this because we want the
|
||||
* DEBUGASSERT to work properly.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, test if we found the task in the array of members. */
|
||||
|
||||
DEBUGASSERT(i < group->tg_nmembers);
|
||||
if (i < group->tg_nmembers)
|
||||
{
|
||||
/* Yes..Is this the last member of the group? */
|
||||
|
||||
if (group->tg_nmembers > 1)
|
||||
{
|
||||
/* No.. remove the member from the array of members */
|
||||
|
||||
group->tg_members[i] = group->tg_members[group->tg_nmembers - 1];
|
||||
group->tg_nmembers--;
|
||||
}
|
||||
|
||||
/* Yes.. that was the last member remaining in the group */
|
||||
|
||||
else
|
||||
{
|
||||
/* Release all of the resource contained within the group */
|
||||
/* Free all un-reaped child exit status */
|
||||
/* Release all of the resource contained within the group */
|
||||
/* Free all un-reaped child exit status */
|
||||
|
||||
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
|
||||
task_removechildren(tcb);
|
||||
group_removechildren(tcb->group);
|
||||
#endif
|
||||
/* Release all shared environment variables */
|
||||
/* Release all shared environment variables */
|
||||
|
||||
#ifndef CONFIG_DISABLE_ENVIRON
|
||||
env_release(tcb);
|
||||
env_release(tcb);
|
||||
#endif
|
||||
/* Release the group container itself */
|
||||
/* Remove the group from the list of groups */
|
||||
|
||||
sched_free(group);
|
||||
}
|
||||
group_remove(group);
|
||||
|
||||
/* Release the group container itself */
|
||||
|
||||
sched_free(group);
|
||||
}
|
||||
#else
|
||||
/* Yes..Is this the last member of the group? */
|
||||
|
||||
/* In any event, we can detach the group from the TCB so that we won't
|
||||
* do this again.
|
||||
*/
|
||||
|
||||
tcb->group = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
void group_leave(FAR _TCB *tcb)
|
||||
{
|
||||
FAR struct task_group_s *group;
|
||||
|
||||
DEBUGASSERT(tcb);
|
||||
|
||||
/* Make sure that we have a group */
|
||||
|
||||
group = tcb->group;
|
||||
if (group)
|
||||
{
|
||||
/* Yes, we have a group.. Is this the last member of the group? */
|
||||
|
||||
if (group->tg_nmembers > 1)
|
||||
{
|
||||
@ -175,7 +229,7 @@ void group_leave(FAR _TCB *tcb)
|
||||
/* Free all un-reaped child exit status */
|
||||
|
||||
#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
|
||||
task_removechildren(tcb);
|
||||
group_removechildren(tcb->group);
|
||||
#endif
|
||||
/* Release all shared environment variables */
|
||||
|
||||
@ -186,7 +240,6 @@ void group_leave(FAR _TCB *tcb)
|
||||
|
||||
sched_free(group);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* In any event, we can detach the group from the TCB so we won't do
|
||||
* this again.
|
||||
@ -196,4 +249,67 @@ void group_leave(FAR _TCB *tcb)
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_removemember
|
||||
*
|
||||
* Description:
|
||||
* Remove a member from a group.
|
||||
*
|
||||
* Parameters:
|
||||
* group - The group from which to remove the member.
|
||||
* pid - The member to be removed.
|
||||
*
|
||||
* Return Value:
|
||||
* On success, returns the number of members remaining in the group (>=0).
|
||||
* Can fail only if the member is not found in the group. On failure,
|
||||
* returns -ENOENT
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during task deletion and also from the reparenting logic, both
|
||||
* in a safe context. No special precautions are required here.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
int group_removemember(FAR struct task_group_s *group, pid_t pid)
|
||||
{
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(group);
|
||||
|
||||
/* Find the member in the array of members and remove it */
|
||||
|
||||
for (i = 0; i < group->tg_nmembers; i++)
|
||||
{
|
||||
/* Does this member have the matching pid */
|
||||
|
||||
if (group->tg_members[i] == pid)
|
||||
{
|
||||
/* Yes.. break out of the loop. We don't do the actual
|
||||
* removal here, instead we re-test i and do the adjustments
|
||||
* outside of the loop. We do this because we want the
|
||||
* DEBUGASSERT to work properly.
|
||||
*/
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now, test if we found the task in the array of members. */
|
||||
|
||||
if (i < group->tg_nmembers)
|
||||
{
|
||||
/* Remove the member from the array of members */
|
||||
|
||||
group->tg_members[i] = group->tg_members[group->tg_nmembers - 1];
|
||||
group->tg_nmembers--;
|
||||
return group->tg_nmembers;
|
||||
}
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
#endif /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
#endif /* HAVE_TASK_GROUP */
|
||||
|
@ -42,6 +42,7 @@
|
||||
#include <sched.h>
|
||||
#include <assert.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include "os_internal.h"
|
||||
@ -74,10 +75,10 @@
|
||||
* Name: group_signal
|
||||
*
|
||||
* Description:
|
||||
* Send a signal to every member of the group to which task belongs.
|
||||
* Send a signal to every member of the group.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The tcb of one task in the task group that needs to be signalled.
|
||||
* group - The task group that needs to be signalled.
|
||||
*
|
||||
* Return Value:
|
||||
* 0 (OK) on success; a negated errno value on failure.
|
||||
@ -88,15 +89,13 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
int group_signal(FAR _TCB *tcb, FAR siginfo_t *info)
|
||||
int group_signal(FAR struct task_group_s *group, FAR siginfo_t *info)
|
||||
{
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
FAR struct task_group_s *group;
|
||||
FAR _TCB *gtcb;
|
||||
int i;
|
||||
|
||||
DEBUGASSERT(tcb && tcb->group && info);
|
||||
group = tcb->group;
|
||||
DEBUGASSERT(group && info);
|
||||
|
||||
/* Make sure that pre-emption is disabled to that we signal all of teh
|
||||
* members of the group before any of them actually run.
|
||||
@ -130,8 +129,35 @@ int group_signal(FAR _TCB *tcb, FAR siginfo_t *info)
|
||||
sched_unlock();
|
||||
return OK;
|
||||
#else
|
||||
return sig_received(tcb, info);
|
||||
return -ENOSYS;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Name: group_signalmember
|
||||
*
|
||||
* Description:
|
||||
* Send a signal to every member of the group to which task belongs.
|
||||
*
|
||||
* Parameters:
|
||||
* tcb - The tcb of one task in the task group that needs to be signalled.
|
||||
*
|
||||
* Return Value:
|
||||
* 0 (OK) on success; a negated errno value on failure.
|
||||
*
|
||||
* Assumptions:
|
||||
* Called during task terminatino in a safe context. No special precautions
|
||||
* are required here.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
int group_signalmember(FAR _TCB *tcb, FAR siginfo_t *info)
|
||||
{
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
DEBUGASSERT(tcb);
|
||||
return group_signal(tcb->group, info);
|
||||
#else
|
||||
return sig_received(tcb, info);
|
||||
#endif
|
||||
}
|
||||
#endif /* HAVE_TASK_GROUP && !CONFIG_DISABLE_SIGNALS */
|
||||
|
@ -79,8 +79,8 @@ static void exited_child(FAR _TCB *rtcb, FAR struct child_status_s *child,
|
||||
|
||||
/* Discard the child entry */
|
||||
|
||||
(void)task_removechild(rtcb, child->ch_pid);
|
||||
task_freechild(child);
|
||||
(void)group_removechild(rtcb->group, child->ch_pid);
|
||||
group_freechild(child);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -212,7 +212,11 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||
|
||||
ctcb = sched_gettcb((pid_t)id);
|
||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
if (!ctcb || ctcb->group->tg_pgid != rtcb->group->tg_gid)
|
||||
#else
|
||||
if (!ctcb || ctcb->ppid != rtcb->pid)
|
||||
#endif
|
||||
{
|
||||
err = ECHILD;
|
||||
goto errout_with_errno;
|
||||
@ -224,7 +228,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||
{
|
||||
/* Check if this specific pid has allocated child status? */
|
||||
|
||||
if (task_findchild(rtcb, (pid_t)id) == NULL)
|
||||
if (group_findchild(rtcb->group, (pid_t)id) == NULL)
|
||||
{
|
||||
/* This specific pid is not a child */
|
||||
|
||||
@ -246,7 +250,11 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||
/* Get the TCB corresponding to this PID and make sure it is our child. */
|
||||
|
||||
ctcb = sched_gettcb((pid_t)id);
|
||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
if (!ctcb || ctcb->group->tg_pgid != rtcb->group->tg_gid)
|
||||
#else
|
||||
if (!ctcb || ctcb->ppid != rtcb->pid)
|
||||
#endif
|
||||
{
|
||||
err = ECHILD;
|
||||
goto errout_with_errno;
|
||||
@ -270,7 +278,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||
{
|
||||
/* We are waiting for any child to exit */
|
||||
|
||||
if (retains && (child = task_exitchild(rtcb)) != NULL)
|
||||
if (retains && (child = group_exitchild(rtcb->group)) != NULL)
|
||||
{
|
||||
/* A child has exited. Apparently we missed the signal.
|
||||
* Return the exit status and break out of the loop.
|
||||
@ -287,7 +295,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
|
||||
{
|
||||
/* Yes ... Get the current status of the child task. */
|
||||
|
||||
child = task_findchild(rtcb, (pid_t)id);
|
||||
child = group_findchild(rtcb->group, (pid_t)id);
|
||||
DEBUGASSERT(child);
|
||||
|
||||
/* Did the child exit? */
|
||||
|
@ -172,17 +172,13 @@
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
* 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)
|
||||
{
|
||||
@ -325,7 +321,11 @@ 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. */
|
||||
|
||||
ctcb = sched_gettcb(pid);
|
||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
if (!ctcb || ctcb->group->tg_pgid != rtcb->group->tg_gid)
|
||||
#else
|
||||
if (!ctcb || ctcb->ppid != rtcb->pid)
|
||||
#endif
|
||||
{
|
||||
err = ECHILD;
|
||||
goto errout_with_errno;
|
||||
@ -337,7 +337,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
{
|
||||
/* Check if this specific pid has allocated child status? */
|
||||
|
||||
if (task_findchild(rtcb, pid) == NULL)
|
||||
if (group_findchild(rtcb->group, pid) == NULL)
|
||||
{
|
||||
err = ECHILD;
|
||||
goto errout_with_errno;
|
||||
@ -357,7 +357,11 @@ 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. */
|
||||
|
||||
ctcb = sched_gettcb(pid);
|
||||
if (!ctcb || ctcb->parent != rtcb->pid)
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
if (!ctcb || ctcb->group->tg_pgid != rtcb->group->tg_gid)
|
||||
#else
|
||||
if (!ctcb || ctcb->ppid != rtcb->pid)
|
||||
#endif
|
||||
{
|
||||
err = ECHILD;
|
||||
goto errout_with_errno;
|
||||
@ -383,7 +387,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
*/
|
||||
|
||||
DEBUGASSERT(!retains || rtcb->group->tg_children);
|
||||
if (retains && (child = task_exitchild(rtcb)) != NULL)
|
||||
if (retains && (child = group_exitchild(rtcb->group)) != NULL)
|
||||
{
|
||||
/* A child has exited. Apparently we missed the signal.
|
||||
* Return the saved exit status.
|
||||
@ -395,8 +399,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
|
||||
/* Discard the child entry and break out of the loop */
|
||||
|
||||
(void)task_removechild(rtcb, child->ch_pid);
|
||||
task_freechild(child);
|
||||
(void)group_removechild(rtcb->group, child->ch_pid);
|
||||
group_freechild(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -407,7 +411,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
{
|
||||
/* Get the current status of the child task. */
|
||||
|
||||
child = task_findchild(rtcb, pid);
|
||||
child = group_findchild(rtcb->group, pid);
|
||||
DEBUGASSERT(child);
|
||||
|
||||
/* Did the child exit? */
|
||||
@ -420,8 +424,8 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
|
||||
|
||||
/* Discard the child entry and break out of the loop */
|
||||
|
||||
(void)task_removechild(rtcb, pid);
|
||||
task_freechild(child);
|
||||
(void)group_removechild(rtcb->group, pid);
|
||||
group_freechild(child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -242,7 +242,7 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
|
||||
|
||||
/* Free all pending exit status */
|
||||
|
||||
task_removechildren(rtcb);
|
||||
group_removechildren(rtcb->group);
|
||||
irqrestore(flags);
|
||||
}
|
||||
#endif
|
||||
|
@ -104,10 +104,7 @@ static inline void task_atexit(FAR _TCB *tcb)
|
||||
|
||||
(*tcb->atexitfunc[index])();
|
||||
|
||||
/* Nullify the atexit function. task_exithook may be called more then
|
||||
* once in most task exit scenarios. Nullifying the atext function
|
||||
* pointer will assure that the callback is performed only once.
|
||||
*/
|
||||
/* Nullify the atexit function to prevent its reuse. */
|
||||
|
||||
tcb->atexitfunc[index] = NULL;
|
||||
}
|
||||
@ -120,10 +117,7 @@ static inline void task_atexit(FAR _TCB *tcb)
|
||||
|
||||
(*tcb->atexitfunc)();
|
||||
|
||||
/* Nullify the atexit function. task_exithook may be called more then
|
||||
* once in most task exit scenarios. Nullifying the atext function
|
||||
* pointer will assure that the callback is performed only once.
|
||||
*/
|
||||
/* Nullify the atexit function to prevent its reuse. */
|
||||
|
||||
tcb->atexitfunc = NULL;
|
||||
}
|
||||
@ -161,10 +155,7 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
|
||||
|
||||
(*tcb->onexitfunc[index])(status, tcb->onexitarg[index]);
|
||||
|
||||
/* Nullify the on_exit function. task_exithook may be called more then
|
||||
* once in most task exit scenarios. Nullifying the atext function
|
||||
* pointer will assure that the callback is performed only once.
|
||||
*/
|
||||
/* Nullify the on_exit function to prevent its reuse. */
|
||||
|
||||
tcb->onexitfunc[index] = NULL;
|
||||
}
|
||||
@ -176,10 +167,7 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
|
||||
|
||||
(*tcb->onexitfunc)(status, tcb->onexitarg);
|
||||
|
||||
/* Nullify the on_exit function. task_exithook may be called more then
|
||||
* once in most task exit scenarios. Nullifying the on_exit function
|
||||
* pointer will assure that the callback is performed only once.
|
||||
*/
|
||||
/* Nullify the on_exit function to prevent its reuse. */
|
||||
|
||||
tcb->onexitfunc = NULL;
|
||||
}
|
||||
@ -198,34 +186,51 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
|
||||
****************************************************************************/
|
||||
|
||||
#ifdef CONFIG_SCHED_HAVE_PARENT
|
||||
static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
static inline void task_sigchild(gid_t pgid, FAR _TCB *ctcb, int status)
|
||||
{
|
||||
FAR struct task_group_s *chgrp = ctcb->group;
|
||||
FAR struct task_group_s *pgrp;
|
||||
siginfo_t info;
|
||||
|
||||
/* Only the final exiting thread in a task group should generate SIGCHLD.
|
||||
* If task groups are not supported then we will report SIGCHLD when the
|
||||
* task exits.
|
||||
*/
|
||||
DEBUGASSERT(chgrp);
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
if (ctcb->group->tg_nmembers == 1)
|
||||
#else
|
||||
if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
|
||||
#endif
|
||||
/* Only the final exiting thread in a task group should generate SIGCHLD. */
|
||||
|
||||
if (chgrp->tg_nmembers == 1)
|
||||
{
|
||||
/* Get the parent task group */
|
||||
|
||||
pgrp = group_find(chgrp->tg_pgid);
|
||||
|
||||
/* It is possible that all of the members of the parent task group
|
||||
* have exited. This would not be an error. In this case, the
|
||||
* child task group has been orphaned.
|
||||
*/
|
||||
|
||||
if (!pgrp)
|
||||
{
|
||||
/* Set the task group ID to an invalid group ID. The dead parent
|
||||
* task group ID could get reused some time in the future.
|
||||
*/
|
||||
|
||||
chgrp->tg_pgid = INVALID_GROUP_ID;
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
/* Check if the parent task group has suppressed retention of child exit
|
||||
* status information. Only 'tasks' report exit status, not pthreads.
|
||||
* pthreads have a different mechanism.
|
||||
*/
|
||||
|
||||
if ((ptcb->group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0)
|
||||
if ((pgrp->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0)
|
||||
{
|
||||
FAR struct child_status_s *child;
|
||||
|
||||
/* No.. Find the exit status entry for this task in the parent TCB */
|
||||
|
||||
child = task_findchild(ptcb, getpid());
|
||||
child = group_findchild(pgrp, getpid());
|
||||
DEBUGASSERT(child);
|
||||
if (child)
|
||||
{
|
||||
@ -238,12 +243,7 @@ static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
|
||||
child->ch_status = status;
|
||||
}
|
||||
}
|
||||
#else
|
||||
/* Decrement the number of children from this parent */
|
||||
|
||||
DEBUGASSERT(ptcb->nchildren > 0);
|
||||
ptcb->nchildren--;
|
||||
#endif
|
||||
#endif /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
/* 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
|
||||
@ -260,16 +260,83 @@ static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
|
||||
* can provide the correct si_code value with the signal.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
(void)group_signal(ptcb, &info);
|
||||
#else
|
||||
(void)sig_received(ptcb, &info);
|
||||
#endif
|
||||
(void)group_signal(pgrp, &info);
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define task_sigchild(ptct,ctcb,status)
|
||||
#endif
|
||||
|
||||
#else /* HAVE_GROUP_MEMBERS */
|
||||
|
||||
static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
|
||||
{
|
||||
siginfo_t info;
|
||||
|
||||
/* If task groups are not supported then we will report SIGCHLD when the
|
||||
* task exits. Unfortunately, there could still be threads in the group
|
||||
* that are still running.
|
||||
*/
|
||||
|
||||
if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
/* Check if the parent task group has suppressed retention of child exit
|
||||
* status information. Only 'tasks' report exit status, not pthreads.
|
||||
* pthreads have a different mechanism.
|
||||
*/
|
||||
|
||||
if ((ptcb->group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0)
|
||||
{
|
||||
FAR struct child_status_s *child;
|
||||
|
||||
/* No.. Find the exit status entry for this task in the parent TCB */
|
||||
|
||||
child = group_findchild(ptcb->group, getpid());
|
||||
DEBUGASSERT(child);
|
||||
if (child)
|
||||
{
|
||||
/* Mark that the child has exit'ed */
|
||||
|
||||
child->ch_flags |= CHILD_FLAG_EXITED;
|
||||
|
||||
/* Save the exit status */
|
||||
|
||||
child->ch_status = status;
|
||||
}
|
||||
}
|
||||
|
||||
#else /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
/* Decrement the number of children from this parent */
|
||||
|
||||
DEBUGASSERT(ptcb->nchildren > 0);
|
||||
ptcb->nchildren--;
|
||||
|
||||
#endif /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = CLD_EXITED;
|
||||
info.si_value.sival_ptr = NULL;
|
||||
info.si_pid = ctcb->pid;
|
||||
info.si_status = status;
|
||||
|
||||
/* Send the signal. We need to use this internal interface so that we
|
||||
* can provide the correct si_code value with the signal.
|
||||
*/
|
||||
|
||||
(void)sig_received(ptcb, &info);
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* HAVE_GROUP_MEMBERS */
|
||||
#else /* CONFIG_SCHED_HAVE_PARENT */
|
||||
|
||||
# define task_sigchild(x,ctcb,status)
|
||||
|
||||
#endif /* CONFIG_SCHED_HAVE_PARENT */
|
||||
|
||||
/****************************************************************************
|
||||
* Name: task_leavegroup
|
||||
@ -282,6 +349,18 @@ static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
|
||||
#ifdef CONFIG_SCHED_HAVE_PARENT
|
||||
static inline void task_leavegroup(FAR _TCB *ctcb, int status)
|
||||
{
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
DEBUGASSERT(ctcb && ctcb->group);
|
||||
|
||||
/* Keep things stationary throughout the following */
|
||||
|
||||
sched_lock();
|
||||
|
||||
/* Send SIGCHLD to all members of the parent's task group */
|
||||
|
||||
task_sigchild(ctcb->group->tg_pgid, ctcb, status);
|
||||
sched_unlock();
|
||||
#else
|
||||
FAR _TCB *ptcb;
|
||||
|
||||
/* Keep things stationary throughout the following */
|
||||
@ -289,12 +368,12 @@ static inline void task_leavegroup(FAR _TCB *ctcb, int status)
|
||||
sched_lock();
|
||||
|
||||
/* Get the TCB of the receiving, parent task. We do this early to
|
||||
* handle multiple calls to task_leavegroup. ctcb->parent is set to an
|
||||
* handle multiple calls to task_leavegroup. ctcb->ppid is set to an
|
||||
* invalid value below and the following call will fail if we are
|
||||
* called again.
|
||||
*/
|
||||
|
||||
ptcb = sched_gettcb(ctcb->parent);
|
||||
ptcb = sched_gettcb(ctcb->ppid);
|
||||
if (!ptcb)
|
||||
{
|
||||
/* The parent no longer exists... bail */
|
||||
@ -307,14 +386,11 @@ static inline void task_leavegroup(FAR _TCB *ctcb, int status)
|
||||
|
||||
task_sigchild(ptcb, ctcb, status);
|
||||
|
||||
/* 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 and all will be well.
|
||||
*/
|
||||
/* Forget who our parent was */
|
||||
|
||||
ctcb->parent = INVALID_PROCESS_ID;
|
||||
ctcb->ppid = INVALID_PROCESS_ID;
|
||||
sched_unlock();
|
||||
#endif
|
||||
}
|
||||
#else
|
||||
# define task_leavegroup(ctcb,status)
|
||||
@ -385,6 +461,16 @@ static inline void task_exitwakeup(FAR _TCB *tcb, int status)
|
||||
|
||||
void task_exithook(FAR _TCB *tcb, int status)
|
||||
{
|
||||
/* Under certain conditions, task_exithook() can be called multiple times.
|
||||
* A bit in the TCB was set the first time this function was called. If
|
||||
* that bit is set, then just ext doing nothing more..
|
||||
*/
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_EXIT_PROCESSING) != 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/* If exit function(s) were registered, call them now before we do any un-
|
||||
* initialization. NOTE: In the case of task_delete(), the exit function
|
||||
* will *not* be called on the thread execution of the task being deleted!
|
||||
@ -433,4 +519,11 @@ void task_exithook(FAR _TCB *tcb, int status)
|
||||
#ifndef CONFIG_DISABLE_SIGNALS
|
||||
sig_cleanup(tcb); /* Deallocate Signal lists */
|
||||
#endif
|
||||
|
||||
/* This function can be re-entered in certain cases. Set a flag
|
||||
* bit in the TCB to not that we have already completed this exit
|
||||
* processing.
|
||||
*/
|
||||
|
||||
tcb->flags |= TCB_FLAG_EXIT_PROCESSING;
|
||||
}
|
||||
|
@ -70,6 +70,141 @@
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
int task_reparent(pid_t ppid, pid_t chpid)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
FAR struct child_status_s *child;
|
||||
#endif
|
||||
FAR struct task_group_s *chgrp;
|
||||
FAR struct task_group_s *ogrp;
|
||||
FAR struct task_group_s *pgrp;
|
||||
_TCB *tcb;
|
||||
gid_t ogid;
|
||||
gid_t pgid;
|
||||
irqstate_t flags;
|
||||
int ret;
|
||||
|
||||
/* Disable interrupts so that nothing can change in the relatinoship of
|
||||
* the three task: Child, current parent, and new parent.
|
||||
*/
|
||||
|
||||
flags = irqsave();
|
||||
|
||||
/* Get the child tasks task group */
|
||||
|
||||
tcb = sched_gettcb(chpid);
|
||||
if (!tcb)
|
||||
{
|
||||
ret = -ECHILD;
|
||||
goto errout_with_ints;
|
||||
}
|
||||
|
||||
DEBUGASSERT(tcb->group);
|
||||
chgrp = tcb->group;
|
||||
|
||||
/* Get the GID of the old parent task's task group (ogid) */
|
||||
|
||||
ogid = chgrp->tg_pgid;
|
||||
|
||||
/* Get the old parent task's task group (ogrp) */
|
||||
|
||||
ogrp = group_find(ogid);
|
||||
if (!ogrp)
|
||||
{
|
||||
ret = -ESRCH;
|
||||
goto errout_with_ints;
|
||||
}
|
||||
|
||||
/* If new parent task's PID (ppid) is zero, then new parent is the
|
||||
* grandparent will be the new parent, i.e., the parent of the current
|
||||
* parent task.
|
||||
*/
|
||||
|
||||
if (ppid == 0)
|
||||
{
|
||||
/* Get the grandparent task's task group (pgrp) */
|
||||
|
||||
pgid = ogrp->tg_pgid;
|
||||
pgrp = group_find(pgid);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the new parent task's task group (pgrp) */
|
||||
|
||||
tcb = sched_gettcb(ppid);
|
||||
if (!tcb)
|
||||
{
|
||||
ret = -ESRCH;
|
||||
goto errout_with_ints;
|
||||
}
|
||||
|
||||
pgrp = tcb->group;
|
||||
pgid = pgrp->tg_gid;
|
||||
}
|
||||
|
||||
if (!pgrp)
|
||||
{
|
||||
ret = -ESRCH;
|
||||
goto errout_with_ints;
|
||||
}
|
||||
|
||||
/* Then reparent the child. Notice that we don't actually change the
|
||||
* parent of the task. Rather, we change the parent task group for
|
||||
* all members of the child's task group.
|
||||
*/
|
||||
|
||||
chgrp->tg_pgid = pgid;
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
/* Remove the child status entry from old parent task group */
|
||||
|
||||
child = group_removechild(ogrp, chpid);
|
||||
if (child)
|
||||
{
|
||||
/* Has the new parent's task group supressed child exit status? */
|
||||
|
||||
if ((pgrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
|
||||
{
|
||||
/* No.. Add the child status entry to the new parent's task group */
|
||||
|
||||
group_addchild(pgrp, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Yes.. Discard the child status entry */
|
||||
|
||||
group_freechild(child);
|
||||
}
|
||||
|
||||
/* Either case is a success */
|
||||
|
||||
ret = OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This would not be an error if the original parent's task group has
|
||||
* suppressed child exit status.
|
||||
*/
|
||||
|
||||
ret = ((ogrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
|
||||
}
|
||||
|
||||
#else /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
DEBUGASSERT(otcb->nchildren > 0);
|
||||
|
||||
otcb->nchildren--; /* The orignal parent now has one few children */
|
||||
ptcb->nchildren++; /* The new parent has one additional child */
|
||||
ret = OK;
|
||||
|
||||
#endif /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
errout_with_ints:
|
||||
irqrestore(flags);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
int task_reparent(pid_t ppid, pid_t chpid)
|
||||
{
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
@ -99,7 +234,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
||||
|
||||
/* Get the PID of the child task's parent (opid) */
|
||||
|
||||
opid = chtcb->parent;
|
||||
opid = chtcb->ppid;
|
||||
|
||||
/* Get the TCB of the child task's parent (otcb) */
|
||||
|
||||
@ -117,7 +252,7 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
||||
|
||||
if (ppid == 0)
|
||||
{
|
||||
ppid = otcb->parent;
|
||||
ppid = otcb->ppid;
|
||||
}
|
||||
|
||||
/* Get the new parent task's TCB (ptcb) */
|
||||
@ -131,12 +266,12 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
||||
|
||||
/* Then reparent the child */
|
||||
|
||||
chtcb->parent = ppid; /* The task specified by ppid is the new parent */
|
||||
chtcb->ppid = ppid; /* The task specified by ppid is the new parent */
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
/* Remove the child status entry from old parent TCB */
|
||||
|
||||
child = task_removechild(otcb, chpid);
|
||||
child = group_removechild(otcb->group, chpid);
|
||||
if (child)
|
||||
{
|
||||
/* Has the new parent's task group supressed child exit status? */
|
||||
@ -145,13 +280,13 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
||||
{
|
||||
/* No.. Add the child status entry to the new parent's task group */
|
||||
|
||||
task_addchild(ptcb, child);
|
||||
group_addchild(ptcb->group, child);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Yes.. Discard the child status entry */
|
||||
|
||||
task_freechild(child);
|
||||
group_freechild(child);
|
||||
}
|
||||
|
||||
/* Either case is a success */
|
||||
@ -166,17 +301,20 @@ int task_reparent(pid_t ppid, pid_t chpid)
|
||||
|
||||
ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
|
||||
}
|
||||
#else
|
||||
|
||||
#else /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
DEBUGASSERT(otcb->nchildren > 0);
|
||||
|
||||
otcb->nchildren--; /* The orignal parent now has one few children */
|
||||
ptcb->nchildren++; /* The new parent has one additional child */
|
||||
ret = OK;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SCHED_CHILD_STATUS */
|
||||
|
||||
errout_with_ints:
|
||||
irqrestore(flags);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_SCHED_HAVE_PARENT */
|
||||
|
@ -172,12 +172,36 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
|
||||
{
|
||||
FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head;
|
||||
|
||||
#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_SCHED_CHILD_STATUS)
|
||||
DEBUGASSERT(tcb && tcb->group && rtcb->group);
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_GROUP_MEMBERS
|
||||
/* Save the ID of the parent tasks' task group in the child's task group.
|
||||
* Do nothing for pthreads. The parent and the child are both members of
|
||||
* the same task group.
|
||||
*/
|
||||
|
||||
if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
|
||||
{
|
||||
/* This is a new task in a new task group, we have to copy the ID from
|
||||
* the parent's task group structure to child's task group.
|
||||
*/
|
||||
|
||||
tcb->group->tg_pgid = rtcb->group->tg_gid;
|
||||
}
|
||||
|
||||
#else
|
||||
DEBUGASSERT(tcb);
|
||||
|
||||
/* Save the parent task's ID in the child task's TCB. I am not sure if
|
||||
* this makes sense for the case of pthreads or not, but I don't think it
|
||||
* is harmful in any event.
|
||||
*/
|
||||
|
||||
tcb->parent = rtcb->pid;
|
||||
tcb->ppid = rtcb->pid;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_SCHED_CHILD_STATUS
|
||||
/* Tasks can also suppress retention of their child status by applying
|
||||
@ -192,13 +216,13 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
|
||||
* parent TCB. There should not be.
|
||||
*/
|
||||
|
||||
child = task_findchild(rtcb, tcb->pid);
|
||||
child = group_findchild(rtcb->group, tcb->pid);
|
||||
DEBUGASSERT(!child);
|
||||
if (!child)
|
||||
{
|
||||
/* Allocate a new status structure */
|
||||
|
||||
child = task_allocchild();
|
||||
child = group_allocchild();
|
||||
}
|
||||
|
||||
/* Did we successfully find/allocate the child status structure? */
|
||||
@ -214,7 +238,7 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
|
||||
|
||||
/* Add the entry into the TCB list of children */
|
||||
|
||||
task_addchild(rtcb, child);
|
||||
group_addchild(rtcb->group, child);
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user