sched/signal/sig_suspend.c: sigsuspend() shouldn't eat the pending signal but dispatch all instead

This commit is contained in:
Xiang Xiao 2018-11-08 07:39:37 -06:00 committed by Gregory Nutt
parent acb83cfc61
commit 27c7974cb1
3 changed files with 25 additions and 26 deletions

View File

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

View File

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

View File

@ -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 */