From: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 15 Nov 2021 04:14:32 +0000 (-0700) Subject: [release/6.0] Fix UnobservedTaskException from SemaphoreSlim.WaitAsync (#61491) X-Git-Tag: accepted/tizen/unified/20221103.165808~280^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=09e3dcb02ebddd53be028bace3d570d2c5586c61;p=platform%2Fupstream%2Fdotnet%2Fruntime.git [release/6.0] Fix UnobservedTaskException from SemaphoreSlim.WaitAsync (#61491) * Fix UnobservedTaskException from SemaphoreSlim.WaitAsync If a SemaphoreSlim.WaitAsync times out, it correctly returns false, but it also results in TaskScheduler.UnobservedTaskException being raised unexpectedly, due to internal use of a faulted task whose exception isn't observed. This fixes that by marking any such exceptions as having been observed. * Fix wasm build Co-authored-by: Stephen Toub --- diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs index bfa8ccd..246ed5b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/SemaphoreSlim.cs @@ -745,7 +745,7 @@ namespace System.Threading public ConfiguredNoThrowAwaiter(Task task) => _task = task; public ConfiguredNoThrowAwaiter GetAwaiter() => this; public bool IsCompleted => _task.IsCompleted; - public void GetResult() { } + public void GetResult() => _task.MarkExceptionsAsHandled(); public void UnsafeOnCompleted(Action continuation) => _task.ConfigureAwait(false).GetAwaiter().UnsafeOnCompleted(continuation); public void OnCompleted(Action continuation) => _task.ConfigureAwait(false).GetAwaiter().OnCompleted(continuation); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs index 458c914..8a21b34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs @@ -1863,6 +1863,12 @@ namespace System.Threading.Tasks return Volatile.Read(ref m_contingentProperties)?.m_exceptionsHolder?.GetCancellationExceptionDispatchInfo(); // may be null } + /// Marks any exceptions stored in the Task as having been handled. + internal void MarkExceptionsAsHandled() + { + Volatile.Read(ref m_contingentProperties)?.m_exceptionsHolder?.MarkAsHandled(calledFromFinalizer: false); + } + /// /// Throws an aggregate exception if the task contains exceptions. /// diff --git a/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs b/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs index 2682166..7aabd01 100644 --- a/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs +++ b/src/libraries/System.Threading/tests/SemaphoreSlimTests.cs @@ -2,7 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Runtime.CompilerServices; using System.Threading.Tasks; +using Microsoft.DotNet.RemoteExecutor; using Xunit; namespace System.Threading.Tests @@ -615,5 +617,28 @@ namespace System.Threading.Tests semaphore.Release(totalWaiters / 2); Task.WaitAll(tasks); } + + [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + public void WaitAsync_Timeout_NoUnhandledException() + { + RemoteExecutor.Invoke(async () => + { + Exception error = null; + TaskScheduler.UnobservedTaskException += (s, e) => Volatile.Write(ref error, e.Exception); + + var sem = new SemaphoreSlim(0); + for (int i = 0; i < 2; ++i) + { + await sem.WaitAsync(1); + GC.Collect(); + GC.WaitForPendingFinalizers(); + } + + if (Volatile.Read(ref error) is Exception e) + { + throw e; + } + }).Dispose(); + } } }