From b4c88cdcecbcf40e1b9a123dcb6056970e256e9b Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Sat, 25 Feb 2012 22:08:52 -0800 Subject: [PATCH] add uv::loop_delete() because of the last change, the loop ptr is no longer cleaned up when the loop exits. This api call addresses that. Sadly, the loop ptr is not "reusable" across multiple calls to uv::run(). --- src/libstd/uv.rs | 97 ++++++++++++++++++++++++++++++++-------------- src/rt/rust_uv.cpp | 10 ++++- 2 files changed, 75 insertions(+), 32 deletions(-) diff --git a/src/libstd/uv.rs b/src/libstd/uv.rs index 0cc89a441ef..3988bd378d2 100644 --- a/src/libstd/uv.rs +++ b/src/libstd/uv.rs @@ -1,5 +1,6 @@ -export loop_new, run, close, run_in_bg, async_init, async_send, - timer_init, timer_start, timer_stop; +export loop_new, loop_delete, run, close, run_in_bg; +export async_init, async_send; +export timer_init, timer_start, timer_stop; // these are processed solely in the // process_operation() crust fn below @@ -44,11 +45,14 @@ type uv_loop_data = { rust_loop_chan: comm::chan }; -type uv_loop = comm::chan; +enum uv_loop { + uv_loop_new(comm::chan, *ctypes::void) +} #[nolink] native mod rustrt { fn rust_uv_loop_new() -> *ctypes::void; + fn rust_uv_loop_delete(loop: *ctypes::void); fn rust_uv_loop_set_data( loop: *ctypes::void, data: *uv_loop_data); @@ -103,7 +107,8 @@ fn loop_new() -> uv_loop unsafe { let rust_loop_chan = comm::chan::(rust_loop_port); // let the task-spawner return - comm::send(ret_recv_chan, copy(rust_loop_chan)); + let user_uv_loop = uv_loop_new(rust_loop_chan, loop_handle); + comm::send(ret_recv_chan, copy(user_uv_loop)); // create our "special" async handle that will // allow all operations against libuv to be @@ -225,7 +230,7 @@ fn loop_new() -> uv_loop unsafe { handles.insert(id, async_handle); let after_cb = after_cbs.get(id); after_cbs.remove(id); - let async = uv_async(id, rust_loop_chan); + let async = uv_async(id, user_uv_loop); id_to_handle.insert(id, copy(async)); task::spawn {|| after_cb(async); @@ -239,7 +244,8 @@ fn loop_new() -> uv_loop unsafe { uv_async_send(id) { let async_cb = async_cbs.get(id); task::spawn {|| - async_cb(uv_async(id, rust_loop_chan)); + let the_loop = user_uv_loop; + async_cb(uv_async(id, the_loop)); }; } @@ -254,7 +260,7 @@ fn loop_new() -> uv_loop unsafe { handles.insert(id, handle); let after_cb = after_cbs.get(id); after_cbs.remove(id); - let new_timer = uv_timer(id, rust_loop_chan); + let new_timer = uv_timer(id, user_uv_loop); id_to_handle.insert(id, copy(new_timer)); task::spawn {|| after_cb(new_timer); @@ -310,15 +316,22 @@ fn loop_new() -> uv_loop unsafe { ret comm::recv(ret_recv_port); } +fn loop_delete(loop: uv_loop) { + let loop_ptr = get_loop_ptr_from_uv_loop(loop); + rustrt::rust_uv_loop_delete(loop_ptr); +} + fn run(loop: uv_loop) { let end_port = comm::port::(); let end_chan = comm::chan::(end_port); - comm::send(loop, msg_run(end_chan)); + let loop_chan = get_loop_chan_from_uv_loop(loop); + comm::send(loop_chan, msg_run(end_chan)); comm::recv(end_port); } fn run_in_bg(loop: uv_loop) { - comm::send(loop, msg_run_in_bg); + let loop_chan = get_loop_chan_from_uv_loop(loop); + comm::send(loop_chan, msg_run_in_bg); } fn async_init ( @@ -326,13 +339,15 @@ fn async_init ( async_cb: fn~(uv_handle), after_cb: fn~(uv_handle)) { let msg = msg_async_init(async_cb, after_cb); - comm::send(loop, msg); + let loop_chan = get_loop_chan_from_uv_loop(loop); + comm::send(loop_chan, msg); } fn async_send(async: uv_handle) { alt async { uv_async(id, loop) { - comm::send(loop, msg_async_send(id)); + let loop_chan = get_loop_chan_from_uv_loop(loop); + comm::send(loop_chan, msg_async_send(id)); } _ { fail "attempting to call async_send() with a" + @@ -348,14 +363,16 @@ fn close(h: uv_handle, cb: fn~()) { fn timer_init(loop: uv_loop, after_cb: fn~(uv_handle)) { let msg = msg_timer_init(after_cb); - comm::send(loop, msg); + let loop_chan = get_loop_chan_from_uv_loop(loop); + comm::send(loop_chan, msg); } fn timer_start(the_timer: uv_handle, timeout: u32, repeat:u32, timer_cb: fn~(uv_handle)) { alt the_timer { - uv_timer(id, loop_chan) { + uv_timer(id, loop) { let msg = msg_timer_start(id, timeout, repeat, timer_cb); + let loop_chan = get_loop_chan_from_uv_loop(loop); comm::send(loop_chan, msg); } _ { @@ -367,7 +384,8 @@ fn timer_start(the_timer: uv_handle, timeout: u32, repeat:u32, fn timer_stop(the_timer: uv_handle, after_cb: fn~(uv_handle)) { alt the_timer { - uv_timer(id, loop_chan) { + uv_timer(id, loop) { + let loop_chan = get_loop_chan_from_uv_loop(loop); let msg = msg_timer_stop(id, after_cb); comm::send(loop_chan, msg); } @@ -397,15 +415,16 @@ fn get_handle_id_from(buf: *u8) -> [u8] unsafe { } fn get_loop_chan_from_data(data: *uv_loop_data) - -> uv_loop unsafe { + -> comm::chan unsafe { ret (*data).rust_loop_chan; } fn get_loop_chan_from_handle(handle: uv_handle) - -> uv_loop { + -> comm::chan { alt handle { uv_async(id,loop) | uv_timer(id,loop) { - ret loop; + let loop_chan = get_loop_chan_from_uv_loop(loop); + ret loop_chan; } _ { fail "unknown form of uv_handle for get_loop_chan_from " @@ -414,6 +433,21 @@ fn get_loop_chan_from_handle(handle: uv_handle) } } +fn get_loop_ptr_from_uv_loop(loop: uv_loop) -> *ctypes::void { + alt loop { + uv_loop_new(loop_chan, loop_ptr) { + ret loop_ptr; + } + } +} +fn get_loop_chan_from_uv_loop(loop: uv_loop) -> comm::chan { + alt loop { + uv_loop_new(loop_chan, loop_ptr) { + ret loop_chan; + } + } +} + fn get_id_from_handle(handle: uv_handle) -> [u8] { alt handle { uv_async(id,loop) | uv_timer(id,loop) { @@ -548,41 +582,44 @@ crust fn process_close_timer( #[test] fn test_uv_new_loop_no_handles() { let test_loop = uv::loop_new(); - run(test_loop); // this should return immediately + uv::run(test_loop); // this should return immediately // since there aren't any handles.. + uv::loop_delete(test_loop); } #[test] fn test_uv_simple_async() { - let test_loop = loop_new(); + let test_loop = uv::loop_new(); let exit_port = comm::port::(); let exit_chan = comm::chan::(exit_port); - async_init(test_loop, {|new_async| - close(new_async) {|| + uv::async_init(test_loop, {|new_async| + uv::close(new_async) {|| comm::send(exit_chan, true); }; }, {|new_async| - async_send(new_async); + uv::async_send(new_async); }); - run(test_loop); + uv::run(test_loop); let result = comm::recv(exit_port); assert result; + uv::loop_delete(test_loop); } #[test] fn test_uv_timer() { - let test_loop = loop_new(); + let test_loop = uv::loop_new(); let exit_port = comm::port::(); let exit_chan = comm::chan::(exit_port); - timer_init(test_loop) {|new_timer| - timer_start(new_timer, 1u32, 0u32) {|started_timer| - timer_stop(started_timer) {|stopped_timer| - close(stopped_timer) {|| + uv::timer_init(test_loop) {|new_timer| + uv::timer_start(new_timer, 1u32, 0u32) {|started_timer| + uv::timer_stop(started_timer) {|stopped_timer| + uv::close(stopped_timer) {|| comm::send(exit_chan, true); }; }; }; }; - run(test_loop); + uv::run(test_loop); assert comm::recv(exit_port); -} \ No newline at end of file + uv::loop_delete(test_loop); +} diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp index 4126896895e..096d40d2235 100644 --- a/src/rt/rust_uv.cpp +++ b/src/rt/rust_uv.cpp @@ -2,7 +2,8 @@ #include "uv.h" // crust fn pointers -typedef void (*crust_async_op_cb)(uv_loop_t* loop, void* data); +typedef void (*crust_async_op_cb)(uv_loop_t* loop, void* data, + uv_async_t* op_handle); typedef void (*crust_simple_cb)(uint8_t* id_buf, void* loop_data); typedef void (*crust_close_cb)(uint8_t* id_buf, void* handle, void* data); @@ -43,7 +44,7 @@ static void native_crust_async_op_cb(uv_async_t* handle, int status) { crust_async_op_cb cb = (crust_async_op_cb)handle->data; void* loop_data = handle->loop->data; - cb(handle->loop, loop_data); + cb(handle->loop, loop_data, handle); } static void @@ -78,6 +79,11 @@ rust_uv_loop_new() { return (void*)uv_loop_new(); } +extern "C" void +rust_uv_loop_delete(uv_loop_t* loop) { + uv_loop_delete(loop); +} + extern "C" void rust_uv_loop_set_data(uv_loop_t* loop, void* data) { loop->data = data;