diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2014-04-14 07:06:14 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2014-04-15 19:45:00 -0700 |
| commit | 93dc55518840ee3cbd570c0d85aa7a445752af8b (patch) | |
| tree | b0e338768e2b094d97d0ca533e94e1f723d59ae3 /src/libnative | |
| parent | 4ca7abb1c4c76b4a23024baacdb7a023692c1d2d (diff) | |
| download | rust-93dc55518840ee3cbd570c0d85aa7a445752af8b.tar.gz rust-93dc55518840ee3cbd570c0d85aa7a445752af8b.zip | |
native: Fix a race in select()
During selection, libnative would erroneously re-acquire ownership of a task when a separate thread still had ownership of the task. The loop in select() was rewritten to acknowledge this race and instead block waiting to re-acquire ownership rather than plowing through. Closes #13494
Diffstat (limited to 'src/libnative')
| -rw-r--r-- | src/libnative/task.rs | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/src/libnative/task.rs b/src/libnative/task.rs index ddfd46ecad9..8a82ae55faa 100644 --- a/src/libnative/task.rs +++ b/src/libnative/task.rs @@ -201,19 +201,30 @@ impl rt::Runtime for Ops { Err(task) => { cast::forget(task.wake()); } } } else { - let mut iter = task.make_selectable(times); + let iter = task.make_selectable(times); let guard = (*me).lock.lock(); (*me).awoken = false; - let success = iter.all(|task| { - match f(task) { - Ok(()) => true, - Err(task) => { - cast::forget(task.wake()); - false + + // Apply the given closure to all of the "selectable tasks", + // bailing on the first one that produces an error. Note that + // care must be taken such that when an error is occurred, we + // may not own the task, so we may still have to wait for the + // task to become available. In other words, if task.wake() + // returns `None`, then someone else has ownership and we must + // wait for their signal. + match iter.map(f).filter_map(|a| a.err()).next() { + None => {} + Some(task) => { + match task.wake() { + Some(task) => { + cast::forget(task); + (*me).awoken = true; + } + None => {} } } - }); - while success && !(*me).awoken { + } + while !(*me).awoken { guard.wait(); } } |
