[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,18 +21,14 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result<s
*blocked & interest *blocked & interest
}; };
let signal = match timeout { let signal = {
None => dequeue_pending_signal(&interest, &thread, &process) let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest);
.ok_or_else(|| errno!(EAGAIN, "no interesting, pending signal"))?, pending_sig_waiter.wait(timeout).map_err(|e| {
Some(timeout) => { if e.errno() == Errno::EINTR {
let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); return e;
pending_sig_waiter.wait(timeout).map_err(|e| { }
if e.errno() == Errno::EINTR { errno!(EAGAIN, "no interesting, pending signal")
return e; })?
}
errno!(EAGAIN, "no interesting, pending signal")
})?
}
}; };
let siginfo = signal.to_info(); 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_queue = self.observer.waiter_queue();
let waiter = Waiter::new(); let waiter = Waiter::new();
loop { 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 // Try to dequeue a pending signal from the current process or thread
if let Some(signal) = if let Some(signal) =
dequeue_pending_signal(&self.interest, &self.thread, &self.process) dequeue_pending_signal(&self.interest, &self.thread, &self.process)
@ -96,18 +77,28 @@ impl PendingSigWaiter {
return Ok(signal); 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 // 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 // some time to try again later. Most likely, the waiter will keep
// waiting until being waken up by the waiter queue, which means // waiting until being waken up by the waiter queue, which means
// the arrival of an interesting signal. // 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 // Do not try again if some error is encountered. There are only
// two possible errors: ETIMEDOUT or EINTR. // two possible errors: ETIMEDOUT or EINTR.
if let Err(e) = res { 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. // 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) = if let Some(signal) =
dequeue_pending_signal(&self.interest, &self.thread, &self.process) dequeue_pending_signal(&self.interest, &self.thread, &self.process)
{ {

@ -472,8 +472,11 @@ int test_sigtimedwait() {
THROW_ERROR("sigprocmask failed unexpectedly"); 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 // 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)) { if (ret == 0 || (ret < 0 && errno != EAGAIN)) {
THROW_ERROR("sigprocmask must return with EAGAIN error"); THROW_ERROR("sigprocmask must return with EAGAIN error");
} }