@@ -159,7 +159,9 @@ impl<T:Freeze + Send> Clone for Arc<T> {
159159
160160#[ doc( hidden) ]
161161struct MutexArcInner < T > { priv lock : Mutex , priv failed : bool , priv data : T }
162+
162163/// An Arc with mutable data protected by a blocking mutex.
164+ #[ no_freeze]
163165struct MutexArc < T > { priv x: UnsafeArc < MutexArcInner < T > > }
164166
165167
@@ -199,10 +201,10 @@ impl<T:Send> MutexArc<T> {
199201 * The reason this function is 'unsafe' is because it is possible to
200202 * construct a circular reference among multiple Arcs by mutating the
201203 * 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
203205 * inside of other Arcs is safe in absence of circular references.
204206 *
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
206208 * runtime is to add a "nesting level counter" inside the stored data, and
207209 * when traversing the arcs, assert that they monotonically decrease.
208210 *
@@ -214,7 +216,7 @@ impl<T:Send> MutexArc<T> {
214216 * blocked on the mutex) will also fail immediately.
215217 */
216218 #[ 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 {
218220 let state = self . x . get ( ) ;
219221 // Borrowck would complain about this if the function were
220222 // not already unsafe. See borrow_rwlock, far below.
@@ -225,9 +227,9 @@ impl<T:Send> MutexArc<T> {
225227 }
226228 }
227229
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().
229231 #[ inline]
230- pub unsafe fn access_cond < ' x , ' c , U > ( & self ,
232+ pub unsafe fn unsafe_access_cond < ' x , ' c , U > ( & self ,
231233 blk : & fn ( x : & ' x mut T ,
232234 c : & ' c Condvar ) -> U )
233235 -> U {
@@ -259,6 +261,39 @@ impl<T:Send> MutexArc<T> {
259261 }
260262}
261263
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+
262297// Common code for {mutex.access,rwlock.write}{,_cond}.
263298#[inline]
264299#[doc(hidden)]
@@ -589,85 +624,98 @@ mod tests {
589624
590625 #[test]
591626 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();
604637 }
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();
611645 }
612646 }
613647 }
614648
615649 #[test] #[should_fail]
616650 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);
629661 }
662+ }
630663
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();
636668 }
637669 }
638670 }
671+
639672 #[test] #[should_fail]
640673 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);
651679 }
680+ };
681+ do arc.access |one| {
682+ assert_eq!(*one, 1);
652683 }
653684 }
685+
654686 #[test] #[should_fail]
655687 pub fn test_mutex_arc_unwrap_poison() {
656688 let arc = MutexArc::new(1);
657- let arc2 = arc.clone();
689+ let arc2 = ~(& arc) .clone();
658690 let (p, c) = comm::stream();
659691 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);
665695 }
666696 }
667697 let _ = p.recv();
668698 let one = arc.unwrap();
669699 assert!(one == 1);
670700 }
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+
671719 #[test] #[should_fail]
672720 fn test_rw_arc_poison_wr() {
673721 let arc = RWArc::new(1);
@@ -681,6 +729,7 @@ mod tests {
681729 assert_eq!(*one, 1);
682730 }
683731 }
732+
684733 #[test] #[should_fail]
685734 fn test_rw_arc_poison_ww() {
686735 let arc = RWArc::new(1);
0 commit comments