From 500ca21d527f700d458df10b891948627f396d97 Mon Sep 17 00:00:00 2001 From: "Zheng, Qi" Date: Tue, 7 Feb 2023 14:28:17 +0800 Subject: [PATCH] [libos] Fix bug of sigtimedwait for timeout NULL --- src/libos/src/signal/do_sigtimedwait.rs | 53 ++++++++++--------------- test/signal/main.c | 5 ++- 2 files changed, 26 insertions(+), 32 deletions(-) diff --git a/src/libos/src/signal/do_sigtimedwait.rs b/src/libos/src/signal/do_sigtimedwait.rs index ac959734..72b85930 100644 --- a/src/libos/src/signal/do_sigtimedwait.rs +++ b/src/libos/src/signal/do_sigtimedwait.rs @@ -21,18 +21,14 @@ pub fn do_sigtimedwait(interest: SigSet, timeout: Option<&Duration>) -> Result dequeue_pending_signal(&interest, &thread, &process) - .ok_or_else(|| errno!(EAGAIN, "no interesting, pending signal"))?, - Some(timeout) => { - let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); - pending_sig_waiter.wait(timeout).map_err(|e| { - if e.errno() == Errno::EINTR { - return e; - } - errno!(EAGAIN, "no interesting, pending signal") - })? - } + let signal = { + let pending_sig_waiter = PendingSigWaiter::new(thread, process, interest); + pending_sig_waiter.wait(timeout).map_err(|e| { + if e.errno() == Errno::EINTR { + return e; + } + errno!(EAGAIN, "no interesting, pending signal") + })? }; let siginfo = signal.to_info(); @@ -70,25 +66,10 @@ impl PendingSigWaiter { }) } - pub fn wait(&self, timeout: &Duration) -> Result> { + pub fn wait(&self, timeout: Option<&Duration>) -> Result> { 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) { diff --git a/test/signal/main.c b/test/signal/main.c index e8a0dcbc..e8f96b5a 100644 --- a/test/signal/main.c +++ b/test/signal/main.c @@ -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"); }