19
19
//! CriticalSection is used and we keep track of who's holding the mutex to
20
20
//! detect recursive locks.
21
21
22
- use crate :: cell:: UnsafeCell ;
22
+ use crate :: cell:: { Cell , UnsafeCell } ;
23
23
use crate :: mem:: { self , MaybeUninit } ;
24
24
use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
25
25
use crate :: sys:: c;
26
26
use crate :: sys:: compat;
27
27
28
28
pub struct Mutex {
29
+ // This is either directly an SRWLOCK (if supported), or a Box<Inner> otherwise.
29
30
lock : AtomicUsize ,
30
- held : UnsafeCell < bool > ,
31
31
}
32
32
33
33
unsafe impl Send for Mutex { }
34
34
unsafe impl Sync for Mutex { }
35
35
36
+ struct Inner {
37
+ remutex : ReentrantMutex ,
38
+ held : Cell < bool > ,
39
+ }
40
+
36
41
#[ derive( Clone , Copy ) ]
37
42
enum Kind {
38
43
SRWLock = 1 ,
@@ -51,7 +56,6 @@ impl Mutex {
51
56
// This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly
52
57
// initializing an SRWLOCK here.
53
58
lock : AtomicUsize :: new ( 0 ) ,
54
- held : UnsafeCell :: new ( false ) ,
55
59
}
56
60
}
57
61
#[ inline]
@@ -60,10 +64,11 @@ impl Mutex {
60
64
match kind ( ) {
61
65
Kind :: SRWLock => c:: AcquireSRWLockExclusive ( raw ( self ) ) ,
62
66
Kind :: CriticalSection => {
63
- let re = self . remutex ( ) ;
64
- ( * re) . lock ( ) ;
65
- if !self . flag_locked ( ) {
66
- ( * re) . unlock ( ) ;
67
+ let inner = & mut * self . inner ( ) ;
68
+ inner. remutex . lock ( ) ;
69
+ if inner. held . replace ( true ) {
70
+ // It was already locked, so we got a recursive lock which we do not want.
71
+ inner. remutex . unlock ( ) ;
67
72
panic ! ( "cannot recursively lock a mutex" ) ;
68
73
}
69
74
}
@@ -73,23 +78,27 @@ impl Mutex {
73
78
match kind ( ) {
74
79
Kind :: SRWLock => c:: TryAcquireSRWLockExclusive ( raw ( self ) ) != 0 ,
75
80
Kind :: CriticalSection => {
76
- let re = self . remutex ( ) ;
77
- if !( * re ) . try_lock ( ) {
81
+ let inner = & mut * self . inner ( ) ;
82
+ if !inner . remutex . try_lock ( ) {
78
83
false
79
- } else if self . flag_locked ( ) {
80
- true
81
- } else {
82
- ( * re) . unlock ( ) ;
84
+ } else if inner. held . replace ( true ) {
85
+ // It was already locked, so we got a recursive lock which we do not want.
86
+ inner. remutex . unlock ( ) ;
83
87
false
88
+ } else {
89
+ true
84
90
}
85
91
}
86
92
}
87
93
}
88
94
pub unsafe fn unlock ( & self ) {
89
- * self . held . get ( ) = false ;
90
95
match kind ( ) {
91
96
Kind :: SRWLock => c:: ReleaseSRWLockExclusive ( raw ( self ) ) ,
92
- Kind :: CriticalSection => ( * self . remutex ( ) ) . unlock ( ) ,
97
+ Kind :: CriticalSection => {
98
+ let inner = & mut * ( self . lock . load ( Ordering :: SeqCst ) as * mut Inner ) ;
99
+ inner. held . set ( false ) ;
100
+ inner. remutex . unlock ( ) ;
101
+ }
93
102
}
94
103
}
95
104
pub unsafe fn destroy ( & self ) {
@@ -98,37 +107,28 @@ impl Mutex {
98
107
Kind :: CriticalSection => match self . lock . load ( Ordering :: SeqCst ) {
99
108
0 => { }
100
109
n => {
101
- Box :: from_raw ( n as * mut ReentrantMutex ) . destroy ( ) ;
110
+ Box :: from_raw ( n as * mut Inner ) . remutex . destroy ( ) ;
102
111
}
103
112
} ,
104
113
}
105
114
}
106
115
107
- unsafe fn remutex ( & self ) -> * mut ReentrantMutex {
116
+ unsafe fn inner ( & self ) -> * mut Inner {
108
117
match self . lock . load ( Ordering :: SeqCst ) {
109
118
0 => { }
110
119
n => return n as * mut _ ,
111
120
}
112
- let re = box ReentrantMutex :: uninitialized ( ) ;
113
- re . init ( ) ;
114
- let re = Box :: into_raw ( re ) ;
115
- match self . lock . compare_and_swap ( 0 , re as usize , Ordering :: SeqCst ) {
116
- 0 => re ,
121
+ let inner = box Inner { remutex : ReentrantMutex :: uninitialized ( ) , held : Cell :: new ( false ) } ;
122
+ inner . remutex . init ( ) ;
123
+ let inner = Box :: into_raw ( inner ) ;
124
+ match self . lock . compare_and_swap ( 0 , inner as usize , Ordering :: SeqCst ) {
125
+ 0 => inner ,
117
126
n => {
118
- Box :: from_raw ( re ) . destroy ( ) ;
127
+ Box :: from_raw ( inner ) . remutex . destroy ( ) ;
119
128
n as * mut _
120
129
}
121
130
}
122
131
}
123
-
124
- unsafe fn flag_locked ( & self ) -> bool {
125
- if * self . held . get ( ) {
126
- false
127
- } else {
128
- * self . held . get ( ) = true ;
129
- true
130
- }
131
- }
132
132
}
133
133
134
134
fn kind ( ) -> Kind {
0 commit comments