Skip to content

Commit 0e9b22e

Browse files
committed
---
yaml --- r: 96934 b: refs/heads/dist-snap c: 962af91 h: refs/heads/master v: v3
1 parent b67650e commit 0e9b22e

File tree

4 files changed

+55
-28
lines changed

4 files changed

+55
-28
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ refs/heads/try: c274a6888410ce3e357e014568b43310ed787d36
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
88
refs/heads/try2: 147ecfdd8221e4a4d4e090486829a06da1e0ca3c
9-
refs/heads/dist-snap: 04c446b4b66068a6742d29cd34326e520373f83e
9+
refs/heads/dist-snap: 962af9198f8f2a1e2d5121ac216b6f4d574ae54c
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503
1212
refs/heads/try3: 9387340aab40a73e8424c48fd42f0c521a4875c0

branches/dist-snap/src/libgreen/simple.rs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,15 @@
1313
1414
use std::cast;
1515
use std::rt::Runtime;
16-
use std::task::TaskOpts;
17-
use std::rt::rtio;
1816
use std::rt::local::Local;
17+
use std::rt::rtio;
1918
use std::rt::task::{Task, BlockedTask};
19+
use std::task::TaskOpts;
2020
use std::unstable::sync::LittleLock;
2121

2222
struct SimpleTask {
2323
lock: LittleLock,
24+
awoken: bool,
2425
}
2526

