Skip to content

Commit 24b4223

Browse files
committed
Migrate uv timer bindings away from ~fn()
1 parent 653406f commit 24b4223

File tree

6 files changed

+151
-127
lines changed

6 files changed

+151
-127
lines changed

src/librustuv/lib.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ via `close` and `delete` methods.
4545

4646
#[feature(macro_rules, globs)];
4747

48+
use std::cast;
4849
use std::str::raw::from_c_str;
4950
use std::vec;
5051
use std::ptr;
@@ -119,6 +120,42 @@ pub trait NativeHandle<T> {
119120
fn native_handle(&self) -> T;
120121
}
121122

123+
/// A type that wraps a uv handle
124+
pub trait UvHandle<T> {
125+
fn uv_handle(&self) -> *T;
126+
127+
// FIXME(#8888) dummy self
128+
fn alloc(_: Option<Self>, ty: uvll::uv_handle_type) -> *T {
129+
unsafe {
130+
let handle = uvll::malloc_handle(ty);
131+
assert!(!handle.is_null());
132+
handle as *T
133+
}
134+
}
135+
136+
unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut Self {
137+
cast::transmute(uvll::get_data_for_uv_handle(*h))
138+
}
139+
140+
fn install(~self) -> ~Self {
141+
unsafe {
142+
let myptr = cast::transmute::<&~Self, *u8>(&self);
143+
uvll::set_data_for_uv_handle(self.uv_handle(), myptr);
144+
}
145+
self
146+
}
147+
148+
fn close_async_(&mut self) {
149+
// we used malloc to allocate all handles, so we must always have at
150+
// least a callback to free all the handles we allocated.
151+
extern fn close_cb(handle: *uvll::uv_handle_t) {
152+
unsafe { uvll::free_handle(handle) }
153+
}
154+
155+
unsafe { uvll::close(self.uv_handle(), close_cb) }
156+
}
157+
}
158+
122159
impl Loop {
123160
pub fn new() -> Loop {
124161
let handle = unsafe { uvll::loop_new() };
@@ -367,7 +404,7 @@ pub fn empty_buf() -> Buf {
367404
/// Borrow a slice to a Buf
368405
pub fn slice_to_uv_buf(v: &[u8]) -> Buf {
369406
let data = vec::raw::to_ptr(v);
370-
unsafe { uvll::uv_buf_init(data as *c_char, v.len() as c_uint) }
407+
uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
371408
}
372409
373410
// XXX: Do these conversions without copying
@@ -383,7 +420,7 @@ pub fn vec_to_uv_buf(v: ~[u8]) -> Buf {
383420
let data = data as *mut u8;
384421
ptr::copy_memory(data, b, l)
385422
}
386-
uvll::uv_buf_init(data as *c_char, v.len() as c_uint)
423+
uvll::uv_buf_t { base: data, len: v.len() as uvll::uv_buf_len_t }
387424
}
388425
}
389426

src/librustuv/macros.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ macro_rules! uvdebug (
2727
})
2828
)
2929

