1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 //! Timers based on win32 WaitableTimers
13 //! This implementation is meant to be used solely on windows. As with other
14 //! implementations, there is a worker thread which is doing all the waiting on
15 //! a large number of timers for all active timers in the system. This worker
16 //! thread uses the select() equivalent, WaitForMultipleObjects. One of the
17 //! objects being waited on is a signal into the worker thread to notify that
18 //! the incoming channel should be looked at.
20 //! Other than that, the implementation is pretty straightforward in terms of
21 //! the other two implementations of timers with nothing *that* new showing up.
26 use std::rt::rtio::{IoResult, Callback};
29 use io::helper_thread::Helper;
31 helper_init!(static mut HELPER: Helper<Req>)
39 NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
40 RemoveTimer(libc::HANDLE, Sender<()>),
43 fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
44 let mut objs = vec![input];
45 let mut chans = vec![];
49 imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
57 match messages.try_recv() {
58 Ok(NewTimer(obj, c, one)) => {
62 Ok(RemoveTimer(obj, c)) => {
64 match objs.iter().position(|&o| o == obj) {
67 drop(chans.remove(i - 1));
72 Err(comm::Disconnected) => {
73 assert_eq!(objs.len(), 1);
74 assert_eq!(chans.len(), 0);
82 match chans.get_mut(idx as uint - 1) {
83 &(ref mut c, oneshot) => { c.call(); oneshot }
87 drop(objs.remove(idx as uint));
88 drop(chans.remove(idx as uint - 1));
94 // returns the current time (in milliseconds)
96 let mut ticks_per_s = 0;
97 assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
98 let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
100 assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
102 return (ticks as u64 * 1000) / (ticks_per_s as u64);
106 pub fn new() -> IoResult<Timer> {
107 unsafe { HELPER.boot(|| {}, helper) }
110 imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
113 Err(super::last_error())
115 Ok(Timer { obj: obj, on_worker: false, })
119 pub fn sleep(ms: u64) {
120 use std::rt::rtio::RtioTimer;
121 let mut t = Timer::new().ok().expect("must allocate a timer!");
125 fn remove(&mut self) {
126 if !self.on_worker { return }
128 let (tx, rx) = channel();
129 unsafe { HELPER.send(RemoveTimer(self.obj, tx)) }
132 self.on_worker = false;
136 impl rtio::RtioTimer for Timer {
137 fn sleep(&mut self, msecs: u64) {
140 // there are 10^6 nanoseconds in a millisecond, and the parameter is in
141 // 100ns intervals, so we multiply by 10^4.
142 let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
144 imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(),
148 let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
151 fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
154 // see above for the calculation
155 let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
157 imp::SetWaitableTimer(self.obj, &due, 0, ptr::null(),
161 unsafe { HELPER.send(NewTimer(self.obj, cb, true)) }
162 self.on_worker = true;
165 fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
168 // see above for the calculation
169 let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
171 imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
172 ptr::null(), ptr::mut_null(), 0)
175 unsafe { HELPER.send(NewTimer(self.obj, cb, false)) }
176 self.on_worker = true;
180 impl Drop for Timer {
183 assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
188 use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
189 LONG, LPVOID, DWORD, c_void};
191 pub type PTIMERAPCROUTINE = *c_void;
194 pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
196 lpTimerName: LPCSTR) -> HANDLE;
197 pub fn SetWaitableTimer(hTimer: HANDLE,
198 pDueTime: *LARGE_INTEGER,
200 pfnCompletionRoutine: PTIMERAPCROUTINE,
201 lpArgToCompletionRoutine: LPVOID,
202 fResume: BOOL) -> BOOL;
203 pub fn WaitForMultipleObjects(nCount: DWORD,
206 dwMilliseconds: DWORD) -> DWORD;
207 pub fn WaitForSingleObject(hHandle: HANDLE,
208 dwMilliseconds: DWORD) -> DWORD;