about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--mk/rt.mk1
-rw-r--r--src/libcore/sys.rs72
-rw-r--r--src/rt/rust_builtin.cpp55
-rw-r--r--src/rt/rust_cond_lock.cpp6
-rw-r--r--src/rt/rust_cond_lock.h15
-rw-r--r--src/rt/rustrt.def.in6
6 files changed, 155 insertions, 0 deletions
diff --git a/mk/rt.mk b/mk/rt.mk
index 02fcdc0def6..aebef1f54f9 100644
--- a/mk/rt.mk
+++ b/mk/rt.mk
@@ -70,6 +70,7 @@ RUNTIME_CS_$(1) := \
               rt/rust_cc.cpp \
               rt/rust_debug.cpp \
               rt/rust_box_annihilator.cpp \
+              rt/rust_cond_lock.cpp \
               rt/memory_region.cpp \
               rt/boxed_region.cpp \
               rt/arch/$$(HOST_$(1))/context.cpp \
diff --git a/src/libcore/sys.rs b/src/libcore/sys.rs
index e0fd21f6c4a..90ea10601ae 100644
--- a/src/libcore/sys.rs
+++ b/src/libcore/sys.rs
@@ -7,6 +7,7 @@ export min_align_of;
 export pref_align_of;
 export refcount;
 export log_str;
+export lock_and_signal, condition, methods;
 
 enum type_desc = {
     first_param: **libc::c_int,
@@ -15,11 +16,20 @@ enum type_desc = {
     // Remaining fields not listed
 };
 
+type rust_cond_lock = *libc::c_void;
+
 #[abi = "cdecl"]
 native mod rustrt {
     pure fn refcount(t: *()) -> libc::intptr_t;
     fn unsupervise();
     pure fn shape_log_str(t: *sys::type_desc, data: *()) -> str;
+
+    fn rust_create_cond_lock() -> rust_cond_lock;
+    fn rust_destroy_cond_lock(lock: rust_cond_lock);
+    fn rust_lock_cond_lock(lock: rust_cond_lock);
+    fn rust_unlock_cond_lock(lock: rust_cond_lock);
+    fn rust_wait_cond_lock(lock: rust_cond_lock);
+    fn rust_signal_cond_lock(lock: rust_cond_lock) -> bool;
 }
 
 #[abi = "rust-intrinsic"]
@@ -74,8 +84,50 @@ pure fn log_str<T>(t: T) -> str {
     }
 }
 
