You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
If you get particularly unlucky with your timing, that call to cancellationTokenRegistration.Dispose() will block on the cancellation handler completing; if that's running on another thread and potentially blocked in it's own right, then the monitor is held and all other calls to AsyncSemaphore will block, synchronously.
I admit it's not immediately obvious to me if this will deadlock permanently:
might be trying to acquire the monitor as well in the cancellation handler -- we might have a case where the cancellation handler is acquiring the monitor and the monitor is blocking on the cancellation handler. But my analysis might be incorrect there.
I suspect one fix is to move info.Cleanup() outside the monitor lock, but not sure if other fixes are available too.
Repro steps
Have code using AsyncSemaphore with cancellation, and get unlucky.
The text was updated successfully, but these errors were encountered:
404 threads are blocked trying to acquire the monitor in AsyncSemaphore.EnterAsync.
The one thread that does have the monitor is in here:
> mscorlib.dll!System.Threading.SpinWait.SpinOnce() Line 146 C#
mscorlib.dll!System.Threading.CancellationTokenSource.WaitForCallbackToComplete(System.Threading.CancellationCallbackInfo callbackInfo) Line 946 C#
mscorlib.dll!System.Threading.CancellationTokenRegistration.Dispose() Line 90 C#
Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.AsyncSemaphore.WaiterInfo.Cleanup() Line 357 C#
Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.AsyncSemaphore.EnterAsync(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) Line 147 C#
22 threads are here in StreamJsonRpc:
mscorlib.dll!System.Threading.SpinWait.SpinOnce() Line 146 C#
mscorlib.dll!System.Threading.CancellationTokenSource.WaitForCallbackToComplete(System.Threading.CancellationCallbackInfo callbackInfo) Line 946 C#
mscorlib.dll!System.Threading.CancellationTokenRegistration.Dispose() Line 90 C#
mscorlib.dll!System.Threading.CancellationTokenSource.Dispose(bool disposing) Line 582 C#
> StreamJsonRpc.dll!StreamJsonRpc.JsonRpc.InvokeCoreAsync(StreamJsonRpc.Protocol.JsonRpcRequest request, System.Type expectedResultType, System.Threading.CancellationToken cancellationToken) Line 1906 C#
22 other threads (suspicious the same number?) are here:
> Microsoft.VisualStudio.Threading.dll!Microsoft.VisualStudio.Threading.AsyncSemaphore.CancellationHandler(object ste) Line 234 C#
AArnott
added a commit
to AArnott/vs-threading
that referenced
this issue
Mar 24, 2022
This avoids calling `CancellationTokenRegistration.Dispose` while holding a private lock in EnterAsync. There is one remaining case where we may hold a lock while calling it, but that's in the inlined case of EnterAsync and CTR will have its default value, and thus could not have anything to block on.
The problematic case that we're fixing is when the token is canceled while EnterAsync is executing between where the CTR is assigned and where we called `info.Cleanup()`. In such a case, we would deadlock because Cleanup would wait for handlers to complete but the handler is waiting for the lock.
Fixesmicrosoft#1000
AArnott
changed the title
AsyncSemaphore.EnterAsync may block on cancellation while holding the monitor
AsyncSemaphore deadlock: EnterAsync holds lock while blocking on cancellation handler which needs lock
Mar 24, 2022
(This is being reported from the analysis from devdiv-1496681
Bug description
AsyncSemaphore.EnterAsync has this specific line:
vs-threading/src/Microsoft.VisualStudio.Threading/AsyncSemaphore.cs
Line 144 in 683b45c
Which calls:
vs-threading/src/Microsoft.VisualStudio.Threading/AsyncSemaphore.cs
Line 356 in 683b45c
If you get particularly unlucky with your timing, that call to cancellationTokenRegistration.Dispose() will block on the cancellation handler completing; if that's running on another thread and potentially blocked in it's own right, then the monitor is held and all other calls to AsyncSemaphore will block, synchronously.
I admit it's not immediately obvious to me if this will deadlock permanently:
vs-threading/src/Microsoft.VisualStudio.Threading/AsyncSemaphore.cs
Line 222 in 683b45c
I suspect one fix is to move info.Cleanup() outside the monitor lock, but not sure if other fixes are available too.
Repro steps
Have code using AsyncSemaphore with cancellation, and get unlucky.
The text was updated successfully, but these errors were encountered: