[Tizen] Unify dnetmemoryenumlib terms to match the codebase (#291)
[platform/upstream/coreclr.git] / src / vm / threadpoolrequest.h
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.
4
5 //=========================================================================
6
7 //
8 // ThreadPoolRequest.h
9 //
10
11 //
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.
17 //
18 //=========================================================================
19
20 #ifndef _THREADPOOL_REQUEST_H
21 #define _THREADPOOL_REQUEST_H
22
23 #include "util.hpp"
24
25 #define TP_QUANTUM 2
26 #define UNUSED_THREADPOOL_INDEX (DWORD)-1
27
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.
33 //
34 //Notes:
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
40 //class.
41 //
42
43 class IPerAppDomainTPCount{  
44 public:
45     virtual void ResetState() = 0;
46     virtual BOOL IsRequestPending() = 0;
47
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;
51
52     //This functions marks the end of requests queued for this domain.
53     virtual void ClearAppDomainRequestsActive() = 0;
54
55     //Clears the "active" flag if it was set, and returns whether it was set.
56     virtual bool TakeActiveRequest() = 0;
57
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; 
63 };
64
65 typedef DPTR(IPerAppDomainTPCount) PTR_IPerAppDomainTPCount;
66
67 #ifdef _MSC_VER
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())
70 #endif
71
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.
77 //
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 {
83 public:
84
85     ManagedPerAppDomainTPCount(TPIndex index) {ResetState(); m_index = index;}
86
87     inline void ResetState()
88     {
89         LIMITED_METHOD_CONTRACT;
90         VolatileStore(&m_numRequestsPending, (LONG)0);
91     }
92     
93     inline BOOL IsRequestPending()
94     {
95         LIMITED_METHOD_CONTRACT;
96
97         LONG count = VolatileLoad(&m_numRequestsPending);
98         return count > 0;
99     }
100
101     void SetAppDomainRequestsActive();
102     void ClearAppDomainRequestsActive();
103     bool TakeActiveRequest();
104
105     inline void SetTPIndex(TPIndex index) 
106     {
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.
111
112         _ASSERTE(m_index.m_dwIndex == UNUSED_THREADPOOL_INDEX);
113
114         m_index = index;
115     }
116     
117     inline BOOL IsTPIndexUnused()
118     {
119         LIMITED_METHOD_CONTRACT;
120         if (m_index.m_dwIndex == UNUSED_THREADPOOL_INDEX)
121         {
122             return TRUE;
123         }
124
125         return FALSE;
126     }
127
128     inline void SetTPIndexUnused()
129     {
130         WRAPPER_NO_CONTRACT;
131         m_index.m_dwIndex = UNUSED_THREADPOOL_INDEX;
132     }
133
134     void DispatchWorkItem(bool* foundWork, bool* wasNotRecalled);
135
136 private:
137     TPIndex m_index;
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];
143     };
144 };
145
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 {
152 public:
153
154     UnManagedPerAppDomainTPCount() 
155     {
156         LIMITED_METHOD_CONTRACT;
157         ResetState();
158     }
159
160     inline void InitResources()
161     {
162         CONTRACTL
163         {
164             THROWS;
165             MODE_ANY;
166             GC_NOTRIGGER;
167             INJECT_FAULT(COMPlusThrowOM());
168         }
169         CONTRACTL_END;
170
171     }    
172
173     inline void CleanupResources()
174     {
175     }    
176
177     inline void ResetState()
178     {
179         LIMITED_METHOD_CONTRACT;
180         m_NumRequests = 0;
181         VolatileStore(&m_outstandingThreadRequestCount, (LONG)0);
182     }
183
184     inline BOOL IsRequestPending()
185     {
186         LIMITED_METHOD_CONTRACT;
187         return VolatileLoad(&m_outstandingThreadRequestCount) != (LONG)0 ? TRUE : FALSE;
188     }
189
190     void SetAppDomainRequestsActive();
191     
192     inline void ClearAppDomainRequestsActive()
193     {
194         LIMITED_METHOD_CONTRACT;
195         VolatileStore(&m_outstandingThreadRequestCount, (LONG)0);
196     }
197
198     bool TakeActiveRequest();
199
200     void QueueUnmanagedWorkRequest(LPTHREAD_START_ROUTINE  function, PVOID context);
201     PVOID DeQueueUnManagedWorkRequest(bool* lastOne);
202
203     void DispatchWorkItem(bool* foundWork, bool* wasNotRecalled);
204
205     inline void SetTPIndexUnused()
206     {        
207         WRAPPER_NO_CONTRACT;
208         _ASSERT(FALSE);
209     }
210
211     inline BOOL IsTPIndexUnused()
212     {
213         WRAPPER_NO_CONTRACT;
214         _ASSERT(FALSE);
215         return FALSE; 
216     }
217
218     inline void SetTPIndex(TPIndex index) 
219     {
220         WRAPPER_NO_CONTRACT;
221         _ASSERT(FALSE); 
222     }   
223
224     inline ULONG GetNumRequests()
225     {
226         LIMITED_METHOD_CONTRACT;
227         return VolatileLoad(&m_NumRequests);
228     }
229
230 private:
231     SpinLock m_lock;
232     ULONG 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];
238     };
239 };
240
241 #ifdef _MSC_VER
242 #pragma warning(default: 4324)  // structure was padded due to __declspec(align())
243 #endif
244
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.
253 //
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{
259 public:
260     static void InitAppDomainIndexList();    
261     static void ResetAppDomainIndex(TPIndex index);
262     static bool AreRequestsPendingInAnyAppDomains();
263     static LONG GetAppDomainIndexForThreadpoolDispatch();
264     static TPIndex AddNewTPIndex();
265
266     inline static IPerAppDomainTPCount* GetPerAppdomainCount(TPIndex index)
267     {
268         return dac_cast<PTR_IPerAppDomainTPCount>(s_appDomainIndexList.Get(index.m_dwIndex-1));
269     }
270
271     inline static UnManagedPerAppDomainTPCount* GetUnmanagedTPCount()
272     {
273         return &s_unmanagedTPCount;
274     }
275
276 private:
277     static DWORD FindFirstFreeTpEntry();
278
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;
282
283     //The list of all per-appdomain work-request counts.
284     static ArrayListStatic s_appDomainIndexList;
285 };
286
287 #endif //_THREADPOOL_REQUEST_H