From 98bf4dc82e3d057c06a6c4406000b698cf2cffaa Mon Sep 17 00:00:00 2001 From: Joel Dice Date: Thu, 29 Aug 2024 12:37:55 -0600 Subject: [PATCH] exit `DispatchWasiEventLoop` without polling if tasks have been canceled If one or more tasks have been canceled during the call to `ThreadPoolWorkQueue.Dispatch`, one or more tasks of interest to the application may have completed, so we return control immediately without polling, allowing the app to exit if it chooses. A practical example of this is in the SharedLibrary smoke test. Without this patch, that test will take over 100 seconds to complete, whereas with this patch it completes in under a second. Signed-off-by: Joel Dice --- .../src/System/Threading/Wasi/WasiEventLoop.cs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index 450bd84898d..e8e7b20dc34 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -14,6 +14,7 @@ internal static class WasiEventLoop // it will be leaked and stay in this list forever. // it will also keep the Pollable handle alive and prevent it from being disposed private static readonly List s_pollables = new(); + private static bool s_tasksCanceled; internal static Task RegisterWasiPollableHandle(int handle, CancellationToken cancellationToken) { @@ -35,6 +36,11 @@ internal static Task RegisterWasiPollable(Pollable pollable, CancellationToken c internal static void DispatchWasiEventLoop() { ThreadPoolWorkQueue.Dispatch(); + if (s_tasksCanceled) + { + s_tasksCanceled = false; + return; + } var holders = new List(s_pollables.Count); var pending = new List(s_pollables.Count); @@ -114,6 +120,11 @@ private static void CancelAndDispose(object? s) return; } + // Tell event loop to exit early, giving the application a + // chance to quit if the task(s) it is interested in have + // completed. + s_tasksCanceled = true; + // it will be removed from s_pollables on the next run self.isDisposed = true; self.pollable.Dispose();