summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-25 17:23:38 +0000
committerpatacongo <patacongo@42af7a65-404d-4744-a932-0658087f49c3>2013-01-25 17:23:38 +0000
commitf2933cc4b65836a712f1ab996512999959a8c48a (patch)
treedd7f8afd13defdb90a4a8ffaba352f90efc3ec3a
parent1520663dd52c25496f285eb2e08077318c600759 (diff)
downloadnuttx-f2933cc4b65836a712f1ab996512999959a8c48a.tar.gz
nuttx-f2933cc4b65836a712f1ab996512999959a8c48a.tar.bz2
nuttx-f2933cc4b65836a712f1ab996512999959a8c48a.zip
Add framework to support task groups
git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5562 42af7a65-404d-4744-a932-0658087f49c3
-rw-r--r--nuttx/include/nuttx/sched.h80
-rw-r--r--nuttx/net/net_poll.c4
-rw-r--r--nuttx/sched/Makefile7
-rw-r--r--nuttx/sched/env_dup.c64
-rw-r--r--nuttx/sched/group_create.c111
-rw-r--r--nuttx/sched/group_join.c107
-rw-r--r--nuttx/sched/group_leave.c127
-rw-r--r--nuttx/sched/os_internal.h15
-rw-r--r--nuttx/sched/os_start.c12
-rw-r--r--nuttx/sched/pthread_create.c43
-rw-r--r--nuttx/sched/sched_releasetcb.c7
-rw-r--r--nuttx/sched/sched_waitid.c6
-rw-r--r--nuttx/sched/sched_waitpid.c6
-rw-r--r--nuttx/sched/sig_action.c2
-rw-r--r--nuttx/sched/task_childstatus.c27
-rw-r--r--nuttx/sched/task_create.c20
-rw-r--r--nuttx/sched/task_exithook.c106
-rw-r--r--nuttx/sched/task_init.c54
-rw-r--r--nuttx/sched/task_reparent.c10
-rw-r--r--nuttx/sched/task_setup.c10
20 files changed, 677 insertions, 141 deletions
diff --git a/nuttx/include/nuttx/sched.h b/nuttx/include/nuttx/sched.h
index 1e75b5020..4a3bae5e4 100644
--- a/nuttx/include/nuttx/sched.h
+++ b/nuttx/include/nuttx/sched.h
@@ -57,6 +57,14 @@
/********************************************************************************
* Pre-processor Definitions
********************************************************************************/
+/* Configuration ****************************************************************/
+/* Task groups currently only supported for retention of child status */
+
+#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
+# define HAVE_TASK_GROUP 1
+#else
+# undef HAVE_TASK_GROUP
+#endif
/* Task Management Definitins ***************************************************/
@@ -64,7 +72,7 @@
#define MAX_LOCK_COUNT 127
-/* Values for the _TCB flags flag bits */
+/* Values for the _TCB flags bits */
#define TCB_FLAG_TTYPE_SHIFT (0) /* Bits 0-1: thread type */
#define TCB_FLAG_TTYPE_MASK (3 << TCB_FLAG_TTYPE_SHIFT)
@@ -74,7 +82,10 @@
#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_NOCLDWAIT (1 << 5) /* Bit 5: Do not retain child exit status */
+
+/* Values for struct task_group tg_flags */
+
+#define GROUP_FLAG_NOCLDWAIT (1 << 0) /* Bit 0: Do not retain child exit status */
/* Values for struct child_status_s ch_flags */
@@ -159,6 +170,7 @@ typedef CODE void (*onexitfunc_t)(int exitcode, FAR void *arg);
typedef struct msgq_s msgq_t;
+/* struct environ_s **************************************************************/
/* The structure used to maintain environment variables */
#ifndef CONFIG_DISABLE_ENVIRON
@@ -173,6 +185,7 @@ typedef struct environ_s environ_t;
# define SIZEOF_ENVIRON_T(alloc) (sizeof(environ_t) + alloc - 1)
#endif
+/* struct child_status_s *********************************************************/
/* This structure is used to maintin information about child tasks.
* pthreads work differently, they have join information. This is
* only for child tasks.
@@ -189,6 +202,7 @@ struct child_status_s
};
#endif
+/* struct dspace_s ***************************************************************/
/* This structure describes a reference counted D-Space region. This must be a
* separately allocated "break-away" structure that can be owned by a task and
* any pthreads created by the task.
@@ -214,6 +228,58 @@ struct dspace_s
};
#endif
+/* struct task_group_s ***********************************************************/
+/* All threads created by pthread_create belong in the same task group (along with
+ * the thread of the original task). struct task_group_s is a shared, "breakaway"
+ * structure referenced by each TCB.
+ *
+ * This structure should contain *all* resources shared by tasks and threads that
+ * belong to the same task group:
+ *
+ * Child exit status
+ * Environment varibles
+ * PIC data space and address environments
+ * File descriptors
+ * FILE streams
+ * Sockets
+ *
+ * Currenty, however, this implementation only applies to child exit status.
+ *
+ * Each instance of struct task_group_s is reference counted. Each instance is
+ * created with a reference count of one. The reference incremeneted when each
+ * thread joins the group and decremented when each thread exits, leaving the
+ * group. When the refernce count decrements to zero, the struc task_group_s
+ * is free.
+ */
+
+#ifdef HAVE_TASK_GROUP
+struct task_group_s
+{
+ uint16_t tg_crefs; /* Count of threads sharing this data */
+ uint8_t tg_flags; /* See GROUP_FLAG_* definitions */
+
+ /* Child exit status **********************************************************/
+
+ FAR struct child_status_s *tg_children; /* Head of a list of child status */
+
+ /* Environment varibles *******************************************************/
+ /* Not yet (see type environ_t) */
+
+ /* PIC data space and address environments */
+ /* Not yet (see struct dspace_s) */
+
+ /* File descriptors */
+ /* Not yet (see struct filelist) */
+
+ /* FILE streams */
+ /* Not yet (see streamlist) */
+
+ /* Sockets */
+ /* Not yet (see struct socketlist) */
+};
+#endif
+
+/* _TCB **************************************************************************/
/* This is the task control block (TCB). Each task or thread is represented by
* a TCB. The TCB is the heart of the NuttX task-control logic.
*/
@@ -225,14 +291,18 @@ struct _TCB
FAR struct _TCB *flink; /* Doubly linked list */
FAR struct _TCB *blink;
+ /* Task Group *****************************************************************/
+
+#ifdef HAVE_TASK_GROUP
+ FAR struct task_group_s *group; /* Pointer to shared task group data */
+#endif
+
/* 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 */
-#ifdef CONFIG_SCHED_CHILD_STATUS /* Retain child thread status */
- FAR struct child_status_s *children; /* Head of a list of child status */
-#else
+#ifndef CONFIG_SCHED_CHILD_STATUS /* Retain child thread status */
uint16_t nchildren; /* This is the number active children */
#endif
#endif
diff --git a/nuttx/net/net_poll.c b/nuttx/net/net_poll.c
index 3021ac35e..1838f541e 100644
--- a/nuttx/net/net_poll.c
+++ b/nuttx/net/net_poll.c
@@ -118,11 +118,11 @@ static uint16_t poll_interrupt(FAR struct uip_driver_s *dev, FAR void *conn,
nllvdbg("flags: %04x\n", flags);
- DEBUGASSERT(info && info->psock && info->fds);
+ DEBUGASSERT(!info || (info->psock && info->fds));
/* 'priv' might be null in some race conditions (?) */
- if (info->fds)
+ if (info)
{
pollevent_t eventset = 0;
diff --git a/nuttx/sched/Makefile b/nuttx/sched/Makefile
index 1ad244450..6a710ff95 100644
--- a/nuttx/sched/Makefile
+++ b/nuttx/sched/Makefile
@@ -87,6 +87,8 @@ SCHED_SRCS += sched_waitid.c sched_wait.c
endif
endif
+GRP_SRCS = group_create.c group_join.c group_leave.c
+
ENV_SRCS = env_getenvironptr.c env_dup.c env_share.c env_release.c
ENV_SRCS += env_findvar.c env_removevar.c
ENV_SRCS += env_clearenv.c env_getenv.c env_putenv.c env_setenv.c env_unsetenv.c
@@ -169,8 +171,9 @@ IRQ_SRCS = irq_initialize.c irq_attach.c irq_dispatch.c irq_unexpectedisr.c
KMM_SRCS = kmm_initialize.c kmm_addregion.c kmm_semaphore.c
KMM_SRCS = kmm_kmalloc.c kmm_kzalloc.c kmm_krealloc.c kmm_kfree.c
-CSRCS = $(MISC_SRCS) $(TSK_SRCS) $(SCHED_SRCS) $(WDOG_SRCS) $(TIME_SRCS) \
- $(SEM_SRCS) $(TIMER_SRCS) $(WORK_SRCS) $(PGFILL_SRCS) $(IRQ_SRCS)
+CSRCS = $(MISC_SRCS) $(TSK_SRCS) $(GRP_SRCS) $(SCHED_SRCS) $(WDOG_SRCS)
+CSRCS += $(TIME_SRCS) $(SEM_SRCS) $(TIMER_SRCS) $(WORK_SRCS) $(PGFILL_SRCS)
+CSRCS += $(IRQ_SRCS)
ifneq ($(CONFIG_DISABLE_CLOCK),y)
CSRCS += $(CLOCK_SRCS)
diff --git a/nuttx/sched/env_dup.c b/nuttx/sched/env_dup.c
index 033348411..30c0b7773 100644
--- a/nuttx/sched/env_dup.c
+++ b/nuttx/sched/env_dup.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/env_dup.c
*
- * Copyright (C) 2007, 2009, 2011 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2011, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -68,7 +68,7 @@
* exact duplicate of the parent task's environment.
*
* Parameters:
- * ptcb The tcb to receive the newly allocated copy of the parspecifiedent
+ * ptcb The tcb to receive the newly allocated copy of the parent
* TCB's environment structure with reference count equal to one
*
* Return Value:
@@ -81,48 +81,42 @@
int env_dup(FAR _TCB *ptcb)
{
+ FAR _TCB *parent = (FAR _TCB*)g_readytorun.head;
+ environ_t *envp = NULL;
int ret = OK;
- if (!ptcb )
- {
- ret = -EINVAL;
- }
- else
- {
- FAR _TCB *parent = (FAR _TCB*)g_readytorun.head;
- environ_t *envp = NULL;
- /* Pre-emption must be disabled throughout the following because the
- * environment may be shared.
- */
+ DEBUGASSERT(ptcb);
+
+ /* Pre-emption must be disabled throughout the following because the
+ * environment may be shared.
+ */
+
+ sched_lock();
- sched_lock();
+ /* Does the parent task have an environment? */
- /* Does the parent task have an environment? */
+ if (parent->envp)
+ {
+ /* Yes..The parent task has an environment, duplicate it */
- if (parent->envp)
+ size_t envlen = parent->envp->ev_alloc;
+ envp = (environ_t*)kmalloc(SIZEOF_ENVIRON_T(envlen));
+ if (!envp)
{
- /* Yes..The parent task has an environment, duplicate it */
-
- size_t envlen = parent->envp->ev_alloc;
- envp = (environ_t*)kmalloc(SIZEOF_ENVIRON_T( envlen ));
- if (!envp)
- {
- ret = -ENOMEM;
- }
- else
- {
- envp->ev_crefs = 1;
- envp->ev_alloc = envlen;
- memcpy( envp->ev_env, parent->envp->ev_env, envlen );
- }
+ ret = -ENOMEM;
}
+ else
+ {
+ envp->ev_crefs = 1;
+ envp->ev_alloc = envlen;
+ memcpy(envp->ev_env, parent->envp->ev_env, envlen);
+ }
+ }
- /* Save the cloned environment in the new TCB */
-
- ptcb->envp = envp;
- sched_unlock();
- }
+ /* Save the cloned environment in the new TCB */
+ ptcb->envp = envp;
+ sched_unlock();
return ret;
}
diff --git a/nuttx/sched/group_create.c b/nuttx/sched/group_create.c
new file mode 100644
index 000000000..d036b9084
--- /dev/null
+++ b/nuttx/sched/group_create.c
@@ -0,0 +1,111 @@
+/*****************************************************************************
+ * sched/group_create.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>
+
+#ifdef HAVE_TASK_GROUP
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Data
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: group_create
+ *
+ * Description:
+ * Create and initialize a new task group structure for the specified TCB.
+ * This function is called as part of the task creation sequence.
+ *
+ * Parameters:
+ * tcb - The tcb in need of the task group.
+ *
+ * Return Value:
+ * 0 (OK) on success; a negated errno value on failure.
+ *
+ * Assumptions:
+ * Called during task creation in a safe context. No special precautions
+ * are required here.
+ *
+ *****************************************************************************/
+
+int group_create(FAR _TCB *tcb)
+{
+ FAR struct task_group_s *group;
+
+ DEBUGASSERT(tcb && !tcb->group);
+
+ /* Allocate the group structure */
+
+ group = (FAR struct task_group_s *)kzalloc(sizeof(struct task_group_s));
+ if (!group)
+ {
+ return -ENOMEM;
+ }
+
+ /* Initialize the group structure and assign it to the tcb */
+
+ group->tg_crefs = 1;
+ tcb->group = group;
+ return OK;
+}
+
+#endif /* HAVE_TASK_GROUP */
diff --git a/nuttx/sched/group_join.c b/nuttx/sched/group_join.c
new file mode 100644
index 000000000..987c1ba87
--- /dev/null
+++ b/nuttx/sched/group_join.c
@@ -0,0 +1,107 @@
+/*****************************************************************************
+ * sched/group_join.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 <debug.h>
+
+#include "os_internal.h"
+
+#ifdef HAVE_TASK_GROUP
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Data
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: group_join
+ *
+ * Description:
+ * Copy the group structure reference from one TCB to another, incrementing
+ * the refrence count on the group. This function is called when a pthread
+ * is produced within the task group so that the pthread can share the
+ * resources of the task group.
+ *
+ * Parameters:
+ * tcb - The TCB of the new "child" task that need to join the group.
+ *
+ * Return Value:
+ * None
+ *
+ * Assumptions:
+ * - The parent task from which the group will be inherited is the task at
+ * the thead of the ready to run list.
+ * - Called during thread creation in a safe context. No special precautions
+ * are required here.
+ *
+ *****************************************************************************/
+
+void group_join(FAR _TCB *tcb)
+{
+ FAR _TCB *ptcb = (FAR _TCB *)g_readytorun.head;
+
+ DEBUGASSERT(ptcb && tcb && ptcb->group && !tcb->group);
+
+ /* Copy the group reference from the parent to the child, incrementing the
+ * reference count.
+ */
+
+ tcb->group = ptcb->group;
+ ptcb->group->tg_crefs++;
+}
+
+#endif /* HAVE_TASK_GROUP */
diff --git a/nuttx/sched/group_leave.c b/nuttx/sched/group_leave.c
new file mode 100644
index 000000000..69a6ea8b2
--- /dev/null
+++ b/nuttx/sched/group_leave.c
@@ -0,0 +1,127 @@
+/*****************************************************************************
+ * sched/group_leave.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 "os_internal.h"
+
+#ifdef HAVE_TASK_GROUP
+
+/*****************************************************************************
+ * Pre-processor Definitions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Types
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Data
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Private Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Public Functions
+ *****************************************************************************/
+
+/*****************************************************************************
+ * Name: group_leave
+ *
+ * Description:
+ * Release a reference on a group. This function is called when a task or
+ * thread exits. It decrements the reference count on the group. If the
+ * reference count decrements to zero, then it frees the group and all of
+ * resources contained in the group.
+ *
+ * Parameters:
+ * tcb - The TCB of the task that is exiting.
+ *
+ * Return Value:
+ * None.
+ *
+ * Assumptions:
+ * Called during task deletion in a safe context. No special precautions
+ * are required here.
+ *
+ *****************************************************************************/
+
+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)
+ {
+ /* Would the reference count decrement to zero? */
+
+ if (group->tg_crefs > 1)
+ {
+ /* No.. just decrement the reference count and return */
+
+ group->tg_crefs--;
+ }
+ else
+ {
+ /* Yes.. Release all of the resource contained within the group */
+ /* Free all un-reaped child exit status */
+
+ task_removechildren(tcb);
+
+ /* Release the group container itself */
+
+ sched_free(group);
+ }
+
+ tcb->group = NULL;
+ }
+}
+
+#endif /* HAVE_TASK_GROUP */
diff --git a/nuttx/sched/os_internal.h b/nuttx/sched/os_internal.h
index dc87cb9a4..ee5ada165 100644
--- a/nuttx/sched/os_internal.h
+++ b/nuttx/sched/os_internal.h
@@ -268,7 +268,20 @@ int task_schedsetup(FAR _TCB *tcb, int priority, start_t start,
int task_argsetup(FAR _TCB *tcb, FAR const char *name, FAR const char *argv[]);
void task_exithook(FAR _TCB *tcb, int status);
int task_deletecurrent(void);
+
#ifdef CONFIG_SCHED_HAVE_PARENT
+int task_reparent(pid_t ppid, pid_t chpid);
+
+#ifdef HAVE_TASK_GROUP
+int group_create(FAR _TCB *tcb);
+void group_join(FAR _TCB *tcb);
+void group_leave(FAR _TCB *tcb);
+#else
+# define group_create(tcb)
+# define group_join(tcb)
+# define group_leave(tcb)
+#endif
+
#ifdef CONFIG_SCHED_CHILD_STATUS
void weak_function task_initialize(void);
FAR struct child_status_s *task_allocchild(void);
@@ -279,8 +292,8 @@ 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
-int task_reparent(pid_t ppid, pid_t chpid);
#endif
+
#ifndef CONFIG_CUSTOM_STACK
int kernel_thread(FAR const char *name, int priority, int stack_size,
main_t entry, FAR const char *argv[]);
diff --git a/nuttx/sched/os_start.c b/nuttx/sched/os_start.c
index a6d4e83b9..244aec967 100644
--- a/nuttx/sched/os_start.c
+++ b/nuttx/sched/os_start.c
@@ -202,6 +202,9 @@ const tasklist_t g_tasklisttable[NUM_TASK_STATES] =
*/
static FAR _TCB g_idletcb;
+#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
+static struct task_group_s g_idlegroup;
+#endif
/* This is the name of the idle task */
@@ -280,13 +283,20 @@ void os_start(void)
g_idletcb.argv[0] = (char*)g_idlename;
#endif /* CONFIG_TASK_NAME_SIZE */
+ /* Join the IDLE group */
+
+#ifdef HAVE_TASK_GROUP
+ g_idlegroup.tg_crefs = 1;
+ g_idlegroup.tg_flags = GROUP_FLAG_NOCLDWAIT;
+ g_idletcb.group = &g_idlegroup;
+#endif
+
/* Then add the idle task's TCB to the head of the ready to run list */
dq_addfirst((FAR dq_entry_t*)&g_idletcb, (FAR dq_queue_t*)&g_readytorun);
/* Initialize the processor-specific portion of the TCB */
- g_idletcb.flags = (TCB_FLAG_TTYPE_KERNEL | TCB_FLAG_NOCLDWAIT);
up_initial_state(&g_idletcb);
/* Initialize the semaphore facility(if in link). This has to be done
diff --git a/nuttx/sched/pthread_create.c b/nuttx/sched/pthread_create.c
index f4d0d8fdf..e37c06892 100644
--- a/nuttx/sched/pthread_create.c
+++ b/nuttx/sched/pthread_create.c
@@ -251,6 +251,7 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
#if CONFIG_RR_INTERVAL > 0
int policy;
#endif
+ int errcode;
pid_t pid;
/* If attributes were not supplied, use the default attributes */
@@ -268,6 +269,12 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
return ENOMEM;
}
+ /* Join the parent's task group */
+
+#ifdef HAVE_TASK_GROUP
+ group_join(ptcb);
+#endif
+
/* Share the address environment of the parent task. NOTE: Only tasks
* created throught the nuttx/binfmt loaders may have an address
* environment.
@@ -277,8 +284,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
ret = up_addrenv_share((FAR const _TCB *)g_readytorun.head, ptcb);
if (ret < 0)
{
- sched_releasetcb(ptcb);
- return -ret;
+ errcode = -ret;
+ goto errout_with_tcb;
}
#endif
@@ -287,8 +294,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
ret = sched_setuppthreadfiles(ptcb);
if (ret != OK)
{
- sched_releasetcb(ptcb);
- return ret;
+ errcode = ret;
+ goto errout_with_tcb;
}
/* Share the parent's envionment */
@@ -300,8 +307,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
pjoin = (FAR join_t*)kzalloc(sizeof(join_t));
if (!pjoin)
{
- sched_releasetcb(ptcb);
- return ENOMEM;
+ errcode = ENOMEM;
+ goto errout_with_tcb;
}
/* Allocate the stack for the TCB */
@@ -309,9 +316,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
ret = up_create_stack(ptcb, attr->stacksize);
if (ret != OK)
{
- sched_releasetcb(ptcb);
- sched_free(pjoin);
- return ENOMEM;
+ errcode = ENOMEM;
+ goto errout_with_join;
}
/* Should we use the priority and scheduler specified in the
@@ -360,9 +366,8 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
TCB_FLAG_TTYPE_PTHREAD);
if (ret != OK)
{
- sched_releasetcb(ptcb);
- sched_free(pjoin);
- return EBUSY;
+ errcode = EBUSY;
+ goto errout_with_join;
}
/* Configure the TCB for a pthread receiving on parameter
@@ -440,10 +445,18 @@ int pthread_create(FAR pthread_t *thread, FAR pthread_attr_t *attr,
dq_rem((FAR dq_entry_t*)ptcb, (dq_queue_t*)&g_inactivetasks);
(void)sem_destroy(&pjoin->data_sem);
(void)sem_destroy(&pjoin->exit_sem);
- sched_releasetcb(ptcb);
- sched_free(pjoin);
- ret = EIO;
+
+ errcode = EIO;
+ goto errout_with_join;
}
return ret;
+
+errout_with_join:
+ sched_free(pjoin);
+ ptcb->joininfo = NULL;
+
+errout_with_tcb:
+ sched_releasetcb(ptcb);
+ return errcode;
}
diff --git a/nuttx/sched/sched_releasetcb.c b/nuttx/sched/sched_releasetcb.c
index 0557c829b..50505f579 100644
--- a/nuttx/sched/sched_releasetcb.c
+++ b/nuttx/sched/sched_releasetcb.c
@@ -1,7 +1,7 @@
/************************************************************************
* sched/sched_releasetcb.c
*
- * Copyright (C) 2007, 2009, 2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2012-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -177,6 +177,11 @@ int sched_releasetcb(FAR _TCB *tcb)
ret = up_addrenv_release(tcb);
#endif
+ /* Leave the group (if we did not already leady in task_exithook.c) */
+
+#ifdef HAVE_TASK_GROUP
+ group_leave(tcb);
+#endif
/* And, finally, release the TCB itself */
sched_free(tcb);
diff --git a/nuttx/sched/sched_waitid.c b/nuttx/sched/sched_waitid.c
index 56bfb36f0..e47e3c38c 100644
--- a/nuttx/sched/sched_waitid.c
+++ b/nuttx/sched/sched_waitid.c
@@ -197,9 +197,9 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Does this task retain child status? */
- retains = ((rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0);
+ retains = ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0);
- if (rtcb->children == NULL && retains)
+ if (rtcb->group->tg_children == NULL && retains)
{
/* There are no children */
@@ -264,7 +264,7 @@ int waitid(idtype_t idtype, id_t id, FAR siginfo_t *info, int options)
* instead).
*/
- DEBUGASSERT(!retains || rtcb->children);
+ DEBUGASSERT(!retains || rtcb->group->tg_children);
if (idtype == P_ALL)
{
/* We are waiting for any child to exit */
diff --git a/nuttx/sched/sched_waitpid.c b/nuttx/sched/sched_waitpid.c
index d7484fca9..2d0fe2e48 100644
--- a/nuttx/sched/sched_waitpid.c
+++ b/nuttx/sched/sched_waitpid.c
@@ -312,9 +312,9 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
#ifdef CONFIG_SCHED_CHILD_STATUS
/* Does this task retain child status? */
- retains = ((rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0);
+ retains = ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0);
- if (rtcb->children == NULL && retains)
+ if (rtcb->group->tg_children == NULL && retains)
{
err = ECHILD;
goto errout_with_errno;
@@ -381,7 +381,7 @@ pid_t waitpid(pid_t pid, int *stat_loc, int options)
* chilren.
*/
- DEBUGASSERT(!retains || rtcb->children);
+ DEBUGASSERT(!retains || rtcb->group->tg_children);
if (retains && (child = task_exitchild(rtcb)) != NULL)
{
/* A child has exited. Apparently we missed the signal.
diff --git a/nuttx/sched/sig_action.c b/nuttx/sched/sig_action.c
index 7d84b6291..b307c1fb6 100644
--- a/nuttx/sched/sig_action.c
+++ b/nuttx/sched/sig_action.c
@@ -237,7 +237,7 @@ int sigaction(int signo, FAR const struct sigaction *act, FAR struct sigaction *
/* Mark that status should be not be retained */
- rtcb->flags |= TCB_FLAG_NOCLDWAIT;
+ rtcb->group->tg_flags |= GROUP_FLAG_NOCLDWAIT;
/* Free all pending exit status */
diff --git a/nuttx/sched/task_childstatus.c b/nuttx/sched/task_childstatus.c
index 6007f03e5..aff2bdf3a 100644
--- a/nuttx/sched/task_childstatus.c
+++ b/nuttx/sched/task_childstatus.c
@@ -111,10 +111,11 @@ static struct child_pool_s g_child_pool;
static void task_dumpchildren(FAR _TCB *tcb, FAR const char *msg)
{
FAR struct child_status_s *child;
+ FAR struct task_group_s *group = tcb->group;
int i;
- dbg("Parent TCB=%p: %s\n", tcb, msg);
- for (i = 0, child = tcb->children; child; i++, child = child->flink)
+ dbg("Parent TCB=%p group=%p: %s\n", tcb, 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",
i, child->ch_flags, child->ch_pid, child->ch_status);
@@ -250,10 +251,12 @@ void task_freechild(FAR struct child_status_s *child)
void task_addchild(FAR _TCB *tcb, 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 = tcb->children;
- tcb->children = child;
+ child->flink = group->tg_children;
+ group->tg_children = child;
task_dumpchildren(tcb, "task_addchild");
}
@@ -282,11 +285,12 @@ 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 task_group_s *group = tcb->group;
FAR struct child_status_s *child;
/* Find the status structure with the matching PID */
- for (child = tcb->children; child; child = child->flink)
+ for (child = group->tg_children; child; child = child->flink)
{
if (child->ch_pid == pid)
{
@@ -318,11 +322,12 @@ 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 task_group_s *group = tcb->group;
FAR struct child_status_s *child;
/* Find the status structure of any child task that has exitted. */
- for (child = tcb->children; child; child = child->flink)
+ for (child = group->tg_children; child; child = child->flink)
{
if ((child->ch_flags & CHILD_FLAG_EXITED) != 0)
{
@@ -357,12 +362,13 @@ 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 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 */
- for (prev = NULL, curr = tcb->children;
+ for (prev = NULL, curr = group->tg_children;
curr;
prev = curr, curr = curr->flink)
{
@@ -384,7 +390,7 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
}
else
{
- tcb->children = curr->flink;
+ group->tg_children = curr->flink;
}
curr->flink = NULL;
@@ -414,18 +420,19 @@ FAR struct child_status_s *task_removechild(FAR _TCB *tcb, pid_t pid)
void task_removechildren(FAR _TCB *tcb)
{
+ FAR struct task_group_s *group = tcb->group;
FAR struct child_status_s *curr;
FAR struct child_status_s *next;
/* Remove all child structures for the TCB and return them to the freelist */
- for (curr = tcb->children; curr; curr = next)
+ for (curr = group->tg_children; curr; curr = next)
{
next = curr->flink;
task_freechild(curr);
}
- tcb->children = NULL;
+ group->tg_children = NULL;
task_dumpchildren(tcb, "task_removechildren");
}
diff --git a/nuttx/sched/task_create.c b/nuttx/sched/task_create.c
index 2ed929ab0..f2aeeeec0 100644
--- a/nuttx/sched/task_create.c
+++ b/nuttx/sched/task_create.c
@@ -108,6 +108,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
{
FAR _TCB *tcb;
pid_t pid;
+ int errcode;
int ret;
/* Allocate a TCB for the new task. */
@@ -115,15 +116,28 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
tcb = (FAR _TCB*)kzalloc(sizeof(_TCB));
if (!tcb)
{
+ errcode = ENOMEM;
goto errout;
}
+ /* Create a new task group */
+
+#ifdef HAVE_TASK_GROUP
+ ret = group_create(tcb);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout_with_tcb;
+ }
+#endif
+
/* Associate file descriptors with the new task */
#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
ret = sched_setuptaskfiles(tcb);
if (ret != OK)
{
+ errcode = -ret;
goto errout_with_tcb;
}
#endif
@@ -138,6 +152,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
ret = up_create_stack(tcb, stack_size);
if (ret != OK)
{
+ errcode = -ret;
goto errout_with_tcb;
}
#endif
@@ -147,6 +162,7 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
ret = task_schedsetup(tcb, priority, task_start, entry, ttype);
if (ret != OK)
{
+ errcode = -ret;
goto errout_with_tcb;
}
@@ -163,6 +179,8 @@ static int thread_create(const char *name, uint8_t ttype, int priority,
ret = task_activate(tcb);
if (ret != OK)
{
+ errcode = get_errno();
+
/* The TCB was added to the active task list by task_schedsetup() */
dq_rem((FAR dq_entry_t*)tcb, (dq_queue_t*)&g_inactivetasks);
@@ -175,7 +193,7 @@ errout_with_tcb:
sched_releasetcb(tcb);
errout:
- errno = ENOMEM;
+ set_errno(errcode);
return ERROR;
}
diff --git a/nuttx/sched/task_exithook.c b/nuttx/sched/task_exithook.c
index 1813c12ed..30ce41f71 100644
--- a/nuttx/sched/task_exithook.c
+++ b/nuttx/sched/task_exithook.c
@@ -197,39 +197,28 @@ static inline void task_onexit(FAR _TCB *tcb, int status)
****************************************************************************/
#ifdef CONFIG_SCHED_HAVE_PARENT
-static inline void task_sigchild(FAR _TCB *tcb, int status)
+static inline void task_sigchild(FAR _TCB *ptcb, FAR _TCB *ctcb, int status)
{
- FAR _TCB *ptcb;
siginfo_t info;
- /* Only exiting tasks should generate SIGCHLD. pthreads use other
- * mechansims.
+ /* 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 ((tcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
+#ifdef CONFIG_SCHED_CHILD_STATUS
+ if (ctcb->group->tg_crefs == 1)
+#else
+ if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) == TCB_FLAG_TTYPE_TASK)
+#endif
{
- /* Keep things stationary through the following */
-
- sched_lock();
-
- /* Get the TCB of the receiving task */
-
- ptcb = sched_gettcb(tcb->parent);
- if (!ptcb)
- {
- /* The parent no longer exists... bail */
-
- sched_unlock();
- return;
- }
-
#ifdef CONFIG_SCHED_CHILD_STATUS
- /* Check if the parent task has suppressed retention of child exit
+ /* 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->flags & TCB_FLAG_NOCLDWAIT) == 0)
+ if ((ptcb->group->tg_flags & GROUP_FLAG_NOCLDWAIT) == 0)
{
FAR struct child_status_s *child;
@@ -255,15 +244,6 @@ static inline void task_sigchild(FAR _TCB *tcb, int status)
ptcb->nchildren--;
#endif
- /* 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, nchildren will be decremented once and
- * all will be well.
- */
-
- tcb->parent = INVALID_PROCESS_ID;
-
/* 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.
@@ -272,7 +252,7 @@ static inline void task_sigchild(FAR _TCB *tcb, int status)
info.si_signo = SIGCHLD;
info.si_code = CLD_EXITED;
info.si_value.sival_ptr = NULL;
- info.si_pid = tcb->pid;
+ info.si_pid = ctcb->pid;
info.si_status = status;
/* Send the signal. We need to use this internal interface so that we
@@ -280,11 +260,59 @@ static inline void task_sigchild(FAR _TCB *tcb, int status)
*/
(void)sig_received(ptcb, &info);
+ }
+}
+#else
+# define task_sigchild(ptct,ctcb,status)
+#endif
+
+/****************************************************************************
+ * Name: task_leavegroup
+ *
+ * Description:
+ * Send the SIGCHILD signal to the parent thread
+ *
+ ****************************************************************************/
+
+#ifdef CONFIG_SCHED_HAVE_PARENT
+static inline void task_leavegroup(FAR _TCB *ctcb, int status)
+{
+ FAR _TCB *ptcb;
+
+ /* Keep things stationary throughout the following */
+
+ 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
+ * invalid value below and the following call will fail if we are
+ * called again.
+ */
+
+ ptcb = sched_gettcb(ctcb->parent);
+ if (!ptcb)
+ {
+ /* The parent no longer exists... bail */
+
sched_unlock();
+ return;
}
+
+ /* Send SIGCHLD to all members of the parent's task group */
+
+ 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.
+ */
+
+ ctcb->parent = INVALID_PROCESS_ID;
+ sched_unlock();
}
#else
-# define task_sigchild(tcb,status)
+# define task_leavegroup(ctcb,status)
#endif
/****************************************************************************
@@ -363,9 +391,9 @@ void task_exithook(FAR _TCB *tcb, int status)
task_onexit(tcb, status);
- /* Send SIGCHLD to the parent of the exit-ing task */
+ /* Leave the task group */
- task_sigchild(tcb, status);
+ task_leavegroup(tcb, status);
/* Wakeup any tasks waiting for this task to exit */
@@ -379,10 +407,12 @@ void task_exithook(FAR _TCB *tcb, int status)
(void)lib_flushall(tcb->streams);
#endif
- /* Discard any un-reaped child status (no zombies here!) */
+ /* Leave the task group. Perhaps discarding any un-reaped child
+ * status (no zombies here!)
+ */
-#if defined(CONFIG_SCHED_HAVE_PARENT) && defined(CONFIG_SCHED_CHILD_STATUS)
- task_removechildren(tcb);
+#ifdef HAVE_TASK_GROUP
+ group_leave(tcb);
#endif
/* Free all file-related resources now. This gets called again
diff --git a/nuttx/sched/task_init.c b/nuttx/sched/task_init.c
index 0f0fdc68e..5ba6b7e7d 100644
--- a/nuttx/sched/task_init.c
+++ b/nuttx/sched/task_init.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/task_init.c
*
- * Copyright (C) 2007, 2009 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007, 2009, 2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -42,6 +42,8 @@
#include <sys/types.h>
#include <stdint.h>
#include <sched.h>
+#include <errno.h>
+
#include <nuttx/arch.h>
#include "os_internal.h"
@@ -102,10 +104,10 @@
* parameters are required, argv may be NULL.
*
* Return Value:
- * OK on success; ERROR on failure. (See task_schedsetup() for possible
- * failure conditions). On failure, the caller is responsible for freeing
- * the stack memory and for calling sched_releasetcb() to free the TCB
- * (which could be in most any state).
+ * OK on success; ERROR on failure with errno set appropriately. (See
+ * task_schedsetup() for possible failure conditions). On failure, the
+ * caller is responsible for freeing the stack memory and for calling
+ * sched_releasetcb() to free the TCB (which could be in most any state).
*
****************************************************************************/
@@ -118,14 +120,28 @@ int task_init(FAR _TCB *tcb, const char *name, int priority,
main_t entry, const char *argv[])
#endif
{
+ int errcode;
int ret;
+ /* Create a new task group */
+
+#ifdef HAVE_TASK_GROUP
+ ret = group_create(tcb);
+ if (ret < 0)
+ {
+ errcode = -ret;
+ goto errout;
+ }
+#endif
+
/* Associate file descriptors with the new task */
#if CONFIG_NFILE_DESCRIPTORS > 0 || CONFIG_NSOCKET_DESCRIPTORS > 0
- if (sched_setuptaskfiles(tcb) != OK)
+ ret = sched_setuptaskfiles(tcb);
+ if (ret < 0)
{
- return ERROR;
+ errcode = -ret;
+ goto errout_with_group;
}
#endif
@@ -143,13 +159,27 @@ int task_init(FAR _TCB *tcb, const char *name, int priority,
ret = task_schedsetup(tcb, priority, task_start, entry,
TCB_FLAG_TTYPE_TASK);
- if (ret == OK)
+ if (ret < OK)
{
- /* Setup to pass parameters to the new task */
-
- (void)task_argsetup(tcb, name, argv);
+ errcode = -ret;
+ goto errout_with_env;
}
- return ret;
+ /* Setup to pass parameters to the new task */
+
+ (void)task_argsetup(tcb, name, argv);
+ return OK;
+
+errout_with_env:
+ env_release(tcb);
+
+errout_with_group:
+#ifdef HAVE_TASK_GROUP
+ group_leave(tcb);
+
+errout:
+#endif
+ set_errno(errcode);
+ return ERROR;
}
diff --git a/nuttx/sched/task_reparent.c b/nuttx/sched/task_reparent.c
index 3a7ece37d..0b502dcce 100644
--- a/nuttx/sched/task_reparent.c
+++ b/nuttx/sched/task_reparent.c
@@ -138,11 +138,11 @@ int task_reparent(pid_t ppid, pid_t chpid)
child = task_removechild(otcb, chpid);
if (child)
{
- /* Has the new parent supressed child exit status? */
+ /* Has the new parent's task group supressed child exit status? */
- if ((ptcb->flags && TCB_FLAG_NOCLDWAIT) == 0)
+ if ((ptcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
{
- /* No.. Add the child status entry to the new parent TCB */
+ /* No.. Add the child status entry to the new parent's task group */
task_addchild(ptcb, child);
}
@@ -159,11 +159,11 @@ int task_reparent(pid_t ppid, pid_t chpid)
}
else
{
- /* This would not be an error if the original parent has
+ /* This would not be an error if the original parent's task group has
* suppressed child exit status.
*/
- ret = ((otcb->flags && TCB_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
+ ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
}
#else
DEBUGASSERT(otcb->nchildren > 0);
diff --git a/nuttx/sched/task_setup.c b/nuttx/sched/task_setup.c
index 66c948cfd..7675c7481 100644
--- a/nuttx/sched/task_setup.c
+++ b/nuttx/sched/task_setup.c
@@ -1,7 +1,7 @@
/****************************************************************************
* sched/task_setup.c
*
- * Copyright (C) 2007-2012 Gregory Nutt. All rights reserved.
+ * Copyright (C) 2007-2013 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
@@ -179,13 +179,11 @@ static inline void task_saveparent(FAR _TCB *tcb, uint8_t ttype)
tcb->parent = rtcb->pid;
#ifdef CONFIG_SCHED_CHILD_STATUS
- /* Exit status only needs to be retained for the case of tasks, however.
- * Tasks can also suppress retention of their child status by applying
- * the SA_NOCLDWAIT flag with sigaction()/
+ /* Tasks can also suppress retention of their child status by applying
+ * the SA_NOCLDWAIT flag with sigaction().
*/
- if (ttype == TCB_FLAG_TTYPE_TASK &&
- (rtcb->flags && TCB_FLAG_NOCLDWAIT) == 0)
+ if ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
{
FAR struct child_status_s *child;