about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJeff Olson <olson.jeffery@gmail.com>2012-02-24 17:43:31 -0800
committerBrian Anderson <banderson@mozilla.com>2012-02-28 17:56:15 -0800
commit0b3a06ab2ca989ab0f0b9fa5fa8aa83a2ec13998 (patch)
tree0d5b1b38c8ab616f231884b253859a019de81c39
parentd461637cc5c896252003eda3e83084bcebb3717e (diff)
downloadrust-0b3a06ab2ca989ab0f0b9fa5fa8aa83a2ec13998.tar.gz
rust-0b3a06ab2ca989ab0f0b9fa5fa8aa83a2ec13998.zip
correcting for libuv behavior that differs between linux & windows
net complexity increase :/
-rw-r--r--src/libstd/uv.rs38
-rw-r--r--src/rt/rust_uv.cpp18
2 files changed, 36 insertions, 20 deletions
diff --git a/src/libstd/uv.rs b/src/libstd/uv.rs
index 90ac5ce4b1c..0cc89a441ef 100644
--- a/src/libstd/uv.rs
+++ b/src/libstd/uv.rs
@@ -8,7 +8,8 @@ enum uv_operation {
     op_close(uv_handle, *ctypes::void),
     op_timer_init([u8]),
     op_timer_start([u8], *ctypes::void, u32, u32),
-    op_timer_stop([u8], *ctypes::void, fn~(uv_handle))
+    op_timer_stop([u8], *ctypes::void, fn~(uv_handle)),
+    op_teardown(*ctypes::void)
 }
 
 enum uv_handle {
@@ -34,7 +35,8 @@ enum uv_msg {
     uv_timer_init([u8], *ctypes::void),
     uv_timer_call([u8]),
     uv_timer_stop([u8], fn~(uv_handle)),
-    uv_end()
+    uv_end(),
+    uv_teardown_check()
 }
 
 type uv_loop_data = {
@@ -148,11 +150,13 @@ fn loop_new() -> uv_loop unsafe {
                 // loop process any pending operations
                 // once its up and running
                 task::spawn_sched(task::manual_threads(1u)) {||
+                    // make sure we didn't start the loop
+                    // without the user registering handles
+                    comm::send(rust_loop_chan, uv_teardown_check);
                     // this call blocks
                     rustrt::rust_uv_run(loop_handle);
                     // when we're done, msg the
                     // end chan
-                    rustrt::rust_uv_stop_op_cb(op_handle);
                     comm::send(end_chan, true);
                     comm::send(rust_loop_chan, uv_end);
                 };
@@ -160,6 +164,8 @@ fn loop_new() -> uv_loop unsafe {
 
               msg_run_in_bg {
                 task::spawn_sched(task::manual_threads(1u)) {||
+                    // see note above
+                    comm::send(rust_loop_chan, uv_teardown_check);
                     // this call blocks
                     rustrt::rust_uv_run(loop_handle);
                 };
@@ -194,6 +200,9 @@ fn loop_new() -> uv_loop unsafe {
                 task::spawn {||
                     cb();
                 };
+                // ask the rust loop to check and see if there
+                // are no more user-registered handles
+                comm::send(rust_loop_chan, uv_teardown_check);
               }
 
               msg_async_init(callback, after_cb) {
@@ -202,6 +211,7 @@ fn loop_new() -> uv_loop unsafe {
                 // data and save the callback for
                 // invocation on msg_async_send
                 let id = gen_handle_id();
+                handles.insert(id, ptr::null());
                 async_cbs.insert(id, callback);
                 after_cbs.insert(id, after_cb);
                 let op = op_async_init(id);
@@ -235,6 +245,7 @@ fn loop_new() -> uv_loop unsafe {
 
               msg_timer_init(after_cb) {
                 let id = gen_handle_id();
+                handles.insert(id, ptr::null());
                 after_cbs.insert(id, after_cb);
                 let op = op_timer_init(id);
                 pass_to_libuv(op_handle, operation_chan, op);
@@ -276,6 +287,18 @@ fn loop_new() -> uv_loop unsafe {
                 after_cb(the_timer);
               }
 
+              uv_teardown_check() {
+                // here we're checking if there are no user-registered
+                // handles (and the loop is running), if this is the
+                // case, then we need to unregister the op_handle via
+                // a uv_close() call, thus allowing libuv to return
+                // on its own.
+                if (handles.size() == 0u) {
+                    let op = op_teardown(op_handle);
+                    pass_to_libuv(op_handle, operation_chan, op);
+                }
+              }
+
               uv_end() {
                 keep_going = false;
               }
@@ -442,6 +465,12 @@ crust fn process_operation(
             rustrt::rust_uv_timer_stop(handle);
             comm::send(loop_chan, uv_timer_stop(id, after_cb));
           }
+          op_teardown(op_handle) {
+            // this is the last msg that'll be processed by
+            // this fn, in the current lifetime of the handle's
+            // uv_loop_t
+            rustrt::rust_uv_stop_op_cb(op_handle);
+          }
           _ { fail "unknown form of uv_operation received"; }
         }
         op_pending = comm::peek(op_port);
@@ -536,7 +565,8 @@ fn test_uv_simple_async() {
         async_send(new_async);
     });
     run(test_loop);
-    assert comm::recv(exit_port);
+    let result = comm::recv(exit_port);
+    assert result;
 }
 
 #[test]
diff --git a/src/rt/rust_uv.cpp b/src/rt/rust_uv.cpp
index 03cd75d4805..4126896895e 100644
--- a/src/rt/rust_uv.cpp
+++ b/src/rt/rust_uv.cpp
@@ -68,10 +68,8 @@ native_close_cb(uv_handle_t* handle) {
 
 static void
 native_close_op_cb(uv_handle_t* op_handle) {
-  uv_loop_t* loop = op_handle->loop;
   current_kernel_free(op_handle);
-  loop->data = 0; // a ptr to some stack-allocated rust mem
-  uv_loop_delete(loop);
+  // uv_run() should return after this..
 }
 
 // native fns bound in rust
@@ -94,25 +92,13 @@ rust_uv_bind_op_cb(uv_loop_t* loop, crust_async_op_cb cb) {
 	async->data = (void*)cb;
 	// decrement the ref count, so that our async bind
 	// doesn't count towards keeping the loop alive
-	uv_unref(loop);
+	//uv_unref(loop);
 	return async;
 }
 
 extern "C" void
 rust_uv_stop_op_cb(uv_handle_t* op_handle) {
-  /*  // this is a hack to get libuv to cleanup a
-  // handle that was made to not prevent the loop
-  // from exiting via uv_unref().
-  uv_ref(op_handle->loop);
   uv_close(op_handle, native_close_op_cb);
-  uv_run(op_handle->loop); // this should process the handle's
-                           // close event and then return
-						   */
-  // the above code is supposed to work to cleanly close
-  // a handler that was uv_unref()'d. but it causes much spew
-  // instead. this is the ugly/quick way to deal w/ it for now.
-  uv_close(op_handle, native_close_op_cb);
-  native_close_op_cb(op_handle);
 }
 
 extern "C" void