core::rt: Add uv timer bindings
This commit is contained in:
parent
76e097761e
commit
4724966b06
6 changed files with 207 additions and 13 deletions
|
|
@ -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> {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
186
src/libcore/rt/uv/timer.rs
Normal file
186
src/libcore/rt/uv/timer.rs
Normal file
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue