@@ -14,6 +14,7 @@ use comm;
14
14
use libc;
15
15
use ptr;
16
16
use option:: * ;
17
+ use either:: { Either , Left , Right } ;
17
18
use task;
18
19
use task:: atomically;
19
20
use unstable:: atomics:: { AtomicOption , AtomicUint , Acquire , Release , SeqCst } ;
@@ -137,6 +138,31 @@ impl<T: Send> UnsafeAtomicRcBox<T> {
137
138
}
138
139
}
139
140
}
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
+ }
140
166
}
141
167
142
168
impl < T : Send > Clone for UnsafeAtomicRcBox < T > {
@@ -380,13 +406,54 @@ mod tests {
380
406
}
381
407
382
408
#[ test]
383
- fn unsafe_unwrap_basic ( ) {
409
+ fn arclike_unwrap_basic ( ) {
384
410
unsafe {
385
411
let x = UnsafeAtomicRcBox :: new ( ~~"hello") ;
386
412
assert ! ( x. unwrap( ) == ~~"hello");
387
413
}
388
414
}
389
415
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
+
390
457
#[test]
391
458
fn exclusive_unwrap_basic() {
392
459
// Unlike the above, also tests no double-freeing of the LittleLock.
0 commit comments