about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2013-05-10 17:07:41 -0700
committerBrian Anderson <banderson@mozilla.com>2013-05-15 12:19:15 -0700
commit4724966b0656761da94e24e73b028cd0d3420a7e (patch)
tree237ffde01617b5c513df382cfb291ca6bac6595b
parent76e097761e0bb11ebe57bd18c13a0c645c655108 (diff)
downloadrust-4724966b0656761da94e24e73b028cd0d3420a7e.tar.gz
rust-4724966b0656761da94e24e73b028cd0d3420a7e.zip
core::rt: Add uv timer bindings
-rw-r--r--src/libcore/rt/local_sched.rs5
-rw-r--r--src/libcore/rt/uv/mod.rs9
-rw-r--r--src/libcore/rt/uv/timer.rs186
-rw-r--r--src/libcore/rt/uv/uvll.rs10
-rw-r--r--src/libstd/uv_ll.rs8
-rw-r--r--src/rt/rust_uv.cpp2
6 files changed, 207 insertions, 13 deletions
diff --git a/src/libcore/rt/local_sched.rs b/src/libcore/rt/local_sched.rs
index 1ef1fd33a83..ffc19c5b5e4 100644
--- a/src/libcore/rt/local_sched.rs
+++ b/src/libcore/rt/local_sched.rs
@@ -97,7 +97,10 @@ pub unsafe fn unsafe_borrow_io() -> *mut IoFactoryObject {
 }
 
 fn tls_key() -> tls::Key {
-    maybe_tls_key().get()
+    match maybe_tls_key() {
+        Some(key) => key,
+        None => abort!("runtime tls key not initialized")
+    }
 }
 
 fn maybe_tls_key() -> Option<tls::Key> {
diff --git a/src/libcore/rt/uv/mod.rs b/src/libcore/rt/uv/mod.rs
index 871fd2a9042..ee3c5ceffd2 100644
--- a/src/libcore/rt/uv/mod.rs
+++ b/src/libcore/rt/uv/mod.rs
@@ -59,6 +59,7 @@ use rt::io::IoError;
 pub use self::file::FsRequest;
 pub use self::net::{StreamWatcher, TcpWatcher};
 pub use self::idle::IdleWatcher;
+pub use self::timer::TimerWatcher;
 
 /// The implementation of `rtio` for libuv
 pub mod uvio;
@@ -69,6 +70,7 @@ pub mod uvll;
 pub mod file;
 pub mod net;
 pub mod idle;
+pub mod timer;
 
 /// XXX: Loop(*handle) is buggy with destructors. Normal structs
 /// with dtors may not be destructured, but tuple structs can,
@@ -125,6 +127,7 @@ pub type NullCallback = ~fn();
 pub type IdleCallback = ~fn(IdleWatcher, Option<UvError>);
 pub type ConnectionCallback = ~fn(StreamWatcher, Option<UvError>);
 pub type FsCallback = ~fn(FsRequest, Option<UvError>);
+pub type TimerCallback = ~fn(TimerWatcher, Option<UvError>);
 
 
 /// Callbacks used by StreamWatchers, set as custom data on the foreign handle
@@ -134,7 +137,8 @@ struct WatcherData {
     connect_cb: Option<ConnectionCallback>,
     close_cb: Option<NullCallback>,
     alloc_cb: Option<AllocCallback>,
-    idle_cb: Option<IdleCallback>
+    idle_cb: Option<IdleCallback>,
+    timer_cb: Option<TimerCallback>
 }
 
 pub trait WatcherInterop {
@@ -162,7 +166,8 @@ impl<H, W: Watcher + NativeHandle<*H>> WatcherInterop for W {
                 connect_cb: None,
                 close_cb: None,
                 alloc_cb: None,
-                idle_cb: None
+                idle_cb: None,
+                timer_cb: None
             };
             let data = transmute::<~WatcherData, *c_void>(data);
             uvll::set_data_for_uv_handle(self.native_handle(), data);
diff --git a/src/libcore/rt/uv/timer.rs b/src/libcore/rt/uv/timer.rs
new file mode 100644
index 00000000000..1045a77da12
--- /dev/null
+++ b/src/libcore/rt/uv/timer.rs
@@ -0,0 +1,186 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use libc::{c_void, c_int};
+use option::Some;
+use rt::uv::uvll;
+use rt::uv::{Watcher, Loop, NativeHandle, TimerCallback, NullCallback};
+use rt::uv::status_to_maybe_uv_error;
+
+pub struct TimerWatcher(*uvll::uv_timer_t);
+impl Watcher for TimerWatcher { }
+
+impl TimerWatcher {
+    pub fn new(loop_: &mut Loop) -> TimerWatcher {
+        unsafe {
+            let handle = uvll::malloc_handle(uvll::UV_TIMER);
+            assert!(handle.is_not_null());
+            assert!(0 == uvll::timer_init(loop_.native_handle(), handle));
+            let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
+            watcher.install_watcher_data();
+            return watcher;
+        }
+    }
+
+    pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
+        {
+            let data = self.get_watcher_data();
+            data.timer_cb = Some(cb);
+        }
+
+        unsafe {
+            uvll::timer_start(self.native_handle(), timer_cb, timeout, repeat);
+        }
+
+        extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
+            let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
+            let data = watcher.get_watcher_data();
+            let cb = data.timer_cb.get_ref();
+            let status = status_to_maybe_uv_error(handle, status);
+            (*cb)(watcher, status);
+        }
+    }
+
+    pub fn stop(&mut self) {
+        unsafe {
+            uvll::timer_stop(self.native_handle());
+        }
+    }
+
+    pub fn close(self, cb: NullCallback) {
+        let mut watcher = self;
+        {
+            let data = watcher.get_watcher_data();
+            assert!(data.close_cb.is_none());
+            data.close_cb = Some(cb);
+        }
+
+        unsafe {
+            uvll::close(watcher.native_handle(), close_cb);
+        }
+
+        extern fn close_cb(handle: *uvll::uv_timer_t) {
+            let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
+            {
+                let mut data = watcher.get_watcher_data();
+                data.close_cb.swap_unwrap()();
+            }
+            watcher.drop_watcher_data();
+            unsafe {
+                uvll::free_handle(handle as *c_void);
+            }
+        }
+    }
+}
+
+impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher {
+    fn from_native_handle(handle: *uvll::uv_timer_t) -> TimerWatcher {
+        TimerWatcher(handle)
+    }
+    fn native_handle(&self) -> *uvll::uv_idle_t {
+        match self { &TimerWatcher(ptr) => ptr }
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+    use rt::uv::Loop;
+    use unstable::run_in_bare_thread;
+
+    #[test]
+    fn smoke_test() {
+        do run_in_bare_thread {
+            let mut count = 0;
+            let count_ptr: *mut int = &mut count;
+            let mut loop_ = Loop::new();
+            let mut timer = TimerWatcher::new(&mut loop_);
+            do timer.start(10, 0) |timer, status| {
+                assert!(status.is_none());
+                unsafe { *count_ptr += 1 };
+                timer.close(||());
+            }
+            loop_.run();
+            loop_.close();
+            assert!(count == 1);
+        }
+    }
+
+    #[test]
+    fn start_twice() {
+        do run_in_bare_thread {
+            let mut count = 0;
+            let count_ptr: *mut int = &mut count;
+            let mut loop_ = Loop::new();
+            let mut timer = TimerWatcher::new(&mut loop_);
+            do timer.start(10, 0) |timer, status| {
+                let mut timer = timer;
+                assert!(status.is_none());
+                unsafe { *count_ptr += 1 };
+                do timer.start(10, 0) |timer, status| {
+                    let mut timer = timer;
+                    assert!(status.is_none());
+                    unsafe { *count_ptr += 1 };
+                    timer.close(||());
+                }
+            }
+            loop_.run();
+            loop_.close();
+            assert!(count == 2);
+        }
+    }
+
+    #[test]
+    fn repeat_stop() {
+        do run_in_bare_thread {
+            let mut count = 0;
+            let count_ptr: *mut int = &mut count;
+            let mut loop_ = Loop::new();
+            let mut timer = TimerWatcher::new(&mut loop_);
+            do timer.start(10, 20) |timer, status| {
+                assert!(status.is_none());
+                unsafe {
+                    *count_ptr += 1;
+
+                    if *count_ptr == 10 {
+
+                        // Stop the timer and do something else
+                        let mut timer = timer;
+                        timer.stop();
+                        // Freeze timer so it can be captured
+                        let timer = timer;
+
+                        let mut loop_ = timer.event_loop();
+                        let mut timer2 = TimerWatcher::new(&mut loop_);
+                        do timer2.start(10, 0) |timer2, status| {
+
+                            unsafe { *count_ptr += 1; }
+
+                            let mut timer2 = timer2;
+                            timer2.close(||());
+
+                            // Restart the original timer
+                            let mut timer = timer;
+                            do timer.start(10, 0) |timer, status| {
+                                unsafe { *count_ptr += 1; }
+                                let mut timer = timer;
+                                timer.close(||());
+                            }
+                        }
+                    }
+                };
+            }
+            loop_.run();
+            loop_.close();
+            assert!(count == 12);
+        }
+    }
+
+}
diff --git a/src/libcore/rt/uv/uvll.rs b/src/libcore/rt/uv/uvll.rs
index 76abf2a195d..94e6b82ab8f 100644
--- a/src/libcore/rt/uv/uvll.rs
+++ b/src/libcore/rt/uv/uvll.rs
@@ -268,9 +268,9 @@ pub unsafe fn buf_init(input: *u8, len: uint) -> uv_buf_t {
 pub unsafe fn timer_init(loop_ptr: *c_void, timer_ptr: *uv_timer_t) -> c_int {
     return rust_uv_timer_init(loop_ptr, timer_ptr);
 }
-pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint,
-                          repeat: uint) -> c_int {
-    return rust_uv_timer_start(timer_ptr, cb, timeout as c_uint, repeat as c_uint);
+pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: u64,
+                          repeat: u64) -> c_int {
+    return rust_uv_timer_start(timer_ptr, cb, timeout, repeat);
 }
 pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> c_int {
     return rust_uv_timer_stop(timer_ptr);
@@ -431,8 +431,8 @@ extern {
                           timer_handle: *uv_timer_t) -> c_int;
     fn rust_uv_timer_start(timer_handle: *uv_timer_t,
                            cb: *u8,
-                           timeout: c_uint,
-                           repeat: c_uint) -> c_int;
+                           timeout: libc::uint64_t,
+                           repeat: libc::uint64_t) -> c_int;
     fn rust_uv_timer_stop(handle: *uv_timer_t) -> c_int;
 
     fn rust_uv_malloc_buf_base_of(sug_size: size_t) -> *u8;
diff --git a/src/libstd/uv_ll.rs b/src/libstd/uv_ll.rs
index a14c048b8de..96ceb1002d8 100644
--- a/src/libstd/uv_ll.rs
+++ b/src/libstd/uv_ll.rs
@@ -819,8 +819,8 @@ extern {
     unsafe fn rust_uv_timer_start(
         timer_handle: *uv_timer_t,
         cb: *u8,
-        timeout: libc::c_uint,
-        repeat: libc::c_uint) -> libc::c_int;
+        timeout: libc::uint64_t,
+        repeat: libc::uint64_t) -> libc::c_int;
     unsafe fn rust_uv_timer_stop(handle: *uv_timer_t) -> libc::c_int;
 
     unsafe fn rust_uv_getaddrinfo(loop_ptr: *libc::c_void,
@@ -1084,8 +1084,8 @@ pub unsafe fn timer_init(loop_ptr: *libc::c_void,
 }
 pub unsafe fn timer_start(timer_ptr: *uv_timer_t, cb: *u8, timeout: uint,
                       repeat: uint) -> libc::c_int {
-    return rust_uv_timer_start(timer_ptr, cb, timeout as libc::c_uint,
-                                    repeat as libc::c_uint);
+    return rust_uv_timer_start(timer_ptr, cb, timeout as libc::uint64_t,
+                               repeat as libc::uint64_t);
 }
 pub unsafe fn timer_stop(timer_ptr: *uv_timer_t) -> libc::c_int {
     return rust_uv_timer_stop(timer_ptr);
diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp
index 8cf2bd4b4ac..fefcbbcacf7 100644
--- a/src/rt/rust_uv.cpp
+++ b/src/rt/rust_uv.cpp
@@ -229,7 +229,7 @@ rust_uv_timer_init(uv_loop_t* loop, uv_timer_t* timer) {
 
 extern "C" int
 rust_uv_timer_start(uv_timer_t* the_timer, uv_timer_cb cb,
-                        uint32_t timeout, uint32_t repeat) {
+                    int64_t timeout, int64_t repeat) {
     return uv_timer_start(the_timer, cb, timeout, repeat);
 }