[libos] Fix bug of sigtimedwait for timeout NULL

This commit is contained in:
Zheng, Qi 2023-02-07 14:28:17 +08:00 committed by volcano
parent dbe404f16a
commit 500ca21d52
2 changed files with 26 additions and 32 deletions

@ -21,10 +21,7 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result<s
*blocked & interest
};
let signal = match timeout {
None => dequeue_pending_signal(&interest, &thread, &process)
.ok_or_else(|| errno!(EAGAIN, "no interesting, pending signal"))?,
Some(timeout) => {
let signal = {
let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest);
pending_sig_waiter.wait(timeout).map_err(|e| {
if e.errno() == Errno::EINTR {
@ -32,7 +29,6 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result<s
}
errno!(EAGAIN, "no interesting, pending signal")
})?
}
};
let siginfo = signal.to_info();
@ -70,25 +66,10 @@ impl PendingSigWaiter {
})
}
pub fn wait(&self, timeout: &Duration) -> Result<Box<dyn Signal>> {
pub fn wait(&self, timeout: Option<&Duration>) -> Result<Box<dyn Signal>> {
let waiter_queue = self.observer.waiter_queue();
let waiter = Waiter::new();
loop {
if *timeout == Duration::new(0, 0) {
// When timeout is reached, it is possible that there is actually an interesting
// signal in the queue, but timeout happens slightly before being interrupted.
// So here we attempt to dequeue again before returning with timeout.
if let Some(signal) =
dequeue_pending_signal(&self.interest, &self.thread, &self.process)
{
return Ok(signal);
}
return_errno!(ETIMEDOUT, "timeout");
}
// Enqueue the waiter so that it can be waken up by the queue later.
waiter_queue.reset_and_enqueue(&waiter);
// Try to dequeue a pending signal from the current process or thread
if let Some(signal) =
dequeue_pending_signal(&self.interest, &self.thread, &self.process)
@ -96,18 +77,28 @@ impl PendingSigWaiter {
return Ok(signal);
}
// If the timeout is zero and if no pending signals, return immediately with an error.
if let Some(duration) = timeout {
if *duration == Duration::new(0, 0) {
return_errno!(ETIMEDOUT, "timeout");
}
}
// Enqueue the waiter so that it can be waken up by the queue later.
waiter_queue.reset_and_enqueue(&waiter);
// As there is no intersting signal to dequeue right now, let's wait
// some time to try again later. Most likely, the waiter will keep
// waiting until being waken up by the waiter queue, which means
// the arrival of an interesting signal.
let res = waiter.wait(Some(timeout));
let res = waiter.wait(timeout);
// Do not try again if some error is encountered. There are only
// two possible errors: ETIMEDOUT or EINTR.
if let Err(e) = res {
// When interrupted, it is possible that the interrupting signal happens
// When interrupted or timeout is reached, it is possible that the interrupting signal happens
// to be an interesting and pending signal. So we attempt to dequeue again.
if e.errno() == Errno::EINTR {
if e.errno() == Errno::EINTR || e.errno() == Errno::ETIMEDOUT {
if let Some(signal) =
dequeue_pending_signal(&self.interest, &self.thread, &self.process)
{

@ -472,8 +472,11 @@ int test_sigtimedwait() {
THROW_ERROR("sigprocmask failed unexpectedly");
}
timeout.tv_sec = 1;
timeout.tv_nsec = 0;
// There is no pending signal, yet; so the syscall must return EAGAIN error
ret = sigtimedwait(&new_mask, &info, NULL);
ret = sigtimedwait(&new_mask, &info, &timeout);
if (ret == 0 || (ret < 0 && errno != EAGAIN)) {
THROW_ERROR("sigprocmask must return with EAGAIN error");
}