[libos] Fix bug of sigtimedwait for timeout NULL
This commit is contained in:
parent
dbe404f16a
commit
500ca21d52
@ -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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user