@@ -30,9 +30,77 @@ public static partial class Monitor
3030 **
3131 ** Exceptions: ArgumentNullException if object is null.
3232 =========================================================================*/
33+ public static void Enter ( object obj )
34+ {
35+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
36+
37+ if ( ! TryEnter_FastPath ( obj ) )
38+ {
39+ Enter_Slowpath ( obj ) ;
40+ }
41+ }
42+
3343 [ MethodImpl ( MethodImplOptions . InternalCall ) ]
34- public static extern void Enter ( object obj ) ;
44+ private static extern bool TryEnter_FastPath ( object obj ) ;
45+
46+ // These must match the values in syncblk.h
47+ private enum EnterHelperResult
48+ {
49+ Contention = 0 ,
50+ Entered = 1 ,
51+ UseSlowPath = 2
52+ }
53+
54+ // These must match the values in syncblk.h
55+ private enum LeaveHelperAction
56+ {
57+ None = 0 ,
58+ Signal = 1 ,
59+ Yield = 2 ,
60+ Contention = 3 ,
61+ Error = 4 ,
62+ } ;
63+
64+ [ MethodImpl ( MethodImplOptions . InternalCall ) ]
65+ private static extern EnterHelperResult TryEnter_FastPath_WithTimeout ( object obj , int timeout ) ;
66+
67+ [ LibraryImport ( RuntimeHelpers . QCall , EntryPoint = "Monitor_Enter_Slowpath" ) ]
68+ private static partial void Enter_Slowpath ( ObjectHandleOnStack obj ) ;
69+
70+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
71+ private static void Enter_Slowpath ( object obj )
72+ {
73+ Enter_Slowpath ( ObjectHandleOnStack . Create ( ref obj ) ) ;
74+ }
3575
76+ [ LibraryImport ( RuntimeHelpers . QCall , EntryPoint = "Monitor_TryEnter_Slowpath" ) ]
77+ private static partial int TryEnter_Slowpath ( ObjectHandleOnStack obj , int timeout ) ;
78+
79+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
80+ private static bool TryEnter_Slowpath ( object obj )
81+ {
82+ if ( TryEnter_Slowpath ( ObjectHandleOnStack . Create ( ref obj ) , 0 ) != 0 )
83+ {
84+ return true ;
85+ }
86+ else
87+ {
88+ return false ;
89+ }
90+ }
91+
92+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
93+ private static bool TryEnter_Slowpath ( object obj , int timeout )
94+ {
95+ if ( TryEnter_Slowpath ( ObjectHandleOnStack . Create ( ref obj ) , timeout ) != 0 )
96+ {
97+ return true ;
98+ }
99+ else
100+ {
101+ return false ;
102+ }
103+ }
36104
37105 // Use a ref bool instead of out to ensure that unverifiable code must
38106 // initialize this value to something. If we used out, the value
@@ -44,7 +112,13 @@ public static void Enter(object obj, ref bool lockTaken)
44112 if ( lockTaken )
45113 ThrowLockTakenException ( ) ;
46114
47- ReliableEnter ( obj , ref lockTaken ) ;
115+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
116+
117+ if ( ! TryEnter_FastPath ( obj ) )
118+ {
119+ Enter_Slowpath ( obj ) ;
120+ }
121+ lockTaken = true ;
48122 Debug . Assert ( lockTaken ) ;
49123 }
50124
@@ -55,9 +129,16 @@ private static void ThrowLockTakenException()
55129 }
56130
57131 [ MethodImpl ( MethodImplOptions . InternalCall ) ]
58- private static extern void ReliableEnter ( object obj , ref bool lockTaken ) ;
132+ private static extern LeaveHelperAction Exit_FastPath ( object obj ) ;
59133
134+ [ LibraryImport ( RuntimeHelpers . QCall , EntryPoint = "Monitor_Exit_Slowpath" ) ]
135+ private static partial void Exit_Slowpath ( ObjectHandleOnStack obj , LeaveHelperAction exitBehavior ) ;
60136
137+ [ MethodImpl ( MethodImplOptions . NoInlining ) ]
138+ private static void Exit_Slowpath ( LeaveHelperAction exitBehavior , object obj )
139+ {
140+ Exit_Slowpath ( ObjectHandleOnStack . Create ( ref obj ) , exitBehavior ) ;
141+ }
61142
62143 /*=========================================================================
63144 ** Release the monitor lock. If one or more threads are waiting to acquire the
@@ -68,8 +149,37 @@ private static void ThrowLockTakenException()
68149 ** SynchronizationLockException if the current thread does not
69150 ** own the lock.
70151 =========================================================================*/
71- [ MethodImpl ( MethodImplOptions . InternalCall ) ]
72- public static extern void Exit ( object obj ) ;
152+ public static void Exit ( object obj )
153+ {
154+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
155+
156+ LeaveHelperAction exitBehavior = Exit_FastPath ( obj ) ;
157+
158+ if ( exitBehavior == LeaveHelperAction . None )
159+ return ;
160+
161+ Exit_Slowpath ( exitBehavior , obj ) ;
162+ }
163+
164+ // Used to implement synchronized methods on non Windows-X86 architectures
165+ internal static void ExitIfLockTaken ( object obj , ref bool lockTaken )
166+ {
167+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
168+
169+ if ( lockTaken )
170+ {
171+ LeaveHelperAction exitBehavior = Exit_FastPath ( obj ) ;
172+
173+ if ( exitBehavior == LeaveHelperAction . None )
174+ {
175+ lockTaken = false ;
176+ return ;
177+ }
178+
179+ Exit_Slowpath ( exitBehavior , obj ) ;
180+ lockTaken = false ;
181+ }
182+ }
73183
74184 /*=========================================================================
75185 ** Similar to Enter, but will never block. That is, if the current thread can
@@ -80,9 +190,41 @@ private static void ThrowLockTakenException()
80190 =========================================================================*/
81191 public static bool TryEnter ( object obj )
82192 {
83- bool lockTaken = false ;
84- TryEnter ( obj , 0 , ref lockTaken ) ;
85- return lockTaken ;
193+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
194+
195+ EnterHelperResult tryEnterResult = TryEnter_FastPath_WithTimeout ( obj , 0 ) ;
196+ if ( tryEnterResult == EnterHelperResult . Entered )
197+ {
198+ return true ;
199+ }
200+ else if ( tryEnterResult == EnterHelperResult . Contention )
201+ {
202+ return false ;
203+ }
204+
205+ return TryEnter_Slowpath ( obj ) ;
206+ }
207+
208+ private static void TryEnter_Timeout_WithLockTaken ( object obj , int millisecondsTimeout , ref bool lockTaken )
209+ {
210+ if ( millisecondsTimeout >= - 1 )
211+ {
212+ EnterHelperResult tryEnterResult = TryEnter_FastPath_WithTimeout ( obj , millisecondsTimeout ) ;
213+ if ( tryEnterResult == EnterHelperResult . Entered )
214+ {
215+ lockTaken = true ;
216+ return ;
217+ }
218+ else if ( millisecondsTimeout == 0 && ( tryEnterResult == EnterHelperResult . Contention ) )
219+ {
220+ return ;
221+ }
222+ }
223+
224+ if ( TryEnter_Slowpath ( obj , millisecondsTimeout ) )
225+ {
226+ lockTaken = true ;
227+ }
86228 }
87229
88230 // The JIT should inline this method to allow check of lockTaken argument to be optimized out
@@ -92,7 +234,9 @@ public static void TryEnter(object obj, ref bool lockTaken)
92234 if ( lockTaken )
93235 ThrowLockTakenException ( ) ;
94236
95- ReliableEnterTimeout ( obj , 0 , ref lockTaken ) ;
237+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
238+
239+ TryEnter_Timeout_WithLockTaken ( obj , 0 , ref lockTaken ) ;
96240 }
97241
98242 /*=========================================================================
@@ -103,13 +247,24 @@ public static void TryEnter(object obj, ref bool lockTaken)
103247 ** Exceptions: ArgumentNullException if object is null.
104248 ** ArgumentException if timeout < -1 (Timeout.Infinite).
105249 =========================================================================*/
106- // The JIT should inline this method to allow check of lockTaken argument to be optimized out
107- // in the typical case. Note that the method has to be transparent for inlining to be allowed by the VM.
108250 public static bool TryEnter ( object obj , int millisecondsTimeout )
109251 {
110- bool lockTaken = false ;
111- TryEnter ( obj , millisecondsTimeout , ref lockTaken ) ;
112- return lockTaken ;
252+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
253+
254+ if ( millisecondsTimeout >= - 1 )
255+ {
256+ EnterHelperResult tryEnterResult = TryEnter_FastPath_WithTimeout ( obj , millisecondsTimeout ) ;
257+ if ( tryEnterResult == EnterHelperResult . Entered )
258+ {
259+ return true ;
260+ }
261+ else if ( millisecondsTimeout == 0 && ( tryEnterResult == EnterHelperResult . Contention ) )
262+ {
263+ return false ;
264+ }
265+ }
266+
267+ return TryEnter_Slowpath ( obj , millisecondsTimeout ) ;
113268 }
114269
115270 // The JIT should inline this method to allow check of lockTaken argument to be optimized out
@@ -119,11 +274,10 @@ public static void TryEnter(object obj, int millisecondsTimeout, ref bool lockTa
119274 if ( lockTaken )
120275 ThrowLockTakenException ( ) ;
121276
122- ReliableEnterTimeout ( obj , millisecondsTimeout , ref lockTaken ) ;
123- }
277+ ArgumentNullException . ThrowIfNull ( obj , null ) ;
124278
125- [ MethodImpl ( MethodImplOptions . InternalCall ) ]
126- private static extern void ReliableEnterTimeout ( object obj , int timeout , ref bool lockTaken ) ;
279+ TryEnter_Timeout_WithLockTaken ( obj , millisecondsTimeout , ref lockTaken ) ;
280+ }
127281
128282 public static bool IsEntered ( object obj )
129283 {
0 commit comments