int sigsuspend(FAR const sigset_t *set)
{
  FAR struct tcb_s *rtcb = (FAR struct tcb_s *)g_readytorun.head;
  sigset_t intersection;
  sigset_t saved_sigprocmask;
  FAR sigpendq_t *sigpend;
  irqstate_t saved_state;
  int unblocksigno;

  /* Several operations must be performed below:  We must determine if any
   * signal is pending and, if not, wait for the signal.  Since signals can
   * be posted from the interrupt level, there is a race condition that
   * can only be eliminated by disabling interrupts!
   */

  sched_lock();  /* Not necessary */
  saved_state = irqsave();

  /* Check if there is a pending signal corresponding to one of the
   * signals that will be unblocked by the new sigprocmask.
   */

  intersection = ~(*set) & sig_pendingset(rtcb);
  if (intersection != NULL_SIGNAL_SET)
    {
      /* One or more of the signals in intersections is sufficient to cause
       * us to not wait.  Pick the lowest numbered signal and mark it not
       * pending.
       */

      unblocksigno = sig_lowest(&intersection);
      sigpend = sig_removependingsignal(rtcb, unblocksigno);
      ASSERT(sigpend);

      sig_releasependingsignal(sigpend);
      irqrestore(saved_state);
    }
  else
    {
      /* Its time to wait. Save a copy of the old sigprocmask and install
       * the new (temporary) sigprocmask
       */

      saved_sigprocmask = rtcb->sigprocmask;
      rtcb->sigprocmask = *set;
      rtcb->sigwaitmask = NULL_SIGNAL_SET;

      /* And wait until one of the unblocked signals is posted */

      up_block_task(rtcb, TSTATE_WAIT_SIG);

      /* We are running again, restore the original sigprocmask */

      rtcb->sigprocmask = saved_sigprocmask;
      irqrestore(saved_state);

      /* Now, handle the (rare?) case where (a) a blocked signal was received
       * while the task was suspended but (b) restoring the original
       * sigprocmask will unblock the signal.
       */

      sig_unmaskpendingsignal();
    }

  sched_unlock();
  return ERROR;
}
Exemple #2
0
int sigprocmask(int how, FAR const sigset_t *set, FAR sigset_t *oset)
{
  FAR struct tcb_s  *rtcb = (FAR struct tcb_s*)g_readytorun.head;
  sigset_t   oldsigprocmask;
  irqstate_t saved_state;
  int        ret = OK;

  sched_lock();

  /* Return the old signal mask if requested */

  oldsigprocmask = rtcb->sigprocmask;
  if (oset)
    {
      *oset = oldsigprocmask;
    }

  /* Modify the current signal mask if so requested */

  if (set)
    {
      /* Some of these operations are non-atomic.  We need to protect
       * ourselves from attempts to process signals from interrupts
       */

      saved_state = irqsave();

      /* Okay, determine what we are supposed to do */

      switch (how)
        {
          /* The resulting set is the union of the current set and the
           * signal set pointed to by set.
           */

          case SIG_BLOCK:
            rtcb->sigprocmask |= *set;
            break;

          /* The resulting set is the intersection of the current set and
           * the complement of the signal set pointed to by _set.
           */

          case SIG_UNBLOCK:
            rtcb->sigprocmask &= ~(*set);
            break;

          /* The resulting set is the signal set pointed to by set. */

          case SIG_SETMASK:
            rtcb->sigprocmask = *set;
            break;

          default: 
            ret = ERROR;
            break;
        }

      irqrestore(saved_state);

      /* Now, process any pending signals that were just unmasked */

      sig_unmaskpendingsignal();
    }

   sched_unlock();
   return ret;
}