From 42a41721afa441bf95846087737bb7f5fe9d4b9f Mon Sep 17 00:00:00 2001 From: Nick Stevens Date: Thu, 20 Oct 2016 11:11:07 -0500 Subject: [PATCH] Fix infinite looping timer thread Due to undefined behavior in pthread when passing in large timeout values, the park_timeout call of the timer thread was spinning very tightly and almost continuously causing poll wakeups. This commit changes the behavior to use a blocking park call when the timeout value is large. Fixes #483 Signed-off-by: Nick Stevens --- src/timer.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/timer.rs b/src/timer.rs index a7b91a8e0..adf857281 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -326,6 +326,7 @@ impl Timer { if actual == curr { // Signal to the wakeup thread that the wakeup time has // been changed. + trace!("unparking wakeup thread"); inner.wakeup_thread.thread().unpark(); return; } @@ -425,9 +426,22 @@ fn spawn_wakeup_thread(state: WakeupState, set_readiness: SetReadiness, start: I trace!("wakeup thread: sleep_until_tick={:?}; now_tick={:?}", sleep_until_tick, now_tick); if now_tick < sleep_until_tick { - let sleep_duration = tick_ms.checked_mul(sleep_until_tick - now_tick).unwrap_or(u64::MAX); - trace!("sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}", tick_ms, now_tick, sleep_until_tick, sleep_duration); - thread::park_timeout(Duration::from_millis(sleep_duration)); + // Calling park_timeout with u64::MAX leads to undefined + // behavior in pthread, causing the park to return immediately + // and causing the thread to tightly spin. Instead of u64::MAX + // on large values, simply use a blocking park. + match tick_ms.checked_mul(sleep_until_tick - now_tick) { + Some(sleep_duration) => { + trace!("sleeping; tick_ms={}; now_tick={}; sleep_until_tick={}; duration={:?}", + tick_ms, now_tick, sleep_until_tick, sleep_duration); + thread::park_timeout(Duration::from_millis(sleep_duration)); + } + None => { + trace!("sleeping; tick_ms={}; now_tick={}; blocking sleep", + tick_ms, now_tick); + thread::park(); + } + } sleep_until_tick = state.load(Ordering::Acquire) as Tick; } else { let actual = state.compare_and_swap(sleep_until_tick as usize, usize::MAX, Ordering::AcqRel) as Tick;