Skip to content

Commit dc718d9

Browse files
committedJun 19, 2012
Adding a lock/condition variable to libcore.
1 parent 9ee1480 commit dc718d9

File tree

6 files changed

+156
-0
lines changed

6 files changed

+156
-0
lines changed
 

‎mk/rt.mk

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ RUNTIME_CS_$(1) := \
7171
rt/rust_cc.cpp \
7272
rt/rust_debug.cpp \
7373
rt/rust_box_annihilator.cpp \
74+
rt/rust_cond_lock.cpp \
7475
rt/memory_region.cpp \
7576
rt/boxed_region.cpp \
7677
rt/arch/$$(HOST_$(1))/context.cpp \

‎src/libcore/sys.rs

+72
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ export min_align_of;
77
export pref_align_of;
88
export refcount;
99
export log_str;
10+
export lock_and_signal, condition, methods;
1011

1112
enum type_desc = {
1213
first_param: **libc::c_int,
@@ -15,11 +16,20 @@ enum type_desc = {
1516
// Remaining fields not listed
1617
};
1718

19+
type rust_cond_lock = *libc::c_void;
20+
1821
#[abi = "cdecl"]
1922
native mod rustrt {
2023
pure fn refcount(t: *()) -> libc::intptr_t;
2124
fn unsupervise();
2225
pure fn shape_log_str(t: *sys::type_desc, data: *()) -> str;
26+
27+
fn rust_create_cond_lock() -> rust_cond_lock;
28+
fn rust_destroy_cond_lock(lock: rust_cond_lock);
29+
fn rust_lock_cond_lock(lock: rust_cond_lock);
30+
fn rust_unlock_cond_lock(lock: rust_cond_lock);
31+
fn rust_wait_cond_lock(lock: rust_cond_lock);
32+
fn rust_signal_cond_lock(lock: rust_cond_lock) -> bool;
2333
}
2434

2535
#[abi = "rust-intrinsic"]
@@ -74,8 +84,50 @@ pure fn log_str<T>(t: T) -> str {
7484
}
7585
}
7686

87+
resource lock_and_signal(lock: rust_cond_lock) {
88+
rustrt::rust_destroy_cond_lock(lock);
89+
}
90+
91+
enum condition {
92+
condition_(rust_cond_lock)
93+
}
94+
95+
resource unlock(lock: rust_cond_lock) {
96+
rustrt::rust_unlock_cond_lock(lock);
97+
}
98+
99+
fn create_lock() -> lock_and_signal {
100+
lock_and_signal(rustrt::rust_create_cond_lock())
101+
}
102+
103+
impl methods for lock_and_signal {
104+
fn lock<T>(f: fn() -> T) -> T {
105+
rustrt::rust_lock_cond_lock(*self);
106+
let _r = unlock(*self);
107+
f()
108+
}
109+
110+
fn lock_cond<T>(f: fn(condition) -> T) -> T {
111+
rustrt::rust_lock_cond_lock(*self);
112+
let _r = unlock(*self);
113+
f(condition_(*self))
114+
}
115+
}
116+
117+
impl methods for condition {
118+
fn wait() {
119+
rustrt::rust_wait_cond_lock(*self);
120+
}
121+
122+
fn signal() -> bool {
123+
rustrt::rust_signal_cond_lock(*self)
124+
}
125+
}
126+
77127
#[cfg(test)]
78128
mod tests {
129+
use std;
130+
import std::arc;
79131

80132
#[test]
81133
fn size_of_basic() {
@@ -121,6 +173,26 @@ mod tests {
121173
assert pref_align_of::<uint>() == 8u;
122174
assert pref_align_of::<*uint>() == 8u;
123175
}
176+
177+
#[test]
178+
fn condition_variable() {
179+
let lock = arc::arc(create_lock());
180+
let lock2 = arc::clone(&lock);
181+
182+
task::spawn {|move lock2|
183+
let lock = arc::get(&lock2);
184+
(*lock).lock_cond {|c|
185+
c.wait();
186+
}
187+
}
188+
189+
let mut signaled = false;
190+
while !signaled {
191+
(*arc::get(&lock)).lock_cond {|c|
192+
signaled = c.signal()
193+
}
194+
}
195+
}
124196
}
125197

126198
// Local Variables:

‎src/rt/rust_builtin.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "sync/timer.h"
88
#include "rust_abi.h"
99
#include "rust_port.h"
10+
#include "rust_cond_lock.h"
1011

1112
#include <time.h>
1213

@@ -861,6 +862,61 @@ rust_task_allow_kill() {
861862
task->allow_kill();
862863
}
863864

865+
extern "C" rust_cond_lock*
866+
rust_create_cond_lock() {
867+
return new rust_cond_lock();
868+
}
869+
870+
extern "C" void
871+
rust_destroy_cond_lock(rust_cond_lock *lock) {
872+
delete lock;
873+
}
874+
875+
extern "C" void
876+
rust_lock_cond_lock(rust_cond_lock *lock) {
877+
lock->lock.lock();
878+
}
879+
880+
extern "C" void
881+
rust_unlock_cond_lock(rust_cond_lock *lock) {
882+
lock->lock.unlock();
883+
}
884+
885+
// The next two functions do not use the built in condition variable features
886+
// because the Rust schedule is not aware of them, and they can block the
887+
// scheduler thread.
888+
889+
extern "C" void
890+
rust_wait_cond_lock(rust_cond_lock *lock) {
891+
rust_task *task = rust_get_current_task();
892+
#ifdef DEBUG_LOCKS
893+
assert(lock->lock.lock_held_by_current_thread());
894+
#endif
895+
assert(NULL == lock->waiting);
896+
lock->waiting = task;
897+
task->block(lock, "waiting for signal");
898+
lock->lock.unlock();
899+
task->yield(false);
900+
lock->lock.lock();
901+
}
902+
903+
extern "C" bool
904+
rust_signal_cond_lock(rust_cond_lock *lock) {
905+
#ifdef DEBUG_LOCKS
906+
assert(lock->lock.lock_held_by_current_thread());
907+
#endif
908+
if(NULL == lock->waiting) {
909+
return false;
910+
}
911+
else {
912+
lock->waiting->wakeup(lock);
913+
lock->waiting = NULL;
914+
return true;
915+
}
916+
}
917+
918+
919+
864920
//
865921
// Local Variables:
866922
// mode: C++

‎src/rt/rust_cond_lock.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
#include "rust_cond_lock.h"
2+
3+
rust_cond_lock::rust_cond_lock()
4+
: waiting(NULL)
5+
{
6+
}

‎src/rt/rust_cond_lock.h

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// -*- c++ -*-
2+
// A lock and condition variable pair that is useable from Rust.
3+
4+
#pragma once
5+
6+
#include "sync/lock_and_signal.h"
7+
#include "rust_globals.h"
8+
#include "rust_task.h"
9+
10+
struct rust_cond_lock : public rust_cond {
11+
rust_cond_lock();
12+
13+
lock_and_signal lock;
14+
rust_task *waiting;
15+
};

‎src/rt/rustrt.def.in

+6
Original file line numberDiff line numberDiff line change
@@ -163,3 +163,9 @@ rust_port_drop
163163
rust_port_task
164164
rust_task_inhibit_kill
165165
rust_task_allow_kill
166+
rust_create_cond_lock
167+
rust_destroy_cond_lock
168+
rust_lock_cond_lock
169+
rust_unlock_cond_lock
170+
rust_wait_cond_lock
171+
rust_signal_cond_lock

0 commit comments

Comments
 (0)
Please sign in to comment.