|
| 1 | +#[doc =" |
| 2 | +Utilities that leverage libuv's `uv_timer_*` API |
| 3 | +"]; |
| 4 | + |
| 5 | +import uv = uv; |
| 6 | +export delayed_send, sleep; |
| 7 | + |
| 8 | +#[doc = " |
| 9 | +Wait for timeout period then send provided value over a channel |
| 10 | +
|
| 11 | +This call returns immediately. Useful as the building block for a number |
| 12 | +of higher-level timer functions. |
| 13 | +
|
| 14 | +Is not guaranteed to wait for exactly the specified time, but will wait |
| 15 | +for *at least* that period of time. |
| 16 | +
|
| 17 | +# Arguments |
| 18 | +
|
| 19 | +msecs - a timeout period, in milliseconds, to wait |
| 20 | +ch - a channel of type T to send a `val` on |
| 21 | +val - a value of type T to send over the provided `ch` |
| 22 | +"] |
| 23 | +fn delayed_send<T: send>(msecs: uint, ch: comm::chan<T>, val: T) { |
| 24 | + task::spawn() {|| |
| 25 | + unsafe { |
| 26 | + let timer_done_po = comm::port::<()>(); |
| 27 | + let timer_done_ch = comm::chan(timer_done_po); |
| 28 | + let timer_done_ch_ptr = ptr::addr_of(timer_done_ch); |
| 29 | + let timer = uv::ll::timer_t(); |
| 30 | + let timer_ptr = ptr::addr_of(timer); |
| 31 | + let hl_loop = uv::global_loop::get(); |
| 32 | + uv::hl::interact(hl_loop) {|loop_ptr| |
| 33 | + uv::hl::ref(hl_loop, timer_ptr); |
| 34 | + let init_result = uv::ll::timer_init(loop_ptr, timer_ptr); |
| 35 | + if (init_result == 0i32) { |
| 36 | + let start_result = uv::ll::timer_start( |
| 37 | + timer_ptr, delayed_send_cb, msecs, 0u); |
| 38 | + if (start_result == 0i32) { |
| 39 | + uv::ll::set_data_for_uv_handle( |
| 40 | + timer_ptr, |
| 41 | + timer_done_ch_ptr as *libc::c_void); |
| 42 | + } |
| 43 | + else { |
| 44 | + let error_msg = uv::ll::get_last_err_info(loop_ptr); |
| 45 | + fail "timer::delayed_send() start failed: "+error_msg; |
| 46 | + } |
| 47 | + } |
| 48 | + else { |
| 49 | + let error_msg = uv::ll::get_last_err_info(loop_ptr); |
| 50 | + fail "timer::delayed_send() init failed: "+error_msg; |
| 51 | + } |
| 52 | + }; |
| 53 | + // delayed_send_cb has been processed by libuv |
| 54 | + comm::recv(timer_done_po); |
| 55 | + // notify the caller immediately |
| 56 | + comm::send(ch, copy(val)); |
| 57 | + // then clean up our handle |
| 58 | + uv::hl::unref_and_close(hl_loop, timer_ptr, |
| 59 | + delayed_send_close_cb); |
| 60 | + // uv_close for this timer has been processed |
| 61 | + comm::recv(timer_done_po); |
| 62 | + } |
| 63 | + }; |
| 64 | +} |
| 65 | + |
| 66 | +#[doc = " |
| 67 | +Blocks the current task for (at least) the specified time period. |
| 68 | +
|
| 69 | +Is not guaranteed to sleep for exactly the specified time, but will sleep |
| 70 | +for *at least* that period of time. |
| 71 | +
|
| 72 | +# Arguments |
| 73 | +
|
| 74 | +* msecs - an amount of time, in milliseconds, for the current task to block |
| 75 | +"] |
| 76 | +fn sleep(msecs: uint) { |
| 77 | + let exit_po = comm::port::<()>(); |
| 78 | + let exit_ch = comm::chan(exit_po); |
| 79 | + delayed_send(msecs, exit_ch, ()); |
| 80 | + comm::recv(exit_po); |
| 81 | +} |
| 82 | + |
| 83 | +// INTERNAL API |
| 84 | +crust fn delayed_send_cb(handle: *uv::ll::uv_timer_t, |
| 85 | + status: libc::c_int) unsafe { |
| 86 | + log(debug, #fmt("delayed_send_cb handle %? status %?", handle, status)); |
| 87 | + let timer_done_ch = |
| 88 | + *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>); |
| 89 | + let stop_result = uv::ll::timer_stop(handle); |
| 90 | + if (stop_result == 0i32) { |
| 91 | + comm::send(timer_done_ch, ()); |
| 92 | + } |
| 93 | + else { |
| 94 | + let loop_ptr = uv::ll::get_loop_for_uv_handle(handle); |
| 95 | + let error_msg = uv::ll::get_last_err_info(loop_ptr); |
| 96 | + fail "timer::sleep() init failed: "+error_msg; |
| 97 | + } |
| 98 | +} |
| 99 | + |
| 100 | +crust fn delayed_send_close_cb(handle: *uv::ll::uv_timer_t) unsafe { |
| 101 | + log(debug, #fmt("delayed_send_close_cb handle %?", handle)); |
| 102 | + let timer_done_ch = |
| 103 | + *(uv::ll::get_data_for_uv_handle(handle) as *comm::chan<()>); |
| 104 | + comm::send(timer_done_ch, ()); |
| 105 | +} |
| 106 | + |
| 107 | +#[cfg(test)] |
| 108 | +mod test { |
| 109 | + #[test] |
| 110 | + fn test_timer_simple_sleep_test() { |
| 111 | + sleep(2000u); |
| 112 | + } |
| 113 | +} |
0 commit comments