3
3
4
4
using System . Diagnostics ;
5
5
using System . Diagnostics . Tracing ;
6
+ using System . Runtime ;
6
7
using System . Runtime . CompilerServices ;
7
8
8
9
namespace System . Threading
9
10
{
10
11
public sealed partial class Lock
11
12
{
12
- private const short SpinCountNotInitialized = short . MinValue ;
13
-
14
13
// NOTE: Lock must not have a static (class) constructor, as Lock itself is used to synchronize
15
14
// class construction. If Lock has its own class constructor, this can lead to infinite recursion.
16
15
// All static data in Lock must be lazy-initialized.
17
16
private static int s_staticsInitializationStage ;
18
- private static bool s_isSingleProcessor ;
17
+ private static int s_processorCount ;
19
18
private static short s_maxSpinCount ;
20
19
private static short s_minSpinCount ;
21
20
22
- /// <summary>
23
- /// Initializes a new instance of the <see cref="Lock"/> class.
24
- /// </summary>
25
- public Lock ( ) => _spinCount = SpinCountNotInitialized ;
26
-
27
21
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
28
22
internal bool TryEnterOneShot ( int currentManagedThreadId )
29
23
{
30
24
Debug . Assert ( currentManagedThreadId != 0 ) ;
31
25
32
- if ( State . TryLock ( this ) )
26
+ if ( this . TryLock ( ) )
33
27
{
34
28
Debug . Assert ( _owningThreadId == 0 ) ;
35
29
Debug . Assert ( _recursionCount == 0 ) ;
@@ -54,20 +48,20 @@ internal void Exit(int currentManagedThreadId)
54
48
}
55
49
56
50
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
57
- private ThreadId TryEnterSlow ( int timeoutMs , ThreadId currentThreadId ) =>
51
+ private bool TryEnterSlow ( int timeoutMs , ThreadId currentThreadId ) =>
58
52
TryEnterSlow ( timeoutMs , currentThreadId , this ) ;
59
53
60
54
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
61
55
internal bool TryEnterSlow ( int timeoutMs , int currentManagedThreadId , object associatedObject ) =>
62
- TryEnterSlow ( timeoutMs , new ThreadId ( ( uint ) currentManagedThreadId ) , associatedObject ) . IsInitialized ;
56
+ TryEnterSlow ( timeoutMs , new ThreadId ( ( uint ) currentManagedThreadId ) , associatedObject ) ;
63
57
64
58
[ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
65
59
internal bool GetIsHeldByCurrentThread ( int currentManagedThreadId )
66
60
{
67
61
Debug . Assert ( currentManagedThreadId != 0 ) ;
68
62
69
63
bool isHeld = _owningThreadId == ( uint ) currentManagedThreadId ;
70
- Debug . Assert ( ! isHeld || new State ( this ) . IsLocked ) ;
64
+ Debug . Assert ( ! isHeld || this . IsLocked ) ;
71
65
return isHeld ;
72
66
}
73
67
@@ -76,14 +70,9 @@ internal uint ExitAll()
76
70
Debug . Assert ( IsHeldByCurrentThread ) ;
77
71
78
72
uint recursionCount = _recursionCount ;
79
- _owningThreadId = 0 ;
80
73
_recursionCount = 0 ;
81
74
82
- State state = State . Unlock ( this ) ;
83
- if ( state . HasAnyWaiters )
84
- {
85
- SignalWaiterIfNecessary ( state ) ;
86
- }
75
+ ReleaseCore ( ) ;
87
76
88
77
return recursionCount ;
89
78
}
@@ -96,108 +85,65 @@ internal void Reenter(uint previousRecursionCount)
96
85
_recursionCount = previousRecursionCount ;
97
86
}
98
87
99
- [ MethodImpl ( MethodImplOptions . AggressiveInlining ) ]
100
- private TryLockResult LazyInitializeOrEnter ( )
88
+ // Returns false until the static variable is lazy-initialized
89
+ internal static bool IsSingleProcessor => s_processorCount == 1 ;
90
+
91
+ internal static void LazyInit ( )
101
92
{
102
- StaticsInitializationStage stage = ( StaticsInitializationStage ) Volatile . Read ( ref s_staticsInitializationStage ) ;
103
- switch ( stage )
93
+ s_maxSpinCount = DefaultMaxSpinCount ;
94
+ s_minSpinCount = DefaultMinSpinCount ;
95
+ s_processorCount = RuntimeImports . RhGetProcessCpuCount ( ) ;
96
+
97
+ // the rest is optional, but let's try once
98
+ if ( s_staticsInitializationStage != ( int ) StaticsInitializationStage . Complete )
104
99
{
105
- case StaticsInitializationStage . Complete :
106
- if ( _spinCount == SpinCountNotInitialized )
107
- {
108
- _spinCount = s_maxSpinCount ;
109
- }
110
- return TryLockResult . Spin ;
111
-
112
- case StaticsInitializationStage . Started :
113
- // Spin-wait until initialization is complete or the lock is acquired to prevent class construction cycles
114
- // later during a full wait
115
- bool sleep = true ;
116
- while ( true )
117
- {
118
- if ( sleep )
119
- {
120
- Thread . UninterruptibleSleep0 ( ) ;
121
- }
122
- else
123
- {
124
- Thread . SpinWait ( 1 ) ;
125
- }
126
-
127
- stage = ( StaticsInitializationStage ) Volatile . Read ( ref s_staticsInitializationStage ) ;
128
- if ( stage == StaticsInitializationStage . Complete )
129
- {
130
- goto case StaticsInitializationStage . Complete ;
131
- }
132
- else if ( stage == StaticsInitializationStage . NotStarted )
133
- {
134
- goto default ;
135
- }
136
-
137
- if ( State . TryLock ( this ) )
138
- {
139
- return TryLockResult . Locked ;
140
- }
141
-
142
- sleep = ! sleep ;
143
- }
144
-
145
- default :
146
- Debug . Assert ( stage == StaticsInitializationStage . NotStarted ) ;
147
- if ( TryInitializeStatics ( ) )
148
- {
149
- goto case StaticsInitializationStage . Complete ;
150
- }
151
- goto case StaticsInitializationStage . Started ;
100
+ InitStatics ( ) ;
152
101
}
153
102
}
154
103
155
104
[ MethodImpl ( MethodImplOptions . NoInlining ) ]
156
- private static bool TryInitializeStatics ( )
105
+ internal static bool InitStatics ( )
157
106
{
158
- // Since Lock is used to synchronize class construction, and some of the statics initialization may involve class
159
- // construction, update the stage first to avoid infinite recursion
160
- switch (
161
- ( StaticsInitializationStage )
162
- Interlocked . CompareExchange (
163
- ref s_staticsInitializationStage ,
164
- ( int ) StaticsInitializationStage . Started ,
165
- ( int ) StaticsInitializationStage . NotStarted ) )
107
+ if ( s_staticsInitializationStage != ( int ) StaticsInitializationStage . Started )
166
108
{
167
- case StaticsInitializationStage . Started :
168
- return false ;
169
- case StaticsInitializationStage . Complete :
109
+ // prevent reentrancy on the same thread
110
+ s_staticsInitializationStage = ( int ) StaticsInitializationStage . Started ;
111
+ try
112
+ {
113
+ s_minSpinCount = DetermineMinSpinCount ( ) ;
114
+ s_maxSpinCount = DetermineMaxSpinCount ( ) ;
115
+ NativeRuntimeEventSource . Log . IsEnabled ( ) ;
116
+
117
+ Volatile . Write ( ref s_staticsInitializationStage , ( int ) StaticsInitializationStage . Complete ) ;
170
118
return true ;
119
+ }
120
+ catch
121
+ {
122
+ // Callers can't handle this failure and also guarantee not coming here again because anything may take locks.
123
+ // However initializing statics is optional, so just ignore the failure.
124
+ s_staticsInitializationStage = ( int ) StaticsInitializationStage . NotStarted ;
125
+ }
171
126
}
172
127
173
- try
174
- {
175
- s_isSingleProcessor = Environment . IsSingleProcessor ;
176
- s_maxSpinCount = DetermineMaxSpinCount ( ) ;
177
- s_minSpinCount = DetermineMinSpinCount ( ) ;
128
+ return false ;
129
+ }
178
130
179
- // Also initialize some types that are used later to prevent potential class construction cycles
180
- NativeRuntimeEventSource . Log . IsEnabled ( ) ;
181
- }
182
- catch
131
+ internal static bool StaticsInitComplete ( )
132
+ {
133
+ if ( Volatile . Read ( ref s_staticsInitializationStage ) == ( int ) StaticsInitializationStage . Complete )
183
134
{
184
- s_staticsInitializationStage = ( int ) StaticsInitializationStage . NotStarted ;
185
- throw ;
135
+ return true ;
186
136
}
187
137
188
- Volatile . Write ( ref s_staticsInitializationStage , ( int ) StaticsInitializationStage . Complete ) ;
189
- return true ;
138
+ return InitStatics ( ) ;
190
139
}
191
140
192
- // Returns false until the static variable is lazy-initialized
193
- internal static bool IsSingleProcessor => s_isSingleProcessor ;
194
-
195
141
// Used to transfer the state when inflating thin locks
196
142
internal void InitializeLocked ( int managedThreadId , uint recursionCount )
197
143
{
198
144
Debug . Assert ( recursionCount == 0 || managedThreadId != 0 ) ;
199
145
200
- _state = managedThreadId == 0 ? State . InitialStateValue : State . LockedStateValue ;
146
+ _state = managedThreadId == 0 ? Unlocked : Locked ;
201
147
_owningThreadId = ( uint ) managedThreadId ;
202
148
_recursionCount = recursionCount ;
203
149
}
0 commit comments