11using System . Diagnostics ;
22using System . Runtime . InteropServices ;
3- using System . Runtime . Versioning ;
43
54namespace DotNext . Threading ;
65
@@ -17,25 +16,23 @@ public class AsyncExclusiveLock : QueuedSynchronizer, IAsyncDisposable
1716 private struct LockManager : ILockManager < DefaultWaitNode >
1817 {
1918 // null - not acquired, Sentinel.Instance - acquired asynchronously, Thread - acquired synchronously
20- private object ? state ;
19+ private bool state ;
2120
22- internal readonly bool Value => state is not null ;
21+ internal readonly bool Value => state ;
2322
24- internal readonly bool VolatileRead ( ) => Volatile . Read ( in state ) is not null ;
23+ internal readonly bool VolatileRead ( ) => Volatile . Read ( in state ) ;
2524
26- public readonly bool IsLockAllowed => state is null ;
25+ public readonly bool IsLockAllowed => state is false ;
2726
28- public void AcquireLock ( bool synchronously )
29- => state = synchronously ? Thread . CurrentThread : Sentinel . Instance ;
27+ public void AcquireLock ( )
28+ => state = true ;
3029
31- internal void ExitLock ( ) => state = null ;
32-
33- readonly bool ILockManager . IsLockHeldByCurrentThread
34- => ReferenceEquals ( state , Thread . CurrentThread ) ;
30+ internal void ExitLock ( ) => state = false ;
3531 }
3632
3733 private ValueTaskPool < bool , DefaultWaitNode , Action < DefaultWaitNode > > pool ;
3834 private LockManager manager ;
35+ private Thread ? lockOwner ;
3936
4037 /// <summary>
4138 /// Initializes a new asynchronous exclusive lock.
@@ -88,10 +85,20 @@ public bool TryAcquire()
8885 return TryAcquireCore ( ) ;
8986 }
9087
88+ private bool IsLockHelpByCurrentThread
89+ {
90+ get => lockOwner is not { } owner || ReferenceEquals ( owner , Thread . CurrentThread ) ;
91+ set
92+ {
93+ if ( value )
94+ lockOwner = Thread . CurrentThread ;
95+ }
96+ }
97+
9198 private bool TryAcquireCore ( )
9299 {
93100 Monitor . Enter ( SyncRoot ) ;
94- var result = TryAcquire ( ref manager , synchronously : true ) ;
101+ var result = IsLockHelpByCurrentThread = TryAcquire ( ref manager ) ;
95102 Monitor . Exit ( SyncRoot ) ;
96103
97104 return result ;
@@ -106,16 +113,22 @@ private bool TryAcquireCore()
106113 /// <exception cref="ArgumentOutOfRangeException"><paramref name="timeout"/> is negative.</exception>
107114 /// <exception cref="ObjectDisposedException">This object has been disposed.</exception>
108115 /// <exception cref="LockRecursionException">The lock is already acquired by the current thread.</exception>
109- [ UnsupportedOSPlatform ( "browser" ) ]
110116 public bool TryAcquire ( TimeSpan timeout , CancellationToken token = default )
111117 {
112- ObjectDisposedException . ThrowIf ( IsDisposed , this ) ;
118+ if ( IsLockHelpByCurrentThread )
119+ throw new LockRecursionException ( ) ;
120+
121+ bool result ;
122+ try
123+ {
124+ IsLockHelpByCurrentThread = result = TryAcquireAsync ( timeout , token ) . Wait ( ) ;
125+ }
126+ catch ( OperationCanceledException e ) when ( e . CancellationToken == token )
127+ {
128+ result = false ;
129+ }
113130
114- return timeout == TimeSpan . Zero
115- ? TryAcquireCore ( )
116- : token . CanBeCanceled
117- ? TryAcquire ( new Timeout ( timeout ) , ref manager , token )
118- : TryAcquire ( new Timeout ( timeout ) , ref manager ) ;
131+ return result ;
119132 }
120133
121134 /// <summary>
@@ -228,7 +241,7 @@ public ValueTask StealAsync(object? reason = null, CancellationToken token = def
228241 // skip dead node
229242 if ( RemoveAndSignal ( current , out var resumable ) )
230243 {
231- manager . AcquireLock ( synchronously : false ) ;
244+ manager . AcquireLock ( ) ;
232245 return resumable ? current : null ;
233246 }
234247 }
@@ -252,16 +265,12 @@ public void Release()
252265 throw new SynchronizationLockException ( ExceptionMessages . NotInLock ) ;
253266
254267 manager . ExitLock ( ) ;
268+ lockOwner = null ;
255269 suspendedCaller = DrainWaitQueue ( ) ;
256270
257271 if ( IsDisposing && IsReadyToDispose )
258272 {
259273 Dispose ( true ) ;
260- Monitor . PulseAll ( SyncRoot ) ;
261- }
262- else
263- {
264- Monitor . Pulse ( SyncRoot ) ;
265274 }
266275 }
267276
0 commit comments