Skip to content

Commit d334efe

Browse files
olsonjefferybrson
authored andcommitted
---
yaml --- r: 15578 b: refs/heads/try c: 83ae83c h: refs/heads/master v: v3
1 parent 21474f2 commit d334efe

File tree

5 files changed

+305
-275
lines changed

5 files changed

+305
-275
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@
22
refs/heads/master: 61b1875c16de39c166b0f4d54bba19f9c6777d1a
33
refs/heads/snap-stage1: e33de59e47c5076a89eadeb38f4934f58a3618a6
44
refs/heads/snap-stage3: 4a81779abd786ff22d71434c6d9a5917ea4cdfff
5-
refs/heads/try: 253fad77883869511e2030352e86904ac2165d7c
5+
refs/heads/try: 83ae83c3b3ae1fa5b12465ef8ad16047a68f71e3
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105

branches/try/src/libstd/std.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ mod net;
2828
mod uv;
2929
mod uv_ll;
3030
mod uv_hl;
31+
mod uv_global_loop;
3132

3233

3334
// Utility modules

branches/try/src/libstd/uv.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ export ll;
3434
import hl = uv_hl;
3535
export hl;
3636

37+
import global_loop = uv_global_loop;
38+
export global_loop;
39+
3740
#[nolink]
3841
native mod rustrt {
3942
fn rust_uv_loop_new() -> *libc::c_void;
Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
#[doc="
2+
Process-wide, lazily started/stopped libuv event loop interaction.
3+
"];
4+
5+
import ll = uv_ll;
6+
import hl = uv_hl;
7+
import get_gl = get;
8+
9+
export get;
10+
11+
native mod rustrt {
12+
fn rust_uv_get_kernel_global_chan_ptr() -> *libc::uintptr_t;
13+
fn rust_uv_get_kernel_global_async_handle() -> *libc::uintptr_t;
14+
fn rust_compare_and_swap_ptr(address: *libc::uintptr_t,
15+
oldval: libc::uintptr_t,
16+
newval: libc::uintptr_t) -> bool;
17+
}
18+
19+
#[doc ="
20+
Race-free helper to get access to a global task where a libuv
21+
loop is running.
22+
23+
# Return
24+
25+
* A `hl::high_level_loop` that encapsulates communication with the global
26+
loop.
27+
"]
28+
fn get() -> hl::high_level_loop {
29+
let global_loop_chan_ptr = rustrt::rust_uv_get_kernel_global_chan_ptr();
30+
log(debug, #fmt("ENTERING global_loop::get() loop chan: %?",
31+
global_loop_chan_ptr));
32+
33+
let builder_fn = {||
34+
let builder = task::builder();
35+
let opts = {
36+
supervise: false,
37+
notify_chan: none,
38+
sched:
39+
some({mode: task::manual_threads(1u),
40+
native_stack_size: none })
41+
};
42+
task::set_opts(builder, opts);
43+
builder
44+
};
45+
unsafe {
46+
log(debug, "before priv::chan_from_global_ptr");
47+
let chan = priv::chan_from_global_ptr::<hl::high_level_msg>(
48+
global_loop_chan_ptr,
49+
builder_fn) {|port|
50+
51+
// the actual body of our global loop lives here
52+
log(debug, "initialized global port task!");
53+
log(debug, "GLOBAL initialized global port task!");
54+
outer_global_loop_body(port);
55+
};
56+
log(debug, "after priv::chan_from_global_ptr");
57+
let handle = get_global_async_handle_native_representation()
58+
as **ll::uv_async_t;
59+
ret { async_handle: handle, op_chan: chan };
60+
}
61+
}
62+
63+
// INTERNAL API
64+
65+
unsafe fn outer_global_loop_body(msg_po: comm::port<hl::high_level_msg>) {
66+
// we're going to use a single libuv-generated loop ptr
67+
// for the duration of the process
68+
let loop_ptr = ll::loop_new();
69+
70+
// data structure for loop goes here..
71+
72+
// immediately weaken the task this is running in.
73+
priv::weaken_task() {|weak_exit_po|
74+
// when we first enter this loop, we're going
75+
// to wait on stand-by to receive a request to
76+
// fire-up the libuv loop
77+
let mut continue = true;
78+
while continue {
79+
log(debug, "in outer_loop...");
80+
continue = either::either(
81+
{|left_val|
82+
// bail out..
83+
// if we catch this msg at this point,
84+
// we should just be able to exit because
85+
// the loop isn't active
86+
log(debug, #fmt("weak_exit_po recv'd msg: %?",
87+
left_val));
88+
false
89+
}, {|right_val|
90+
log(debug, "about to enter inner loop");
91+
inner_global_loop_body(weak_exit_po, msg_po, loop_ptr,
92+
copy(right_val))
93+
}, comm::select2(weak_exit_po, msg_po));
94+
log(debug,#fmt("GLOBAL LOOP EXITED, WAITING TO RESTART? %?",
95+
continue));
96+
}
97+
};
98+
99+
ll::loop_delete(loop_ptr);
100+
}
101+
102+
unsafe fn inner_global_loop_body(weak_exit_po_in: comm::port<()>,
103+
msg_po_in: comm::port<hl::high_level_msg>,
104+
loop_ptr: *libc::c_void,
105+
-first_interaction: hl::high_level_msg) -> bool {
106+
// resend the msg
107+
comm::send(comm::chan(msg_po_in), first_interaction);
108+
109+
// black magic
110+
let weak_exit_po_ptr = ptr::addr_of(weak_exit_po_in);
111+
hl::run_high_level_loop(
112+
loop_ptr,
113+
msg_po_in,
114+
// before_run
115+
{|async_handle|
116+
log(debug,#fmt("global_loop before_run: async_handle %?",
117+
async_handle));
118+
// set the handle as the global
119+
set_global_async_handle(0u as *ll::uv_async_t,
120+
async_handle);
121+
// when this is ran, our async_handle is set up, so let's
122+
// do an async_send with it
123+
ll::async_send(async_handle);
124+
},
125+
// before_msg_drain
126+
{|async_handle|
127+
log(debug,#fmt("global_loop before_msg_drain: async_handle %?",
128+
async_handle));
129+
let weak_exit_po = *weak_exit_po_ptr;
130+
if(comm::peek(weak_exit_po)) {
131+
// if this is true, immediately bail and return false, causing
132+
// the libuv loop to start tearing down
133+
log(debug,"got weak_exit meg inside libuv loop");
134+
comm::recv(weak_exit_po);
135+
false
136+
}
137+
// if no weak_exit_po msg is received, then we'll let the
138+
// loop continue
139+
else {
140+
true
141+
}
142+
},
143+
// before_tear_down
144+
{|async_handle|
145+
log(debug,#fmt("global_loop before_tear_down: async_handle %?",
146+
async_handle));
147+
set_global_async_handle(async_handle,
148+
0 as *ll::uv_async_t);
149+
});
150+
// supposed to return a bool to indicate to the enclosing loop whether
151+
// it should continue or not..
152+
ret true;
153+
}
154+
155+
unsafe fn get_global_async_handle_native_representation()
156+
-> *libc::uintptr_t {
157+
ret rustrt::rust_uv_get_kernel_global_async_handle();
158+
}
159+
160+
unsafe fn get_global_async_handle() -> *ll::uv_async_t {
161+
ret (*get_global_async_handle_native_representation()) as *ll::uv_async_t;
162+
}
163+
164+
unsafe fn set_global_async_handle(old: *ll::uv_async_t,
165+
new_ptr: *ll::uv_async_t) {
166+
rustrt::rust_compare_and_swap_ptr(
167+
get_global_async_handle_native_representation(),
168+
old as libc::uintptr_t,
169+
new_ptr as libc::uintptr_t);
170+
}
171+
172+
#[cfg(test)]
173+
mod test {
174+
crust fn simple_timer_close_cb(timer_ptr: *ll::uv_timer_t) unsafe {
175+
let exit_ch_ptr = ll::get_data_for_uv_handle(
176+
timer_ptr as *libc::c_void) as *comm::chan<bool>;
177+
let exit_ch = *exit_ch_ptr;
178+
comm::send(exit_ch, true);
179+
log(debug, #fmt("EXIT_CH_PTR simple_timer_close_cb exit_ch_ptr: %?",
180+
exit_ch_ptr));
181+
}
182+
crust fn simple_timer_cb(timer_ptr: *ll::uv_timer_t,
183+
status: libc::c_int) unsafe {
184+
log(debug, "in simple timer cb");
185+
ll::timer_stop(timer_ptr);
186+
let hl_loop = get_gl();
187+
hl::interact(hl_loop) {|loop_ptr|
188+
log(debug, "closing timer");
189+
//ll::close(timer_ptr as *libc::c_void, simple_timer_close_cb);
190+
hl::unref_handle(hl_loop, timer_ptr, simple_timer_close_cb);
191+
log(debug, "about to deref exit_ch_ptr");
192+
log(debug, "after msg sent on deref'd exit_ch");
193+
};
194+
log(debug, "exiting simple timer cb");
195+
}
196+
197+
fn impl_uv_hl_simple_timer(hl_loop: hl::high_level_loop) unsafe {
198+
let exit_po = comm::port::<bool>();
199+
let exit_ch = comm::chan(exit_po);
200+
let exit_ch_ptr = ptr::addr_of(exit_ch);
201+
log(debug, #fmt("EXIT_CH_PTR newly created exit_ch_ptr: %?",
202+
exit_ch_ptr));
203+
let timer_handle = ll::timer_t();
204+
let timer_ptr = ptr::addr_of(timer_handle);
205+
hl::interact(hl_loop) {|loop_ptr|
206+
log(debug, "user code inside interact loop!!!");
207+
let init_status = ll::timer_init(loop_ptr, timer_ptr);
208+
if(init_status == 0i32) {
209+
hl::ref_handle(hl_loop, timer_ptr);
210+
ll::set_data_for_uv_handle(
211+
timer_ptr as *libc::c_void,
212+
exit_ch_ptr as *libc::c_void);
213+
let start_status = ll::timer_start(timer_ptr, simple_timer_cb,
214+
1u, 0u);
215+
if(start_status == 0i32) {
216+
}
217+
else {
218+
fail "failure on ll::timer_start()";
219+
}
220+
}
221+
else {
222+
fail "failure on ll::timer_init()";
223+
}
224+
};
225+
comm::recv(exit_po);
226+
log(debug, "global_loop timer test: msg recv on exit_po, done..");
227+
}
228+
#[test]
229+
#[ignore(cfg(target_os = "freebsd"))]
230+
fn test_uv_global_loop_high_level_global_timer() unsafe {
231+
let hl_loop = get_gl();
232+
task::spawn_sched(task::manual_threads(1u), {||
233+
impl_uv_hl_simple_timer(hl_loop);
234+
});
235+
impl_uv_hl_simple_timer(hl_loop);
236+
}
237+
}

0 commit comments

Comments
 (0)