2627
impl Runtime for SimpleTask {
@@ -30,30 +31,37 @@ impl Runtime for SimpleTask {
3031
f: |BlockedTask| -> Result<(), BlockedTask>) {
3132
assert!(times == 1);
3233

33-
let my_lock: *mut LittleLock = &mut self.lock;
34+
let me = &mut *self as *mut SimpleTask;
35+
let cur_dupe = &*cur_task as *Task;
3436
cur_task.put_runtime(self as ~Runtime);
37+
let task = BlockedTask::block(cur_task);
3538

39+
// See libnative/task.rs for what's going on here with the `awoken`
40+
// field and the while loop around wait()
3641
unsafe {
37-
let cur_task_dupe = *cast::transmute::<&~Task, &uint>(&cur_task);
38-
let task = BlockedTask::block(cur_task);
39-
40-
let mut guard = (*my_lock).lock();
42+
let mut guard = (*me).lock.lock();
43+
(*me).awoken = false;
4144
match f(task) {
42-
Ok(()) => guard.wait(),
45+
Ok(()) => {
46+
while !(*me).awoken {
47+
guard.wait();
48+
}
49+
}
4350
Err(task) => { cast::forget(task.wake()); }
4451
}
4552
drop(guard);
46-
cur_task = cast::transmute::<uint, ~Task>(cur_task_dupe);
53+
cur_task = cast::transmute(cur_dupe);
4754
}
4855
Local::put(cur_task);
4956
}
5057
fn reawaken(mut ~self, mut to_wake: ~Task) {
51-
let lock: *mut LittleLock = &mut self.lock;
58+
let me = &mut *self as *mut SimpleTask;
5259
to_wake.put_runtime(self as ~Runtime);
5360
unsafe {
5461
cast::forget(to_wake);
55-
let _l = (*lock).lock();
56-
(*lock).signal();
62+
let _l = (*me).lock.lock();
63+
(*me).awoken = true;
64+
(*me).lock.signal();
5765
}
5866
}
5967

@@ -72,6 +80,9 @@ impl Runtime for SimpleTask {
7280

7381
pub fn task() -> ~Task {
7482
let mut task = ~Task::new();
75-
task.put_runtime(~SimpleTask { lock: LittleLock::new() } as ~Runtime);
83+
task.put_runtime(~SimpleTask {
84+
lock: LittleLock::new(),
85+
awoken: false,
86+
} as ~Runtime);
7687
return task;
7788
}

branches/dist-snap/src/libnative/task.rs

Lines changed: 29 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub fn new() -> ~Task {
3333
let mut task = ~Task::new();
3434
task.put_runtime(~Ops {
3535
lock: unsafe { Mutex::new() },
36+
awoken: false,
3637
} as ~rt::Runtime);
3738
return task;
3839
}
@@ -85,7 +86,8 @@ pub fn spawn_opts(opts: TaskOpts, f: proc()) {
8586
// This structure is the glue between channels and the 1:1 scheduling mode. This
8687
// structure is allocated once per task.
8788
struct Ops {
88-
lock: Mutex, // native synchronization
89+
lock: Mutex, // native synchronization
90+
awoken: bool, // used to prevent spurious wakeups
8991
}
9092

9193
impl rt::Runtime for Ops {
@@ -139,25 +141,38 @@ impl rt::Runtime for Ops {
139141
// reasoning for this is the same logic as above in that the task silently
140142
// transfers ownership via the `uint`, not through normal compiler
141143
// semantics.
144+
//
145+
// On a mildly unrelated note, it should also be pointed out that OS
146+
// condition variables are susceptible to spurious wakeups, which we need to
147+
// be ready for. In order to accomodate for this fact, we have an extra
148+
// `awoken` field which indicates whether we were actually woken up via some
149+
// invocation of `reawaken`. This flag is only ever accessed inside the
150+
// lock, so there's no need to make it atomic.
142151
fn deschedule(mut ~self, times: uint, mut cur_task: ~Task,
143152
f: |BlockedTask| -> Result<(), BlockedTask>) {
144-
let my_lock: *mut Mutex = &mut self.lock as *mut Mutex;
153+
let me = &mut *self as *mut Ops;
145154
cur_task.put_runtime(self as ~rt::Runtime);
146155

147156
unsafe {
148157
let cur_task_dupe = *cast::transmute::<&~Task, &uint>(&cur_task);
149158
let task = BlockedTask::block(cur_task);
150159

151160
if times == 1 {
152-
(*my_lock).lock();
161+
(*me).lock.lock();
162+
(*me).awoken = false;
153163
match f(task) {
154-
Ok(()) => (*my_lock).wait(),
164+
Ok(()) => {
165+
while !(*me).awoken {
166+
(*me).lock.wait();
167+
}
168+
}
155169
Err(task) => { cast::forget(task.wake()); }
156170
}
157-
(*my_lock).unlock();
171+
(*me).lock.unlock();
158172
} else {
159173
let mut iter = task.make_selectable(times);
160-
(*my_lock).lock();
174+
(*me).lock.lock();
175+
(*me).awoken = false;
161176
let success = iter.all(|task| {
162177
match f(task) {
163178
Ok(()) => true,
@@ -167,10 +182,10 @@ impl rt::Runtime for Ops {
167182
}
168183
}
169184
});
170-
if success {
171-
(*my_lock).wait();
185+
while success && !(*me).awoken {
186+
(*me).lock.wait();
172187
}
173-
(*my_lock).unlock();
188+
(*me).lock.unlock();
174189
}
175190
// re-acquire ownership of the task
176191
cur_task = cast::transmute::<uint, ~Task>(cur_task_dupe);
@@ -184,12 +199,13 @@ impl rt::Runtime for Ops {
184199
// why it's valid to do so.
185200
fn reawaken(mut ~self, mut to_wake: ~Task, _can_resched: bool) {
186201
unsafe {
187-
let lock: *mut Mutex = &mut self.lock as *mut Mutex;
202+
let me = &mut *self as *mut Ops;
188203
to_wake.put_runtime(self as ~rt::Runtime);
189204
cast::forget(to_wake);
190-
(*lock).lock();
191-
(*lock).signal();
192-
(*lock).unlock();
205+
(*me).lock.lock();
206+
(*me).awoken = true;
207+
(*me).lock.signal();
208+
(*me).lock.unlock();
193209
}
194210
}
195211

branches/dist-snap/src/libstd/comm/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -875,7 +875,7 @@ impl<T: Send> Port<T> {
875875
let data = self.try_recv_inc(false);
876876
if data.is_none() &&
877877
unsafe { (*packet).cnt.load(SeqCst) } != DISCONNECTED {
878-
fail!("bug: woke up too soon");
878+
fail!("bug: woke up too soon {}", unsafe { (*packet).cnt.load(SeqCst) });
879879
}
880880
return data;
881881
}

0 commit comments

Comments
 (0)