Skip to content

Commit 3770086

Browse files
committed
---
yaml --- r: 146527 b: refs/heads/try2 c: 28219fc h: refs/heads/master i: 146525: 5963565 146523: 180fd20 146519: 0e2f51a 146511: 0f2414e 146495: f8a1a19 v: v3
1 parent 0ab78dd commit 3770086

File tree

8 files changed

+280
-267
lines changed

8 files changed

+280
-267
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 9286d5113d843e65fb13ff0cf142c1bfb10124f7
8+
refs/heads/try2: 28219fc679e6c2f747ad3e49eb746a383797ef9b
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/librustuv/async.rs

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

11+
use std::cast;
1112
use std::libc::c_int;
13+
use std::rt::rtio::{Callback, RemoteCallback};
14+
use std::unstable::sync::Exclusive;
1215

1316
use uvll;
14-
use super::{Watcher, Loop, NativeHandle, AsyncCallback, WatcherInterop};
15-
use super::status_to_maybe_uv_error;
17+
use super::{Loop, UvHandle};
1618

17-
pub struct AsyncWatcher(*uvll::uv_async_t);
18-
impl Watcher for AsyncWatcher { }
19+
// The entire point of async is to call into a loop from other threads so it
20+
// does not need to home.
21+
pub struct AsyncWatcher {
22+
handle: *uvll::uv_async_t,
23+
24+
// A flag to tell the callback to exit, set from the dtor. This is
25+
// almost never contested - only in rare races with the dtor.
26+
exit_flag: Exclusive<bool>
27+
}
28+
29+
struct Payload {
30+
callback: ~Callback,
31+
exit_flag: Exclusive<bool>,
32+
}
1933

2034
impl AsyncWatcher {
21-
pub fn new(loop_: &mut Loop, cb: AsyncCallback) -> AsyncWatcher {
35+
pub fn new(loop_: &mut Loop, cb: ~Callback) -> AsyncWatcher {
36+
let handle = UvHandle::alloc(None::<AsyncWatcher>, uvll::UV_ASYNC);
37+
assert_eq!(unsafe {
38+
uvll::async_init(loop_.native_handle(), handle, async_cb)
39+
}, 0);
40+
let flag = Exclusive::new(false);
41+
let payload = ~Payload { callback: cb, exit_flag: flag.clone() };
2242
unsafe {
23-
let handle = uvll::malloc_handle(uvll::UV_ASYNC);
24-
assert!(handle.is_not_null());
25-
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
26-
watcher.install_watcher_data();
27-
let data = watcher.get_watcher_data();
28-
data.async_cb = Some(cb);
29-
assert_eq!(0, uvll::uv_async_init(loop_.native_handle(), handle, async_cb));
30-
return watcher;
43+
let payload: *u8 = cast::transmute(payload);
44+
uvll::set_data_for_uv_handle(handle, payload);
3145
}
46+
return AsyncWatcher { handle: handle, exit_flag: flag, };
47+
}
48+
}
3249

33-
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
34-
let mut watcher: AsyncWatcher = NativeHandle::from_native_handle(handle);
35-
let status = status_to_maybe_uv_error(status);
36-
let data = watcher.get_watcher_data();
37-
let cb = data.async_cb.get_ref();
38-
(*cb)(watcher, status);
39-
}
50+
impl UvHandle<uvll::uv_async_t> for AsyncWatcher {
51+
fn uv_handle(&self) -> *uvll::uv_async_t { self.handle }
52+
unsafe fn from_uv_handle<'a>(h: &'a *T) -> &'a mut AsyncWatcher {
53+
fail!("async watchers can't be built from their handles");
4054
}
55+
}
56+
57+
extern fn async_cb(handle: *uvll::uv_async_t, status: c_int) {
58+
assert!(status == 0);
59+
let payload: &mut Payload = unsafe {
60+
cast::transmute(uvll::get_data_for_uv_handle(handle))
61+
};
62+
63+
// The synchronization logic here is subtle. To review,
64+
// the uv async handle type promises that, after it is
65+
// triggered the remote callback is definitely called at
66+
// least once. UvRemoteCallback needs to maintain those
67+
// semantics while also shutting down cleanly from the
68+
// dtor. In our case that means that, when the
69+
// UvRemoteCallback dtor calls `async.send()`, here `f` is
70+
// always called later.
71+
72+
// In the dtor both the exit flag is set and the async
73+
// callback fired under a lock. Here, before calling `f`,
74+
// we take the lock and check the flag. Because we are
75+
// checking the flag before calling `f`, and the flag is
76+
// set under the same lock as the send, then if the flag
77+
// is set then we're guaranteed to call `f` after the
78+
// final send.
79+
80+
// If the check was done after `f()` then there would be a
81+
// period between that call and the check where the dtor
82+
// could be called in the other thread, missing the final
83+
// callback while still destroying the handle.
84+
85+
let should_exit = unsafe {
86+
payload.exit_flag.with_imm(|&should_exit| should_exit)
87+
};
88+
89+
payload.callback.call();
90+
91+
if should_exit {
92+
unsafe { uvll::close(handle, close_cb) }
93+
}
94+
}
4195