30+
// get a handle for the current scheduler
31+
macro_rules! get_handle_to_current_scheduler(
32+
() => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
33+
)
34+
3035
pub fn dumb_println(args: &fmt::Arguments) {
3136
use std::rt::io::native::stdio::stderr;
3237
use std::rt::io::Writer;

src/librustuv/timer.rs

Lines changed: 98 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,58 +8,123 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11+
use std::cell::Cell;
12+
use std::comm::{oneshot, stream, PortOne, ChanOne};
1113
use std::libc::c_int;
14+
use std::rt::BlockedTask;
15+
use std::rt::local::Local;
16+
use std::rt::rtio::RtioTimer;
17+
use std::rt::sched::{Scheduler, SchedHandle};
1218

1319
use uvll;
14-
use super::{Watcher, Loop, NativeHandle, TimerCallback, status_to_maybe_uv_error};
20+
use super::{Loop, NativeHandle, UvHandle};
21+
use uvio::HomingIO;
1522

16-
pub struct TimerWatcher(*uvll::uv_timer_t);
17-
impl Watcher for TimerWatcher { }
23+
pub struct TimerWatcher {
24+
handle: *uvll::uv_timer_t,
25+
home: SchedHandle,
26+
action: Option<NextAction>,
27+
}
28+
29+
pub enum NextAction {
30+
WakeTask(BlockedTask),
31+
SendOnce(ChanOne<()>),
32+
SendMany(Chan<()>),
33+
}
1834

1935
impl TimerWatcher {
20-
pub fn new(loop_: &mut Loop) -> TimerWatcher {
21-
unsafe {
22-
let handle = uvll::malloc_handle(uvll::UV_TIMER);
23-
assert!(handle.is_not_null());
24-
assert!(0 == uvll::uv_timer_init(loop_.native_handle(), handle));
25-
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
26-
watcher.install_watcher_data();
27-
return watcher;
28-
}
36+
pub fn new(loop_: &mut Loop) -> ~TimerWatcher {
37+
let handle = UvHandle::alloc(None::<TimerWatcher>, uvll::UV_TIMER);
38+
assert_eq!(unsafe {
39+
uvll::timer_init(loop_.native_handle(), handle)
40+
}, 0);
41+
let me = ~TimerWatcher {
42+
handle: handle,
43+
action: None,
44+
home: get_handle_to_current_scheduler!(),
45+
};
46+
return me.install();
2947
}
3048

31-
pub fn start(&mut self, timeout: u64, repeat: u64, cb: TimerCallback) {
32-
{
33-
let data = self.get_watcher_data();
34-
data.timer_cb = Some(cb);
35-
}
49+
fn start(&mut self, msecs: u64, period: u64) {
50+
assert_eq!(unsafe {
51+
uvll::timer_start(self.handle, timer_cb, msecs, period)
52+
}, 0)
53+
}
54+
55+
fn stop(&mut self) {
56+
assert_eq!(unsafe { uvll::timer_stop(self.handle) }, 0)
57+
}
58+
}
59+
60+
impl HomingIO for TimerWatcher {
61+
fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
62+
}
63+
64+
impl UvHandle<uvll::uv_timer_t> for TimerWatcher {
65+
fn uv_handle(&self) -> *uvll::uv_timer_t { self.handle }
66+
}
3667

37-
unsafe {
38-
uvll::uv_timer_start(self.native_handle(), timer_cb, timeout, repeat);
68+
impl RtioTimer for TimerWatcher {
69+
fn sleep(&mut self, msecs: u64) {
70+
do self.home_for_io_with_sched |self_, scheduler| {
71+
do scheduler.deschedule_running_task_and_then |_sched, task| {
72+
self_.action = Some(WakeTask(task));
73+
self_.start(msecs, 0);
74+
}
75+
self_.stop();
3976
}
77+
}
78+
79+
fn oneshot(&mut self, msecs: u64) -> PortOne<()> {
80+
let (port, chan) = oneshot();
81+
let chan = Cell::new(chan);
4082

41-
extern fn timer_cb(handle: *uvll::uv_timer_t, status: c_int) {
42-
let mut watcher: TimerWatcher = NativeHandle::from_native_handle(handle);
43-
let data = watcher.get_watcher_data();
44-
let cb = data.timer_cb.get_ref();
45-
let status = status_to_maybe_uv_error(status);
46-
(*cb)(watcher, status);
83+
do self.home_for_io |self_| {
84+
self_.action = Some(SendOnce(chan.take()));
85+
self_.start(msecs, 0);
4786
}
87+
88+
return port;
4889
}
4990

50-
pub fn stop(&mut self) {
51-
unsafe {
52-
uvll::uv_timer_stop(self.native_handle());
91+
fn period(&mut self, msecs: u64) -> Port<()> {
92+
let (port, chan) = stream();
93+
let chan = Cell::new(chan);
94+
95+
do self.home_for_io |self_| {
96+
self_.action = Some(SendMany(chan.take()));
97+
self_.start(msecs, msecs);
5398
}
99+
100+
return port;
54101
}
55102
}
56103

57-
impl NativeHandle<*uvll::uv_timer_t> for TimerWatcher {
58-
fn from_native_handle(handle: *uvll::uv_timer_t) -> TimerWatcher {
59-
TimerWatcher(handle)
104+
extern fn timer_cb(handle: *uvll::uv_timer_t, _status: c_int) {
105+
let handle = handle as *uvll::uv_handle_t;
106+
let foo: &mut TimerWatcher = unsafe { UvHandle::from_uv_handle(&handle) };
107+
108+
match foo.action.take_unwrap() {
109+
WakeTask(task) => {
110+
let sched: ~Scheduler = Local::take();
111+
sched.resume_blocked_task_immediately(task);
112+
}
113+
SendOnce(chan) => chan.send(()),
114+
SendMany(chan) => {
115+
chan.send(());
116+
foo.action = Some(SendMany(chan));
117+
}
60118
}
61-
fn native_handle(&self) -> *uvll::uv_idle_t {
62-
match self { &TimerWatcher(ptr) => ptr }
119+
}
120+
121+
impl Drop for TimerWatcher {
122+
fn drop(&mut self) {
123+
do self.home_for_io |self_| {
124+
self_.action = None;
125+
self_.stop();
126+
self_.close_async_();
127+
}
63128
}
64129
}
65130

src/librustuv/uvio.rs

Lines changed: 4 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ use std::c_str::CString;
1212
use std::cast::transmute;
1313
use std::cast;
1414
use std::cell::Cell;
15-
use std::comm::{SendDeferred, SharedChan, Port, PortOne, GenericChan};
16-
use std::libc;
15+
use std::clone::Clone;
16+
use std::comm::{SendDeferred, SharedChan, GenericChan};
1717
use std::libc::{c_int, c_uint, c_void, pid_t};
1818
use std::ptr;
1919
use std::str;
@@ -49,7 +49,7 @@ use addrinfo::{GetAddrInfoRequest, accum_addrinfo};
4949

5050
// XXX we should not be calling uvll functions in here.
5151

52-
trait HomingIO {
52+
pub trait HomingIO {
5353

5454
fn home<'r>(&'r mut self) -> &'r mut SchedHandle;
5555

@@ -135,11 +135,6 @@ impl Drop for HomingMissile {
135135
}
136136
}
137137

138-
// get a handle for the current scheduler
139-
macro_rules! get_handle_to_current_scheduler(
140-
() => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
141-
)
142-
143138
enum SocketNameKind {
144139
TcpPeer,
145140
Tcp,
@@ -581,9 +576,7 @@ impl IoFactory for UvIoFactory {
581576
}
582577

583578
fn timer_init(&mut self) -> Result<~RtioTimer, IoError> {
584-
let watcher = TimerWatcher::new(self.uv_loop());
585-
let home = get_handle_to_current_scheduler!();
586-
Ok(~UvTimer::new(watcher, home) as ~RtioTimer)
579+
Ok(TimerWatcher::new(self.uv_loop()) as ~RtioTimer)
587580
}
588581

589582
fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
@@ -1365,82 +1358,6 @@ impl RtioUdpSocket for UvUdpSocket {
13651358
}
13661359
}
13671360

1368-
pub struct UvTimer {
1369-
priv watcher: timer::TimerWatcher,
1370-
priv home: SchedHandle,
1371-
}
1372-
1373-
impl HomingIO for UvTimer {
1374-
fn home<'r>(&'r mut self) -> &'r mut SchedHandle { &mut self.home }
1375-
}
1376-
1377-
impl UvTimer {
1378-
fn new(w: timer::TimerWatcher, home: SchedHandle) -> UvTimer {
1379-
UvTimer { watcher: w, home: home }
1380-
}
1381-
}
1382-
1383-
impl Drop for UvTimer {
1384-
fn drop(&mut self) {
1385-
let (_m, scheduler) = self.fire_homing_missile_sched();
1386-
uvdebug!("closing UvTimer");
1387-
do scheduler.deschedule_running_task_and_then |_, task| {
1388-
let task_cell = Cell::new(task);
1389-
do self.watcher.close {
1390-
let scheduler: ~Scheduler = Local::take();
1391-
scheduler.resume_blocked_task_immediately(task_cell.take());
1392-
}
1393-
}
1394-
}
1395-
}
1396-
1397-
impl RtioTimer for UvTimer {
1398-
fn sleep(&mut self, msecs: u64) {
1399-
let (_m, scheduler) = self.fire_homing_missile_sched();
1400-
do scheduler.deschedule_running_task_and_then |_sched, task| {
1401-
uvdebug!("sleep: entered scheduler context");
1402-
let task_cell = Cell::new(task);
1403-
do self.watcher.start(msecs, 0) |_, status| {
1404-
assert!(status.is_none());
1405-
let scheduler: ~Scheduler = Local::take();
1406-
scheduler.resume_blocked_task_immediately(task_cell.take());
1407-
}
1408-
}
1409-
self.watcher.stop();
1410-
}
1411-
1412-
fn oneshot(&mut self, msecs: u64) -> PortOne<()> {
1413-
use std::comm::oneshot;
1414-
1415-
let (port, chan) = oneshot();
1416-
let chan = Cell::new(chan);
1417-
let _m = self.fire_homing_missile();
1418-
do self.watcher.start(msecs, 0) |_, status| {
1419-
assert!(status.is_none());
1420-
assert!(!chan.is_empty());
1421-
chan.take().send_deferred(());
1422-
}
1423-
1424-
return port;
1425-
}
1426-
1427-
fn period(&mut self, msecs: u64) -> Port<()> {
1428-
use std::comm::stream;
1429-
1430-
let (port, chan) = stream();
1431-
let chan = Cell::new(chan);
1432-
let _m = self.fire_homing_missile();
1433-
do self.watcher.start(msecs, msecs) |_, status| {
1434-
assert!(status.is_none());
1435-
do chan.with_ref |chan| {
1436-
chan.send_deferred(());
1437-
}
1438-
}
1439-
1440-
return port;
1441-
}
1442-
}
1443-
14441361
pub struct UvFileStream {
14451362
priv loop_: Loop,
14461363
priv fd: c_int,

src/librustuv/uvll.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,11 @@ pub static STDIO_INHERIT_STREAM: c_int = 0x04;
8080
pub static STDIO_READABLE_PIPE: c_int = 0x10;
8181
pub static STDIO_WRITABLE_PIPE: c_int = 0x20;
8282

83+
#[cfg(unix)]
84+
pub type uv_buf_len_t = libc::size_t;
85+
#[cfg(windows)]
86+
pub type uv_buf_len_t = u32;
87+
8388
// see libuv/include/uv-unix.h
8489
#[cfg(unix)]
8590
pub struct uv_buf_t {

src/rt/rust_uv.cpp

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -135,11 +135,6 @@ rust_uv_get_stream_handle_from_write_req(uv_write_t* write_req) {
135135
return write_req->handle;
136136
}
137137

138-
extern "C" void
139-
rust_uv_buf_init(uv_buf_t* out_buf, char* base, size_t len) {
140-
*out_buf = uv_buf_init(base, len);
141-
}
142-
143138
extern "C" uv_loop_t*
144139
rust_uv_get_loop_for_uv_handle(uv_handle_t* handle) {
145140
return handle->loop;

0 commit comments

Comments
 (0)