From 27c7974cb112e77012a1c9f0723aeb0af50e67ea Mon Sep 17 00:00:00 2001 From: Xiang Xiao Date: Thu, 8 Nov 2018 07:39:37 -0600 Subject: [PATCH] sched/signal/sig_suspend.c: sigsuspend() shouldn't eat the pending signal but dispatch all instead --- sched/signal/sig_suspend.c | 38 ++++++++++---------------- sched/signal/sig_unmaskpendingsignal.c | 11 ++++++-- sched/signal/signal.h | 2 +- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/sched/signal/sig_suspend.c b/sched/signal/sig_suspend.c index 242596c419..a4f5ebdf68 100644 --- a/sched/signal/sig_suspend.c +++ b/sched/signal/sig_suspend.c @@ -93,11 +93,8 @@ int sigsuspend(FAR const sigset_t *set) { FAR struct tcb_s *rtcb = this_task(); - sigset_t intersection; sigset_t saved_sigprocmask; - FAR sigpendq_t *sigpend; irqstate_t flags; - int unblocksigno; /* sigsuspend() is a cancellation point */ @@ -112,36 +109,30 @@ int sigsuspend(FAR const sigset_t *set) sched_lock(); /* Not necessary */ flags = enter_critical_section(); + /* 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; + /* Check if there is a pending signal corresponding to one of the * signals that will be unblocked by the new sigprocmask. */ - intersection = ~(*set) & nxsig_pendingset(rtcb); - if (intersection != NULL_SIGNAL_SET) + if (nxsig_unmask_pendingsignal()) { - /* 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. + /* Dispatching one or more of the signals is sufficient to cause + * us to not wait. Restore the original sigprocmask. */ - unblocksigno = nxsig_lowest(&intersection); - sigpend = nxsig_remove_pendingsignal(rtcb, unblocksigno); - DEBUGASSERT(sigpend); - - nxsig_release_pendingsignal(sigpend); + rtcb->sigprocmask = saved_sigprocmask; leave_critical_section(flags); } 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 */ + /* Its time to wait until one of the unblocked signals is posted */ up_block_task(rtcb, TSTATE_WAIT_SIG); @@ -160,5 +151,6 @@ int sigsuspend(FAR const sigset_t *set) sched_unlock(); leave_cancellation_point(); - return ERROR; /* ??REVISIT: Always returns ERROR?? */ + set_errno(EINTR); + return ERROR; } diff --git a/sched/signal/sig_unmaskpendingsignal.c b/sched/signal/sig_unmaskpendingsignal.c index c47392ad6f..ef439f635e 100644 --- a/sched/signal/sig_unmaskpendingsignal.c +++ b/sched/signal/sig_unmaskpendingsignal.c @@ -58,7 +58,7 @@ * ****************************************************************************/ -void nxsig_unmask_pendingsignal(void) +bool nxsig_unmask_pendingsignal(void) { FAR struct tcb_s *rtcb = this_task(); sigset_t unmaskedset; @@ -79,10 +79,15 @@ void nxsig_unmask_pendingsignal(void) */ unmaskedset = ~(rtcb->sigprocmask) & nxsig_pendingset(rtcb); + if (unmaskedset == NULL_SIGNAL_SET) + { + sched_unlock(); + return false; + } /* Loop while there are unmasked pending signals to be processed. */ - while (unmaskedset != NULL_SIGNAL_SET) + do { /* Pending signals will be processed from lowest numbered signal * to highest @@ -117,7 +122,9 @@ void nxsig_unmask_pendingsignal(void) } } } + while (unmaskedset != NULL_SIGNAL_SET); sched_unlock(); + return true; } diff --git a/sched/signal/signal.h b/sched/signal/signal.h index 3ecaf7906b..32d72a6c38 100644 --- a/sched/signal/signal.h +++ b/sched/signal/signal.h @@ -215,6 +215,6 @@ int nxsig_mqnotempty(int tid, int signo, FAR void *sival_ptr); void nxsig_release_pendingsigaction(FAR sigq_t *sigq); void nxsig_release_pendingsignal(FAR sigpendq_t *sigpend); FAR sigpendq_t *nxsig_remove_pendingsignal(FAR struct tcb_s *stcb, int signo); -void nxsig_unmask_pendingsignal(void); +bool nxsig_unmask_pendingsignal(void); #endif /* __SCHED_SIGNAL_SIGNAL_H */