summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorKoundinya Veluri <kouvel@users.noreply.github.com>2019-04-19 19:22:53 -0700
committerGitHub <noreply@github.com>2019-04-19 19:22:53 -0700
commit0410c3e4fe54590eea34aead28f550539d814b98 (patch)
tree0a7d9b8ee2df4e672024ed410ee04e267f8e5bbe /src
parent924d4fcc6961a76881a42a5a4a80479352708ace (diff)
downloadcoreclr-0410c3e4fe54590eea34aead28f550539d814b98.tar.gz
coreclr-0410c3e4fe54590eea34aead28f550539d814b98.tar.bz2
coreclr-0410c3e4fe54590eea34aead28f550539d814b98.zip
Implement APIs for some threading metrics (CoreCLR) (#24113)
Implement APIs for some threading metrics (CoreCLR) API review: https://github.com/dotnet/corefx/issues/35500
Diffstat (limited to 'src')
-rw-r--r--src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs53
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/Monitor.cs9
-rw-r--r--src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs30
-rw-r--r--src/classlibnative/bcltype/objectnative.cpp6
-rw-r--r--src/classlibnative/bcltype/objectnative.h1
-rw-r--r--src/vm/comthreadpool.cpp24
-rw-r--r--src/vm/comthreadpool.h3
-rw-r--r--src/vm/ecalllist.h4
-rw-r--r--src/vm/syncblk.cpp1
-rw-r--r--src/vm/threadpoolrequest.h6
-rw-r--r--src/vm/threads.cpp82
-rw-r--r--src/vm/threads.h112
-rw-r--r--src/vm/win32threadpool.cpp24
-rw-r--r--src/vm/win32threadpool.h4
14 files changed, 325 insertions, 34 deletions
diff --git a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
index 19c043da5a..fc53fc158f 100644
--- a/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
+++ b/src/System.Private.CoreLib/shared/System/Threading/ThreadPool.cs
@@ -381,6 +381,26 @@ namespace System.Threading
return null;
}
}
+
+ public int Count
+ {
+ get
+ {
+ bool lockTaken = false;
+ try
+ {
+ m_foreignLock.Enter(ref lockTaken);
+ return Math.Max(0, m_tailIndex - m_headIndex);
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ m_foreignLock.Exit(useMemoryBarrier: false);
+ }
+ }
+ }
+ }
}
internal bool loggingEnabled;
@@ -512,6 +532,21 @@ namespace System.Threading
return callback;
}
+ public long LocalCount
+ {
+ get
+ {
+ long count = 0;
+ foreach (WorkStealingQueue workStealingQueue in WorkStealingQueueList.Queues)
+ {
+ count += workStealingQueue.Count;
+ }
+ return count;
+ }
+ }
+
+ public long GlobalCount => workItems.Count;
+
/// <summary>
/// Dispatches work items to this thread.
/// </summary>
@@ -1241,5 +1276,23 @@ namespace System.Threading
internal static object[] GetLocallyQueuedWorkItemsForDebugger() =>
ToObjectArray(GetLocallyQueuedWorkItems());
+
+ /// <summary>
+ /// Gets the number of work items that are currently queued to be processed.
+ /// </summary>
+ /// <remarks>
+ /// For a thread pool implementation that may have different types of work items, the count includes all types that can
+ /// be tracked, which may only be the user work items including tasks. Some implementations may also include queued
+ /// timer and wait callbacks in the count. On Windows, the count is unlikely to include the number of pending IO
+ /// completions, as they get posted directly to an IO completion port.
+ /// </remarks>
+ public static long PendingWorkItemCount
+ {
+ get
+ {
+ ThreadPoolWorkQueue workQueue = ThreadPoolGlobals.workQueue;
+ return workQueue.LocalCount + workQueue.GlobalCount + PendingUnmanagedWorkItemCount;
+ }
+ }
}
}
diff --git a/src/System.Private.CoreLib/src/System/Threading/Monitor.cs b/src/System.Private.CoreLib/src/System/Threading/Monitor.cs
index 2701b3b555..cb3a0f61d5 100644
--- a/src/System.Private.CoreLib/src/System/Threading/Monitor.cs
+++ b/src/System.Private.CoreLib/src/System/Threading/Monitor.cs
@@ -233,5 +233,14 @@ namespace System.Threading
ObjPulseAll(obj);
}
+
+ /// <summary>
+ /// Gets the number of times there was contention upon trying to take a <see cref="Monitor"/>'s lock so far.
+ /// </summary>
+ public static extern long LockContentionCount
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
}
}
diff --git a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs
index 89030787ed..76eb2db0ad 100644
--- a/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs
+++ b/src/System.Private.CoreLib/src/System/Threading/ThreadPool.CoreCLR.cs
@@ -231,6 +231,36 @@ namespace System.Threading
GetAvailableThreadsNative(out workerThreads, out completionPortThreads);
}
+ /// <summary>
+ /// Gets the number of thread pool threads that currently exist.
+ /// </summary>
+ /// <remarks>
+ /// For a thread pool implementation that may have different types of threads, the count includes all types.
+ /// </remarks>
+ public static extern int ThreadCount
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
+
+ /// <summary>
+ /// Gets the number of work items that have been processed so far.
+ /// </summary>
+ /// <remarks>
+ /// For a thread pool implementation that may have different types of work items, the count includes all types.
+ /// </remarks>
+ public static extern long CompletedWorkItemCount
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
+
+ private static extern long PendingUnmanagedWorkItemCount
+ {
+ [MethodImpl(MethodImplOptions.InternalCall)]
+ get;
+ }
+
private static RegisteredWaitHandle RegisterWaitForSingleObject( // throws RegisterWaitException
WaitHandle waitObject,
WaitOrTimerCallback callBack,
diff --git a/src/classlibnative/bcltype/objectnative.cpp b/src/classlibnative/bcltype/objectnative.cpp
index 5304e0110e..a5619e107f 100644
--- a/src/classlibnative/bcltype/objectnative.cpp
+++ b/src/classlibnative/bcltype/objectnative.cpp
@@ -355,3 +355,9 @@ FCIMPL1(FC_BOOL_RET, ObjectNative::IsLockHeld, Object* pThisUNSAFE)
}
FCIMPLEND
+FCIMPL0(INT64, ObjectNative::GetMonitorLockContentionCount)
+{
+ FCALL_CONTRACT;
+ return (INT64)Thread::GetTotalMonitorLockContentionCount();
+}
+FCIMPLEND
diff --git a/src/classlibnative/bcltype/objectnative.h b/src/classlibnative/bcltype/objectnative.h
index 573b04ea0a..3d008d95a9 100644
--- a/src/classlibnative/bcltype/objectnative.h
+++ b/src/classlibnative/bcltype/objectnative.h
@@ -38,6 +38,7 @@ public:
static FCDECL1(void, Pulse, Object* pThisUNSAFE);
static FCDECL1(void, PulseAll, Object* pThisUNSAFE);
static FCDECL1(FC_BOOL_RET, IsLockHeld, Object* pThisUNSAFE);
+ static FCDECL0(INT64, GetMonitorLockContentionCount);
};
#endif // _OBJECTNATIVE_H_
diff --git a/src/vm/comthreadpool.cpp b/src/vm/comthreadpool.cpp
index 18db9951cb..f5dc4233e0 100644
--- a/src/vm/comthreadpool.cpp
+++ b/src/vm/comthreadpool.cpp
@@ -182,6 +182,30 @@ FCIMPL2(VOID, ThreadPoolNative::CorGetAvailableThreads,DWORD* workerThreads, DWO
FCIMPLEND
/*****************************************************************************************************/
+FCIMPL0(INT32, ThreadPoolNative::GetThreadCount)
+{
+ FCALL_CONTRACT;
+ return ThreadpoolMgr::GetThreadCount();
+}
+FCIMPLEND
+
+/*****************************************************************************************************/
+FCIMPL0(INT64, ThreadPoolNative::GetCompletedWorkItemCount)
+{
+ FCALL_CONTRACT;
+ return (INT64)Thread::GetTotalThreadPoolCompletionCount();
+}
+FCIMPLEND
+
+/*****************************************************************************************************/
+FCIMPL0(INT64, ThreadPoolNative::GetPendingUnmanagedWorkItemCount)
+{
+ FCALL_CONTRACT;
+ return PerAppDomainTPCountList::GetUnmanagedTPCount()->GetNumRequests();
+}
+FCIMPLEND
+
+/*****************************************************************************************************/
FCIMPL0(VOID, ThreadPoolNative::NotifyRequestProgress)
{
diff --git a/src/vm/comthreadpool.h b/src/vm/comthreadpool.h
index 6b0f4ec969..d830c9e505 100644
--- a/src/vm/comthreadpool.h
+++ b/src/vm/comthreadpool.h
@@ -28,6 +28,9 @@ public:
static FCDECL2(FC_BOOL_RET, CorSetMinThreads, DWORD workerThreads, DWORD completionPortThreads);
static FCDECL2(VOID, CorGetMinThreads, DWORD* workerThreads, DWORD* completionPortThreads);
static FCDECL2(VOID, CorGetAvailableThreads, DWORD* workerThreads, DWORD* completionPortThreads);
+ static FCDECL0(INT32, GetThreadCount);
+ static FCDECL0(INT64, GetCompletedWorkItemCount);
+ static FCDECL0(INT64, GetPendingUnmanagedWorkItemCount);
static FCDECL0(VOID, NotifyRequestProgress);
static FCDECL0(FC_BOOL_RET, NotifyRequestComplete);
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 50071ed410..4d9de5b4b9 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -678,6 +678,9 @@ FCFuncStart(gThreadPoolFuncs)
FCFuncElement("GetAvailableThreadsNative", ThreadPoolNative::CorGetAvailableThreads)
FCFuncElement("SetMinThreadsNative", ThreadPoolNative::CorSetMinThreads)
FCFuncElement("GetMinThreadsNative", ThreadPoolNative::CorGetMinThreads)
+ FCFuncElement("get_ThreadCount", ThreadPoolNative::GetThreadCount)
+ FCFuncElement("get_CompletedWorkItemCount", ThreadPoolNative::GetCompletedWorkItemCount)
+ FCFuncElement("get_PendingUnmanagedWorkItemCount", ThreadPoolNative::GetPendingUnmanagedWorkItemCount)
FCFuncElement("RegisterWaitForSingleObjectNative", ThreadPoolNative::CorRegisterWaitForSingleObject)
FCFuncElement("BindIOCompletionCallbackNative", ThreadPoolNative::CorBindIoCompletionCallback)
FCFuncElement("SetMaxThreadsNative", ThreadPoolNative::CorSetMaxThreads)
@@ -915,6 +918,7 @@ FCFuncStart(gMonitorFuncs)
FCFuncElement("ObjPulse", ObjectNative::Pulse)
FCFuncElement("ObjPulseAll", ObjectNative::PulseAll)
FCFuncElement("IsEnteredNative", ObjectNative::IsLockHeld)
+ FCFuncElement("get_LockContentionCount", ObjectNative::GetMonitorLockContentionCount)
FCFuncEnd()
FCFuncStart(gOverlappedFuncs)
diff --git a/src/vm/syncblk.cpp b/src/vm/syncblk.cpp
index ce31ac90b3..9aea18f0c6 100644
--- a/src/vm/syncblk.cpp
+++ b/src/vm/syncblk.cpp
@@ -2575,6 +2575,7 @@ BOOL AwareLock::EnterEpilogHelper(Thread* pCurThread, INT32 timeOut)
FireEtwContentionStart_V1(ETW::ContentionLog::ContentionStructs::ManagedContention, GetClrInstanceId());
LogContention();
+ Thread::IncrementMonitorLockContentionCount(pCurThread);
OBJECTREF obj = GetOwningObject();
diff --git a/src/vm/threadpoolrequest.h b/src/vm/threadpoolrequest.h
index eaba82389c..3b2da28b56 100644
--- a/src/vm/threadpoolrequest.h
+++ b/src/vm/threadpoolrequest.h
@@ -221,6 +221,12 @@ public:
_ASSERT(FALSE);
}
+ inline ULONG GetNumRequests()
+ {
+ LIMITED_METHOD_CONTRACT;
+ return VolatileLoad(&m_NumRequests);
+ }
+
private:
SpinLock m_lock;
ULONG m_NumRequests;
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 70c26118ea..37d30c392a 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -83,7 +83,9 @@ PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(MethodTable* pMT)
BOOL Thread::s_fCleanFinalizedThread = FALSE;
-Volatile<LONG> Thread::s_threadPoolCompletionCountOverflow = 0;
+UINT64 Thread::s_workerThreadPoolCompletionCountOverflow = 0;
+UINT64 Thread::s_ioThreadPoolCompletionCountOverflow = 0;
+UINT64 Thread::s_monitorLockContentionCountOverflow = 0;
CrstStatic g_DeadlockAwareCrst;
@@ -1528,7 +1530,9 @@ Thread::Thread()
m_sfEstablisherOfActualHandlerFrame.Clear();
#endif // WIN64EXCEPTIONS
- m_threadPoolCompletionCount = 0;
+ m_workerThreadPoolCompletionCount = 0;
+ m_ioThreadPoolCompletionCount = 0;
+ m_monitorLockContentionCount = 0;
Thread *pThread = GetThread();
InitContext();
@@ -5350,9 +5354,15 @@ BOOL ThreadStore::RemoveThread(Thread *target)
if (target->IsBackground())
s_pThreadStore->m_BackgroundThreadCount--;
- FastInterlockExchangeAdd(
- &Thread::s_threadPoolCompletionCountOverflow,
- target->m_threadPoolCompletionCount);
+ FastInterlockExchangeAddLong(
+ (LONGLONG *)&Thread::s_workerThreadPoolCompletionCountOverflow,
+ target->m_workerThreadPoolCompletionCount);
+ FastInterlockExchangeAddLong(
+ (LONGLONG *)&Thread::s_ioThreadPoolCompletionCountOverflow,
+ target->m_ioThreadPoolCompletionCount);
+ FastInterlockExchangeAddLong(
+ (LONGLONG *)&Thread::s_monitorLockContentionCountOverflow,
+ target->m_monitorLockContentionCount);
_ASSERTE(s_pThreadStore->m_ThreadCount >= 0);
_ASSERTE(s_pThreadStore->m_BackgroundThreadCount >= 0);
@@ -8002,7 +8012,23 @@ BOOL ThreadStore::HoldingThreadStore(Thread *pThread)
}
}
-LONG Thread::GetTotalThreadPoolCompletionCount()
+NOINLINE void Thread::OnIncrementCountOverflow(UINT32 *threadLocalCount, UINT64 *overflowCount)
+{
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(threadLocalCount != nullptr);
+ _ASSERTE(overflowCount != nullptr);
+
+ // Increment overflow, accumulate the count for this increment into the overflow count and reset the thread-local count
+
+ // The thread store lock, in coordination with other places that read these values, ensures that both changes
+ // below become visible together
+ ThreadStoreLockHolder tsl;
+
+ *threadLocalCount = 0;
+ InterlockedExchangeAdd64((LONGLONG *)overflowCount, (LONGLONG)UINT32_MAX + 1);
+}
+
+UINT64 Thread::GetTotalCount(SIZE_T threadLocalCountOffset, UINT64 *overflowCount)
{
CONTRACTL
{
@@ -8011,32 +8037,44 @@ LONG Thread::GetTotalThreadPoolCompletionCount()
}
CONTRACTL_END;
- LONG total;
- if (g_fEEStarted) //make sure we actually have a thread store
- {
- // make sure up-to-date thread-local counts are visible to us
- ::FlushProcessWriteBuffers();
+ // enumerate all threads, summing their local counts.
+ ThreadStoreLockHolder tsl;
- // enumerate all threads, summing their local counts.
- ThreadStoreLockHolder tsl;
+ UINT64 total = GetOverflowCount(overflowCount);
- total = s_threadPoolCompletionCountOverflow.Load();
+ Thread *pThread = NULL;
+ while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
+ {
+ total += *GetThreadLocalCountRef(pThread, threadLocalCountOffset);
+ }
- Thread *pThread = NULL;
- while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
- {
- total += pThread->m_threadPoolCompletionCount;
- }
+ return total;
+}
+
+UINT64 Thread::GetTotalThreadPoolCompletionCount()
+{
+ CONTRACTL
+ {
+ NOTHROW;
+ MODE_ANY;
}
- else
+ CONTRACTL_END;
+
+ // enumerate all threads, summing their local counts.
+ ThreadStoreLockHolder tsl;
+
+ UINT64 total = GetWorkerThreadPoolCompletionCountOverflow() + GetIOThreadPoolCompletionCountOverflow();
+
+ Thread *pThread = NULL;
+ while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
{
- total = s_threadPoolCompletionCountOverflow.Load();
+ total += pThread->m_workerThreadPoolCompletionCount;
+ total += pThread->m_ioThreadPoolCompletionCount;
}
return total;
}
-
INT32 Thread::ResetManagedThreadObject(INT32 nPriority)
{
CONTRACTL {
diff --git a/src/vm/threads.h b/src/vm/threads.h
index e5307d9a5d..ee3e69f4f2 100644
--- a/src/vm/threads.h
+++ b/src/vm/threads.h
@@ -3871,21 +3871,113 @@ private:
#endif // defined(FEATURE_PROFAPI_ATTACH_DETACH) || defined(DATA_PROFAPI_ATTACH_DETACH)
private:
- Volatile<LONG> m_threadPoolCompletionCount;
- static Volatile<LONG> s_threadPoolCompletionCountOverflow; //counts completions for threads that have been destroyed.
+ UINT32 m_workerThreadPoolCompletionCount;
+ static UINT64 s_workerThreadPoolCompletionCountOverflow;
+ UINT32 m_ioThreadPoolCompletionCount;
+ static UINT64 s_ioThreadPoolCompletionCountOverflow;
+ UINT32 m_monitorLockContentionCount;
+ static UINT64 s_monitorLockContentionCountOverflow;
-public:
- static void IncrementThreadPoolCompletionCount()
+#ifndef DACCESS_COMPILE
+private:
+ static UINT32 *GetThreadLocalCountRef(Thread *pThread, SIZE_T threadLocalCountOffset)
{
- LIMITED_METHOD_CONTRACT;
- Thread* pThread = GetThread();
- if (pThread)
- pThread->m_threadPoolCompletionCount++;
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(threadLocalCountOffset <= sizeof(Thread) - sizeof(UINT32));
+
+ return (UINT32 *)((SIZE_T)pThread + threadLocalCountOffset);
+ }
+
+ static void IncrementCount(Thread *pThread, SIZE_T threadLocalCountOffset, UINT64 *overflowCount)
+ {
+ WRAPPER_NO_CONTRACT;
+ _ASSERTE(overflowCount != nullptr);
+
+ if (pThread != nullptr)
+ {
+ UINT32 *threadLocalCount = GetThreadLocalCountRef(pThread, threadLocalCountOffset);
+ UINT32 newCount = *threadLocalCount + 1;
+ if (newCount != 0)
+ {
+ VolatileStoreWithoutBarrier(threadLocalCount, newCount);
+ }
+ else
+ {
+ OnIncrementCountOverflow(threadLocalCount, overflowCount);
+ }
+ }
else
- FastInterlockIncrement(&s_threadPoolCompletionCountOverflow);
+ {
+ InterlockedIncrement64((LONGLONG *)overflowCount);
+ }
+ }
+
+ static void OnIncrementCountOverflow(UINT32 *threadLocalCount, UINT64 *overflowCount);
+
+ static UINT64 GetOverflowCount(UINT64 *overflowCount)
+ {
+ WRAPPER_NO_CONTRACT;
+
+ if (sizeof(void *) >= sizeof(*overflowCount))
+ {
+ return VolatileLoad(overflowCount);
+ }
+ return InterlockedCompareExchange64((LONGLONG *)overflowCount, 0, 0); // prevent tearing
+ }
+
+ static UINT64 GetTotalCount(SIZE_T threadLocalCountOffset, UINT64 *overflowCount);
+
+public:
+ static void IncrementWorkerThreadPoolCompletionCount(Thread *pThread)
+ {
+ WRAPPER_NO_CONTRACT;
+ IncrementCount(pThread, offsetof(Thread, m_workerThreadPoolCompletionCount), &s_workerThreadPoolCompletionCountOverflow);
+ }
+
+ static UINT64 GetWorkerThreadPoolCompletionCountOverflow()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetOverflowCount(&s_workerThreadPoolCompletionCountOverflow);
+ }
+
+ static UINT64 GetTotalWorkerThreadPoolCompletionCount()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetTotalCount(offsetof(Thread, m_workerThreadPoolCompletionCount), &s_workerThreadPoolCompletionCountOverflow);
+ }
+
+ static void IncrementIOThreadPoolCompletionCount(Thread *pThread)
+ {
+ WRAPPER_NO_CONTRACT;
+ IncrementCount(pThread, offsetof(Thread, m_ioThreadPoolCompletionCount), &s_ioThreadPoolCompletionCountOverflow);
+ }
+
+ static UINT64 GetIOThreadPoolCompletionCountOverflow()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetOverflowCount(&s_ioThreadPoolCompletionCountOverflow);
+ }
+
+ static UINT64 GetTotalThreadPoolCompletionCount();
+
+ static void IncrementMonitorLockContentionCount(Thread *pThread)
+ {
+ WRAPPER_NO_CONTRACT;
+ IncrementCount(pThread, offsetof(Thread, m_monitorLockContentionCount), &s_monitorLockContentionCountOverflow);
}
- static LONG GetTotalThreadPoolCompletionCount();
+ static UINT64 GetMonitorLockContentionCountOverflow()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetOverflowCount(&s_monitorLockContentionCountOverflow);
+ }
+
+ static UINT64 GetTotalMonitorLockContentionCount()
+ {
+ WRAPPER_NO_CONTRACT;
+ return GetTotalCount(offsetof(Thread, m_monitorLockContentionCount), &s_monitorLockContentionCountOverflow);
+ }
+#endif // !DACCESS_COMPILE
private:
diff --git a/src/vm/win32threadpool.cpp b/src/vm/win32threadpool.cpp
index f340542b0c..da44beb72e 100644
--- a/src/vm/win32threadpool.cpp
+++ b/src/vm/win32threadpool.cpp
@@ -693,6 +693,18 @@ BOOL ThreadpoolMgr::GetAvailableThreads(DWORD* AvailableWorkerThreads,
return TRUE;
}
+INT32 ThreadpoolMgr::GetThreadCount()
+{
+ WRAPPER_NO_CONTRACT;
+
+ if (!IsInitialized())
+ {
+ return 0;
+ }
+
+ return WorkerCounter.DangerousGetDirtyCounts().NumActive + CPThreadCounter.DangerousGetDirtyCounts().NumActive;
+}
+
void QueueUserWorkItemHelp(LPTHREAD_START_ROUTINE Function, PVOID Context)
{
STATIC_CONTRACT_THROWS;
@@ -911,7 +923,7 @@ void ThreadpoolMgr::AdjustMaxWorkersActive()
_ASSERTE(ThreadAdjustmentLock.IsHeld());
DWORD currentTicks = GetTickCount();
- LONG totalNumCompletions = Thread::GetTotalThreadPoolCompletionCount();
+ LONG totalNumCompletions = (LONG)Thread::GetTotalWorkerThreadPoolCompletionCount();
LONG numCompletions = totalNumCompletions - VolatileLoad(&PriorCompletedWorkRequests);
LARGE_INTEGER startTime = CurrentSampleStartTime;
@@ -2864,6 +2876,10 @@ DWORD WINAPI ThreadpoolMgr::AsyncCallbackCompletion(PVOID pArgs)
((WAITORTIMERCALLBACKFUNC) waitInfo->Callback)
( waitInfo->Context, asyncCallback->waitTimedOut != FALSE);
+
+#ifndef FEATURE_PAL
+ Thread::IncrementIOThreadPoolCompletionCount(pThread);
+#endif
}
return ERROR_SUCCESS;
@@ -3604,6 +3620,12 @@ Top:
((LPOVERLAPPED_COMPLETION_ROUTINE) key)(errorCode, numBytes, pOverlapped);
}
+ if ((void *)key != CallbackForInitiateDrainageOfCompletionPortQueue &&
+ (void *)key != CallbackForContinueDrainageOfCompletionPortQueue)
+ {
+ Thread::IncrementIOThreadPoolCompletionCount(pThread);
+ }
+
if (pThread == NULL) {
pThread = GetThread();
}
diff --git a/src/vm/win32threadpool.h b/src/vm/win32threadpool.h
index 55f321c37f..ff47ea2007 100644
--- a/src/vm/win32threadpool.h
+++ b/src/vm/win32threadpool.h
@@ -244,6 +244,8 @@ public:
static BOOL GetAvailableThreads(DWORD* AvailableWorkerThreads,
DWORD* AvailableIOCompletionThreads);
+ static INT32 GetThreadCount();
+
static BOOL QueueUserWorkItem(LPTHREAD_START_ROUTINE Function,
PVOID Context,
ULONG Flags,
@@ -841,7 +843,7 @@ public:
static void NotifyWorkItemCompleted()
{
WRAPPER_NO_CONTRACT;
- Thread::IncrementThreadPoolCompletionCount();
+ Thread::IncrementWorkerThreadPoolCompletionCount(GetThread());
UpdateLastDequeueTime();
}