@@ -159,7 +159,9 @@ impl<T:Freeze + Send> Clone for Arc<T> {
159
159
160
160
#[ doc( hidden) ]
161
161
struct MutexArcInner < T > { priv lock : Mutex , priv failed : bool , priv data : T }
162
+
162
163
/// An Arc with mutable data protected by a blocking mutex.
164
+ #[ no_freeze]
163
165
struct MutexArc < T > { priv x: UnsafeArc < MutexArcInner < T > > }
164
166
165
167
@@ -199,10 +201,10 @@ impl<T:Send> MutexArc<T> {
199
201
* The reason this function is 'unsafe' is because it is possible to
200
202
* construct a circular reference among multiple Arcs by mutating the
201
203
* underlying data. This creates potential for deadlock, but worse, this
202
- * will guarantee a memory leak of all involved Arcs. Using mutex Arcs
204
+ * will guarantee a memory leak of all involved Arcs. Using MutexArcs
203
205
* inside of other Arcs is safe in absence of circular references.
204
206
*
205
- * If you wish to nest mutex_arcs , one strategy for ensuring safety at
207
+ * If you wish to nest MutexArcs , one strategy for ensuring safety at
206
208
* runtime is to add a "nesting level counter" inside the stored data, and
207
209
* when traversing the arcs, assert that they monotonically decrease.
208
210
*
@@ -214,7 +216,7 @@ impl<T:Send> MutexArc<T> {
214
216
* blocked on the mutex) will also fail immediately.
215
217
*/
216
218
#[ inline]
217
- pub unsafe fn access < U > ( & self , blk : & fn ( x : & mut T ) -> U ) -> U {
219
+ pub unsafe fn unsafe_access < U > ( & self , blk : & fn ( x : & mut T ) -> U ) -> U {
218
220
let state = self . x . get ( ) ;
219
221
// Borrowck would complain about this if the function were
220
222
// not already unsafe. See borrow_rwlock, far below.
@@ -225,9 +227,9 @@ impl<T:Send> MutexArc<T> {
225
227
}
226
228
}
227
229
228
- /// As access (), but with a condvar, as sync::mutex.lock_cond().
230
+ /// As unsafe_access (), but with a condvar, as sync::mutex.lock_cond().
229
231
#[ inline]
230
- pub unsafe fn access_cond < ' x , ' c , U > ( & self ,
232
+ pub unsafe fn unsafe_access_cond < ' x , ' c , U > ( & self ,
231
233
blk : & fn ( x : & ' x mut T ,
232
234
c : & ' c Condvar ) -> U )
233
235
-> U {
@@ -259,6 +261,39 @@ impl<T:Send> MutexArc<T> {
259
261
}
260
262
}
261
263
264
+ impl<T:Freeze + Send> MutexArc<T> {
265
+
266
+ /**
267
+ * As unsafe_access.
268
+ *
269
+ * The difference between access and unsafe_access is that the former
270
+ * forbids mutexes to be nested. While unsafe_access can be used on
271
+ * MutexArcs without freezable interiors, this safe version of access
272
+ * requires the Freeze bound, which prohibits access on MutexArcs which
273
+ * might contain nested MutexArcs inside.
274
+ *
275
+ * The purpose of this is to offer a safe implementation of MutexArc to be
276
+ * used instead of RWArc in cases where no readers are needed and sightly
277
+ * better performance is required.
278
+ *
279
+ * Both methods have the same failure behaviour as unsafe_access and
280
+ * unsafe_access_cond.
281
+ */
282
+ #[inline]
283
+ pub fn access<U>(&self, blk: &fn(x: &mut T) -> U) -> U {
284
+ unsafe { self.unsafe_access(blk) }
285
+ }
286
+
287
+ /// As unsafe_access_cond but safe and Freeze.
288
+ #[inline]
289
+ pub fn access_cond<'x, 'c, U>(&self,
290
+ blk: &fn(x: &'x mut T,
291
+ c: &'c Condvar) -> U)
292
+ -> U {
293
+ unsafe { self.unsafe_access_cond(blk) }
294
+ }
295
+ }
296
+
262
297
// Common code for {mutex.access,rwlock.write}{,_cond}.
263
298
#[inline]
264
299
#[doc(hidden)]
@@ -589,85 +624,98 @@ mod tests {
589
624
590
625
#[test]
591
626
fn test_mutex_arc_condvar() {
592
- unsafe {
593
- let arc = MutexArc::new(false);
594
- let arc2 = arc.clone();
595
- let (p, c) = comm::oneshot();
596
- let (c, p) = (Cell::new(c), Cell::new(p));
597
- do task::spawn {
598
- // wait until parent gets in
599
- p.take().recv();
600
- do arc2.access_cond |state, cond| {
601
- *state = true;
602
- cond.signal();
603
- }
627
+ let arc = ~MutexArc::new(false);
628
+ let arc2 = ~arc.clone();
629
+ let (p,c) = comm::oneshot();
630
+ let (c,p) = (Cell::new(c), Cell::new(p));
631
+ do task::spawn || {
632
+ // wait until parent gets in
633
+ p.take().recv();
634
+ do arc2.access_cond |state, cond| {
635
+ *state = true;
636
+ cond.signal();
604
637
}
605
- do arc.access_cond |state, cond| {
606
- c.take().send(());
607
- assert!(!*state);
608
- while !*state {
609
- cond.wait();
610
- }
638
+ }
639
+
640
+ do arc.access_cond |state, cond| {
641
+ c.take().send(());
642
+ assert!(!*state);
643
+ while !*state {
644
+ cond.wait();
611
645
}
612
646
}
613
647
}
614
648
615
649
#[test] #[should_fail]
616
650
fn test_arc_condvar_poison() {
617
- unsafe {
618
- let arc = MutexArc::new(1);
619
- let arc2 = arc.clone();
620
- let (p, c) = comm::stream();
621
-
622
- do task::spawn_unlinked {
623
- let _ = p.recv();
624
- do arc2.access_cond |one, cond| {
625
- cond.signal();
626
- // Parent should fail when it wakes up.
627
- assert_eq!(*one, 0);
628
- }
651
+ let arc = ~MutexArc::new(1);
652
+ let arc2 = ~arc.clone();
653
+ let (p, c) = comm::stream();
654
+
655
+ do task::spawn_unlinked || {
656
+ let _ = p.recv();
657
+ do arc2.access_cond |one, cond| {
658
+ cond.signal();
659
+ // Parent should fail when it wakes up.
660
+ assert_eq!(*one, 0);
629
661
}
662
+ }
630
663
631
- do arc.access_cond |one, cond| {
632
- c.send(());
633
- while *one == 1 {
634
- cond.wait();
635
- }
664
+ do arc.access_cond |one, cond| {
665
+ c.send(());
666
+ while *one == 1 {
667
+ cond.wait();
636
668
}
637
669
}
638
670
}
671
+
639
672
#[test] #[should_fail]
640
673
fn test_mutex_arc_poison() {
641
- unsafe {
642
- let arc = MutexArc::new(1);
643
- let arc2 = arc.clone();
644
- do task::try {
645
- do arc2.access |one| {
646
- assert_eq!(*one, 2);
647
- }
648
- };
649
- do arc.access |one| {
650
- assert_eq!(*one, 1);
674
+ let arc = ~MutexArc::new(1);
675
+ let arc2 = ~arc.clone();
676
+ do task::try || {
677
+ do arc2.access |one| {
678
+ assert_eq!(*one, 2);
651
679
}
680
+ };
681
+ do arc.access |one| {
682
+ assert_eq!(*one, 1);
652
683
}
653
684
}
685
+
654
686
#[test] #[should_fail]
655
687
pub fn test_mutex_arc_unwrap_poison() {
656
688
let arc = MutexArc::new(1);
657
- let arc2 = arc.clone();
689
+ let arc2 = ~(& arc) .clone();
658
690
let (p, c) = comm::stream();
659
691
do task::spawn {
660
- unsafe {
661
- do arc2.access |one| {
662
- c.send(());
663
- assert!(*one == 2);
664
- }
692
+ do arc2.access |one| {
693
+ c.send(());
694
+ assert!(*one == 2);
665
695
}
666
696
}
667
697
let _ = p.recv();
668
698
let one = arc.unwrap();
669
699
assert!(one == 1);
670
700
}
701
+
702
+ #[test]
703
+ fn test_unsafe_mutex_arc_nested() {
704
+ unsafe {
705
+ // Tests nested mutexes and access
706
+ // to underlaying data.
707
+ let arc = ~MutexArc::new(1);
708
+ let arc2 = ~MutexArc::new(*arc);
709
+ do task::spawn || {
710
+ do (*arc2).unsafe_access |mutex| {
711
+ do (*mutex).access |one| {
712
+ assert!(*one == 1);
713
+ }
714
+ }
715
+ };
716
+ }
717
+ }
718
+
671
719
#[test] #[should_fail]
672
720
fn test_rw_arc_poison_wr() {
673
721
let arc = RWArc::new(1);
@@ -681,6 +729,7 @@ mod tests {
681
729
assert_eq!(*one, 1);
682
730
}
683
731
}
732
+
684
733
#[test] #[should_fail]
685
734
fn test_rw_arc_poison_ww() {
686
735
let arc = RWArc::new(1);
0 commit comments