Skip to content

Commit 6a5f69a

Browse files
committed
---
yaml --- r: 143000 b: refs/heads/try2 c: 2a99163 h: refs/heads/master v: v3
1 parent 80d9199 commit 6a5f69a

File tree

2 files changed

+69
-2
lines changed

2 files changed

+69
-2
lines changed

[refs]

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ refs/heads/snap-stage3: 78a7676898d9f80ab540c6df5d4c9ce35bb50463
55
refs/heads/try: 519addf6277dbafccbb4159db4b710c37eaa2ec5
66
refs/tags/release-0.1: 1f5c5126e96c79d22cb7862f75304136e204f105
77
refs/heads/ndm: f3868061cd7988080c30d6d5bf352a5a5fe2460b
8-
refs/heads/try2: 10a400ffaa8b67add66a62bde0ef3c415d7aed5f
8+
refs/heads/try2: 2a99163f5d54ff26921cda0b12a99e5bd768b873
99
refs/heads/dist-snap: ba4081a5a8573875fed17545846f6f6902c8ba8d
1010
refs/tags/release-0.2: c870d2dffb391e14efb05aa27898f1f6333a9596
1111
refs/tags/release-0.3: b5f0d0f648d9a6153664837026ba1be43d3e2503

branches/try2/src/libstd/unstable/sync.rs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ use comm;
1414
use libc;
1515
use ptr;
1616
use option::*;
17+
use either::{Either, Left, Right};
1718
use task;
1819
use task::atomically;
1920
use unstable::atomics::{AtomicOption,AtomicUint,Acquire,Release,SeqCst};
@@ -137,6 +138,31 @@ impl<T: Send> UnsafeAtomicRcBox<T> {
137138
}
138139
}
139140
}
141+
142+
/// As unwrap above, but without blocking. Returns 'Left(self)' if this is
143+
/// not the last reference; 'Right(unwrapped_data)' if so.
144+
pub unsafe fn try_unwrap(self) -> Either<UnsafeAtomicRcBox<T>, T> {
145+
let mut this = self; // FIXME(#4330) mutable self
146+
let mut data: ~AtomicRcBoxData<T> = cast::transmute(this.data);
147+
// This can of course race with anybody else who has a handle, but in
148+
// such a case, the returned count will always be at least 2. If we
149+
// see 1, no race was possible. All that matters is 1 or not-1.
150+
let count = data.count.load(Acquire);
151+
assert!(count >= 1);
152+
// The more interesting race is one with an unwrapper. They may have
153+
// already dropped their count -- but if so, the unwrapper pointer
154+
// will have been set first, which the barriers ensure we will see.
155+
// (Note: using is_empty(), not take(), to not free the unwrapper.)
156+
if count == 1 && data.unwrapper.is_empty(Acquire) {
157+
// Tell this handle's destructor not to run (we are now it).
158+
this.data = ptr::mut_null();
159+
// FIXME(#3224) as above
160+
Right(data.data.take_unwrap())
161+
} else {
162+
cast::forget(data);
163+
Left(this)
164+
}
165+
}
140166
}
141167

142168
impl<T: Send> Clone for UnsafeAtomicRcBox<T> {
@@ -380,13 +406,54 @@ mod tests {
380406
}
381407

382408
#[test]
383-
fn unsafe_unwrap_basic() {
409+
fn arclike_unwrap_basic() {
384410
unsafe {
385411
let x = UnsafeAtomicRcBox::new(~~"hello");
386412
assert!(x.unwrap() == ~~"hello");
387413
}
388414
}
389415
416+
#[test]
417+
fn arclike_try_unwrap() {
418+
unsafe {
419+
let x = UnsafeAtomicRcBox::new(~~"hello");
420+
assert!(x.try_unwrap().expect_right("try_unwrap failed") == ~~"hello");
421+
}
422+
}
423+
424+
#[test]
425+
fn arclike_try_unwrap_fail() {
426+
unsafe {
427+
let x = UnsafeAtomicRcBox::new(~~"hello");
428+
let x2 = x.clone();
429+
let left_x = x.try_unwrap();
430+
assert!(left_x.is_left());
431+
util::ignore(left_x);
432+
assert!(x2.try_unwrap().expect_right("try_unwrap none") == ~~"hello");
433+
}
434+
}
435+
436+
#[test]
437+
fn arclike_try_unwrap_unwrap_race() {
438+
// When an unwrap and a try_unwrap race, the unwrapper should always win.
439+
unsafe {
440+
let x = UnsafeAtomicRcBox::new(~~"hello");
441+
let x2 = Cell::new(x.clone());
442+
let (p,c) = comm::stream();
443+
do task::spawn {
444+
c.send(());
445+
assert!(x2.take().unwrap() == ~~"hello");
446+
c.send(());
447+
}
448+
p.recv();
449+
task::yield(); // Try to make the unwrapper get blocked first.
450+
let left_x = x.try_unwrap();
451+
assert!(left_x.is_left());
452+
util::ignore(left_x);
453+
p.recv();
454+
}
455+
}
456+
390457
#[test]
391458
fn exclusive_unwrap_basic() {
392459
// Unlike the above, also tests no double-freeing of the LittleLock.

0 commit comments

Comments
 (0)