about summary refs log tree commit diff
path: root/src/rt/rust_task.cpp
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-11-11 15:34:35 -0800
committerBrian Anderson <banderson@mozilla.com>2011-11-11 16:11:31 -0800
commit3d9023fa4ddc8dbb5d9be0e4e4ef5c284c6b077a (patch)
treeff4ed0e61a85f4f11e4b094fac90d488462403bf /src/rt/rust_task.cpp
parent07771ec25bc394a4a053252a2b5441f3160a0568 (diff)
downloadrust-3d9023fa4ddc8dbb5d9be0e4e4ef5c284c6b077a.tar.gz
rust-3d9023fa4ddc8dbb5d9be0e4e4ef5c284c6b077a.zip
rt: Take the task lock when dropping port refcounts
Sucks, but otherwise there are races when one task drops the refcount to zero
followed by another bumping it again
Diffstat (limited to 'src/rt/rust_task.cpp')
-rw-r--r--src/rt/rust_task.cpp35
1 files changed, 15 insertions, 20 deletions
diff --git a/src/rt/rust_task.cpp b/src/rt/rust_task.cpp
index 5164f6ac181..e5d43e7b308 100644
--- a/src/rt/rust_task.cpp
+++ b/src/rt/rust_task.cpp
@@ -127,15 +127,20 @@ rust_task::~rust_task()
          name, (uintptr_t)this, ref_count);
 
     if(user.notify_enabled) {
-        rust_port *target =
-            get_port_by_chan_handle(&user.notify_chan);
-        if(target) {
-            task_notification msg;
-            msg.id = user.id;
-            msg.result = failed ? tr_failure : tr_success;
-
-            target->send(&msg);
-            target->deref();
+        rust_task *target_task = kernel->get_task_by_id(user.notify_chan.task);
+        if (target_task) {
+            rust_port *target_port =
+                target_task->get_port_by_id(user.notify_chan.port);
+            if(target_port) {
+                task_notification msg;
+                msg.id = user.id;
+                msg.result = failed ? tr_failure : tr_success;
+
+                target_port->send(&msg);
+                scoped_lock with(target_task->lock);
+                target_port->deref();
+            }
+            target_task->deref();
         }
     }
 
@@ -553,8 +558,7 @@ rust_port_id rust_task::register_port(rust_port *port) {
 }
 
 void rust_task::release_port(rust_port_id id) {
-    I(sched, !lock.lock_held_by_current_thread());
-    scoped_lock with(lock);
+    I(sched, lock.lock_held_by_current_thread());
     port_table.remove(id);
 }
 
@@ -569,15 +573,6 @@ rust_port *rust_task::get_port_by_id(rust_port_id id) {
     return port;
 }
 
-rust_port *rust_task::get_port_by_chan_handle(chan_handle *handle) {
-    rust_task *target_task = kernel->get_task_by_id(handle->task);
-    if(target_task) {
-        rust_port *port = target_task->get_port_by_id(handle->port);
-        target_task->deref();
-        return port;
-    }
-    return NULL;
-}
 
 // Temporary routine to allow boxes on one task's shared heap to be reparented
 // to another.