void sig_unmaskpendingsignal(void) { FAR _TCB *rtcb = (FAR _TCB*)g_readytorun.head; sigset_t unmaskedset; FAR sigpendq_t *pendingsig; int signo; /* Prohibit any context switches until we are done with this. * We may still be performing signal operations from interrupt * handlers, however, none of the pending signals that we * are concerned with here should be effected. */ sched_lock(); /* Get the set of pending signals that were just unmasked. The * following operation should be safe because the sigprocmask * can only be changed on this thread of execution. */ unmaskedset = ~(rtcb->sigprocmask) & sig_pendingset(rtcb); /* Loop while there are unmasked pending signals to be processed. */ while (unmaskedset != NULL_SIGNAL_SET) { /* Pending signals will be processed from lowest numbered signal * to highest */ signo = sig_lowest(&unmaskedset); if (signo != ERROR) { /* Remove the signal from the set of unmasked signals. NOTE: * this implicitly assumes that only one instance for a given * signal number is pending. */ sigdelset(&unmaskedset, signo); /* Remove the pending signal from the list of pending signals */ if ((pendingsig = sig_removependingsignal(rtcb, signo)) != NULL) { /* If there is one, then process it like a normal signal */ sig_received(rtcb, &pendingsig->info); /* Then remove it from the pending signal list */ sig_releasependingsignal(pendingsig); } } } sched_unlock(); }
int sigpending(FAR sigset_t *set) { FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; int ret = ERROR; if (set) { *set = sig_pendingset(rtcb); ret = OK; } return ret; }
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 sigtimedwait(FAR const sigset_t *set, FAR struct siginfo *info, FAR const struct timespec *timeout) { FAR struct tcb_s *rtcb = (FAR struct tcb_s*)g_readytorun.head; sigset_t intersection; FAR sigpendq_t *sigpend; irqstate_t saved_state; int32_t waitticks; int ret = ERROR; DEBUGASSERT(rtcb->waitdog == NULL); sched_lock(); /* Not necessary */ /* 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! */ saved_state = irqsave(); /* Check if there is a pending signal corresponding to one of the * signals in the pending signal set argument. */ 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. */ sigpend = sig_removependingsignal(rtcb, sig_lowest(&intersection)); ASSERT(sigpend); /* Return the signal info to the caller if so requested */ if (info) { memcpy(info, &sigpend->info, sizeof(struct siginfo)); } /* Then dispose of the pending signal structure properly */ sig_releasependingsignal(sigpend); irqrestore(saved_state); /* The return value is the number of the signal that awakened us */ ret = sigpend->info.si_signo; } /* We will have to wait for a signal to be posted to this task. */ else { /* Save the set of pending signals to wait for */ rtcb->sigwaitmask = *set; /* Check if we should wait for the timeout */ if (timeout) { /* Convert the timespec to system clock ticks, making sure that * the resulting delay is greater than or equal to the requested * time in nanoseconds. */ #ifdef CONFIG_HAVE_LONG_LONG uint64_t waitticks64 = ((uint64_t)timeout->tv_sec * NSEC_PER_SEC + (uint64_t)timeout->tv_nsec + NSEC_PER_TICK - 1) / NSEC_PER_TICK; DEBUGASSERT(waitticks64 <= UINT32_MAX); waitticks = (uint32_t)waitticks64; #else uint32_t waitmsec; DEBUGASSERT(timeout->tv_sec < UINT32_MAX / MSEC_PER_SEC); waitmsec = timeout->tv_sec * MSEC_PER_SEC + (timeout->tv_nsec + NSEC_PER_MSEC - 1) / NSEC_PER_MSEC; waitticks = MSEC2TICK(waitmsec); #endif /* Create a watchdog */ rtcb->waitdog = wd_create(); DEBUGASSERT(rtcb->waitdog); if (rtcb->waitdog) { /* This little bit of nonsense is necessary for some * processors where sizeof(pointer) < sizeof(uint32_t). * see wdog.h. */ wdparm_t wdparm; wdparm.pvarg = (FAR void *)rtcb; /* Start the watchdog */ wd_start(rtcb->waitdog, waitticks, (wdentry_t)sig_timeout, 1, wdparm.dwarg); /* Now wait for either the signal or the watchdog */ up_block_task(rtcb, TSTATE_WAIT_SIG); /* We no longer need the watchdog */ wd_delete(rtcb->waitdog); rtcb->waitdog = NULL; } /* REVISIT: And do what if there are no watchdog timers? The wait * will fail and we will return something bogus. */ } /* No timeout, just wait */ else { /* And wait until one of the unblocked signals is posted */ up_block_task(rtcb, TSTATE_WAIT_SIG); } /* We are running again, clear the sigwaitmask */ rtcb->sigwaitmask = NULL_SIGNAL_SET; /* When we awaken, the cause will be in the TCB. Get the signal number * or timeout) that awakened us. */ if (GOOD_SIGNO(rtcb->sigunbinfo.si_signo)) { /* We were awakened by a signal... but is it one of the signals that * we were waiting for? */ if (sigismember(set, rtcb->sigunbinfo.si_signo)) { /* Yes.. the return value is the number of the signal that * awakened us. */ ret = rtcb->sigunbinfo.si_signo; } else { /* No... then set EINTR and report an error */ set_errno(EINTR); ret = ERROR; } } else { /* Otherwise, we must have been awakened by the timeout. Set EGAIN * and return an error. */ DEBUGASSERT(rtcb->sigunbinfo.si_signo == SIG_WAIT_TIMEOUT); set_errno(EAGAIN); ret = ERROR; } /* Return the signal info to the caller if so requested */ if (info) { memcpy(info, &rtcb->sigunbinfo, sizeof(struct siginfo)); } irqrestore(saved_state); } sched_unlock(); return ret; }