1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
extern crate time;

use std::sync::{Mutex, Condvar, PoisonError, MutexGuard};

pub struct CondVar {
	pair: (Mutex<bool>, Condvar)
}

pub type CondVarResult<Guard> = Result<(), PoisonError<Guard>>;

enum Notify {
	One,
	All,
}

impl ::CondVar {
	pub fn new() -> ::CondVar {
		::CondVar {
			pair: (Mutex::new(false), Condvar::new())
		}
	}

	pub fn notify_one(&self) {
        	self.notify(Notify::One)
	}

        pub fn notify_all(&self) {
                self.notify(Notify::All)
        }

        fn notify(&self, notify: Notify) {
                let &(ref lock, ref cvar) = &self.pair;

                let mut predicate = lock.lock().unwrap();
                *predicate = true;

                match notify {
                        Notify::One => cvar.notify_one(),
                        Notify::All => cvar.notify_all(),
                }
        }

        pub fn wait(&self) -> CondVarResult<MutexGuard<bool>> {
		let &(ref lock, ref cvar) = &self.pair;
		let mut predicate = try!(lock.lock());
		
		while !*predicate {
			predicate = try!(cvar.wait(predicate));
		}

		Ok(())
	}

	pub fn wait_timeout_ms(&self, timeout_ms: i64) -> CondVarResult<(MutexGuard<bool>,bool)> {
		let &(ref lock, ref cvar) = &self.pair;
		let predicate = lock.lock();
                match predicate {
			Err(poison) => return Err(PoisonError::new((poison.into_inner(),false))),
			_ => ()
                }
                let mut predicate = predicate.unwrap();

		let mut remaining_ms = timeout_ms;
		while !*predicate && remaining_ms > 0 {
			let before_ms = time::precise_time_ns()/1000;

			let (new, _) = try!(cvar.wait_timeout_ms(predicate, remaining_ms as u32));
			predicate = new;

			let after_ms = time::precise_time_ns()/1000;
			remaining_ms -= (after_ms - before_ms) as i64;
		}

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	use std::sync::Arc;
	use std::thread::{sleep_ms, spawn};

	use time::get_time;
	use ::CondVar;

	#[test]
	fn test_wait() {
		let cvar1 = Arc::new(CondVar::new());
		let cvar2 = cvar1.clone();

		spawn(move || {
			cvar2.notify_one();
		});

		cvar1.wait().unwrap();
	}

	#[test]
	fn test_wait_timeout_ms() {
		let cvar1 = Arc::new(CondVar::new());
		let cvar2 = cvar1.clone();

		spawn(move || {
			sleep_ms(500);
			cvar2.notify_one();
		});

		assert_eq!(cvar1.wait_timeout_ms(1000).unwrap(), ());
	}

	#[test]
	fn test_wait_timeout_ms_fail() {
		let cvar1 = Arc::new(CondVar::new());
		let cvar2 = cvar1.clone();

		spawn(move || {
			sleep_ms(1000);
			cvar2.notify_one();
		});

		let t1 = get_time();
		let t1: u64 = (t1.sec as u64)*1000 + (t1.nsec as u64)/1_000_000;
		cvar1.wait_timeout_ms(500).unwrap();
		let t2 = get_time();
		let t2: u64 = (t2.sec as u64)*1000 + (t2.nsec as u64)/1_000_000;
		if t2 - t1 > 1000 {
			panic!();
		}
	}

}