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; }
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; }