1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 //=========================================================================
12 // This file contains definitions of classes needed to mainain per-appdomain
13 // thread pool work requests. This is needed as unmanaged and managed work
14 // requests are allocted, managed and dispatched in drastically different ways.
15 // However, the scheduler need be aware of these differences, and it should
16 // simply talk to a common interface for managing work request counts.
18 //=========================================================================
20 #ifndef _THREADPOOL_REQUEST_H
21 #define _THREADPOOL_REQUEST_H
26 #define UNUSED_THREADPOOL_INDEX (DWORD)-1
28 //--------------------------------------------------------------------------
29 //IPerAppDomainTPCount is an interface for implementing per-appdomain thread
30 //pool state. It's implementation should include logic to maintain work-counts,
31 //notify thread pool class when work arrives or no work is left. Finally
32 //there is logic to dipatch work items correctly in the right domain.
35 //This class was designed to support both the managed and unmanaged uses
36 //of thread pool. The unmananged part may directly be used through com
37 //interfaces. The differences between the actual management of counts and
38 //dispatching of work is quite different between the two. This interface
39 //hides these differences to the thread scheduler implemented by the thread pool
43 class IPerAppDomainTPCount{
45 virtual void ResetState() = 0;
46 virtual BOOL IsRequestPending() = 0;
48 //This functions marks the begining of requests queued for the domain.
49 //It needs to notify the scheduler of work-arrival among other things.
50 virtual void SetAppDomainRequestsActive() = 0;
52 //This functions marks the end of requests queued for this domain.
53 virtual void ClearAppDomainRequestsActive() = 0;
55 //Clears the "active" flag if it was set, and returns whether it was set.
56 virtual bool TakeActiveRequest() = 0;
58 //Takes care of dispatching requests in the right domain.
59 virtual void DispatchWorkItem(bool* foundWork, bool* wasNotRecalled) = 0;
60 virtual void SetTPIndexUnused() = 0;
61 virtual BOOL IsTPIndexUnused() = 0;
62 virtual void SetTPIndex(TPIndex index) = 0;
65 typedef DPTR(IPerAppDomainTPCount) PTR_IPerAppDomainTPCount;
68 // Disable this warning - we intentionally want __declspec(align()) to insert padding for us
69 #pragma warning(disable: 4324) // structure was padded due to __declspec(align())
72 //--------------------------------------------------------------------------
73 //ManagedPerAppDomainTPCount maintains per-appdomain thread pool state.
74 //This class maintains the count of per-appdomain work-items queued by
75 //ThreadPool.QueueUserWorkItem. It also dispatches threads in the appdomain
76 //correctly by setting up the right exception handling frames etc.
78 //Note: The counts are not accurate, and neither do they need to be. The
79 //actual work queue is in managed (implemented in threadpool.cs). This class
80 //just provides heuristics to the thread pool scheduler, along with
81 //synchronization to indicate start/end of requests to the scheduler.
82 class ManagedPerAppDomainTPCount : public IPerAppDomainTPCount {
85 ManagedPerAppDomainTPCount(TPIndex index) {ResetState(); m_index = index;}
87 inline void ResetState()
89 LIMITED_METHOD_CONTRACT;
90 VolatileStore(&m_numRequestsPending, (LONG)0);
93 inline BOOL IsRequestPending()
95 LIMITED_METHOD_CONTRACT;
97 LONG count = VolatileLoad(&m_numRequestsPending);
101 void SetAppDomainRequestsActive();
102 void ClearAppDomainRequestsActive();
103 bool TakeActiveRequest();
105 inline void SetTPIndex(TPIndex index)
107 LIMITED_METHOD_CONTRACT;
108 //This function should be called during appdomain creation when no managed code
109 //has started running yet. That implies, no requests should be pending
110 //or dispatched to this structure yet.
112 _ASSERTE(m_index.m_dwIndex == UNUSED_THREADPOOL_INDEX);
117 inline BOOL IsTPIndexUnused()
119 LIMITED_METHOD_CONTRACT;
120 if (m_index.m_dwIndex == UNUSED_THREADPOOL_INDEX)
128 inline void SetTPIndexUnused()
131 m_index.m_dwIndex = UNUSED_THREADPOOL_INDEX;
134 void DispatchWorkItem(bool* foundWork, bool* wasNotRecalled);
138 struct DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) {
139 BYTE m_padding1[MAX_CACHE_LINE_SIZE - sizeof(LONG)];
140 // Only use with VolatileLoad+VolatileStore+FastInterlockCompareExchange
141 LONG m_numRequestsPending;
142 BYTE m_padding2[MAX_CACHE_LINE_SIZE];
146 //--------------------------------------------------------------------------
147 //UnManagedPerAppDomainTPCount maintains the thread pool state/counts for
148 //unmanaged work requests. From thread pool point of view we treat unmanaged
149 //requests as a special "appdomain". This helps in scheduling policies, and
150 //follow same fairness policies as requests in other appdomains.
151 class UnManagedPerAppDomainTPCount : public IPerAppDomainTPCount {
154 UnManagedPerAppDomainTPCount()
156 LIMITED_METHOD_CONTRACT;
160 inline void InitResources()
167 INJECT_FAULT(COMPlusThrowOM());
173 inline void CleanupResources()
177 inline void ResetState()
179 LIMITED_METHOD_CONTRACT;
181 VolatileStore(&m_outstandingThreadRequestCount, (LONG)0);
184 inline BOOL IsRequestPending()
186 LIMITED_METHOD_CONTRACT;
187 return VolatileLoad(&m_outstandingThreadRequestCount) != (LONG)0 ? TRUE : FALSE;
190 void SetAppDomainRequestsActive();
192 inline void ClearAppDomainRequestsActive()
194 LIMITED_METHOD_CONTRACT;
195 VolatileStore(&m_outstandingThreadRequestCount, (LONG)0);
198 bool TakeActiveRequest();
200 void QueueUnmanagedWorkRequest(LPTHREAD_START_ROUTINE function, PVOID context);
201 PVOID DeQueueUnManagedWorkRequest(bool* lastOne);
203 void DispatchWorkItem(bool* foundWork, bool* wasNotRecalled);
205 inline void SetTPIndexUnused()
211 inline BOOL IsTPIndexUnused()
218 inline void SetTPIndex(TPIndex index)
224 inline ULONG GetNumRequests()
226 LIMITED_METHOD_CONTRACT;
227 return VolatileLoad(&m_NumRequests);
233 struct DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) {
234 BYTE m_padding1[MAX_CACHE_LINE_SIZE - sizeof(LONG)];
235 // Only use with VolatileLoad+VolatileStore+FastInterlockCompareExchange
236 LONG m_outstandingThreadRequestCount;
237 BYTE m_padding2[MAX_CACHE_LINE_SIZE];
242 #pragma warning(default: 4324) // structure was padded due to __declspec(align())
245 //--------------------------------------------------------------------------
246 //PerAppDomainTPCountList maintains the collection of per-appdomain thread
247 //pool states. Per appdomain counts are added to the list during appdomain
248 //creation inside the sdomain lock. The counts are reset during appdomain
249 //unload after all the threads have
250 //This class maintains the count of per-appdomain work-items queued by
251 //ThreadPool.QueueUserWorkItem. It also dispatches threads in the appdomain
252 //correctly by setting up the right exception handling frames etc.
254 //Note: The counts are not accurate, and neither do they need to be. The
255 //actual work queue is in managed (implemented in threadpool.cs). This class
256 //just provides heuristics to the thread pool scheduler, along with
257 //synchronization to indicate start/end of requests to the scheduler.
258 class PerAppDomainTPCountList{
260 static void InitAppDomainIndexList();
261 static void ResetAppDomainIndex(TPIndex index);
262 static bool AreRequestsPendingInAnyAppDomains();
263 static LONG GetAppDomainIndexForThreadpoolDispatch();
264 static TPIndex AddNewTPIndex();
266 inline static IPerAppDomainTPCount* GetPerAppdomainCount(TPIndex index)
268 return dac_cast<PTR_IPerAppDomainTPCount>(s_appDomainIndexList.Get(index.m_dwIndex-1));
271 inline static UnManagedPerAppDomainTPCount* GetUnmanagedTPCount()
273 return &s_unmanagedTPCount;
277 static DWORD FindFirstFreeTpEntry();
279 static BYTE s_padding[MAX_CACHE_LINE_SIZE - sizeof(LONG)];
280 DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) static LONG s_ADHint;
281 DECLSPEC_ALIGN(MAX_CACHE_LINE_SIZE) static UnManagedPerAppDomainTPCount s_unmanagedTPCount;
283 //The list of all per-appdomain work-request counts.
284 static ArrayListStatic s_appDomainIndexList;
287 #endif //_THREADPOOL_REQUEST_H