@@ -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
@@ -190,6 +192,35 @@ impl<T:Send> MutexArc<T> {
190192 MutexArc { x : UnsafeArc :: new ( data) }
191193 }
192194
195+
196+ /// Refer unsafe_access and access methods for the documentaiton.
197+ #[ inline]
198+ unsafe fn lock_and_access < U > ( & self , blk : & fn ( x : & mut T ) -> U ) -> U {
199+ let state = self . x . get ( ) ;
200+ // Borrowck would complain about this if the function were
201+ // not already unsafe. See borrow_rwlock, far below.
202+ do ( & ( * state) . lock ) . lock {
203+ check_poison ( true , ( * state) . failed ) ;
204+ let _z = PoisonOnFail ( & mut ( * state) . failed ) ;
205+ blk ( & mut ( * state) . data )
206+ }
207+ }
208+
209+ #[ inline]
210+ unsafe fn lock_and_access_cond < ' x , ' c , U > ( & self ,
211+ blk : & fn ( x : & ' x mut T ,
212+ c : & ' c Condvar ) -> U )
213+ -> U {
214+ let state = self . x . get ( ) ;
215+ do ( & ( * state) . lock ) . lock_cond |cond| {
216+ check_poison ( true , ( * state) . failed ) ;
217+ let _z = PoisonOnFail ( & mut ( * state) . failed ) ;
218+ blk ( & mut ( * state) . data ,
219+ & Condvar { is_mutex : true ,
220+ failed : & mut ( * state) . failed ,
221+ cond : cond } )
222+ }
223+ }
193224 /**
194225 * Access the underlying mutable data with mutual exclusion from other
195226 * tasks. The argument closure will be run with the mutex locked; all
@@ -215,31 +246,16 @@ impl<T:Send> MutexArc<T> {
215246 */
216247 #[ inline]
217248 pub unsafe fn unsafe_access < U > ( & self , blk : & fn ( x : & mut T ) -> U ) -> U {
218- let state = self . x . get ( ) ;
219- // Borrowck would complain about this if the function were
220- // not already unsafe. See borrow_rwlock, far below.
221- do ( & ( * state) . lock ) . lock {
222- check_poison ( true , ( * state) . failed ) ;
223- let _z = PoisonOnFail ( & mut ( * state) . failed ) ;
224- blk ( & mut ( * state) . data )
225- }
249+ self . lock_and_access ( blk)
226250 }
227251
228- /// As access (), but with a condvar, as sync::mutex.lock_cond().
252+ /// As unsafe_access (), but with a condvar, as sync::mutex.lock_cond().
229253 #[ inline]
230254 pub unsafe fn unsafe_access_cond < ' x , ' c , U > ( & self ,
231255 blk : & fn ( x : & ' x mut T ,
232256 c : & ' c Condvar ) -> U )
233257 -> U {
234- let state = self . x . get ( ) ;
235- do ( & ( * state) . lock ) . lock_cond |cond| {
236- check_poison ( true , ( * state) . failed ) ;
237- let _z = PoisonOnFail ( & mut ( * state) . failed ) ;
238- blk ( & mut ( * state) . data ,
239- & Condvar { is_mutex : true ,
240- failed : & mut ( * state) . failed ,
241- cond : cond } )
242- }
258+ self . lock_and_access_cond ( blk)
243259 }
244260
245261 /**
@@ -259,6 +275,34 @@ impl<T:Send> MutexArc<T> {
259275 }
260276}
261277
278+ impl<T:Freeze + Send> MutexArc<T> {
279+
280+ /**
281+ * As unsafe_access.
282+ *
283+ * The difference between access and unsafe_access is that the former
284+ * forbids mutexes to be nested. The purpose of this is to offer a safe
285+ * implementation of both methods access and access_cond to be used instead
286+ * of rwlock in cases where no readers are needed and sightly better performance
287+ * is required.
288+ *
289+ * Both methods have the same failure behaviour as unsafe_access and
290+ * unsafe_access_cond.
291+ */
292+ #[inline]
293+ pub fn access<U>(&self, blk: &fn(x: &mut T) -> U) -> U {
294+ unsafe { self.lock_and_access(blk) }
295+ }
296+
297+ #[inline]
298+ pub fn access_cond<'x, 'c, U>(&self,
299+ blk: &fn(x: &'x mut T,
300+ c: &'c Condvar) -> U)
301+ -> U {
302+ unsafe { self.lock_and_access_cond(blk) }
303+ }
304+ }
305+
262306// Common code for {mutex.access,rwlock.write}{,_cond}.
263307#[inline]
264308#[doc(hidden)]
@@ -589,6 +633,100 @@ mod tests {
589633
590634 #[test]
591635 fn test_mutex_arc_condvar() {
636+ let arc = ~MutexArc::new(false);
637+ let arc2 = ~arc.clone();
638+ let (p,c) = comm::oneshot();
639+ let (c,p) = (Cell::new(c), Cell::new(p));
640+ do task::spawn || {
641+ // wait until parent gets in
642+ p.take().recv();
643+ do arc2.access_cond |state, cond| {
644+ *state = true;
645+ cond.signal();
646+ }
647+ }
648+
649+ do arc.access_cond |state, cond| {
650+ c.take().send(());
651+ assert!(!*state);
652+ while !*state {
653+ cond.wait();
654+ }
655+ }
656+ }
657+
658+ #[test] #[should_fail]
659+ fn test_arc_condvar_poison() {
660+ let arc = ~MutexArc::new(1);
661+ let arc2 = ~arc.clone();
662+ let (p, c) = comm::stream();
663+
664+ do task::spawn_unlinked || {
665+ let _ = p.recv();
666+ do arc2.access_cond |one, cond| {
667+ cond.signal();
668+ // Parent should fail when it wakes up.
669+ assert_eq!(*one, 0);
670+ }
671+ }
672+
673+ do arc.access_cond |one, cond| {
674+ c.send(());
675+ while *one == 1 {
676+ cond.wait();
677+ }
678+ }
679+ }
680+
681+ #[test] #[should_fail]
682+ fn test_mutex_arc_poison() {
683+ let arc = ~MutexArc::new(1);
684+ let arc2 = ~arc.clone();
685+ do task::try || {
686+ do arc2.access |one| {
687+ assert_eq!(*one, 2);
688+ }
689+ };
690+ do arc.access |one| {
691+ assert_eq!(*one, 1);
692+ }
693+ }
694+
695+ #[test] #[should_fail]
696+ pub fn test_mutex_arc_unwrap_poison() {
697+ let arc = MutexArc::new(1);
698+ let arc2 = ~(&arc).clone();
699+ let (p, c) = comm::stream();
700+ do task::spawn {
701+ do arc2.access |one| {
702+ c.send(());
703+ assert!(*one == 2);
704+ }
705+ }
706+ let _ = p.recv();
707+ let one = arc.unwrap();
708+ assert!(one == 1);
709+ }
710+
711+ #[test]
712+ fn test_unsafe_mutex_arc_nested() {
713+ unsafe {
714+ // Tests nested mutexes and access
715+ // to underlaying data.
716+ let arc = ~MutexArc::new(1);
717+ let arc2 = ~MutexArc::new(*arc);
718+ do task::spawn || {
719+ do (*arc2).unsafe_access |mutex| {
720+ do (*mutex).access |one| {
721+ assert!(*one == 1);
722+ }
723+ }
724+ };
725+ }
726+ }
727+
728+ #[test]
729+ fn test_unsafe_mutex_arc_condvar() {
592730 unsafe {
593731 let arc = MutexArc::new(false);
594732 let arc2 = arc.clone();
@@ -613,7 +751,7 @@ mod tests {
613751 }
614752
615753 #[test] #[should_fail]
616- fn test_arc_condvar_poison () {
754+ fn test_unsafe_arc_condvar_poison () {
617755 unsafe {
618756 let arc = MutexArc::new(1);
619757 let arc2 = arc.clone();
@@ -637,7 +775,7 @@ mod tests {
637775 }
638776 }
639777 #[test] #[should_fail]
640- fn test_mutex_arc_poison () {
778+ fn test_unsafe_mutex_arc_poison () {
641779 unsafe {
642780 let arc = MutexArc::new(1);
643781 let arc2 = arc.clone();
@@ -651,8 +789,9 @@ mod tests {
651789 }
652790 }
653791 }
792+
654793 #[test] #[should_fail]
655- pub fn test_mutex_arc_unwrap_poison () {
794+ pub fn test_unsafe_mutex_arc_unwrap_poison () {
656795 let arc = MutexArc::new(1);
657796 let arc2 = arc.clone();
658797 let (p, c) = comm::stream();
@@ -668,6 +807,7 @@ mod tests {
668807 let one = arc.unwrap();
669808 assert!(one == 1);
670809 }
810+
671811 #[test] #[should_fail]
672812 fn test_rw_arc_poison_wr() {
673813 let arc = RWArc::new(1);
@@ -681,6 +821,7 @@ mod tests {
681821 assert_eq!(*one, 1);
682822 }
683823 }
824+
684825 #[test] #[should_fail]
685826 fn test_rw_arc_poison_ww() {
686827 let arc = RWArc::new(1);
0 commit comments