예제 #1
0
int sig_dispatch(pid_t pid, FAR siginfo_t *info)
{
#ifdef HAVE_GROUP_MEMBERS

  FAR struct tcb_s *stcb;
  FAR struct task_group_s *group;

  /* Get the TCB associated with the pid */

  stcb = sched_gettcb(pid);
  if (stcb)
    {
      /* The task/thread associated with this PID is still active.  Get its
       * task group.
       */

      group = stcb->group;
    }
  else
    {
      /* The task/thread associated with this PID has exited.  In the normal
       * usage model, the PID should correspond to the PID of the task that
       * created the task group.  Try looking it up.
       */

      group = group_findbypid(pid);
    }

  /* Did we locate the group? */

  if (group)
    {
      /* Yes.. call group_signal() to send the signal to the correct group
       * member.
       */

      return group_signal(group, info);
    }
  else
    {
      return -ESRCH;
    }

#else

  FAR struct tcb_s *stcb;

  /* Get the TCB associated with the pid */

  stcb = sched_gettcb(pid);
  if (!stcb)
    {
      return -ESRCH;
    }

  return sig_tcbdispatch(stcb, info);

#endif
}
예제 #2
0
static void pthread_condtimedout(int argc, uint32_t pid, uint32_t signo)
{
#ifdef HAVE_GROUP_MEMBERS

  FAR struct tcb_s *tcb;
  siginfo_t info;

  /* The logic below if equivalent to sigqueue(), but uses sig_tcbdispatch()
   * instead of sig_dispatch().  This avoids the group signal deliver logic
   * and assures, instead, that the signal is delivered specifically to this
   * thread that is known to be waiting on the signal.
   */

  /* Get the waiting TCB.  sched_gettcb() might return NULL if the task has
   * exited for some reason.
   */

  tcb = sched_gettcb((pid_t)pid);
  if (tcb)
    {
      /* Create the siginfo structure */

      info.si_signo           = signo;
      info.si_code            = SI_QUEUE;
      info.si_errno           = ETIMEDOUT;
      info.si_value.sival_ptr = NULL;
#ifdef CONFIG_SCHED_HAVE_PARENT
      info.si_pid             = (pid_t)pid;
      info.si_status          = OK;
#endif

      /* Process the receipt of the signal.  The scheduler is not locked as
       * is normally the case when this function is called because we are in
       * a watchdog timer interrupt handler.
       */

      (void)sig_tcbdispatch(tcb, &info);
    }

#else /* HAVE_GROUP_MEMBERS */

  /* Things are a little easier if there are not group members.  We can just
   * use sigqueue().
   */

#ifdef CONFIG_CAN_PASS_STRUCTS
  union sigval value;

  /* Send the specified signal to the specified task. */

  value.sival_ptr = NULL;
  (void)sigqueue((int)pid, (int)signo, value);
#else
  (void)sigqueue((int)pid, (int)signo, NULL);
#endif

#endif /* HAVE_GROUP_MEMBERS */
}
예제 #3
0
static inline void task_sigchild(FAR struct tcb_s *ptcb,
                                 FAR struct tcb_s *ctcb, int status)
{
  siginfo_t info;

  /* If task groups are not supported then we will report SIGCHLD when the
   * task exits.  Unfortunately, there could still be threads in the group
   * that are still running.
   */

#ifndef CONFIG_DISABLE_PTHREAD
  if ((ctcb->flags & TCB_FLAG_TTYPE_MASK) != TCB_FLAG_TTYPE_PTHREAD)
#endif
    {
#ifdef CONFIG_SCHED_CHILD_STATUS
      /* Save the exit status now of the main thread */

      task_exitstatus(ptcb->group, status);

#else /* CONFIG_SCHED_CHILD_STATUS */

      /* Decrement the number of children from this parent */

      DEBUGASSERT(ptcb->nchildren > 0);
      ptcb->nchildren--;

#endif /* CONFIG_SCHED_CHILD_STATUS */

      /* 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             = ctcb->group->tg_task;
#else
      info.si_pid             = ctcb->pid;
#endif
      info.si_status          = status;

      /* Send the signal.  We need to use this internal interface so that we
       * can provide the correct si_code value with the signal.
       */

      (void)sig_tcbdispatch(ptcb, &info);
    }
}
예제 #4
0
int pthread_kill(pthread_t thread, int signo)
{
#ifdef HAVE_GROUP_MEMBERS
    /* If group members are support then pthread_kill() differs from kill().
     * kill(), in this case, must following the POSIX rules for delivery of
     * signals in the group environment.  Otherwise, kill(), like
     * pthread_kill() will just deliver the signal to the thread ID it is
     * requested to use.
     */

#ifdef CONFIG_SCHED_HAVE_PARENT
    FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
#endif
    FAR struct tcb_s *stcb;
    siginfo_t info;
    int ret;

    /* Make sure that the signal is valid */

    if (!GOOD_SIGNO(signo))
    {
        ret = -EINVAL;
        goto errout;
    }

    /* Keep things stationary through the following */

    sched_lock();

    /* Create the siginfo structure */

    info.si_signo           = signo;
    info.si_code            = SI_USER;
    info.si_value.sival_ptr = NULL;
#ifdef CONFIG_SCHED_HAVE_PARENT
    info.si_pid             = rtcb->pid;
    info.si_status          = OK;
#endif

    /* Get the TCB associated with the thread */

    stcb = sched_gettcb((pid_t)thread);
    if (!stcb)
    {
        ret = -ESRCH;
        goto errout_with_lock;
    }

    /* Dispatch the signal to thread, bypassing normal task group thread
     * dispatch rules.
     */

    ret = sig_tcbdispatch(stcb, &info);
    sched_unlock();

    if (ret < 0)
    {
        goto errout;
    }

    return OK;

errout_with_lock:
    sched_unlock();
errout:
    return -ret;

#else
    /* If group members are not supported then pthread_kill is basically the
     * same as kill().
     */

    int ret;

    set_errno(EINVAL);
    ret = kill((pid_t)thread, signo);
    if (ret != OK)
    {
        ret = get_errno();
    }

    return ret;
#endif
}
예제 #5
0
static int group_signal_handler(pid_t pid, FAR void *arg)
{
  FAR struct group_signal_s *info = (FAR struct group_signal_s *)arg;
  FAR struct tcb_s *tcb;
  FAR sigactq_t *sigact;
  int ret;

  DEBUGASSERT(info);

  /* Get the TCB associated with the group member */

  tcb = sched_gettcb(pid);
  DEBUGASSERT(tcb);
  if (tcb)
    {
      /* Set this one as the default if we have not already set the default. */

      if (!info->dtcb)
        {
          info->dtcb = tcb;
        }

      /* Is the thread waiting for this signal (in this case, the signal is
       * probably blocked).
       */

      if (sigismember(&tcb->sigwaitmask, info->siginfo->si_signo) && !info->atcb)
        {
          /* Yes.. This means that the task is suspended, waiting for this
           * signal to occur. Stop looking and use this TCB.  The
           * requirement is this:  If a task group receives a signal and
           * more than one thread is waiting on that signal, then one and
           * only one indeterminate thread out of that waiting group will
           * receive the signal.
           */

          ret = sig_tcbdispatch(tcb, info->siginfo);
          if (ret < 0)
            {
              return ret;
            }

          /* Limit to one thread */

          info->atcb = tcb;
          if (info->ptcb != NULL);
            {
              return 1; /* Terminate the search */
            }
        }

      /* Is this signal unblocked on this thread? */

      if (!sigismember(&tcb->sigprocmask, info->siginfo->si_signo) &&
          !info->ptcb && tcb != info->atcb)
        {
          /* Yes.. remember this TCB if we have not encountered any
           * other threads that have the signal unblocked.
           */

          if (!info->utcb)
            {
              info->utcb = tcb;
            }

          /* Is there also an action associated with the task? */

          sigact = sig_findaction(tcb, info->siginfo->si_signo);
          if (sigact)
            {
              /* Yes.. then use this thread.  The requirement is this:
               * If a task group receives a signal then one and only one
               * indeterminate thread in the task group which is not
               * blocking the signal will receive the signal.
               */

              ret = sig_tcbdispatch(tcb, info->siginfo);
              if (ret < 0)
                {
                  return ret;
                }

              /* Limit to one thread */

              info->ptcb = tcb;
              if (info->atcb != NULL)
                {
                  return 1; /* Terminate the search */
                }
            }
        }
    }

  return 0; /* Keep searching */
}
예제 #6
0
int group_signal(FAR struct task_group_s *group, FAR siginfo_t *siginfo)
{
#ifdef HAVE_GROUP_MEMBERS
  struct group_signal_s info;
  FAR struct tcb_s *tcb;
  int ret;

  DEBUGASSERT(group && siginfo);

  info.siginfo = siginfo;
  info.dtcb    = NULL;     /* Default, valid TCB */
  info.utcb    = NULL;     /* TCB with this signal unblocked */
  info.atcb    = NULL;     /* This TCB was awakened */
  info.ptcb    = NULL;     /* This TCB received the signal */

  /* Make sure that pre-emption is disabled to that we signal all of the
   * members of the group before any of them actually run. (This does
   * nothing if were were called from an interrupt handler).
   */

  sched_lock();

  /* Now visit each member of the group and perform signal handling checks. */

  ret = group_foreachchild(group, group_signal_handler, &info);
  if (ret < 0)
    {
      goto errout;
    }

  /* We need to dispatch the signal in any event (if nothing else so that it
   * can be added to the pending signal list). If we found a thread with the
   * signal unblocked, then use that thread.
   */

  if (info.atcb == NULL && info.ptcb == NULL)
    {
      if (info.utcb)
        {
          tcb = info.utcb;
        }

      /* Otherwise use the default TCB.  There should always be a default
       * TCB. It will have the signal blocked, but can be used to get the
       * signal to a pending state.
       */

      else /* if (info.dtcb) */
        {
          DEBUGASSERT(info.dtcb);
          tcb = info.dtcb;
        }

      /* Now deliver the signal to the selected group member */

      ret = sig_tcbdispatch(tcb, siginfo);
    }

errout:
  sched_unlock();
  return ret;

#else

  return -ENOSYS;
  
#endif
}