diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index 60560e43fc7a69..a440561b2b8ae0 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -20,6 +20,7 @@
$(MSBuildThisFileDirectory)src\ILLink\
true
+ true
@@ -236,7 +237,6 @@
-
diff --git a/src/coreclr/System.Private.CoreLib/src/System/Threading/Timer.CoreCLR.cs b/src/coreclr/System.Private.CoreLib/src/System/Threading/Timer.CoreCLR.cs
deleted file mode 100644
index e91e8966e31e64..00000000000000
--- a/src/coreclr/System.Private.CoreLib/src/System/Threading/Timer.CoreCLR.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-using Microsoft.Win32.SafeHandles;
-using System.Diagnostics;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace System.Threading
-{
- internal sealed partial class TimerQueue
- {
- #region interface to native per-AppDomain timer
-
- // We use a SafeHandle to ensure that the native timer is destroyed when the AppDomain is unloaded.
- private sealed class AppDomainTimerSafeHandle : SafeHandleZeroOrMinusOneIsInvalid
- {
- public AppDomainTimerSafeHandle()
- : base(true)
- {
- }
-
- protected override bool ReleaseHandle()
- {
- return DeleteAppDomainTimer(handle);
- }
- }
-
- private readonly int _id; // TimerQueues[_id] == this
-
- private AppDomainTimerSafeHandle? m_appDomainTimer;
-
- private TimerQueue(int id)
- {
- _id = id;
- }
-
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- private bool SetTimer(uint actualDuration)
- {
- if (m_appDomainTimer == null || m_appDomainTimer.IsInvalid)
- {
- Debug.Assert(!_isTimerScheduled);
- Debug.Assert(_id >= 0 && _id < Instances.Length && this == Instances[_id]);
-
- m_appDomainTimer = CreateAppDomainTimer(actualDuration, _id);
- return !m_appDomainTimer.IsInvalid;
- }
- else
- {
- return ChangeAppDomainTimer(m_appDomainTimer, actualDuration);
- }
- }
-
- // The VM calls this when a native timer fires.
- internal static void AppDomainTimerCallback(int id)
- {
- Debug.Assert(id >= 0 && id < Instances.Length && Instances[id]._id == id);
- Instances[id].FireNextTimers();
- }
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AppDomainTimer_Create")]
- private static partial AppDomainTimerSafeHandle CreateAppDomainTimer(uint dueTime, int id);
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AppDomainTimer_Change")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool ChangeAppDomainTimer(AppDomainTimerSafeHandle handle, uint dueTime);
-
- [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "AppDomainTimer_Delete")]
- [return: MarshalAs(UnmanagedType.Bool)]
- private static partial bool DeleteAppDomainTimer(IntPtr handle);
-
- #endregion
- }
-}
diff --git a/src/coreclr/debug/daccess/request.cpp b/src/coreclr/debug/daccess/request.cpp
index 4b7bee7cbd1d40..6aae7bd1b4c131 100644
--- a/src/coreclr/debug/daccess/request.cpp
+++ b/src/coreclr/debug/daccess/request.cpp
@@ -348,20 +348,9 @@ ClrDataAccess::GetThreadpoolData(struct DacpThreadpoolData *threadpoolData)
threadpoolData->MaxLimitTotalCPThreads = ThreadpoolMgr::MaxLimitTotalCPThreads;
threadpoolData->CurrentLimitTotalCPThreads = (LONG)(counts.NumActive); //legacy: currently has no meaning
threadpoolData->MinLimitTotalCPThreads = ThreadpoolMgr::MinLimitTotalCPThreads;
-
- TADDR pEntry = DacGetTargetAddrForHostAddr(&ThreadpoolMgr::TimerQueue,true);
- ThreadpoolMgr::LIST_ENTRY entry;
- DacReadAll(pEntry,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
- TADDR node = (TADDR) entry.Flink;
threadpoolData->NumTimers = 0;
- while (node && node != pEntry)
- {
- threadpoolData->NumTimers++;
- DacReadAll(node,&entry,sizeof(ThreadpoolMgr::LIST_ENTRY),true);
- node = (TADDR) entry.Flink;
- }
+ threadpoolData->AsyncTimerCallbackCompletionFPtr = NULL;
- threadpoolData->AsyncTimerCallbackCompletionFPtr = (CLRDATA_ADDRESS) GFN_TADDR(ThreadpoolMgr__AsyncTimerCallbackCompletion);
SOSDacLeave();
return hr;
}
diff --git a/src/coreclr/inc/dacvars.h b/src/coreclr/inc/dacvars.h
index 5ce668353c4fb1..4e91e8fa189f37 100644
--- a/src/coreclr/inc/dacvars.h
+++ b/src/coreclr/inc/dacvars.h
@@ -110,7 +110,6 @@ DEFINE_DACVAR(ThreadpoolMgr::ThreadCounter, ThreadpoolMgr__CPThreadCounter, Thre
DEFINE_DACVAR(LONG, ThreadpoolMgr__MaxFreeCPThreads, ThreadpoolMgr::MaxFreeCPThreads)
DEFINE_DACVAR(LONG, ThreadpoolMgr__MaxLimitTotalCPThreads, ThreadpoolMgr::MaxLimitTotalCPThreads)
DEFINE_DACVAR(LONG, ThreadpoolMgr__MinLimitTotalCPThreads, ThreadpoolMgr::MinLimitTotalCPThreads)
-DEFINE_DACVAR(LIST_ENTRY, ThreadpoolMgr__TimerQueue, ThreadpoolMgr::TimerQueue)
DEFINE_DACVAR_NO_DUMP(SIZE_T, dac__HillClimbingLog, ::HillClimbingLog)
DEFINE_DACVAR(int, dac__HillClimbingLogFirstIndex, ::HillClimbingLogFirstIndex)
DEFINE_DACVAR(int, dac__HillClimbingLogSize, ::HillClimbingLogSize)
diff --git a/src/coreclr/inc/gfunc_list.h b/src/coreclr/inc/gfunc_list.h
index ddb05092db5b41..d5c5b67d9633e3 100644
--- a/src/coreclr/inc/gfunc_list.h
+++ b/src/coreclr/inc/gfunc_list.h
@@ -10,7 +10,6 @@
#define DEFINE_DACGFN_STATIC(class, func)
#endif
-DEFINE_DACGFN_STATIC(ThreadpoolMgr, AsyncTimerCallbackCompletion)
DEFINE_DACGFN(DACNotifyCompilationFinished)
DEFINE_DACGFN(ThePreStub)
diff --git a/src/coreclr/inc/utilcode.h b/src/coreclr/inc/utilcode.h
index f9444ab439ae6d..8f65ae980430de 100644
--- a/src/coreclr/inc/utilcode.h
+++ b/src/coreclr/inc/utilcode.h
@@ -3898,16 +3898,6 @@ inline BOOL IsGateSpecialThread ()
return !!(t_ThreadType & ThreadType_Gate);
}
-// check if current thread is a Timer thread
-inline BOOL IsTimerSpecialThread ()
-{
- STATIC_CONTRACT_NOTHROW;
- STATIC_CONTRACT_GC_NOTRIGGER;
- STATIC_CONTRACT_MODE_ANY;
-
- return !!(t_ThreadType & ThreadType_Timer);
-}
-
// check if current thread is a debugger helper thread
inline BOOL IsDbgHelperSpecialThread ()
{
diff --git a/src/coreclr/vm/comthreadpool.cpp b/src/coreclr/vm/comthreadpool.cpp
index 9cf77c6c3b201b..6c3f82f4fdc42b 100644
--- a/src/coreclr/vm/comthreadpool.cpp
+++ b/src/coreclr/vm/comthreadpool.cpp
@@ -852,144 +852,3 @@ FCIMPL1(FC_BOOL_RET, ThreadPoolNative::CorPostQueuedCompletionStatus, LPOVERLAPP
FC_RETURN_BOOL(res);
}
FCIMPLEND
-
-
-/********************************************************************************************************************/
-
-
-/******************************************************************************************/
-/* */
-/* Timer Functions */
-/* */
-/******************************************************************************************/
-
-void AppDomainTimerCallback_Worker(LPVOID ptr)
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- THROWS;
- MODE_COOPERATIVE;
- }
- CONTRACTL_END;
-
-#ifdef _DEBUG
- MethodDesc *pMeth = CoreLibBinder::GetMethod(METHOD__TIMER_QUEUE__APPDOMAIN_TIMER_CALLBACK);
- LogCall(pMeth,"AppDomainTimerCallback");
-#endif
-
- ThreadpoolMgr::TimerInfoContext* pTimerInfoContext = (ThreadpoolMgr::TimerInfoContext*)ptr;
- ARG_SLOT args[] = { PtrToArgSlot(pTimerInfoContext->TimerId) };
- MethodDescCallSite(METHOD__TIMER_QUEUE__APPDOMAIN_TIMER_CALLBACK).Call(args);
-}
-
-VOID WINAPI AppDomainTimerCallback(PVOID callbackState, BOOLEAN timerOrWaitFired)
-{
- Thread* pThread = GetThreadNULLOk();
- if (pThread == NULL)
- {
- // TODO: how do we notify user of OOM here?
- ClrFlsSetThreadType(ThreadType_Threadpool_Worker);
- pThread = SetupThreadNoThrow();
- if (pThread == NULL) {
- return;
- }
- }
-
- CONTRACTL
- {
- THROWS;
- MODE_ANY;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- GCX_COOP();
-
- ThreadpoolMgr::TimerInfoContext* pTimerInfoContext = (ThreadpoolMgr::TimerInfoContext*)callbackState;
- ManagedThreadBase::ThreadPool(AppDomainTimerCallback_Worker, pTimerInfoContext);
-}
-
-extern "C" HANDLE QCALLTYPE AppDomainTimer_Create(INT32 dueTime, INT32 timerId)
-{
- QCALL_CONTRACT;
-
- HANDLE hTimer = NULL;
- BEGIN_QCALL;
-
- _ASSERTE(dueTime >= 0);
- _ASSERTE(timerId >= 0);
-
- AppDomain* pAppDomain = GetThread()->GetDomain();
-
- ThreadpoolMgr::TimerInfoContext* timerContext = new ThreadpoolMgr::TimerInfoContext();
- timerContext->TimerId = timerId;
- NewHolder timerContextHolder(timerContext);
-
- BOOL res = ThreadpoolMgr::CreateTimerQueueTimer(
- &hTimer,
- (WAITORTIMERCALLBACK)AppDomainTimerCallback,
- (PVOID)timerContext,
- (ULONG)dueTime,
- (ULONG)-1 /* this timer doesn't repeat */,
- 0 /* no flags */);
-
- if (!res)
- {
- if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
- COMPlusThrow(kNotSupportedException);
- else
- COMPlusThrowWin32();
- }
- else
- {
- timerContextHolder.SuppressRelease();
- }
-
- END_QCALL;
- return hTimer;
-}
-
-extern "C" BOOL QCALLTYPE AppDomainTimer_Delete(HANDLE hTimer)
-{
- QCALL_CONTRACT;
-
- BOOL res = FALSE;
- BEGIN_QCALL;
-
- _ASSERTE(hTimer != NULL && hTimer != INVALID_HANDLE_VALUE);
- res = ThreadpoolMgr::DeleteTimerQueueTimer(hTimer, NULL);
-
- if (!res)
- {
- DWORD errorCode = ::GetLastError();
- if (errorCode != ERROR_IO_PENDING)
- COMPlusThrowWin32(HRESULT_FROM_WIN32(errorCode));
- }
-
- END_QCALL;
- return res;
-}
-
-
-extern "C" BOOL QCALLTYPE AppDomainTimer_Change(HANDLE hTimer, INT32 dueTime)
-{
- QCALL_CONTRACT;
-
- BOOL res = FALSE;
- BEGIN_QCALL;
-
- _ASSERTE(hTimer != NULL && hTimer != INVALID_HANDLE_VALUE);
- _ASSERTE(dueTime >= 0);
-
- res = ThreadpoolMgr::ChangeTimerQueueTimer(
- hTimer,
- (ULONG)dueTime,
- (ULONG)-1 /* this timer doesn't repeat */);
-
- if (!res)
- COMPlusThrowWin32();
-
- END_QCALL;
- return res;
-}
diff --git a/src/coreclr/vm/comthreadpool.h b/src/coreclr/vm/comthreadpool.h
index 1b700cd91fd810..46d9fda34d857b 100644
--- a/src/coreclr/vm/comthreadpool.h
+++ b/src/coreclr/vm/comthreadpool.h
@@ -60,9 +60,6 @@ class ThreadPoolNative
extern "C" INT64 QCALLTYPE ThreadPool_GetCompletedWorkItemCount();
extern "C" BOOL QCALLTYPE ThreadPool_RequestWorkerThread();
extern "C" BOOL QCALLTYPE ThreadPool_PerformGateActivities(INT32 cpuUtilization);
-extern "C" HANDLE QCALLTYPE AppDomainTimer_Create(INT32 dueTime, INT32 timerId);
-extern "C" BOOL QCALLTYPE AppDomainTimer_Change(HANDLE hTimer, INT32 dueTime);
-extern "C" BOOL QCALLTYPE AppDomainTimer_Delete(HANDLE hTimer);
VOID QueueUserWorkItemManagedCallback(PVOID pArg);
void WINAPI BindIoCompletionCallbackStub(DWORD ErrorCode,
diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h
index c7ea9e3c40fedd..0e73fbccbf2e4a 100644
--- a/src/coreclr/vm/corelib.h
+++ b/src/coreclr/vm/corelib.h
@@ -906,9 +906,6 @@ DEFINE_METHOD(TPWAITORTIMER_HELPER, PERFORM_WAITORTIMER_CALLBACK,
DEFINE_CLASS(TP_WAIT_CALLBACK, Threading, _ThreadPoolWaitCallback)
DEFINE_METHOD(TP_WAIT_CALLBACK, PERFORM_WAIT_CALLBACK, PerformWaitCallback, SM_RetBool)
-DEFINE_CLASS(TIMER_QUEUE, Threading, TimerQueue)
-DEFINE_METHOD(TIMER_QUEUE, APPDOMAIN_TIMER_CALLBACK, AppDomainTimerCallback, SM_Int_RetVoid)
-
DEFINE_CLASS(THREAD_POOL, Threading, ThreadPool)
DEFINE_METHOD(THREAD_POOL, ENSURE_GATE_THREAD_RUNNING, EnsureGateThreadRunning, SM_RetVoid)
DEFINE_METHOD(THREAD_POOL, UNSAFE_QUEUE_UNMANAGED_WORK_ITEM, UnsafeQueueUnmanagedWorkItem, SM_IntPtr_IntPtr_RetVoid)
diff --git a/src/coreclr/vm/qcallentrypoints.cpp b/src/coreclr/vm/qcallentrypoints.cpp
index 92c36b3089458b..5b5f4c8a8ac1b8 100644
--- a/src/coreclr/vm/qcallentrypoints.cpp
+++ b/src/coreclr/vm/qcallentrypoints.cpp
@@ -212,9 +212,6 @@ static const Entry s_QCall[] =
DllImportEntry(ThreadPool_GetCompletedWorkItemCount)
DllImportEntry(ThreadPool_RequestWorkerThread)
DllImportEntry(ThreadPool_PerformGateActivities)
- DllImportEntry(AppDomainTimer_Create)
- DllImportEntry(AppDomainTimer_Change)
- DllImportEntry(AppDomainTimer_Delete)
#ifdef TARGET_UNIX
DllImportEntry(WaitHandle_CorWaitOnePrioritizedNative)
#endif
diff --git a/src/coreclr/vm/threadpoolrequest.cpp b/src/coreclr/vm/threadpoolrequest.cpp
index 6e1caf5187650c..ddccec27b6d5d9 100644
--- a/src/coreclr/vm/threadpoolrequest.cpp
+++ b/src/coreclr/vm/threadpoolrequest.cpp
@@ -385,8 +385,7 @@ void UnManagedPerAppDomainTPCount::QueueUnmanagedWorkRequest(LPTHREAD_START_ROUT
_ASSERTE(pWorkRequest != NULL);
PREFIX_ASSUME(pWorkRequest != NULL);
- if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, ThreadPoolEnqueue) &&
- !ThreadpoolMgr::AreEtwQueueEventsSpeciallyHandled(function))
+ if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, ThreadPoolEnqueue))
FireEtwThreadPoolEnqueue(pWorkRequest, GetClrInstanceId());
m_lock.Init(LOCK_TYPE_DEFAULT);
@@ -493,8 +492,7 @@ void UnManagedPerAppDomainTPCount::DispatchWorkItem(bool* foundWork, bool* wasNo
wrFunction = pWorkRequest->Function;
wrContext = pWorkRequest->Context;
- if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, ThreadPoolDequeue) &&
- !ThreadpoolMgr::AreEtwQueueEventsSpeciallyHandled(wrFunction))
+ if (ETW_EVENT_ENABLED(MICROSOFT_WINDOWS_DOTNETRUNTIME_PROVIDER_DOTNET_Context, ThreadPoolDequeue))
FireEtwThreadPoolDequeue(pWorkRequest, GetClrInstanceId());
ThreadpoolMgr::FreeWorkRequest(pWorkRequest);
diff --git a/src/coreclr/vm/threads.cpp b/src/coreclr/vm/threads.cpp
index f7cdf70d02d195..85e0c6df70cc04 100644
--- a/src/coreclr/vm/threads.cpp
+++ b/src/coreclr/vm/threads.cpp
@@ -703,7 +703,7 @@ Thread* SetupThread()
pThread->SetThreadState(Thread::TS_CompletionPortThread);
pThread->SetBackground(TRUE);
}
- else if (IsTimerSpecialThread() || IsWaitSpecialThread())
+ else if (IsWaitSpecialThread())
{
pThread->SetThreadState(Thread::TS_TPWorkerThread);
pThread->SetBackground(TRUE);
@@ -794,7 +794,7 @@ Thread* SetupThread()
{
pThread->SetThreadState(Thread::TS_CompletionPortThread);
}
- else if (IsTimerSpecialThread() || IsWaitSpecialThread())
+ else if (IsWaitSpecialThread())
{
pThread->SetThreadState(Thread::TS_TPWorkerThread);
}
@@ -7183,7 +7183,6 @@ BOOL Thread::HaveExtraWorkForFinalizer()
LIMITED_METHOD_CONTRACT;
return RequireSyncBlockCleanup()
- || ThreadpoolMgr::HaveTimerInfosToFlush()
|| Thread::CleanupNeededForFinalizedThread()
|| (m_DetachCount > 0)
|| SystemDomain::System()->RequireAppDomainCleanup()
@@ -7231,9 +7230,6 @@ void Thread::DoExtraWorkForFinalizer()
Thread::CleanupDetachedThreads();
}
- // If there were any TimerInfos waiting to be released, they'll get flushed now
- ThreadpoolMgr::FlushQueueOfTimerInfos();
-
if (YieldProcessorNormalization::IsMeasurementScheduled())
{
GCX_PREEMP();
@@ -7585,7 +7581,7 @@ void ManagedThreadBase::KickOff(ADCallBackFcnType pTarget, LPVOID args)
ManagedThreadBase_FullTransition(pTarget, args, ManagedThread);
}
-// The IOCompletion, QueueUserWorkItem, AddTimer, RegisterWaitForSingleObject cases in the ThreadPool
+// The IOCompletion, QueueUserWorkItem, RegisterWaitForSingleObject cases in the ThreadPool
void ManagedThreadBase::ThreadPool(ADCallBackFcnType pTarget, LPVOID args)
{
WRAPPER_NO_CONTRACT;
diff --git a/src/coreclr/vm/threads.h b/src/coreclr/vm/threads.h
index 99b547bf639d5d..ee2ca0a1de9489 100644
--- a/src/coreclr/vm/threads.h
+++ b/src/coreclr/vm/threads.h
@@ -352,17 +352,6 @@ const CLONE_QUEUE_USER_APC_FLAGS SpecialUserModeApcWithContextFlags =
#endif // FEATURE_SPECIAL_USER_MODE_APC
-/***************************************************************************/
-// Public enum shared between thread and threadpool
-// These are two kinds of threadpool thread that the threadpool mgr needs
-// to keep track of
-enum ThreadpoolThreadType
-{
- WorkerThread,
- CompletionPortThread,
- WaitThread,
- TimerMgrThread
-};
//***************************************************************************
// Public functions
//
@@ -6013,7 +6002,7 @@ struct ManagedThreadBase
static void KickOff(ADCallBackFcnType pTarget,
LPVOID args);
- // The IOCompletion, QueueUserWorkItem, AddTimer, RegisterWaitForSingleObject cases in
+ // The IOCompletion, QueueUserWorkItem, RegisterWaitForSingleObject cases in
// the ThreadPool
static void ThreadPool(ADCallBackFcnType pTarget, LPVOID args);
diff --git a/src/coreclr/vm/win32threadpool.cpp b/src/coreclr/vm/win32threadpool.cpp
index e8e49f4179802a..609ac1c6a77b06 100644
--- a/src/coreclr/vm/win32threadpool.cpp
+++ b/src/coreclr/vm/win32threadpool.cpp
@@ -121,8 +121,6 @@ DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) unsigned int ThreadpoolMgr::LastDequeueTime;
SPTR_IMPL(WorkRequest,ThreadpoolMgr,WorkRequestHead); // Head of work request queue
SPTR_IMPL(WorkRequest,ThreadpoolMgr,WorkRequestTail); // Head of work request queue
-SVAL_IMPL(ThreadpoolMgr::LIST_ENTRY,ThreadpoolMgr,TimerQueue); // queue of timers
-
//unsigned int ThreadpoolMgr::LastCpuSamplingTime=0; // last time cpu utilization was sampled by gate thread
unsigned int ThreadpoolMgr::LastCPThreadCreation=0; // last time a completion port thread was created
unsigned int ThreadpoolMgr::NumberOfProcessors; // = NumberOfWorkerThreads - no. of blocked threads
@@ -136,21 +134,12 @@ ThreadpoolMgr::LIST_ENTRY ThreadpoolMgr::WaitThreadsHead;
CLRLifoSemaphore* ThreadpoolMgr::WorkerSemaphore;
CLRLifoSemaphore* ThreadpoolMgr::RetiredWorkerSemaphore;
-CrstStatic ThreadpoolMgr::TimerQueueCriticalSection;
-HANDLE ThreadpoolMgr::TimerThread=NULL;
-Thread *ThreadpoolMgr::pTimerThread=NULL;
-
-// Cacheline aligned, hot variable
-DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) DWORD ThreadpoolMgr::LastTickCount;
-
// Cacheline aligned, hot variable
DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) LONG ThreadpoolMgr::GateThreadStatus=GATE_THREAD_STATUS_NOT_RUNNING;
// Move out of from preceeding variables' cache line
DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) ThreadpoolMgr::RecycledListsWrapper ThreadpoolMgr::RecycledLists;
-ThreadpoolMgr::TimerInfo *ThreadpoolMgr::TimerInfosToBeRecycled = NULL;
-
BOOL ThreadpoolMgr::IsApcPendingOnWaitThread = FALSE;
#ifndef DACCESS_COMPILE
@@ -369,7 +358,6 @@ BOOL ThreadpoolMgr::Initialize()
{
WorkerCriticalSection.Init(CrstThreadpoolWorker);
}
- TimerQueueCriticalSection.Init(CrstThreadpoolTimerQueue);
if (!UsePortableThreadPool())
{
@@ -377,9 +365,6 @@ BOOL ThreadpoolMgr::Initialize()
InitializeListHead(&WaitThreadsHead);
}
- // initialize TimerQueue
- InitializeListHead(&TimerQueue);
-
if (!UsePortableThreadPoolForIO())
{
RetiredCPWakeupEvent = new CLREvent();
@@ -423,7 +408,6 @@ BOOL ThreadpoolMgr::Initialize()
{
WorkerCriticalSection.Destroy();
}
- TimerQueueCriticalSection.Destroy();
bExceptionCaught = TRUE;
}
@@ -4289,782 +4273,4 @@ BOOL ThreadpoolMgr::SufficientDelaySinceLastDequeue()
#endif
#endif
-/************************************************************************/
-
-struct CreateTimerThreadParams {
- CLREvent event;
- BOOL setupSucceeded;
-};
-
-BOOL ThreadpoolMgr::CreateTimerQueueTimer(PHANDLE phNewTimer,
- WAITORTIMERCALLBACK Callback,
- PVOID Parameter,
- DWORD DueTime,
- DWORD Period,
- ULONG Flag)
-{
- CONTRACTL
- {
- THROWS; // EnsureInitialized, CreateAutoEvent can throw
- if (GetThreadNULLOk()) {GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);} // There can be calls thru ICorThreadpool
- MODE_ANY;
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- EnsureInitialized();
-
- // For now we use just one timer thread. Consider using multiple timer threads if
- // number of timers in the queue exceeds a certain threshold. The logic and code
- // would be similar to the one for creating wait threads.
- if (NULL == TimerThread)
- {
- CrstHolder csh(&TimerQueueCriticalSection);
-
- // check again
- if (NULL == TimerThread)
- {
- CreateTimerThreadParams params;
- params.event.CreateAutoEvent(FALSE);
-
- params.setupSucceeded = FALSE;
-
- HANDLE TimerThreadHandle = Thread::CreateUtilityThread(Thread::StackSize_Small, TimerThreadStart, ¶ms, W(".NET Timer"));
-
- if (TimerThreadHandle == NULL)
- {
- params.event.CloseEvent();
- ThrowOutOfMemory();
- }
-
- {
- GCX_PREEMP();
- for(;;)
- {
- // if a host throws because it couldnt allocate another thread,
- // just retry the wait.
- if (SafeWait(¶ms.event,INFINITE, FALSE) != WAIT_TIMEOUT)
- break;
- }
- }
- params.event.CloseEvent();
-
- if (!params.setupSucceeded)
- {
- CloseHandle(TimerThreadHandle);
- *phNewTimer = NULL;
- return FALSE;
- }
-
- TimerThread = TimerThreadHandle;
- }
-
- }
-
-
- NewHolder timerInfoHolder;
- TimerInfo * timerInfo = new (nothrow) TimerInfo;
- if (NULL == timerInfo)
- ThrowOutOfMemory();
-
- timerInfoHolder.Assign(timerInfo);
-
- timerInfo->FiringTime = DueTime;
- timerInfo->Function = Callback;
- timerInfo->Context = Parameter;
- timerInfo->Period = Period;
- timerInfo->state = 0;
- timerInfo->flag = Flag;
- timerInfo->ExternalCompletionEvent = INVALID_HANDLE;
- timerInfo->ExternalEventSafeHandle = NULL;
-
- *phNewTimer = (HANDLE)timerInfo;
-
- BOOL status = QueueUserAPC((PAPCFUNC)InsertNewTimer,TimerThread,(size_t)timerInfo);
- if (FALSE == status)
- {
- *phNewTimer = NULL;
- return FALSE;
- }
-
- timerInfoHolder.SuppressRelease();
- return TRUE;
-}
-
-#ifdef _MSC_VER
-#ifdef HOST_64BIT
-#pragma warning (disable : 4716)
-#else
-#pragma warning (disable : 4715)
-#endif
-#endif
-DWORD WINAPI ThreadpoolMgr::TimerThreadStart(LPVOID p)
-{
- ClrFlsSetThreadType (ThreadType_Timer);
-
- STATIC_CONTRACT_THROWS;
- STATIC_CONTRACT_GC_TRIGGERS; // due to SetApartment
- STATIC_CONTRACT_MODE_PREEMPTIVE;
- /* cannot use contract because of SEH
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_PREEMPTIVE;
- }
- CONTRACTL_END;*/
-
- CreateTimerThreadParams* params = (CreateTimerThreadParams*)p;
-
- Thread* pThread = SetupThreadNoThrow();
-
- params->setupSucceeded = (pThread == NULL) ? 0 : 1;
- params->event.Set();
-
- if (pThread == NULL)
- return 0;
-
- pTimerThread = pThread;
- // Timer threads never die
-
- LastTickCount = GetTickCount();
-
-#ifdef FEATURE_COMINTEROP
- if (pThread->SetApartment(Thread::AS_InMTA) != Thread::AS_InMTA)
- {
- // @todo: should we log the failure
- return 0;
- }
-#endif // FEATURE_COMINTEROP
-
- for (;;)
- {
- // moved to its own function since EX_TRY consumes stack
-#ifdef _MSC_VER
-#pragma inline_depth (0) // the function containing EX_TRY can't be inlined here
-#endif
- TimerThreadFire();
-#ifdef _MSC_VER
-#pragma inline_depth (20)
-#endif
- }
-
- // unreachable
-}
-
-void ThreadpoolMgr::TimerThreadFire()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- }
- CONTRACTL_END;
-
- EX_TRY {
- DWORD timeout = FireTimers();
- ClrSleepEx(timeout, TRUE);
-
- // the thread could wake up either because an APC completed or the sleep timeout
- // in both case, we need to sweep the timer queue, firing timers, and readjusting
- // the next firing time
-
- }
- EX_CATCH {
- // Assert on debug builds since a dead timer thread is a fatal error
- _ASSERTE(FALSE);
- EX_RETHROW;
- }
- EX_END_CATCH(SwallowAllExceptions);
-}
-
-#ifdef _MSC_VER
-#ifdef HOST_64BIT
-#pragma warning (default : 4716)
-#else
-#pragma warning (default : 4715)
-#endif
-#endif
-
-// Executed as an APC in timer thread
-void ThreadpoolMgr::InsertNewTimer(TimerInfo* pArg)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- _ASSERTE(pArg);
- TimerInfo * timerInfo = pArg;
-
- if (timerInfo->state & TIMER_DELETE)
- { // timer was deleted before it could be registered
- DeleteTimer(timerInfo);
- return;
- }
-
- // set the firing time = current time + due time (note initially firing time = due time)
- DWORD currentTime = GetTickCount();
- if (timerInfo->FiringTime == (ULONG) -1)
- {
- timerInfo->state = TIMER_REGISTERED;
- timerInfo->refCount = 1;
-
- }
- else
- {
- timerInfo->FiringTime += currentTime;
-
- timerInfo->state = (TIMER_REGISTERED | TIMER_ACTIVE);
- timerInfo->refCount = 1;
-
- // insert the timer in the queue
- InsertTailList(&TimerQueue,(&timerInfo->link));
- }
-
- return;
-}
-
-
-// executed by the Timer thread
-// sweeps through the list of timers, readjusting the firing times, queueing APCs for
-// those that have expired, and returns the next firing time interval
-DWORD ThreadpoolMgr::FireTimers()
-{
- CONTRACTL
- {
- THROWS; // QueueUserWorkItem can throw
- if (GetThreadNULLOk()) { GC_TRIGGERS;} else {DISABLED(GC_NOTRIGGER);}
- if (GetThreadNULLOk()) { MODE_PREEMPTIVE;} else { DISABLED(MODE_ANY);}
- }
- CONTRACTL_END;
-
- DWORD currentTime = GetTickCount();
- DWORD nextFiringInterval = (DWORD) -1;
- TimerInfo* timerInfo = NULL;
-
- EX_TRY
- {
- for (LIST_ENTRY* node = (LIST_ENTRY*) TimerQueue.Flink;
- node != &TimerQueue;
- )
- {
- timerInfo = (TimerInfo*) node;
- node = (LIST_ENTRY*) node->Flink;
-
- if (TimeExpired(LastTickCount, currentTime, timerInfo->FiringTime))
- {
- if (timerInfo->Period == 0 || timerInfo->Period == (ULONG) -1)
- {
- DeactivateTimer(timerInfo);
- }
-
- InterlockedIncrement(&timerInfo->refCount);
-
- if (UsePortableThreadPool())
- {
- GCX_COOP();
-
- ARG_SLOT args[] = { PtrToArgSlot(AsyncTimerCallbackCompletion), PtrToArgSlot(timerInfo) };
- MethodDescCallSite(METHOD__THREAD_POOL__UNSAFE_QUEUE_UNMANAGED_WORK_ITEM).Call(args);
- }
- else
- {
- QueueUserWorkItem(AsyncTimerCallbackCompletion,
- timerInfo,
- QUEUE_ONLY /* TimerInfo take care of deleting*/);
- }
-
- if (timerInfo->Period != 0 && timerInfo->Period != (ULONG)-1)
- {
- ULONG nextFiringTime = timerInfo->FiringTime + timerInfo->Period;
- DWORD firingInterval;
- if (TimeExpired(timerInfo->FiringTime, currentTime, nextFiringTime))
- {
- // Enough time has elapsed to fire the timer yet again. The timer is not able to keep up with the short
- // period, have it fire 1 ms from now to avoid spinning without a delay.
- timerInfo->FiringTime = currentTime + 1;
- firingInterval = 1;
- }
- else
- {
- timerInfo->FiringTime = nextFiringTime;
- firingInterval = TimeInterval(nextFiringTime, currentTime);
- }
-
- if (firingInterval < nextFiringInterval)
- nextFiringInterval = firingInterval;
- }
- }
- else
- {
- DWORD firingInterval = TimeInterval(timerInfo->FiringTime, currentTime);
- if (firingInterval < nextFiringInterval)
- nextFiringInterval = firingInterval;
- }
- }
- }
- EX_CATCH
- {
- // If QueueUserWorkItem throws OOM, swallow the exception and retry on
- // the next call to FireTimers(), otherwise retrhow.
- Exception *ex = GET_EXCEPTION();
- // undo the call to DeactivateTimer()
- InterlockedDecrement(&timerInfo->refCount);
- timerInfo->state = timerInfo->state & TIMER_ACTIVE;
- InsertTailList(&TimerQueue, (&timerInfo->link));
- if (ex->GetHR() != E_OUTOFMEMORY)
- {
- EX_RETHROW;
- }
- }
- EX_END_CATCH(RethrowTerminalExceptions);
-
- LastTickCount = currentTime;
-
- return nextFiringInterval;
-}
-
-DWORD WINAPI ThreadpoolMgr::AsyncTimerCallbackCompletion(PVOID pArgs)
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- }
- CONTRACTL_END;
-
- Thread* pThread = GetThreadNULLOk();
- if (pThread == NULL)
- {
- HRESULT hr = ERROR_SUCCESS;
-
- ClrFlsSetThreadType(ThreadType_Threadpool_Worker);
- pThread = SetupThreadNoThrow(&hr);
-
- if (pThread == NULL)
- {
- return hr;
- }
- }
-
- {
- TimerInfo* timerInfo = (TimerInfo*) pArgs;
- ((WAITORTIMERCALLBACKFUNC) timerInfo->Function) (timerInfo->Context, TRUE) ;
-
- if (InterlockedDecrement(&timerInfo->refCount) == 0)
- {
- DeleteTimer(timerInfo);
- }
- }
-
- return ERROR_SUCCESS;
-}
-
-
-// removes the timer from the timer queue, thereby cancelling it
-// there may still be pending callbacks that haven't completed
-void ThreadpoolMgr::DeactivateTimer(TimerInfo* timerInfo)
-{
- LIMITED_METHOD_CONTRACT;
-
- RemoveEntryList((LIST_ENTRY*) timerInfo);
-
- // This timer info could go into another linked list of timer infos
- // waiting to be released. Reinitialize the list pointers
- InitializeListHead(&timerInfo->link);
- timerInfo->state = timerInfo->state & ~TIMER_ACTIVE;
-}
-
-DWORD WINAPI ThreadpoolMgr::AsyncDeleteTimer(PVOID pArgs)
-{
- CONTRACTL
- {
- THROWS;
- MODE_PREEMPTIVE;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- Thread * pThread = GetThreadNULLOk();
- if (pThread == NULL)
- {
- HRESULT hr = ERROR_SUCCESS;
-
- ClrFlsSetThreadType(ThreadType_Threadpool_Worker);
- pThread = SetupThreadNoThrow(&hr);
-
- if (pThread == NULL)
- {
- return hr;
- }
- }
-
- DeleteTimer((TimerInfo*) pArgs);
-
- return ERROR_SUCCESS;
-}
-
-void ThreadpoolMgr::DeleteTimer(TimerInfo* timerInfo)
-{
- CONTRACTL
- {
- if (GetThreadNULLOk() == pTimerThread) { NOTHROW; } else { THROWS; }
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- _ASSERTE((timerInfo->state & TIMER_ACTIVE) == 0);
-
- _ASSERTE(!(timerInfo->flag & WAIT_FREE_CONTEXT));
-
- if (timerInfo->flag & WAIT_INTERNAL_COMPLETION)
- {
- timerInfo->InternalCompletionEvent.Set();
- return; // the timerInfo will be deleted by the thread that's waiting on InternalCompletionEvent
- }
-
- // ExternalCompletionEvent comes from Host, ExternalEventSafeHandle from managed code.
- // They are mutually exclusive.
- _ASSERTE(!(timerInfo->ExternalCompletionEvent != INVALID_HANDLE &&
- timerInfo->ExternalEventSafeHandle != NULL));
-
- if (timerInfo->ExternalCompletionEvent != INVALID_HANDLE)
- {
- SetEvent(timerInfo->ExternalCompletionEvent);
- timerInfo->ExternalCompletionEvent = INVALID_HANDLE;
- }
-
- // We cannot block the timer thread, so some cleanup is deferred to other threads.
- if (GetThreadNULLOk() == pTimerThread)
- {
- // Notify the ExternalEventSafeHandle with an user work item
- if (timerInfo->ExternalEventSafeHandle != NULL)
- {
- BOOL success = FALSE;
- EX_TRY
- {
- if (QueueUserWorkItem(AsyncDeleteTimer,
- timerInfo,
- QUEUE_ONLY) != FALSE)
- {
- success = TRUE;
- }
- }
- EX_CATCH
- {
- }
- EX_END_CATCH(SwallowAllExceptions);
-
- // If unable to queue a user work item, fall back to queueing timer for release
- // which will happen *sometime* in the future.
- if (success == FALSE)
- {
- QueueTimerInfoForRelease(timerInfo);
- }
-
- return;
- }
-
- // Releasing GC handles can block. So we wont do this on the timer thread.
- // We'll put it in a list which will be processed by a worker thread
- if (timerInfo->Context != NULL)
- {
- QueueTimerInfoForRelease(timerInfo);
- return;
- }
- }
-
- // To get here we are either not the Timer thread or there is no blocking work to be done
-
- if (timerInfo->Context != NULL)
- {
- GCX_COOP();
- delete (ThreadpoolMgr::TimerInfoContext*)timerInfo->Context;
- }
-
- if (timerInfo->ExternalEventSafeHandle != NULL)
- {
- ReleaseTimerInfo(timerInfo);
- }
-
- delete timerInfo;
-
-}
-
-// We add TimerInfos from deleted timers into a linked list.
-// A worker thread will later release the handles held by the TimerInfo
-// and recycle them if possible.
-void ThreadpoolMgr::QueueTimerInfoForRelease(TimerInfo *pTimerInfo)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- // The synchronization in this method depends on the fact that
- // - There is only one timer thread
- // - The one and only timer thread is executing this method.
- // - This function wont go into an alertable state. That could trigger another APC.
- // Else two threads can be queueing timerinfos and a race could
- // lead to leaked memory and handles
- _ASSERTE(pTimerThread == GetThread());
- TimerInfo *pHead = NULL;
-
- // Make sure this timer info has been deactivated and removed from any other lists
- _ASSERTE((pTimerInfo->state & TIMER_ACTIVE) == 0);
- //_ASSERTE(pTimerInfo->link.Blink == &(pTimerInfo->link) &&
- // pTimerInfo->link.Flink == &(pTimerInfo->link));
- // Make sure "link" is the first field in TimerInfo
- _ASSERTE(pTimerInfo == (PVOID)&pTimerInfo->link);
-
- // Grab any previously published list
- if ((pHead = InterlockedExchangeT(&TimerInfosToBeRecycled, NULL)) != NULL)
- {
- // If there already is a list, just append
- InsertTailList((LIST_ENTRY *)pHead, &pTimerInfo->link);
- pTimerInfo = pHead;
- }
- else
- // If this is the head, make its next and previous ptrs point to itself
- InitializeListHead((LIST_ENTRY*)&pTimerInfo->link);
-
- // Publish the list
- (void) InterlockedExchangeT(&TimerInfosToBeRecycled, pTimerInfo);
-
-}
-
-void ThreadpoolMgr::FlushQueueOfTimerInfos()
-{
- CONTRACTL
- {
- THROWS;
- GC_TRIGGERS;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- TimerInfo *pHeadTimerInfo = NULL, *pCurrTimerInfo = NULL;
- LIST_ENTRY *pNextInfo = NULL;
-
- if ((pHeadTimerInfo = InterlockedExchangeT(&TimerInfosToBeRecycled, NULL)) == NULL)
- return;
-
- do
- {
- RemoveHeadList((LIST_ENTRY *)pHeadTimerInfo, pNextInfo);
- _ASSERTE(pNextInfo != NULL);
-
- pCurrTimerInfo = (TimerInfo *) pNextInfo;
-
- GCX_COOP();
- if (pCurrTimerInfo->Context != NULL)
- {
- delete (ThreadpoolMgr::TimerInfoContext*)pCurrTimerInfo->Context;
- }
-
- if (pCurrTimerInfo->ExternalEventSafeHandle != NULL)
- {
- ReleaseTimerInfo(pCurrTimerInfo);
- }
-
- delete pCurrTimerInfo;
-
- }
- while ((TimerInfo *)pNextInfo != pHeadTimerInfo);
-}
-
-/************************************************************************/
-BOOL ThreadpoolMgr::ChangeTimerQueueTimer(
- HANDLE Timer,
- ULONG DueTime,
- ULONG Period)
-{
- CONTRACTL
- {
- THROWS;
- MODE_ANY;
- GC_NOTRIGGER;
- INJECT_FAULT(COMPlusThrowOM());
- }
- CONTRACTL_END;
-
- _ASSERTE(IsInitialized());
- _ASSERTE(Timer); // not possible to give invalid handle in managed code
-
- NewHolder updateInfoHolder;
- TimerUpdateInfo *updateInfo = new TimerUpdateInfo;
- updateInfoHolder.Assign(updateInfo);
-
- updateInfo->Timer = (TimerInfo*) Timer;
- updateInfo->DueTime = DueTime;
- updateInfo->Period = Period;
-
- BOOL status = QueueUserAPC((PAPCFUNC)UpdateTimer,
- TimerThread,
- (size_t) updateInfo);
-
- if (status)
- updateInfoHolder.SuppressRelease();
-
- return(status);
-}
-
-void ThreadpoolMgr::UpdateTimer(TimerUpdateInfo* pArgs)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_NOTRIGGER;
- MODE_ANY;
- }
- CONTRACTL_END;
-
- TimerUpdateInfo* updateInfo = (TimerUpdateInfo*) pArgs;
- TimerInfo* timerInfo = updateInfo->Timer;
-
- timerInfo->Period = updateInfo->Period;
-
- if (updateInfo->DueTime == (ULONG) -1)
- {
- if (timerInfo->state & TIMER_ACTIVE)
- {
- DeactivateTimer(timerInfo);
- }
- // else, noop (the timer was already inactive)
- _ASSERTE((timerInfo->state & TIMER_ACTIVE) == 0);
-
- delete updateInfo;
- return;
- }
-
- DWORD currentTime = GetTickCount();
- timerInfo->FiringTime = currentTime + updateInfo->DueTime;
-
- delete updateInfo;
-
- if (! (timerInfo->state & TIMER_ACTIVE))
- {
- // timer not active (probably a one shot timer that has expired), so activate it
- timerInfo->state |= TIMER_ACTIVE;
- _ASSERTE(timerInfo->refCount >= 1);
- // insert the timer in the queue
- InsertTailList(&TimerQueue,(&timerInfo->link));
-
- }
-
- return;
-}
-
-/************************************************************************/
-BOOL ThreadpoolMgr::DeleteTimerQueueTimer(
- HANDLE Timer,
- HANDLE Event)
-{
- CONTRACTL
- {
- THROWS;
- MODE_ANY;
- GC_TRIGGERS;
- }
- CONTRACTL_END;
-
- _ASSERTE(IsInitialized()); // cannot call delete before creating timer
- _ASSERTE(Timer); // not possible to give invalid handle in managed code
-
- // make volatile to avoid compiler reordering check after async call.
- // otherwise, DeregisterTimer could delete timerInfo before the comparison.
- VolatilePtr timerInfo = (TimerInfo*) Timer;
-
- if (Event == (HANDLE) -1)
- {
- //CONTRACT_VIOLATION(ThrowsViolation);
- timerInfo->InternalCompletionEvent.CreateAutoEvent(FALSE);
- timerInfo->flag |= WAIT_INTERNAL_COMPLETION;
- }
- else if (Event)
- {
- timerInfo->ExternalCompletionEvent = Event;
- }
-#ifdef _DEBUG
- else /* Event == NULL */
- {
- _ASSERTE(timerInfo->ExternalCompletionEvent == INVALID_HANDLE);
- }
-#endif
-
- BOOL isBlocking = timerInfo->flag & WAIT_INTERNAL_COMPLETION;
-
- BOOL status = QueueUserAPC((PAPCFUNC)DeregisterTimer,
- TimerThread,
- (size_t)(TimerInfo*)timerInfo);
-
- if (FALSE == status)
- {
- if (isBlocking)
- timerInfo->InternalCompletionEvent.CloseEvent();
- return FALSE;
- }
-
- if (isBlocking)
- {
- _ASSERTE(timerInfo->ExternalEventSafeHandle == NULL);
- _ASSERTE(timerInfo->ExternalCompletionEvent == INVALID_HANDLE);
- _ASSERTE(GetThreadNULLOk() != pTimerThread);
-
- timerInfo->InternalCompletionEvent.Wait(INFINITE,TRUE /*alertable*/);
- timerInfo->InternalCompletionEvent.CloseEvent();
- // Release handles and delete TimerInfo
- _ASSERTE(timerInfo->refCount == 0);
- // if WAIT_INTERNAL_COMPLETION flag is not set, timerInfo will be deleted in DeleteTimer.
- timerInfo->flag &= ~WAIT_INTERNAL_COMPLETION;
- DeleteTimer(timerInfo);
- }
- return status;
-}
-
-void ThreadpoolMgr::DeregisterTimer(TimerInfo* pArgs)
-{
- CONTRACTL
- {
- NOTHROW;
- GC_TRIGGERS;
- MODE_PREEMPTIVE;
- }
- CONTRACTL_END;
-
- TimerInfo* timerInfo = (TimerInfo*) pArgs;
-
- if (! (timerInfo->state & TIMER_REGISTERED) )
- {
- // set state to deleted, so that it does not get registered
- timerInfo->state |= TIMER_DELETE ;
-
- // since the timer has not even been registered, we dont need an interlock to decrease the RefCount
- timerInfo->refCount--;
-
- return;
- }
-
- if (timerInfo->state & TIMER_ACTIVE)
- {
- DeactivateTimer(timerInfo);
- }
-
- if (InterlockedDecrement(&timerInfo->refCount) == 0 )
- {
- DeleteTimer(timerInfo);
- }
- return;
-}
-
#endif // !DACCESS_COMPILE
diff --git a/src/coreclr/vm/win32threadpool.h b/src/coreclr/vm/win32threadpool.h
index b08d7ca32e9c2f..b0fbe2531d374f 100644
--- a/src/coreclr/vm/win32threadpool.h
+++ b/src/coreclr/vm/win32threadpool.h
@@ -33,10 +33,6 @@ Revision History:
#define WAIT_ACTIVE 0x02
#define WAIT_DELETE 0x04
-#define TIMER_REGISTERED 0x01
-#define TIMER_ACTIVE 0x02
-#define TIMER_DELETE 0x04
-
#define WAIT_SINGLE_EXECUTION 0x00000001
#define WAIT_FREE_CONTEXT 0x00000002
#define WAIT_INTERNAL_COMPLETION 0x00000004
@@ -97,7 +93,6 @@ class ThreadpoolMgr
friend class ClrDataAccess;
friend struct DelegateInfo;
friend class ThreadPoolNative;
- friend class TimerNative;
friend class UnManagedPerAppDomainTPCount;
friend class ManagedPerAppDomainTPCount;
friend class PerAppDomainTPCountList;
@@ -219,10 +214,6 @@ class ThreadpoolMgr
MEMTYPE_COUNT = 3,
};
- typedef struct {
- INT32 TimerId;
- } TimerInfoContext;
-
#ifndef DACCESS_COMPILE
static void StaticInitialize()
{
@@ -318,25 +309,8 @@ class ThreadpoolMgr
VolatileStore(&LastDequeueTime, (unsigned int)GetTickCount());
}
- static BOOL CreateTimerQueueTimer(PHANDLE phNewTimer,
- WAITORTIMERCALLBACK Callback,
- PVOID Parameter,
- DWORD DueTime,
- DWORD Period,
- ULONG Flags);
-
- static BOOL ChangeTimerQueueTimer(HANDLE Timer,
- ULONG DueTime,
- ULONG Period);
- static BOOL DeleteTimerQueueTimer(HANDLE Timer,
- HANDLE CompletionEvent);
-
static void RecycleMemory(LPVOID mem, enum MemType memType);
- static void FlushQueueOfTimerInfos();
-
- static BOOL HaveTimerInfosToFlush() { return TimerInfosToBeRecycled != NULL; }
-
#ifndef TARGET_UNIX
static LPOVERLAPPED CompletionPortDispatchWorkWithinAppDomain(Thread* pThread, DWORD* pErrorCode, DWORD* pNumBytes, size_t* pKey);
static void StoreOverlappedInfoInThread(Thread* pThread, DWORD dwErrorCode, DWORD dwNumBytes, size_t key, LPOVERLAPPED lpOverlapped);
@@ -345,12 +319,6 @@ class ThreadpoolMgr
// Enable filtering of correlation ETW events for cases handled at a higher abstraction level
#ifndef DACCESS_COMPILE
- static FORCEINLINE BOOL AreEtwQueueEventsSpeciallyHandled(LPTHREAD_START_ROUTINE Function)
- {
- // Timer events are handled at a higher abstraction level: in the managed Timer class
- return (Function == ThreadpoolMgr::AsyncTimerCallbackCompletion);
- }
-
static FORCEINLINE BOOL AreEtwIOQueueEventsSpeciallyHandled(LPOVERLAPPED_COMPLETION_ROUTINE Function)
{
// We handle registered waits at a higher abstraction level
@@ -568,21 +536,6 @@ class ThreadpoolMgr
HANDLE Handle;
} WaitEvent ;
- // Timer
- typedef struct {
- LIST_ENTRY link; // doubly linked list of timers
- ULONG FiringTime; // TickCount of when to fire next
- WAITORTIMERCALLBACK Function; // Function to call when timer fires
- PVOID Context; // Context to pass to function when timer fires
- ULONG Period;
- DWORD flag; // How do we deal with the context
- DWORD state;
- LONG refCount;
- HANDLE ExternalCompletionEvent; // only one of this is used, but cant do a union since CLREvent has a non-default constructor
- CLREvent InternalCompletionEvent; // flags indicates which one is being used
- OBJECTHANDLE ExternalEventSafeHandle;
- } TimerInfo;
-
static VOID AcquireWaitInfo(WaitInfo *pInfo)
{
}
@@ -594,26 +547,8 @@ class ThreadpoolMgr
pInfo->ExternalCompletionEvent);
#endif
}
- static VOID AcquireTimerInfo(TimerInfo *pInfo)
- {
- }
- static VOID ReleaseTimerInfo(TimerInfo *pInfo)
- {
- WRAPPER_NO_CONTRACT;
-#ifndef DACCESS_COMPILE
- ReleaseInfo(pInfo->ExternalEventSafeHandle,
- pInfo->ExternalCompletionEvent);
-#endif
- }
typedef Holder WaitInfoHolder;
- typedef Holder TimerInfoHolder;
-
- typedef struct {
- TimerInfo* Timer; // timer to be updated
- ULONG DueTime ; // new due time
- ULONG Period ; // new period
- } TimerUpdateInfo;
// Definitions and data structures to support recycling of high-frequency
// memory blocks. We use a spin-lock to access the list
@@ -913,8 +848,6 @@ class ThreadpoolMgr
static DWORD WINAPI AsyncCallbackCompletion(PVOID pArgs);
- static void QueueTimerInfoForRelease(TimerInfo *pTimerInfo);
-
static void DeactivateWait(WaitInfo* waitInfo);
static void DeactivateNthWait(WaitInfo* waitInfo, DWORD index);
@@ -985,18 +918,6 @@ class ThreadpoolMgr
static LPVOID GetRecycledMemory(enum MemType memType);
- static DWORD WINAPI TimerThreadStart(LPVOID args);
- static void TimerThreadFire(); // helper method used by TimerThreadStart
- static void WINAPI InsertNewTimer(TimerInfo* pArg);
- static DWORD FireTimers();
- static DWORD WINAPI AsyncTimerCallbackCompletion(PVOID pArgs);
- static void DeactivateTimer(TimerInfo* timerInfo);
- static DWORD WINAPI AsyncDeleteTimer(PVOID pArgs);
- static void DeleteTimer(TimerInfo* timerInfo);
- static void WINAPI UpdateTimer(TimerUpdateInfo* pArgs);
-
- static void WINAPI DeregisterTimer(TimerInfo* pArgs);
-
inline static DWORD QueueDeregisterWait(HANDLE waitThread, WaitInfo* waitInfo)
{
CONTRACTL
@@ -1085,13 +1006,6 @@ class ThreadpoolMgr
static CrstStatic WaitThreadsCriticalSection;
static LIST_ENTRY WaitThreadsHead; // queue of wait threads, each thread can handle upto 64 waits
- static TimerInfo *TimerInfosToBeRecycled; // list of delegate infos associated with deleted timers
- static CrstStatic TimerQueueCriticalSection; // critical section to synchronize timer queue access
- SVAL_DECL(LIST_ENTRY,TimerQueue); // queue of timers
- static HANDLE TimerThread; // Currently we only have one timer thread
- static Thread* pTimerThread;
- DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) static DWORD LastTickCount; // the count just before timer thread goes to sleep
-
static BOOL InitCompletionPortThreadpool; // flag indicating whether completion port threadpool has been initialized
static HANDLE GlobalCompletionPort; // used for binding io completions on file handles
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/TimerQueue.Portable.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/TimerQueue.Portable.cs
index 1177300c711d70..2816f0ab6a858e 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/TimerQueue.Portable.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/TimerQueue.Portable.cs
@@ -40,7 +40,7 @@ private static List InitializeScheduledTimerManager_Locked()
// using UnsafeStart() instead of Start()
Thread timerThread = new Thread(TimerThread)
{
- Name = ".NET Timers",
+ Name = ".NET Timer",
IsBackground = true
};
timerThread.UnsafeStart();