42-
pub fn send(&mut self) {
96+
extern fn close_cb(handle: *uvll::uv_handle_t) {
97+
// drop the payload
98+
let _payload: ~Payload = unsafe {
99+
cast::transmute(uvll::get_data_for_uv_handle(handle))
100+
};
101+
// and then free the handle
102+
unsafe { uvll::free_handle(handle) }
103+
}
104+
105+
impl RemoteCallback for AsyncWatcher {
106+
fn fire(&mut self) {
107+
unsafe { uvll::async_send(self.handle) }
108+
}
109+
}
110+
111+
impl Drop for AsyncWatcher {
112+
fn drop(&mut self) {
43113
unsafe {
44-
let handle = self.native_handle();
45-
uvll::uv_async_send(handle);
114+
do self.exit_flag.with |should_exit| {
115+
// NB: These two things need to happen atomically. Otherwise
116+
// the event handler could wake up due to a *previous*
117+
// signal and see the exit flag, destroying the handle
118+
// before the final send.
119+
*should_exit = true;
120+
uvll::async_send(self.handle)
121+
}
46122
}
47123
}
48124
}
49125

50-
impl NativeHandle<*uvll::uv_async_t> for AsyncWatcher {
51-
fn from_native_handle(handle: *uvll::uv_async_t) -> AsyncWatcher {
52-
AsyncWatcher(handle)
53-
}
54-
fn native_handle(&self) -> *uvll::uv_async_t {
55-
match self { &AsyncWatcher(ptr) => ptr }
126+
#[cfg(test)]
127+
mod test_remote {
128+
use std::cell::Cell;
129+
use std::rt::test::*;
130+
use std::rt::thread::Thread;
131+
use std::rt::tube::Tube;
132+
use std::rt::rtio::EventLoop;
133+
use std::rt::local::Local;
134+
use std::rt::sched::Scheduler;
135+
136+
#[test]
137+
fn test_uv_remote() {
138+
do run_in_mt_newsched_task {
139+
let mut tube = Tube::new();
140+
let tube_clone = tube.clone();
141+
let remote_cell = Cell::new_empty();
142+
do Local::borrow |sched: &mut Scheduler| {
143+
let tube_clone = tube_clone.clone();
144+
let tube_clone_cell = Cell::new(tube_clone);
145+
let remote = do sched.event_loop.remote_callback {
146+
// This could be called multiple times
147+
if !tube_clone_cell.is_empty() {
148+
tube_clone_cell.take().send(1);
149+
}
150+
};
151+
remote_cell.put_back(remote);
152+
}
153+
let thread = do Thread::start {
154+
remote_cell.take().fire();
155+
};
156+
157+
assert!(tube.recv() == 1);
158+
thread.join();
159+
}
56160
}
57161
}
58162

branches/try2/src/librustuv/idle.rs

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

11-
use std::libc::c_int;
11+
use std::cast;
12+
use std::libc::{c_int, c_void};
1213

1314
use uvll;
14-
use super::{Watcher, Loop, NativeHandle, IdleCallback, status_to_maybe_uv_error};
15-
16-
pub struct IdleWatcher(*uvll::uv_idle_t);
17-
impl Watcher for IdleWatcher { }
15+
use super::{Loop, UvHandle};
16+
use std::rt::rtio::{Callback, PausibleIdleCallback};
17+
18+
pub struct IdleWatcher {
19+
handle: *uvll::uv_idle_t,
20+
idle_flag: bool,
21+
closed: bool,
22+
callback: Option<~Callback>,
23+
}
1824

1925
impl IdleWatcher {
20-
pub fn new(loop_: &mut Loop) -> IdleWatcher {
26+
pub fn new(loop_: &mut Loop) -> ~IdleWatcher {
27+
let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
28+
assert_eq!(unsafe {
29+
uvll::idle_init(loop_.native_handle(), handle)
30+
}, 0);
31+
let me = ~IdleWatcher {
32+
handle: handle,
33+
idle_flag: false,
34+
closed: false,
35+
callback: None,
36+
};
37+
return me.install();
38+
}
39+
40+
pub fn onetime(loop_: &mut Loop, f: proc()) {
41+
let handle = UvHandle::alloc(None::<IdleWatcher>, uvll::UV_IDLE);
2142
unsafe {
22-
let handle = uvll::malloc_handle(uvll::UV_IDLE);
23-
assert!(handle.is_not_null());
24-
assert_eq!(uvll::uv_idle_init(loop_.native_handle(), handle), 0);
25-
let mut watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
26-
watcher.install_watcher_data();
27-
return watcher
43+
assert_eq!(uvll::idle_init(loop_.native_handle(), handle), 0);
44+
let data: *c_void = cast::transmute(~f);
45+
uvll::set_data_for_uv_handle(handle, data);
46+
assert_eq!(uvll::idle_start(handle, onetime_cb), 0)
2847
}
29-
}
3048

31-
pub fn start(&mut self, cb: IdleCallback) {
32-
{
33-
let data = self.get_watcher_data();
34-
data.idle_cb = Some(cb);
49+
extern fn onetime_cb(handle: *uvll::uv_idle_t, status: c_int) {
50+
assert_eq!(status, 0);
51+
unsafe {
52+
let data = uvll::get_data_for_uv_handle(handle);
53+
let f: ~proc() = cast::transmute(data);
54+
(*f)();
55+
uvll::idle_stop(handle);
56+
uvll::close(handle, close_cb);
57+
}
3558
}
3659

37-
unsafe {
38-
assert_eq!(uvll::uv_idle_start(self.native_handle(), idle_cb), 0)
60+
extern fn close_cb(handle: *uvll::uv_handle_t) {
61+
unsafe { uvll::free_handle(handle) }
3962
}
4063
}
64+
}
4165

42-
pub fn restart(&mut self) {
43-
unsafe {
44-
assert!(self.get_watcher_data().idle_cb.is_some());
45-
assert_eq!(uvll::uv_idle_start(self.native_handle(), idle_cb), 0)
66+
impl PausibleIdleCallback for IdleWatcher {
67+
fn start(&mut self, cb: ~Callback) {
68+
assert!(self.callback.is_none());
69+
self.callback = Some(cb);
70+
assert_eq!(unsafe { uvll::idle_start(self.handle, idle_cb) }, 0)
71+
self.idle_flag = true;
72+
}
73+
fn pause(&mut self) {
74+
if self.idle_flag == true {
75+
assert_eq!(unsafe {uvll::idle_stop(self.handle) }, 0);
76+
self.idle_flag = false;
4677
}
4778
}
48-
49-
pub fn stop(&mut self) {
50-
// NB: Not resetting the Rust idle_cb to None here because `stop` is
51-
// likely called from *within* the idle callback, causing a use after
52-
// free
53-
54-
unsafe {
55-
assert_eq!(uvll::uv_idle_stop(self.native_handle()), 0);
79+
fn resume(&mut self) {
80+
if self.idle_flag == false {
81+
assert_eq!(unsafe { uvll::idle_start(self.handle, idle_cb) }, 0)
82+
self.idle_flag = true;
83+
}
84+
}
85+
fn close(&mut self) {
86+
self.pause();
87+
if !self.closed {
88+
self.closed = true;
89+
self.close_async_();
5690
}
5791
}
5892
}
5993

60-
impl NativeHandle<*uvll::uv_idle_t> for IdleWatcher {
61-
fn from_native_handle(handle: *uvll::uv_idle_t) -> IdleWatcher {
62-
IdleWatcher(handle)
63-
}
64-
fn native_handle(&self) -> *uvll::uv_idle_t {
65-
match self { &IdleWatcher(ptr) => ptr }
66-
}
94+
impl UvHandle<uvll::uv_idle_t> for IdleWatcher {
95+
fn uv_handle(&self) -> *uvll::uv_idle_t { self.handle }
6796
}
6897

6998
extern fn idle_cb(handle: *uvll::uv_idle_t, status: c_int) {
70-
let mut idle_watcher: IdleWatcher = NativeHandle::from_native_handle(handle);
71-
let data = idle_watcher.get_watcher_data();
72-
let cb: &IdleCallback = data.idle_cb.get_ref();
73-
let status = status_to_maybe_uv_error(status);
74-
(*cb)(idle_watcher, status);
99+
assert_eq!(status, 0);
100+
let idle: &mut IdleWatcher = unsafe { UvHandle::from_uv_handle(&handle) };
101+
assert!(idle.callback.is_some());
102+
idle.callback.get_mut_ref().call();
75103
}
76104

77105
#[cfg(test)]

0 commit comments

Comments
 (0)