summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-26 17:28:20 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-26 17:28:20 +0000
commit03a486c40db2af681a40776e54d7f936c7e9d499 (patch)
tree86bcd215a785d7499f6472475df1c6c879574751
parentf372377c724eb5b626107c58223888a08197d4af (diff)
downloadnuttx-03a486c40db2af681a40776e54d7f936c7e9d499.tar.gz
nuttx-03a486c40db2af681a40776e54d7f936c7e9d499.tar.bz2
nuttx-03a486c40db2af681a40776e54d7f936c7e9d499.zip
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
-rw-r--r--nuttx/ChangeLog4
-rw-r--r--nuttx/include/nuttx/sched.h12
-rw-r--r--nuttx/sched/Makefile16
-rw-r--r--nuttx/sched/group_childstatus.c (renamed from nuttx/sched/task_childstatus.c)89
-rw-r--r--nuttx/sched/group_create.c99
-rw-r--r--nuttx/sched/group_find.c125
-rw-r--r--nuttx/sched/group_internal.h71
-rw-r--r--nuttx/sched/group_join.c48
-rw-r--r--nuttx/sched/group_leave.c212
-rw-r--r--nuttx/sched/group_signal.c40
-rw-r--r--nuttx/sched/sched_waitid.c22
-rw-r--r--nuttx/sched/sched_waitpid.c40
-rw-r--r--nuttx/sched/sig_action.c2
-rw-r--r--nuttx/sched/task_exithook.c175
-rw-r--r--nuttx/sched/task_reparent.c156
-rw-r--r--nuttx/sched/task_setup.c32
16 files changed, 926 insertions, 217 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog
index f23a3ed73..858f82819 100644
--- a/nuttx/ChangeLog
+++ b/nuttx/ChangeLog
@@ -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.
diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h
index dd33b4570..8ebb7db4c 100644
--- a/nuttx/include/nuttx/sched.h
+++ b/nuttx/include/nuttx/sched.h
@@ -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 */
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index 6a0b99144..d059152e0 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -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
diff --git a/nuttx/sched/task_childstatus.c b/nuttx/sched/group_childstatus.c
index c0df3d534..ef42b6c34 100644
--- a/nuttx/sched/task_childstatus.c
+++ b/nuttx/sched/group_childstatus.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 */
diff --git a/nuttx/sched/group_create.c b/nuttx/sched/group_create.c
index da91fa065..768641be1 100644
--- a/nuttx/sched/group_create.c
+++ b/nuttx/sched/group_create.c
@@ -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,12 +65,88 @@
/*****************************************************************************
* 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;
}
diff --git a/nuttx/sched/group_find.c b/nuttx/sched/group_find.c
new file mode 100644
index 000000000..eb3989223
--- /dev/null
+++ b/nuttx/sched/group_find.c
@@ -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 */
diff --git a/nuttx/sched/group_internal.h b/nuttx/sched/group_internal.h
index aa8476e3c..b78b38453 100644
--- a/nuttx/sched/group_internal.h
+++ b/nuttx/sched/group_internal.h
@@ -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);
+
+#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_find(gid) (NULL)
+# define group_addmember(group,pid) (0)
+# define group_removemember(group,pid) (1)
+#endif
+
#ifndef CONFIG_DISABLE_SIGNALS
-int group_signal(FAR _TCB *tcb, FAR siginfo_t *info);
+int group_signal(FAR struct task_group_s *group, FAR siginfo_t *info);
#else
-# 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_signal(tcb,info) (0)
+# 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 */
diff --git a/nuttx/sched/group_join.c b/nuttx/sched/group_join.c
index 077c45763..70319b3a1 100644
--- a/nuttx/sched/group_join.c
+++ b/nuttx/sched/group_join.c
@@ -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 */
diff --git a/nuttx/sched/group_leave.c b/nuttx/sched/group_leave.c
index d5fa9dbaf..add424185 100644
--- a/nuttx/sched/group_leave.c
+++ b/nuttx/sched/group_leave.c
@@ -66,6 +66,65 @@
*****************************************************************************/
/*****************************************************************************
+ * 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++)
- {
- /* 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. */
+ /* Is the group now empty? */
- DEBUGASSERT(i < group->tg_nmembers);
- if (i < group->tg_nmembers)
+ if (ret == 0)
{
- /* 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 */
+
+ group_remove(group);
+
+ /* Release the group container itself */
- sched_free(group);
- }
+ 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 */
diff --git a/nuttx/sched/group_signal.c b/nuttx/sched/group_signal.c
index 5020ec436..009ab7a55 100644
--- a/nuttx/sched/group_signal.c
+++ b/nuttx/sched/group_signal.c
@@ -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 */
diff --git a/nuttx/sched/sched_waitid.c b/nuttx/sched/sched_waitid.c
index 41e488f90..9c24189c4 100644
--- a/nuttx/sched/sched_waitid.c
+++ b/nuttx/sched/sched_waitid.c
@@ -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? */
diff --git a/nuttx/sched/sched_waitpid.c b/nuttx/sched/sched_waitpid.c
index 4af7f7ef3..0285c2673 100644
--- a/nuttx/sched/sched_waitpid.c
+++ b/nuttx/sched/sched_waitpid.c
@@ -172,16 +172,12 @@
*
* Assumptions:
*
- *****************************************************************************/
-
-/***************************************************************************
- * NOTE: This is a partially functional, experimental version of waitpid()
+ * 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.
*
- * 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;
}
}
diff --git a/nuttx/sched/sig_action.c b/nuttx/sched/sig_action.c
index fe72cc22d..5c00179dc 100644
--- a/nuttx/sched/sig_action.c
+++ b/nuttx/sched/sig_action.c
@@ -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
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index cbada851a..3fdf08bf7 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -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,20 +186,96 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
****************************************************************************/
#ifdef CONFIG_SCHED_HAVE_PARENT
+#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;
+
+ DEBUGASSERT(chgrp);
+
+ /* 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 ((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 = group_findchild(pgrp, 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;
+ }
+ }
+#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)group_signal(pgrp, &info);
+ }
+}
+
+#else /* HAVE_GROUP_MEMBERS */
+
static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
{
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.
+ /* 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.
*/
-#ifdef CONFIG_SCHED_CHILD_STATUS
- if (ctcb->group->tg_nmembers == 1)
-#else
if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
-#endif
{
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Check if the parent task group has suppressed retention of child exit
@@ -225,7 +289,7 @@ static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
/* No.. Find the exit status entry for this task in the parent TCB */
- child = task_findchild(ptcb, getpid());
+ child = group_findchild(ptcb->group, getpid());
DEBUGASSERT(child);
if (child)
{
@@ -238,12 +302,15 @@ static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
child->ch_status = status;
}
}
-#else
+
+#else /* CONFIG_SCHED_CHILD_STATUS */
+
/* 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 +327,16 @@ 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
}
}
-#else
-# define task_sigchild(ptct,ctcb,status)
-#endif
+
+#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;
}
diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c
index 1193c9a7f..5bb62893f 100644
--- a/nuttx/sched/task_reparent.c
+++ b/nuttx/sched/task_reparent.c
@@ -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 */
diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c
index b66f3cc7c..b770d46e6 100644
--- a/nuttx/sched/task_setup.c
+++ b/nuttx/sched/task_setup.c
@@ -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