static void group_assigngid(FAR struct task_group_s *group)
{
  irqstate_t flags;
  gid_t gid;

  /* Pre-emption should already be enabled, but lets be paranoid careful */

  sched_lock();

  /* Loop until we create a unique ID */

  for (;;)
    {
      /* Increment the ID counter.  This is global data so be extra paranoid. */

      flags = irqsave();
      gid = ++g_gidcounter;

      /* Check for overflow */

      if (gid <= 0)
        {
          g_gidcounter = 1;
          irqrestore(flags);
        }
      else
        {
          /* Does a task group with this ID already exist? */

          irqrestore(flags);
          if (group_findbygid(gid) == NULL)
            {
              /* Now assign this ID to the group and return */

              group->tg_gid = gid;
              sched_unlock();
              return;
            }
        }
    }
}
Beispiel #2
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;
}
Beispiel #3
0
int group_addrenv(FAR struct tcb_s *tcb)
{
  FAR struct task_group_s *group;
  FAR struct task_group_s *oldgroup;
  irqstate_t flags;
  gid_t gid;
  int ret;

  /* NULL for the tcb means to use the TCB of the task at the head of the
   * ready to run list.
   */

  if (!tcb)
    {
      tcb = (FAR struct tcb_s *)g_readytorun.head;
    }

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

  /* Does the group have an address environment? */

  if ((group->tg_flags & GROUP_FLAG_ADDRENV) == 0)
    {
      /* No... just return perhaps leaving a different address environment
       * intact.
       */

      return OK;
    }

  /* Get the ID of the group that needs the address environment */

  gid = group->tg_gid;
  DEBUGASSERT(gid != 0);

  /* Are we going to change address environments? */

  flags = irqsave();
  if (gid != g_gid_current)
    {
      /* Yes.. Is there a current address environment in place? */

      if (g_gid_current != 0)
        {
          /* Find the old group with this ID. */

          oldgroup = group_findbygid(g_gid_current);
          DEBUGASSERT(oldgroup &&
                     (oldgroup->tg_flags & GROUP_FLAG_ADDRENV) != 0);

          if (oldgroup)
            {
              /* We need to flush the D-Cache and Invalidate the I-Cache for
               * the group whose environment is disappearing.
               */

              up_addrenv_coherent(&oldgroup->addrenv);
            }
        }

      /* Instantiate the new address environment (removing the old
       * environment in the process).  For the case of kernel threads,
       * the old mappings will be removed and no new mappings will be
       * instantiated.
       */

      ret = up_addrenv_select(&group->addrenv, NULL);
      if (ret < 0)
        {
          bdbg("ERROR: up_addrenv_select failed: %d\n", ret);
        }

      /* Save the new, current group */
  
      g_gid_current = gid;
    }

  irqrestore(flags);
  return OK;
}
Beispiel #4
0
static inline void task_sigchild(gid_t pgid, FAR struct tcb_s *ctcb, int status)
{
  FAR struct task_group_s *chgrp = ctcb->group;
  FAR struct task_group_s *pgrp;
  siginfo_t info;

  DEBUGASSERT(chgrp);

  /* Get the parent task group.  It is possible that all of the members of
   * the parent task group have exited.  This would not be an error.  In
   * this case, the child task group has been orphaned.
   */

  pgrp = group_findbygid(pgid);
  if (!pgrp)
    {
      /* Set the task group ID to an invalid group ID.  The dead parent
       * task group ID could get reused some time in the future.
       */

      chgrp->tg_pgid = INVALID_GROUP_ID;
      return;
    }

  /* Save the exit status now if this is the main thread of the task group
   * that is exiting. Only the exiting main task of a task group carries
   * interpretable exit  Check if this is the main task that is exiting.
   */

#ifndef CONFIG_DISABLE_PTHREAD
  if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
#endif
    {
      task_exitstatus(pgrp, status);
    }

  /* But only the final exiting thread in a task group, whatever it is,
   * should generate SIGCHLD.
   */

  if (chgrp->tg_nmembers == 1)
    {
      /* Mark that all of the threads in the task group have exited */

      task_groupexit(pgrp);

      /* Create the siginfo structure.  We don't actually know the cause.
       * That is a bug. Let's just say that the child task just exited
       * for now.
       */

      info.si_signo           = SIGCHLD;
      info.si_code            = CLD_EXITED;
      info.si_errno           = OK;
      info.si_value.sival_ptr = NULL;
#ifndef CONFIG_DISABLE_PTHREAD
      info.si_pid             = chgrp->tg_task;
#else
      info.si_pid             = ctcb->pid;
#endif
      info.si_status          = status;

      /* Send the signal to one thread in the group */

      (void)group_signal(pgrp, &info);
    }
}