]> git.lizzy.rs Git - rust.git/blob - src/libsync/arc.rs
test: Make manual changes to deal with the fallout from removal of
[rust.git] / src / libsync / arc.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * Concurrency-enabled mechanisms for sharing mutable and/or immutable state
13  * between tasks.
14  *
15  * # Example
16  *
17  * In this example, a large vector of floats is shared between several tasks.
18  * With simple pipes, without Arc, a copy would have to be made for each task.
19  *
20  * ```rust
21  * extern crate sync;
22  * extern crate rand;
23  *
24  * use std::slice;
25  * use sync::Arc;
26  *
27  * fn main() {
28  *     let numbers = slice::from_fn(100, |i| (i as f32) * rand::random());
29  *     let shared_numbers = Arc::new(numbers);
30  *
31  *     for _ in range(0, 10) {
32  *         let (tx, rx) = channel();
33  *         tx.send(shared_numbers.clone());
34  *
35  *         spawn(proc() {
36  *             let shared_numbers = rx.recv();
37  *             let local_numbers = shared_numbers.get();
38  *
39  *             // Work with the local numbers
40  *         });
41  *     }
42  * }
43  * ```
44  */
45
46 #[allow(missing_doc, dead_code)];
47
48
49 use sync;
50 use sync::{Mutex, RWLock};
51
52 use std::cast;
53 use std::kinds::marker;
54 use std::sync::arc::UnsafeArc;
55 use std::task;
56
57 #[cfg(stage0)]
58 use std::kinds::Share;
59
60 /// As sync::condvar, a mechanism for unlock-and-descheduling and
61 /// signaling, for use with the Arc types.
62 pub struct ArcCondvar<'a> {
63     priv is_mutex: bool,
64     priv failed: &'a bool,
65     priv cond: &'a sync::Condvar<'a>
66 }
67
68 impl<'a> ArcCondvar<'a> {
69     /// Atomically exit the associated Arc and block until a signal is sent.
70     #[inline]
71     pub fn wait(&self) { self.wait_on(0) }
72
73     /**
74      * Atomically exit the associated Arc and block on a specified condvar
75      * until a signal is sent on that same condvar (as sync::cond.wait_on).
76      *
77      * wait() is equivalent to wait_on(0).
78      */
79     #[inline]
80     pub fn wait_on(&self, condvar_id: uint) {
81         assert!(!*self.failed);
82         self.cond.wait_on(condvar_id);
83         // This is why we need to wrap sync::condvar.
84         check_poison(self.is_mutex, *self.failed);
85     }
86
87     /// Wake up a blocked task. Returns false if there was no blocked task.
88     #[inline]
89     pub fn signal(&self) -> bool { self.signal_on(0) }
90
91     /**
92      * Wake up a blocked task on a specified condvar (as
93      * sync::cond.signal_on). Returns false if there was no blocked task.
94      */
95     #[inline]
96     pub fn signal_on(&self, condvar_id: uint) -> bool {
97         assert!(!*self.failed);
98         self.cond.signal_on(condvar_id)
99     }
100
101     /// Wake up all blocked tasks. Returns the number of tasks woken.
102     #[inline]
103     pub fn broadcast(&self) -> uint { self.broadcast_on(0) }
104
105     /**
106      * Wake up all blocked tasks on a specified condvar (as
107      * sync::cond.broadcast_on). Returns the number of tasks woken.
108      */
109     #[inline]
110     pub fn broadcast_on(&self, condvar_id: uint) -> uint {
111         assert!(!*self.failed);
112         self.cond.broadcast_on(condvar_id)
113     }
114 }
115
116 /****************************************************************************
117  * Immutable Arc
118  ****************************************************************************/
119
120 /// An atomically reference counted wrapper for shared immutable state.
121 pub struct Arc<T> { priv x: UnsafeArc<T> }
122
123
124 /**
125  * Access the underlying data in an atomically reference counted
126  * wrapper.
127  */
128 impl<T: Share + Send> Arc<T> {
129     /// Create an atomically reference counted wrapper.
130     #[inline]
131     pub fn new(data: T) -> Arc<T> {
132         Arc { x: UnsafeArc::new(data) }
133     }
134
135     #[inline]
136     pub fn get<'a>(&'a self) -> &'a T {
137         unsafe { &*self.x.get_immut() }
138     }
139 }
140
141 impl<T: Share + Send> Clone for Arc<T> {
142     /**
143     * Duplicate an atomically reference counted wrapper.
144     *
145     * The resulting two `arc` objects will point to the same underlying data
146     * object. However, one of the `arc` objects can be sent to another task,
147     * allowing them to share the underlying data.
148     */
149     #[inline]
150     fn clone(&self) -> Arc<T> {
151         Arc { x: self.x.clone() }
152     }
153 }
154
155 /****************************************************************************
156  * Mutex protected Arc (unsafe)
157  ****************************************************************************/
158
159 #[doc(hidden)]
160 struct MutexArcInner<T> { lock: Mutex, failed: bool, data: T }
161
162 /// An Arc with mutable data protected by a blocking mutex.
163 pub struct MutexArc<T> {
164     priv x: UnsafeArc<MutexArcInner<T>>,
165     priv marker: marker::NoFreeze,
166 }
167
168 impl<T:Send> Clone for MutexArc<T> {
169     /// Duplicate a mutex-protected Arc. See arc::clone for more details.
170     #[inline]
171     fn clone(&self) -> MutexArc<T> {
172         // NB: Cloning the underlying mutex is not necessary. Its reference
173         // count would be exactly the same as the shared state's.
174         MutexArc { x: self.x.clone(),
175                    marker: marker::NoFreeze, }
176     }
177 }
178
179 impl<T:Send> MutexArc<T> {
180     /// Create a mutex-protected Arc with the supplied data.
181     pub fn new(user_data: T) -> MutexArc<T> {
182         MutexArc::new_with_condvars(user_data, 1)
183     }
184
185     /**
186      * Create a mutex-protected Arc with the supplied data and a specified number
187      * of condvars (as sync::Mutex::new_with_condvars).
188      */
189     pub fn new_with_condvars(user_data: T, num_condvars: uint) -> MutexArc<T> {
190         let data = MutexArcInner {
191             lock: Mutex::new_with_condvars(num_condvars),
192             failed: false, data: user_data
193         };
194         MutexArc { x: UnsafeArc::new(data),
195                    marker: marker::NoFreeze, }
196     }
197
198     /**
199      * Access the underlying mutable data with mutual exclusion from other
200      * tasks. The argument closure will be run with the mutex locked; all
201      * other tasks wishing to access the data will block until the closure
202      * finishes running.
203      *
204      * If you wish to nest MutexArcs, one strategy for ensuring safety at
205      * runtime is to add a "nesting level counter" inside the stored data, and
206      * when traversing the arcs, assert that they monotonically decrease.
207      *
208      * # Failure
209      *
210      * Failing while inside the Arc will unlock the Arc while unwinding, so
211      * that other tasks won't block forever. It will also poison the Arc:
212      * any tasks that subsequently try to access it (including those already
213      * blocked on the mutex) will also fail immediately.
214      */
215     #[inline]
216     pub fn access<U>(&self, blk: |x: &mut T| -> U) -> U {
217         let state = self.x.get();
218         unsafe {
219             // Borrowck would complain about this if the code were
220             // not already unsafe. See borrow_rwlock, far below.
221             (&(*state).lock).lock(|| {
222                 check_poison(true, (*state).failed);
223                 let _z = PoisonOnFail::new(&mut (*state).failed);
224                 blk(&mut (*state).data)
225             })
226         }
227     }
228
229     /// As access(), but with a condvar, as sync::mutex.lock_cond().
230     #[inline]
231     pub fn access_cond<U>(&self, blk: |x: &mut T, c: &ArcCondvar| -> U) -> U {
232         let state = self.x.get();
233         unsafe {
234             (&(*state).lock).lock_cond(|cond| {
235                 check_poison(true, (*state).failed);
236                 let _z = PoisonOnFail::new(&mut (*state).failed);
237                 blk(&mut (*state).data,
238                     &ArcCondvar {is_mutex: true,
239                             failed: &(*state).failed,
240                             cond: cond })
241             })
242         }
243     }
244 }
245
246 // Common code for {mutex.access,rwlock.write}{,_cond}.
247 #[inline]
248 #[doc(hidden)]
249 fn check_poison(is_mutex: bool, failed: bool) {
250     if failed {
251         if is_mutex {
252             fail!("Poisoned MutexArc - another task failed inside!");
253         } else {
254             fail!("Poisoned rw_arc - another task failed inside!");
255         }
256     }
257 }
258
259 #[doc(hidden)]
260 struct PoisonOnFail {
261     flag: *mut bool,
262     failed: bool,
263 }
264
265 impl Drop for PoisonOnFail {
266     fn drop(&mut self) {
267         unsafe {
268             /* assert!(!*self.failed);
269                -- might be false in case of cond.wait() */
270             if !self.failed && task::failing() {
271                 *self.flag = true;
272             }
273         }
274     }
275 }
276
277 impl PoisonOnFail {
278     fn new<'a>(flag: &'a mut bool) -> PoisonOnFail {
279         PoisonOnFail {
280             flag: flag,
281             failed: task::failing()
282         }
283     }
284 }
285
286 /****************************************************************************
287  * R/W lock protected Arc
288  ****************************************************************************/
289
290 #[doc(hidden)]
291 struct RWArcInner<T> { lock: RWLock, failed: bool, data: T }
292 /**
293  * A dual-mode Arc protected by a reader-writer lock. The data can be accessed
294  * mutably or immutably, and immutably-accessing tasks may run concurrently.
295  *
296  * Unlike mutex_arcs, rw_arcs are safe, because they cannot be nested.
297  */
298 pub struct RWArc<T> {
299     priv x: UnsafeArc<RWArcInner<T>>,
300     priv marker: marker::NoFreeze,
301     priv marker1: marker::NoShare,
302 }
303
304 impl<T: Share + Send> Clone for RWArc<T> {
305     /// Duplicate a rwlock-protected Arc. See arc::clone for more details.
306     #[inline]
307     fn clone(&self) -> RWArc<T> {
308         RWArc { x: self.x.clone(),
309                 marker: marker::NoFreeze,
310                 marker1: marker::NoShare, }
311     }
312
313 }
314
315 impl<T: Share + Send> RWArc<T> {
316     /// Create a reader/writer Arc with the supplied data.
317     pub fn new(user_data: T) -> RWArc<T> {
318         RWArc::new_with_condvars(user_data, 1)
319     }
320
321     /**
322      * Create a reader/writer Arc with the supplied data and a specified number
323      * of condvars (as sync::RWLock::new_with_condvars).
324      */
325     pub fn new_with_condvars(user_data: T, num_condvars: uint) -> RWArc<T> {
326         let data = RWArcInner {
327             lock: RWLock::new_with_condvars(num_condvars),
328             failed: false, data: user_data
329         };
330         RWArc { x: UnsafeArc::new(data),
331                 marker: marker::NoFreeze,
332                 marker1: marker::NoShare, }
333     }
334
335     /**
336      * Access the underlying data mutably. Locks the rwlock in write mode;
337      * other readers and writers will block.
338      *
339      * # Failure
340      *
341      * Failing while inside the Arc will unlock the Arc while unwinding, so
342      * that other tasks won't block forever. As MutexArc.access, it will also
343      * poison the Arc, so subsequent readers and writers will both also fail.
344      */
345     #[inline]
346     pub fn write<U>(&self, blk: |x: &mut T| -> U) -> U {
347         unsafe {
348             let state = self.x.get();
349             (*borrow_rwlock(state)).write(|| {
350                 check_poison(false, (*state).failed);
351                 let _z = PoisonOnFail::new(&mut (*state).failed);
352                 blk(&mut (*state).data)
353             })
354         }
355     }
356
357     /// As write(), but with a condvar, as sync::rwlock.write_cond().
358     #[inline]
359     pub fn write_cond<U>(&self,
360                          blk: |x: &mut T, c: &ArcCondvar| -> U)
361                          -> U {
362         unsafe {
363             let state = self.x.get();
364             (*borrow_rwlock(state)).write_cond(|cond| {
365                 check_poison(false, (*state).failed);
366                 let _z = PoisonOnFail::new(&mut (*state).failed);
367                 blk(&mut (*state).data,
368                     &ArcCondvar {is_mutex: false,
369                               failed: &(*state).failed,
370                               cond: cond})
371             })
372         }
373     }
374
375     /**
376      * Access the underlying data immutably. May run concurrently with other
377      * reading tasks.
378      *
379      * # Failure
380      *
381      * Failing will unlock the Arc while unwinding. However, unlike all other
382      * access modes, this will not poison the Arc.
383      */
384     pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
385         unsafe {
386             let state = self.x.get();
387             (*state).lock.read(|| {
388                 check_poison(false, (*state).failed);
389                 blk(&(*state).data)
390             })
391         }
392     }
393
394     /**
395      * As write(), but with the ability to atomically 'downgrade' the lock.
396      * See sync::rwlock.write_downgrade(). The RWWriteMode token must be used
397      * to obtain the &mut T, and can be transformed into a RWReadMode token by
398      * calling downgrade(), after which a &T can be obtained instead.
399      *
400      * # Example
401      *
402      * ```rust
403      * use sync::RWArc;
404      *
405      * let arc = RWArc::new(1);
406      * arc.write_downgrade(|mut write_token| {
407      *     write_token.write_cond(|state, condvar| {
408      *         // ... exclusive access with mutable state ...
409      *     });
410      *     let read_token = arc.downgrade(write_token);
411      *     read_token.read(|state| {
412      *         // ... shared access with immutable state ...
413      *     });
414      * })
415      * ```
416      */
417     pub fn write_downgrade<U>(&self, blk: |v: RWWriteMode<T>| -> U) -> U {
418         unsafe {
419             let state = self.x.get();
420             (*borrow_rwlock(state)).write_downgrade(|write_mode| {
421                 check_poison(false, (*state).failed);
422                 blk(RWWriteMode {
423                     data: &mut (*state).data,
424                     token: write_mode,
425                     poison: PoisonOnFail::new(&mut (*state).failed)
426                 })
427             })
428         }
429     }
430
431     /// To be called inside of the write_downgrade block.
432     pub fn downgrade<'a>(&self, token: RWWriteMode<'a, T>)
433                          -> RWReadMode<'a, T> {
434         unsafe {
435             // The rwlock should assert that the token belongs to us for us.
436             let state = self.x.get();
437             let RWWriteMode {
438                 data: data,
439                 token: t,
440                 poison: _poison
441             } = token;
442             // Let readers in
443             let new_token = (*state).lock.downgrade(t);
444             // Whatever region the input reference had, it will be safe to use
445             // the same region for the output reference. (The only 'unsafe' part
446             // of this cast is removing the mutability.)
447             let new_data = data;
448             // Downgrade ensured the token belonged to us. Just a sanity check.
449             assert!((&(*state).data as *T as uint) == (new_data as *mut T as uint));
450             // Produce new token
451             RWReadMode {
452                 data: new_data,
453                 token: new_token,
454             }
455         }
456     }
457 }
458
459 // Borrowck rightly complains about immutably aliasing the rwlock in order to
460 // lock it. This wraps the unsafety, with the justification that the 'lock'
461 // field is never overwritten; only 'failed' and 'data'.
462 #[doc(hidden)]
463 fn borrow_rwlock<T: Share + Send>(state: *mut RWArcInner<T>) -> *RWLock {
464     unsafe { cast::transmute(&(*state).lock) }
465 }
466
467 /// The "write permission" token used for RWArc.write_downgrade().
468 pub struct RWWriteMode<'a, T> {
469     priv data: &'a mut T,
470     priv token: sync::RWLockWriteMode<'a>,
471     priv poison: PoisonOnFail,
472 }
473
474 /// The "read permission" token used for RWArc.write_downgrade().
475 pub struct RWReadMode<'a, T> {
476     priv data: &'a T,
477     priv token: sync::RWLockReadMode<'a>,
478 }
479
480 impl<'a, T: Share + Send> RWWriteMode<'a, T> {
481     /// Access the pre-downgrade RWArc in write mode.
482     pub fn write<U>(&mut self, blk: |x: &mut T| -> U) -> U {
483         match *self {
484             RWWriteMode {
485                 data: &ref mut data,
486                 token: ref token,
487                 poison: _
488             } => {
489                 token.write(|| blk(data))
490             }
491         }
492     }
493
494     /// Access the pre-downgrade RWArc in write mode with a condvar.
495     pub fn write_cond<U>(&mut self,
496                          blk: |x: &mut T, c: &ArcCondvar| -> U)
497                          -> U {
498         match *self {
499             RWWriteMode {
500                 data: &ref mut data,
501                 token: ref token,
502                 poison: ref poison
503             } => {
504                 token.write_cond(|cond| {
505                     unsafe {
506                         let cvar = ArcCondvar {
507                             is_mutex: false,
508                             failed: &*poison.flag,
509                             cond: cond
510                         };
511                         blk(data, &cvar)
512                     }
513                 })
514             }
515         }
516     }
517 }
518
519 impl<'a, T: Share + Send> RWReadMode<'a, T> {
520     /// Access the post-downgrade rwlock in read mode.
521     pub fn read<U>(&self, blk: |x: &T| -> U) -> U {
522         match *self {
523             RWReadMode {
524                 data: data,
525                 token: ref token
526             } => {
527                 token.read(|| blk(data))
528             }
529         }
530     }
531 }
532
533 /****************************************************************************
534  * Copy-on-write Arc
535  ****************************************************************************/
536
537 pub struct CowArc<T> { priv x: UnsafeArc<T> }
538
539 /// A Copy-on-write Arc functions the same way as an `arc` except it allows
540 /// mutation of the contents if there is only a single reference to
541 /// the data. If there are multiple references the data is automatically
542 /// cloned and the task modifies the cloned data in place of the shared data.
543 impl<T: Clone + Send + Share> CowArc<T> {
544     /// Create a copy-on-write atomically reference counted wrapper
545     #[inline]
546     pub fn new(data: T) -> CowArc<T> {
547         CowArc { x: UnsafeArc::new(data) }
548     }
549
550     #[inline]
551     pub fn get<'a>(&'a self) -> &'a T {
552         unsafe { &*self.x.get_immut() }
553     }
554
555     /// get a mutable reference to the contents. If there are more then one
556     /// reference to the contents of the `CowArc` will be cloned
557     /// and this reference updated to point to the cloned data.
558     #[inline]
559     pub fn get_mut<'a>(&'a mut self) -> &'a mut T {
560         if !self.x.is_owned() {
561             *self = CowArc::new(self.get().clone())
562         }
563         unsafe { &mut *self.x.get() }
564     }
565 }
566
567 impl<T: Clone + Send + Share> Clone for CowArc<T> {
568     /// Duplicate a Copy-on-write Arc. See arc::clone for more details.
569     fn clone(&self) -> CowArc<T> {
570         CowArc { x: self.x.clone() }
571     }
572 }
573
574
575
576 /****************************************************************************
577  * Tests
578  ****************************************************************************/
579
580 #[cfg(test)]
581 mod tests {
582
583     use super::{Arc, RWArc, MutexArc, CowArc};
584
585     use std::task;
586     use std::vec_ng::Vec;
587
588     #[test]
589     fn manually_share_arc() {
590         let v = vec!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
591         let arc_v = Arc::new(v);
592
593         let (tx, rx) = channel();
594
595         task::spawn(proc() {
596             let arc_v: Arc<Vec<int>> = rx.recv();
597
598             let v = arc_v.get().clone();
599             assert_eq!(*v.get(3), 4);
600         });
601
602         tx.send(arc_v.clone());
603
604         assert_eq!(*arc_v.get().get(2), 3);
605         assert_eq!(*arc_v.get().get(4), 5);
606
607         info!("{:?}", arc_v);
608     }
609
610     #[test]
611     fn test_mutex_arc_condvar() {
612         let arc = ~MutexArc::new(false);
613         let arc2 = ~arc.clone();
614         let (tx, rx) = channel();
615         task::spawn(proc() {
616             // wait until parent gets in
617             rx.recv();
618             arc2.access_cond(|state, cond| {
619                 *state = true;
620                 cond.signal();
621             })
622         });
623
624         arc.access_cond(|state, cond| {
625             tx.send(());
626             assert!(!*state);
627             while !*state {
628                 cond.wait();
629             }
630         })
631     }
632
633     #[test] #[should_fail]
634     fn test_arc_condvar_poison() {
635         let arc = ~MutexArc::new(1);
636         let arc2 = ~arc.clone();
637         let (tx, rx) = channel();
638
639         spawn(proc() {
640             let _ = rx.recv();
641             arc2.access_cond(|one, cond| {
642                 cond.signal();
643                 // Parent should fail when it wakes up.
644                 assert_eq!(*one, 0);
645             })
646         });
647
648         arc.access_cond(|one, cond| {
649             tx.send(());
650             while *one == 1 {
651                 cond.wait();
652             }
653         })
654     }
655
656     #[test] #[should_fail]
657     fn test_mutex_arc_poison() {
658         let arc = ~MutexArc::new(1);
659         let arc2 = ~arc.clone();
660         let _ = task::try(proc() {
661             arc2.access(|one| {
662                 assert_eq!(*one, 2);
663             })
664         });
665         arc.access(|one| {
666             assert_eq!(*one, 1);
667         })
668     }
669
670     #[test]
671     fn test_mutex_arc_nested() {
672         // Tests nested mutexes and access
673         // to underlaying data.
674         let arc = ~MutexArc::new(1);
675         let arc2 = ~MutexArc::new(*arc);
676         task::spawn(proc() {
677             (*arc2).access(|mutex| {
678                 (*mutex).access(|one| {
679                     assert!(*one == 1);
680                 })
681             })
682         });
683     }
684
685     #[test]
686     fn test_mutex_arc_access_in_unwind() {
687         let arc = MutexArc::new(1i);
688         let arc2 = arc.clone();
689         let _ = task::try::<()>(proc() {
690             struct Unwinder {
691                 i: MutexArc<int>
692             }
693             impl Drop for Unwinder {
694                 fn drop(&mut self) {
695                     self.i.access(|num| *num += 1);
696                 }
697             }
698             let _u = Unwinder { i: arc2 };
699             fail!();
700         });
701         assert_eq!(2, arc.access(|n| *n));
702     }
703
704     #[test] #[should_fail]
705     fn test_rw_arc_poison_wr() {
706         let arc = RWArc::new(1);
707         let arc2 = arc.clone();
708         let _ = task::try(proc() {
709             arc2.write(|one| {
710                 assert_eq!(*one, 2);
711             })
712         });
713         arc.read(|one| {
714             assert_eq!(*one, 1);
715         })
716     }
717
718     #[test] #[should_fail]
719     fn test_rw_arc_poison_ww() {
720         let arc = RWArc::new(1);
721         let arc2 = arc.clone();
722         let _ = task::try(proc() {
723             arc2.write(|one| {
724                 assert_eq!(*one, 2);
725             })
726         });
727         arc.write(|one| {
728             assert_eq!(*one, 1);
729         })
730     }
731     #[test] #[should_fail]
732     fn test_rw_arc_poison_dw() {
733         let arc = RWArc::new(1);
734         let arc2 = arc.clone();
735         let _ = task::try(proc() {
736             arc2.write_downgrade(|mut write_mode| {
737                 write_mode.write(|one| {
738                     assert_eq!(*one, 2);
739                 })
740             })
741         });
742         arc.write(|one| {
743             assert_eq!(*one, 1);
744         })
745     }
746     #[test]
747     fn test_rw_arc_no_poison_rr() {
748         let arc = RWArc::new(1);
749         let arc2 = arc.clone();
750         let _ = task::try(proc() {
751             arc2.read(|one| {
752                 assert_eq!(*one, 2);
753             })
754         });
755         arc.read(|one| {
756             assert_eq!(*one, 1);
757         })
758     }
759     #[test]
760     fn test_rw_arc_no_poison_rw() {
761         let arc = RWArc::new(1);
762         let arc2 = arc.clone();
763         let _ = task::try(proc() {
764             arc2.read(|one| {
765                 assert_eq!(*one, 2);
766             })
767         });
768         arc.write(|one| {
769             assert_eq!(*one, 1);
770         })
771     }
772     #[test]
773     fn test_rw_arc_no_poison_dr() {
774         let arc = RWArc::new(1);
775         let arc2 = arc.clone();
776         let _ = task::try(proc() {
777             arc2.write_downgrade(|write_mode| {
778                 let read_mode = arc2.downgrade(write_mode);
779                 read_mode.read(|one| {
780                     assert_eq!(*one, 2);
781                 })
782             })
783         });
784         arc.write(|one| {
785             assert_eq!(*one, 1);
786         })
787     }
788     #[test]
789     fn test_rw_arc() {
790         let arc = RWArc::new(0);
791         let arc2 = arc.clone();
792         let (tx, rx) = channel();
793
794         task::spawn(proc() {
795             arc2.write(|num| {
796                 for _ in range(0, 10) {
797                     let tmp = *num;
798                     *num = -1;
799                     task::deschedule();
800                     *num = tmp + 1;
801                 }
802                 tx.send(());
803             })
804         });
805
806         // Readers try to catch the writer in the act
807         let mut children = Vec::new();
808         for _ in range(0, 5) {
809             let arc3 = arc.clone();
810             let mut builder = task::task();
811             children.push(builder.future_result());
812             builder.spawn(proc() {
813                 arc3.read(|num| {
814                     assert!(*num >= 0);
815                 })
816             });
817         }
818
819         // Wait for children to pass their asserts
820         for r in children.mut_iter() {
821             let _ = r.recv();
822         }
823
824         // Wait for writer to finish
825         rx.recv();
826         arc.read(|num| {
827             assert_eq!(*num, 10);
828         })
829     }
830
831     #[test]
832     fn test_rw_arc_access_in_unwind() {
833         let arc = RWArc::new(1i);
834         let arc2 = arc.clone();
835         let _ = task::try::<()>(proc() {
836             struct Unwinder {
837                 i: RWArc<int>
838             }
839             impl Drop for Unwinder {
840                 fn drop(&mut self) {
841                     self.i.write(|num| *num += 1);
842                 }
843             }
844             let _u = Unwinder { i: arc2 };
845             fail!();
846         });
847         assert_eq!(2, arc.read(|n| *n));
848     }
849
850     #[test]
851     fn test_rw_downgrade() {
852         // (1) A downgrader gets in write mode and does cond.wait.
853         // (2) A writer gets in write mode, sets state to 42, and does signal.
854         // (3) Downgrader wakes, sets state to 31337.
855         // (4) tells writer and all other readers to contend as it downgrades.
856         // (5) Writer attempts to set state back to 42, while downgraded task
857         //     and all reader tasks assert that it's 31337.
858         let arc = RWArc::new(0);
859
860         // Reader tasks
861         let mut reader_convos = Vec::new();
862         for _ in range(0, 10) {
863             let ((tx1, rx1), (tx2, rx2)) = (channel(), channel());
864             reader_convos.push((tx1, rx2));
865             let arcn = arc.clone();
866             task::spawn(proc() {
867                 rx1.recv(); // wait for downgrader to give go-ahead
868                 arcn.read(|state| {
869                     assert_eq!(*state, 31337);
870                     tx2.send(());
871                 })
872             });
873         }
874
875         // Writer task
876         let arc2 = arc.clone();
877         let ((tx1, rx1), (tx2, rx2)) = (channel(), channel());
878         task::spawn(proc() {
879             rx1.recv();
880             arc2.write_cond(|state, cond| {
881                 assert_eq!(*state, 0);
882                 *state = 42;
883                 cond.signal();
884             });
885             rx1.recv();
886             arc2.write(|state| {
887                 // This shouldn't happen until after the downgrade read
888                 // section, and all other readers, finish.
889                 assert_eq!(*state, 31337);
890                 *state = 42;
891             });
892             tx2.send(());
893         });
894
895         // Downgrader (us)
896         arc.write_downgrade(|mut write_mode| {
897             write_mode.write_cond(|state, cond| {
898                 tx1.send(()); // send to another writer who will wake us up
899                 while *state == 0 {
900                     cond.wait();
901                 }
902                 assert_eq!(*state, 42);
903                 *state = 31337;
904                 // send to other readers
905                 for &(ref mut rc, _) in reader_convos.mut_iter() {
906                     rc.send(())
907                 }
908             });
909             let read_mode = arc.downgrade(write_mode);
910             read_mode.read(|state| {
911                 // complete handshake with other readers
912                 for &(_, ref mut rp) in reader_convos.mut_iter() {
913                     rp.recv()
914                 }
915                 tx1.send(()); // tell writer to try again
916                 assert_eq!(*state, 31337);
917             });
918         });
919
920         rx2.recv(); // complete handshake with writer
921     }
922     #[cfg(test)]
923     fn test_rw_write_cond_downgrade_read_race_helper() {
924         // Tests that when a downgrader hands off the "reader cloud" lock
925         // because of a contending reader, a writer can't race to get it
926         // instead, which would result in readers_and_writers. This tests
927         // the sync module rather than this one, but it's here because an
928         // rwarc gives us extra shared state to help check for the race.
929         // If you want to see this test fail, go to sync.rs and replace the
930         // line in RWLock::write_cond() that looks like:
931         //     "blk(&ArcCondvar { order: opt_lock, ..*cond })"
932         // with just "blk(cond)".
933         let x = RWArc::new(true);
934         let (tx, rx) = channel();
935
936         // writer task
937         let xw = x.clone();
938         task::spawn(proc() {
939             xw.write_cond(|state, c| {
940                 tx.send(()); // tell downgrader it's ok to go
941                 c.wait();
942                 // The core of the test is here: the condvar reacquire path
943                 // must involve order_lock, so that it cannot race with a reader
944                 // trying to receive the "reader cloud lock hand-off".
945                 *state = false;
946             })
947         });
948
949         rx.recv(); // wait for writer to get in
950
951         x.write_downgrade(|mut write_mode| {
952             write_mode.write_cond(|state, c| {
953                 assert!(*state);
954                 // make writer contend in the cond-reacquire path
955                 c.signal();
956             });
957             // make a reader task to trigger the "reader cloud lock" handoff
958             let xr = x.clone();
959             let (tx, rx) = channel();
960             task::spawn(proc() {
961                 tx.send(());
962                 xr.read(|_state| { })
963             });
964             rx.recv(); // wait for reader task to exist
965
966             let read_mode = x.downgrade(write_mode);
967             read_mode.read(|state| {
968                 // if writer mistakenly got in, make sure it mutates state
969                 // before we assert on it
970                 for _ in range(0, 5) { task::deschedule(); }
971                 // make sure writer didn't get in.
972                 assert!(*state);
973             })
974         });
975     }
976     #[test]
977     fn test_rw_write_cond_downgrade_read_race() {
978         // Ideally the above test case would have deschedule statements in it that
979         // helped to expose the race nearly 100% of the time... but adding
980         // deschedules in the intuitively-right locations made it even less likely,
981         // and I wasn't sure why :( . This is a mediocre "next best" option.
982         for _ in range(0, 8) { test_rw_write_cond_downgrade_read_race_helper(); }
983     }
984
985     #[test]
986     fn test_cowarc_clone()
987     {
988         let cow0 = CowArc::new(75u);
989         let cow1 = cow0.clone();
990         let cow2 = cow1.clone();
991
992         assert!(75 == *cow0.get());
993         assert!(75 == *cow1.get());
994         assert!(75 == *cow2.get());
995
996         assert!(cow0.get() == cow1.get());
997         assert!(cow0.get() == cow2.get());
998     }
999
1000     #[test]
1001     fn test_cowarc_clone_get_mut()
1002     {
1003         let mut cow0 = CowArc::new(75u);
1004         let mut cow1 = cow0.clone();
1005         let mut cow2 = cow1.clone();
1006
1007         assert!(75 == *cow0.get_mut());
1008         assert!(75 == *cow1.get_mut());
1009         assert!(75 == *cow2.get_mut());
1010
1011         *cow0.get_mut() += 1;
1012         *cow1.get_mut() += 2;
1013         *cow2.get_mut() += 3;
1014
1015         assert!(76 == *cow0.get());
1016         assert!(77 == *cow1.get());
1017         assert!(78 == *cow2.get());
1018
1019         // none should point to the same backing memory
1020         assert!(cow0.get() != cow1.get());
1021         assert!(cow0.get() != cow2.get());
1022         assert!(cow1.get() != cow2.get());
1023     }
1024
1025     #[test]
1026     fn test_cowarc_clone_get_mut2()
1027     {
1028         let mut cow0 = CowArc::new(75u);
1029         let cow1 = cow0.clone();
1030         let cow2 = cow1.clone();
1031
1032         assert!(75 == *cow0.get());
1033         assert!(75 == *cow1.get());
1034         assert!(75 == *cow2.get());
1035
1036         *cow0.get_mut() += 1;
1037
1038         assert!(76 == *cow0.get());
1039         assert!(75 == *cow1.get());
1040         assert!(75 == *cow2.get());
1041
1042         // cow1 and cow2 should share the same contents
1043         // cow0 should have a unique reference
1044         assert!(cow0.get() != cow1.get());
1045         assert!(cow0.get() != cow2.get());
1046         assert!(cow1.get() == cow2.get());
1047     }
1048 }