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:
patacongo 2013-01-26 17:28:20 +00:00
parent 0cefbf4762
commit fc8136d5d3
16 changed files with 937 additions and 228 deletions

View File

@ -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.

View File

@ -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 */

View File

@ -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

View File

@ -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 */

View File

@ -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
View 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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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 */

View File

@ -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? */

View File

@ -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;
}
}

View File

@ -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

View File

@ -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;
}

View File

@ -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 */

View File

@ -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