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