Esempio n. 1
0
int task_reparent(pid_t ppid, pid_t chpid)
{
#ifdef CONFIG_SCHED_CHILD_STATUS
  FAR struct child_status_s *child;
#endif
  FAR struct task_group_s *chgrp;
  FAR struct task_group_s *ogrp;
  FAR struct task_group_s *pgrp;
  struct tcb_s *tcb;
  gid_t ogid;
  gid_t pgid;
  irqstate_t flags;
  int ret;

  /* Disable interrupts so that nothing can change in the relatinoship of
   * the three task:  Child, current parent, and new parent.
   */

  flags = irqsave();

  /* Get the child tasks task group */

  tcb = sched_gettcb(chpid);
  if (!tcb)
    {
      ret = -ECHILD;
      goto errout_with_ints;
    }

  DEBUGASSERT(tcb->group);
  chgrp = tcb->group;

  /* Get the GID of the old parent task's task group (ogid) */

  ogid = chgrp->tg_pgid;

  /* Get the old parent task's task group (ogrp) */

  ogrp = group_findbygid(ogid);
  if (!ogrp)
    {
      ret = -ESRCH;
      goto errout_with_ints;
    }

  /* If new parent task's PID (ppid) is zero, then new parent is the
   * grandparent will be the new parent, i.e., the parent of the current
   * parent task.
   */

  if (ppid == 0)
    {
      /* Get the grandparent task's task group (pgrp) */

      pgid = ogrp->tg_pgid;
      pgrp = group_findbygid(pgid);
    }
  else
    {
      /* Get the new parent task's task group (pgrp) */

      tcb = sched_gettcb(ppid);
      if (!tcb)
        {
          ret = -ESRCH;
          goto errout_with_ints;
        }

      pgrp = tcb->group;
      pgid = pgrp->tg_gid;
    }

  if (!pgrp)
    {
      ret = -ESRCH;
      goto errout_with_ints;
    }

  /* Then reparent the child.  Notice that we don't actually change the
   * parent of the task. Rather, we change the parent task group for
   * all members of the child's task group.
   */

  chgrp->tg_pgid = pgid;

#ifdef CONFIG_SCHED_CHILD_STATUS
  /* Remove the child status entry from old parent task group */

  child = group_removechild(ogrp, chpid);
  if (child)
    {
      /* Has the new parent's task group supressed child exit status? */

      if ((pgrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
        {
          /* No.. Add the child status entry to the new parent's task group */

          group_addchild(pgrp, child);
        }
      else
        {
          /* Yes.. Discard the child status entry */

          group_freechild(child);
        }

      /* Either case is a success */

      ret = OK;
    }
  else
    {
      /* This would not be an error if the original parent's task group has
       * suppressed child exit status.
       */

      ret = ((ogrp->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
    }

#else /* CONFIG_SCHED_CHILD_STATUS */

  DEBUGASSERT(otcb->nchildren > 0);

  otcb->nchildren--;     /* The orignal parent now has one few children */
  ptcb->nchildren++;     /* The new parent has one additional child */
  ret = OK;

#endif /* CONFIG_SCHED_CHILD_STATUS */

errout_with_ints:
  irqrestore(flags);
  return ret;
}
Esempio n. 2
0
static inline void task_saveparent(FAR struct tcb_s *tcb, uint8_t ttype)
{
  FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head;

#if defined(HAVE_GROUP_MEMBERS) || defined(CONFIG_SCHED_CHILD_STATUS)
  DEBUGASSERT(tcb && tcb->group && rtcb->group);
#else
#endif

#ifdef HAVE_GROUP_MEMBERS
  /* Save the ID of the parent tasks' task group in the child's task group.
   * Do nothing for pthreads.  The parent and the child are both members of
   * the same task group.
   */

#ifndef CONFIG_DISABLE_PTHREAD
  if ((tcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
#endif
    {
      /* This is a new task in a new task group, we have to copy the ID from
       * the parent's task group structure to child's task group.
       */

      tcb->group->tg_pgid = rtcb->group->tg_gid;
    }

#else
  DEBUGASSERT(tcb);

  /* Save the parent task's ID in the child task's TCB.  I am not sure if
   * this makes sense for the case of pthreads or not, but I don't think it
   * is harmful in any event.
   */

  tcb->ppid = rtcb->pid;
#endif

#ifdef CONFIG_SCHED_CHILD_STATUS
  /* Tasks can also suppress retention of their child status by applying
   * the SA_NOCLDWAIT flag with sigaction().
   */

  if ((rtcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
    {
      FAR struct child_status_s *child;

      /* Make sure that there is not already a structure for this PID in the
       * parent TCB.  There should not be.
       */

      child = group_findchild(rtcb->group, tcb->pid);
      DEBUGASSERT(!child);
      if (!child)
        {
          /* Allocate a new status structure  */

          child = group_allocchild();
        }

      /* Did we successfully find/allocate the child status structure? */

      DEBUGASSERT(child);
      if (child)
        {
          /* Yes.. Initialize the structure */

          child->ch_flags  = ttype;
          child->ch_pid    = tcb->pid;
          child->ch_status = 0;

          /* Add the entry into the TCB list of children */

          group_addchild(rtcb->group, child);
        }
    }
#else
  DEBUGASSERT(rtcb->nchildren < UINT16_MAX);
  rtcb->nchildren++;
#endif
}
Esempio n. 3
0
int task_reparent(pid_t ppid, pid_t chpid)
{
#ifdef CONFIG_SCHED_CHILD_STATUS
  FAR struct child_status_s *child;
#endif
  struct tcb_s *ptcb;
  struct tcb_s *chtcb;
  struct tcb_s *otcb;
  pid_t opid;
  irqstate_t flags;
  int ret;

  /* Disable interrupts so that nothing can change in the relatinoship of
   * the three task:  Child, current parent, and new parent.
   */

  flags = irqsave();

  /* Get the child tasks TCB (chtcb) */

  chtcb = sched_gettcb(chpid);
  if (!chtcb)
    {
      ret = -ECHILD;
      goto errout_with_ints;
    }

  /* Get the PID of the child task's parent (opid) */

  opid = chtcb->ppid;

  /* Get the TCB of the child task's parent (otcb) */

  otcb = sched_gettcb(opid);
  if (!otcb)
    {
      ret = -ESRCH;
      goto errout_with_ints;
    }

  /* If new parent task's PID (ppid) is zero, then new parent is the
   * grandparent will be the new parent, i.e., the parent of the current
   * parent task.
   */

  if (ppid == 0)
    {
      ppid = otcb->ppid;
    }

  /* Get the new parent task's TCB (ptcb) */

  ptcb = sched_gettcb(ppid);
  if (!ptcb)
    {
      ret = -ESRCH;
      goto errout_with_ints;
    }

  /* Then reparent the child */

  chtcb->ppid = ppid;  /* The task specified by ppid is the new parent */

#ifdef CONFIG_SCHED_CHILD_STATUS
  /* Remove the child status entry from old parent TCB */

  child = group_removechild(otcb->group, chpid);
  if (child)
    {
      /* Has the new parent's task group supressed child exit status? */

      if ((ptcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0)
        {
          /* No.. Add the child status entry to the new parent's task group */

          group_addchild(ptcb->group, child);
        }
      else
        {
          /* Yes.. Discard the child status entry */

          group_freechild(child);
        }

      /* Either case is a success */

      ret = OK;
    }
  else
    {
      /* This would not be an error if the original parent's task group has
       * suppressed child exit status.
       */

      ret = ((otcb->group->tg_flags && GROUP_FLAG_NOCLDWAIT) == 0) ? -ENOENT : OK;
    }

#else /* CONFIG_SCHED_CHILD_STATUS */

  DEBUGASSERT(otcb->nchildren > 0);

  otcb->nchildren--;     /* The orignal parent now has one few children */
  ptcb->nchildren++;     /* The new parent has one additional child */
  ret = OK;

#endif /* CONFIG_SCHED_CHILD_STATUS */

errout_with_ints:
  irqrestore(flags);
  return ret;
}