Add framework to support task groups

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@5562 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2013-01-25 17:23:38 +00:00
parent 99603c9a02
commit 03fd50017d
20 changed files with 681 additions and 145 deletions

View File

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

View File

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

View File

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

View File

@ -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:
@ -80,16 +80,12 @@
****************************************************************************/
int env_dup(FAR _TCB *ptcb)
{
int ret = OK;
if (!ptcb )
{
ret = -EINVAL;
}
else
{
FAR _TCB *parent = (FAR _TCB*)g_readytorun.head;
environ_t *envp = NULL;
int ret = OK;
DEBUGASSERT(ptcb);
/* Pre-emption must be disabled throughout the following because the
* environment may be shared.
@ -121,8 +117,6 @@ int env_dup(FAR _TCB *ptcb)
ptcb->envp = envp;
sched_unlock();
}
return ret;
}

111
sched/group_create.c Normal file
View File

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

107
sched/group_join.c Normal file
View File

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

127
sched/group_leave.c Normal file
View File

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

View File

@ -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[]);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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)
{
/* 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
if (ctcb->group->tg_crefs == 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
* 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);
sched_unlock();
}
}
#else
# define task_sigchild(tcb,status)
# 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_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

View File

@ -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)
{
errcode = -ret;
goto errout_with_env;
}
/* Setup to pass parameters to the new task */
(void)task_argsetup(tcb, name, argv);
}
return ret;
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;
}

View File

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

View File

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