+resource lock_and_signal(lock: rust_cond_lock) {
+    rustrt::rust_destroy_cond_lock(lock);
+}
+
+enum condition {
+    condition_(rust_cond_lock)
+}
+
+resource unlock(lock: rust_cond_lock) {
+    rustrt::rust_unlock_cond_lock(lock);
+}
+
+fn create_lock() -> lock_and_signal {
+    lock_and_signal(rustrt::rust_create_cond_lock())
+}
+
+impl methods for lock_and_signal {
+    fn lock<T>(f: fn() -> T) -> T {
+        rustrt::rust_lock_cond_lock(*self);
+        let _r = unlock(*self);
+        f()
+    }
+
+    fn lock_cond<T>(f: fn(condition) -> T) -> T {
+        rustrt::rust_lock_cond_lock(*self);
+        let _r = unlock(*self);
+        f(condition_(*self))
+    }
+}
+
+impl methods for condition {
+    fn wait() {
+        rustrt::rust_wait_cond_lock(*self);
+    }
+
+    fn signal() -> bool {
+        rustrt::rust_signal_cond_lock(*self)
+    }
+}
+
 #[cfg(test)]
 mod tests {
+    use std;
+    import std::arc;
 
     #[test]
     fn size_of_basic() {
@@ -121,6 +173,26 @@ mod tests {
         assert pref_align_of::<uint>() == 8u;
         assert pref_align_of::<*uint>() == 8u;
     }
+
+    #[test]
+    fn condition_variable() {
+        let lock = arc::arc(create_lock());
+        let lock2 = arc::clone(&lock);
+
+        task::spawn {|move lock2|
+            let lock = arc::get(&lock2);
+            (*lock).lock_cond {|c|
+                c.wait();
+            }
+        }
+
+        let mut signaled = false;
+        while !signaled {
+            (*arc::get(&lock)).lock_cond {|c|
+                signaled = c.signal()
+            }
+        }
+    }
 }
 
 // Local Variables:
diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp
index 2a65012b52a..25da500cb23 100644
--- a/src/rt/rust_builtin.cpp
+++ b/src/rt/rust_builtin.cpp
@@ -7,6 +7,7 @@
 #include "sync/timer.h"
 #include "rust_abi.h"
 #include "rust_port.h"
+#include "rust_cond_lock.h"
 
 #include <time.h>
 
@@ -862,6 +863,60 @@ rust_task_allow_kill() {
     task->allow_kill();
 }
 
+extern "C" rust_cond_lock*
+rust_create_cond_lock() {
+    return new rust_cond_lock();
+}
+
+extern "C" void
+rust_destroy_cond_lock(rust_cond_lock *lock) {
+    delete lock;
+}
+
+extern "C" void
+rust_lock_cond_lock(rust_cond_lock *lock) {
+    lock->lock.lock();
+}
+
+extern "C" void
+rust_unlock_cond_lock(rust_cond_lock *lock) {
+    lock->lock.unlock();
+}
+
+// The next two functions do not use the built in condition variable features
+// because the Rust schedule is not aware of them, and they can block the
+// scheduler thread.
+
+extern "C" void
+rust_wait_cond_lock(rust_cond_lock *lock) {
+    rust_task *task = rust_get_current_task();
+#ifdef DEBUG_LOCKS
+    assert(lock->lock.lock_held_by_current_thread());
+#endif
+    assert(NULL == lock->waiting);
+    lock->waiting = task;
+    lock->lock.unlock();
+    task->block(lock, "waiting for signal");
+    lock->lock.lock();
+    lock->waiting = NULL;
+}
+
+extern "C" bool
+rust_signal_cond_lock(rust_cond_lock *lock) {
+#ifdef DEBUG_LOCKS
+    assert(lock->lock.lock_held_by_current_thread());
+#endif
+    if(NULL == lock->waiting) {
+        return false;
+    }
+    else {
+        lock->waiting->wakeup(lock);
+        return true;
+    }
+}
+
+
+
 //
 // Local Variables:
 // mode: C++
diff --git a/src/rt/rust_cond_lock.cpp b/src/rt/rust_cond_lock.cpp
new file mode 100644
index 00000000000..cdeccfdc26c
--- /dev/null
+++ b/src/rt/rust_cond_lock.cpp
@@ -0,0 +1,6 @@
+#include "rust_cond_lock.h"
+
+rust_cond_lock::rust_cond_lock()
+    : waiting(NULL)
+{
+}
diff --git a/src/rt/rust_cond_lock.h b/src/rt/rust_cond_lock.h
new file mode 100644
index 00000000000..0adafd59678
--- /dev/null
+++ b/src/rt/rust_cond_lock.h
@@ -0,0 +1,15 @@
+// -*- c++ -*-
+// A lock and condition variable pair that is useable from Rust.
+
+#pragma once
+
+#include "sync/lock_and_signal.h"
+#include "rust_globals.h"
+#include "rust_task.h"
+
+struct rust_cond_lock : public rust_cond {
+    rust_cond_lock();
+
+    lock_and_signal lock;
+    rust_task *waiting;
+};
diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in
index 7977c42cfa4..5cf6ee61773 100644
--- a/src/rt/rustrt.def.in
+++ b/src/rt/rustrt.def.in
@@ -163,3 +163,9 @@ rust_port_drop
 rust_port_task
 rust_task_inhibit_kill
 rust_task_allow_kill
+rust_create_cond_lock
+rust_destroy_cond_lock
+rust_lock_cond_lock
+rust_unlock_cond_lock
+rust_wait_cond_lock
+rust_signal_cond_lock