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:
parent
99603c9a02
commit
03fd50017d
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 )
|
||||
|
||||
DEBUGASSERT(ptcb);
|
||||
|
||||
/* Pre-emption must be disabled throughout the following because the
|
||||
* environment may be shared.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
|
||||
/* Does the parent task have an environment? */
|
||||
|
||||
if (parent->envp)
|
||||
{
|
||||
ret = -EINVAL;
|
||||
}
|
||||
else
|
||||
{
|
||||
FAR _TCB *parent = (FAR _TCB*)g_readytorun.head;
|
||||
environ_t *envp = NULL;
|
||||
/* Yes..The parent task has an environment, duplicate it */
|
||||
|
||||
/* Pre-emption must be disabled throughout the following because the
|
||||
* environment may be shared.
|
||||
*/
|
||||
|
||||
sched_lock();
|
||||
|
||||
/* Does the parent task have an environment? */
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
111
sched/group_create.c
Normal file
111
sched/group_create.c
Normal 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
107
sched/group_join.c
Normal 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
127
sched/group_leave.c
Normal 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 */
|
@ -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[]);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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");
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user