From 3e7c20f906ddf21938bd5efa7ebe6e1525fdef16 Mon Sep 17 00:00:00 2001 From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Tue, 27 Aug 2024 18:53:10 -0700 Subject: [PATCH] Stop counting work items from ThreadPoolTypedWorkItemQueue for ThreadPool.CompletedWorkItemCount (#106854) * Stop counting work items from ThreadPoolTypedWorkItemQueue as completed work items * Fix CompletedWorkItemCount * Update src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs Co-authored-by: Koundinya Veluri * Run CompletedWorkItemCountTest on Windows only --------- Co-authored-by: Eduardo Manuel Velarde Polar Co-authored-by: Koundinya Veluri --- .../System/Threading/ThreadPoolWorkQueue.cs | 6 ++++- .../tests/ThreadPoolTests.cs | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs index bc0fe4556bb31..89dac7492578f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/ThreadPoolWorkQueue.cs @@ -1393,7 +1393,11 @@ void IThreadPoolWorkItem.Execute() currentThread.ResetThreadPoolThread(); } - ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount); + // Discount a work item here to avoid counting most of the queue processing work items + if (completedCount > 1) + { + ThreadInt64PersistentCounter.Add(tl.threadLocalCompletionCountObject!, completedCount - 1); + } } } diff --git a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs index a182c7c583630..a26b000055a7f 100644 --- a/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs +++ b/src/libraries/System.Threading.ThreadPool/tests/ThreadPoolTests.cs @@ -1440,6 +1440,33 @@ static async Task RunAsyncIOTest() }, ioCompletionPortCount.ToString()).Dispose(); } + + [ConditionalFact(nameof(IsThreadingAndRemoteExecutorSupported))] + [PlatformSpecific(TestPlatforms.Windows)] + public static unsafe void ThreadPoolCompletedWorkItemCountTest() + { + // Run in a separate process to test in a clean thread pool environment such that we don't count external work items + RemoteExecutor.Invoke(() => + { + using var manualResetEvent = new ManualResetEventSlim(false); + + var overlapped = new Overlapped(); + NativeOverlapped* nativeOverlapped = overlapped.Pack((errorCode, numBytes, innerNativeOverlapped) => + { + Overlapped.Free(innerNativeOverlapped); + manualResetEvent.Set(); + }, null); + + ThreadPool.UnsafeQueueNativeOverlapped(nativeOverlapped); + manualResetEvent.Wait(); + + // Allow work item(s) to be marked as completed during this time, should be only one + ThreadTestHelpers.WaitForCondition(() => ThreadPool.CompletedWorkItemCount == 1); + Thread.Sleep(50); + Assert.Equal(1, ThreadPool.CompletedWorkItemCount); + }).Dispose(); + } + public static bool IsThreadingAndRemoteExecutorSupported => PlatformDetection.IsThreadingSupported && RemoteExecutor.IsSupported;