@@ -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
@@ -190,6 +192,35 @@ impl<T:Send> MutexArc<T> {
190
192
MutexArc { x : UnsafeArc :: new ( data) }
191
193
}
192
194
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
+ }
193
224
/**
194
225
* Access the underlying mutable data with mutual exclusion from other
195
226
* tasks. The argument closure will be run with the mutex locked; all
@@ -215,31 +246,16 @@ impl<T:Send> MutexArc<T> {
215
246
*/
216
247
#[ inline]
217
248
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)
226
250
}
227
251
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().
229
253
#[ inline]
230
254
pub unsafe fn unsafe_access_cond < ' x , ' c , U > ( & self ,
231
255
blk : & fn ( x : & ' x mut T ,
232
256
c : & ' c Condvar ) -> U )
233
257
-> 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)
243
259
}
244
260
245
261
/**
@@ -259,6 +275,34 @@ impl<T:Send> MutexArc<T> {
259
275
}
260
276
}
261
277
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
+
262
306
// Common code for {mutex.access,rwlock.write}{,_cond}.
263
307
#[inline]
264
308
#[doc(hidden)]
@@ -589,6 +633,100 @@ mod tests {
589
633
590
634
#[test]
591
635
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() {
592
730
unsafe {
593
731
let arc = MutexArc::new(false);
594
732
let arc2 = arc.clone();
@@ -613,7 +751,7 @@ mod tests {
613
751
}
614
752
615
753
#[test] #[should_fail]
616
- fn test_arc_condvar_poison () {
754
+ fn test_unsafe_arc_condvar_poison () {
617
755
unsafe {
618
756
let arc = MutexArc::new(1);
619
757
let arc2 = arc.clone();
@@ -637,7 +775,7 @@ mod tests {
637
775
}
638
776
}
639
777
#[test] #[should_fail]
640
- fn test_mutex_arc_poison () {
778
+ fn test_unsafe_mutex_arc_poison () {
641
779
unsafe {
642
780
let arc = MutexArc::new(1);
643
781
let arc2 = arc.clone();
@@ -651,8 +789,9 @@ mod tests {
651
789
}
652
790
}
653
791
}
792
+
654
793
#[test] #[should_fail]
655
- pub fn test_mutex_arc_unwrap_poison () {
794
+ pub fn test_unsafe_mutex_arc_unwrap_poison () {
656
795
let arc = MutexArc::new(1);
657
796
let arc2 = arc.clone();
658
797
let (p, c) = comm::stream();
@@ -668,6 +807,7 @@ mod tests {
668
807
let one = arc.unwrap();
669
808
assert!(one == 1);
670
809
}
810
+
671
811
#[test] #[should_fail]
672
812
fn test_rw_arc_poison_wr() {
673
813
let arc = RWArc::new(1);
@@ -681,6 +821,7 @@ mod tests {
681
821
assert_eq!(*one, 1);
682
822
}
683
823
}
824
+
684
825
#[test] #[should_fail]
685
826
fn test_rw_arc_poison_ww() {
686
827
let arc = RWArc::new(1);
0 commit comments