Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

374 lines
12 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. EXECQ.H
  5. Abstract:
  6. Defines classes related to execution queues.
  7. Classes defined:
  8. CExecRequest An abstract request.
  9. CExecQueue A queue of requests with an associated thread
  10. History:
  11. 23-Jul-96 a-raymcc Created.
  12. 3/10/97 a-levn Fully documented
  13. 9/6/97 a-levn Rewrote for thread pool
  14. --*/
  15. #ifndef __EXECQUEUE__H_
  16. #define __EXECQUEUE__H_
  17. #include "sync.h"
  18. #include "wbemutil.h"
  19. #ifdef __COLLECT_ALLOC_STAT
  20. #include "stackcom.h"
  21. #endif
  22. //******************************************************************************
  23. //******************************************************************************
  24. //
  25. // class CExecRequest
  26. //
  27. // Abstract base class for any schedulable request
  28. //
  29. //******************************************************************************
  30. //
  31. // Execute
  32. //
  33. // Primary method. Executes the request, whatever that means.
  34. //
  35. // Returns:
  36. //
  37. // int: return code. 0 means success, everything else --- failure.
  38. // Exact error codes are request-specific.
  39. //
  40. //******************************************************************************
  41. class POLARITY CExecRequest
  42. {
  43. protected:
  44. HANDLE m_hWhenDone;
  45. CExecRequest* m_pNext;
  46. long m_lPriority;
  47. bool m_fOk;
  48. public:
  49. void SetWhenDoneHandle(HANDLE h) {m_hWhenDone = h;}
  50. HANDLE GetWhenDoneHandle() {return m_hWhenDone;}
  51. void SetNext(CExecRequest* pNext) {m_pNext = pNext;}
  52. CExecRequest* GetNext() {return m_pNext;}
  53. void SetPriority(long lPriority) {m_lPriority = lPriority;}
  54. long GetPriority() {return m_lPriority;}
  55. virtual void DumpError(){ DEBUGTRACE((LOG_WBEMCORE,
  56. "No additional info\n"));};
  57. bool IsOk( void ) { return m_fOk; }
  58. public:
  59. CExecRequest();
  60. virtual ~CExecRequest();
  61. virtual HRESULT Execute() = 0;
  62. };
  63. //******************************************************************************
  64. //******************************************************************************
  65. //
  66. // class CExecQueue
  67. //
  68. // CExecQueue represents the concept of a queue of requests with an associated
  69. // thread to execute those requests. In a lot of respects, it is similar to
  70. // a message queue. Requests are added to the queue (which is represented by
  71. // an array) and the thread (created by the Run function) picks them up one
  72. // by one and executes them.
  73. //
  74. // The trick is what to do if while processing one request, another one
  75. // is generated and needs to be processed before the first one succeeds. This
  76. // is similar to a SendMessage, but trickier: the thread generating the new
  77. // request may not be the thread attached to the queue!
  78. //
  79. // To overcome this problem, we make all our waits interruptible in the
  80. // following sense. Whenever the thread attached to the queue needs to block
  81. // waiting for something to happen (which is when another thread may post a
  82. // new request and deadlock the system), it uses QueueWaitForSingleObject
  83. // instead. This function will wait for the object that the thread wanted to
  84. // wait for but it will also wake up if a new Critical request is added to
  85. // the queue and process any such request while waiting.
  86. //
  87. // See QueueWaitForSingleObject for details.
  88. //
  89. // Operations of CExecQueue are protected by a critical section, so multiple
  90. // threads can add requests simultaneously.
  91. //
  92. //******************************************************************************
  93. //
  94. // Constructor
  95. //
  96. // Creates and initializes all the synchronization objects, as well as the
  97. // thread local storage required by QueueWaitForSingleObject.
  98. //
  99. //******************************************************************************
  100. //
  101. // Destructor
  102. //
  103. // Deletes synchronization objects.
  104. //
  105. //******************************************************************************
  106. //
  107. // virtual Enqueue
  108. //
  109. // Adds a request to the queue. The acction depends on whether the request is
  110. // critical or not. If not, it is added to the queue and the semaphor of
  111. // non-critical requests is incremented. The processing thread will pick it up
  112. // in FIFO order. If critical, request is added to the front of the queye and
  113. // the semaphor of critical requests is incremented. This will cause the
  114. // processing thread to take this request the next time it enters into a
  115. // waiting state (see QueueWaitForSingleObject).
  116. //
  117. //******************************************************************************
  118. //
  119. // QueueWaitForSingleObject
  120. //
  121. // The core of the trick. In WINMGMT, whenever a thread needs to wait for an
  122. // object, it calls this function instead. This function checks if the calling
  123. // thread is the registered processing thread for any CExecQueue object (by
  124. // looking up the m_dwTlsIndex thread local variable for the thread). If it
  125. // is not, the function simply calls WaitForSingleObject.
  126. //
  127. // If it is, the function queries the queue for the semaphore indicating the
  128. // number of critical requests on the queue. It then calls
  129. // WaitForMultipleObjects with the original handle and the semaphore. If the
  130. // semaphore is signaled during the wait (or was singlaled when we came in),
  131. // this function picks up the first requests on the queue and executes it;
  132. // once that request is complete, it resumes the wait (with adjusted timeout).
  133. //
  134. // Parameters:
  135. //
  136. // HANDLE hHandle The handle of synchronization object to wait for.
  137. // DWORD dwTimeout Timeout in milliseconds.
  138. //
  139. // Returns:
  140. //
  141. // Same values as WaitForSingleObject:
  142. // WAIT_OBJECT_0 hHandle became signaled
  143. // WAIT_TIMEOUT Timed out.
  144. //
  145. //******************************************************************************
  146. //**************************** protected ***************************************
  147. //
  148. // Register
  149. //
  150. // Registers the calling thread as the processing thread of this queue by
  151. // storing the pointer to the queue in the m_dwTlsIndex thread local storage
  152. // variable. QueueWaitForSingleObject reads this index to interrupt waits
  153. // when needed (see QueueWaitForSingleObject).
  154. //
  155. // Returns:
  156. //
  157. // CExecQueue*: the previous CExecQueue this thread was registered for,
  158. // or NULL if none. The caller MUST not delete this object.
  159. //
  160. //******************************************************************************
  161. //
  162. // ThreadMain
  163. //
  164. // This is the function that the thread created by Run executes. It sits in
  165. // an infinite loop, retrieving requests and executing them one by one.
  166. // This function never returns.
  167. //
  168. //******************************************************************************
  169. //
  170. // Dequeue
  171. //
  172. // Retrieves the request at the head of the queue and removes it from the
  173. // queue.
  174. //
  175. // Returns:
  176. //
  177. // CExecRequest*: the request that was at the head of the queue, or NULL
  178. // if the queue was empty. The caller must delete this
  179. // object when no longer needed.
  180. //
  181. //******************************************************************************
  182. //
  183. // static _ThreadEntry
  184. //
  185. // Stub function used to create the tread. Calls ThreadEntry on the real
  186. // CExecQueue.
  187. //
  188. // Parameters:
  189. //
  190. // LPVOID pObj Actually CExecQueue* to the queue this thread is
  191. // supposed to serve.
  192. //
  193. // Returns:
  194. //
  195. // never.
  196. //
  197. //******************************************************************************
  198. //
  199. // static InitTls
  200. //
  201. // Invoked only once during the life of the system (not the life of a queue),
  202. // creates a thread local storage location where the pointer to the queue is
  203. // stored for the attached threads (see Register and QueueWaitForSingleObject)
  204. //
  205. //******************************************************************************
  206. //
  207. // GetNormalReadyHandle
  208. //
  209. // Returns the handle to the semaphore which contains the number of
  210. // non-critical requests currently on the queue.
  211. //
  212. // Returns:
  213. //
  214. // HANDLE: the the semaphore
  215. //
  216. //******************************************************************************
  217. //
  218. // GetCriticalReadyHandle
  219. //
  220. // Returns the handle to the semaphore which contains the number of
  221. // critical requests currently on the queue.
  222. //
  223. // Returns:
  224. //
  225. // HANDLE: the the semaphore
  226. //
  227. //******************************************************************************
  228. //
  229. // Execute
  230. //
  231. // Dequeues and executes a single request.
  232. //
  233. //******************************************************************************
  234. class POLARITY CExecQueue
  235. {
  236. protected:
  237. class CThreadRecord
  238. {
  239. public:
  240. CExecQueue* m_pQueue;
  241. CExecRequest* m_pCurrentRequest;
  242. BOOL m_bReady;
  243. BOOL m_bExitNow;
  244. HANDLE m_hThread;
  245. HANDLE m_hAttention;
  246. public:
  247. CThreadRecord(CExecQueue* pQueue);
  248. ~CThreadRecord();
  249. void Signal();
  250. };
  251. protected:
  252. static long mstatic_lNumInits;
  253. long m_lRef;
  254. CCritSec m_cs;
  255. CFlexArray m_aThreads;
  256. CExecRequest* m_pHead;
  257. CExecRequest* m_pTail;
  258. long m_lNumThreads;
  259. long m_lNumIdle;
  260. long m_lNumRequests;
  261. long m_lMaxThreads;
  262. long m_lHiPriBound;
  263. long m_lHiPriMaxThreads;
  264. long m_lStartSlowdownCount;
  265. long m_lAbsoluteLimitCount;
  266. long m_lOneSecondDelayCount;
  267. double m_dblAlpha;
  268. double m_dblBeta;
  269. DWORD m_dwTimeout;
  270. DWORD m_dwOverflowTimeout;
  271. BOOL m_bShutDonwCalled;
  272. protected:
  273. virtual void ThreadMain(CThreadRecord* pRecord);
  274. virtual void LogError(CExecRequest* pRequest, int nRes);
  275. static DWORD WINAPI _ThreadEntry(LPVOID pObj);
  276. static void InitTls();
  277. virtual HRESULT InitializeThread();
  278. virtual void UninitializeThread();
  279. virtual BOOL CreateNewThread();
  280. static void Register(CThreadRecord* pRecord);
  281. virtual void ShutdownThread(CThreadRecord* pRecord);
  282. virtual BOOL IsSuitableThread(CThreadRecord* pRecord, CExecRequest* pReq);
  283. virtual BOOL DoesNeedNewThread(CExecRequest* pReq);
  284. virtual BOOL IsIdleTooLong(CThreadRecord* pRecord, DWORD dwIdle);
  285. virtual DWORD GetIdleTimeout(CThreadRecord* pRecord);
  286. virtual BOOL IsAppropriateThread();
  287. virtual DWORD WaitForSingleObjectWhileBusy(HANDLE hHandle, DWORD dwWait,
  288. CThreadRecord* pRecord);
  289. virtual DWORD UnblockedWaitForSingleObject(HANDLE hHandle, DWORD dwWait,
  290. CThreadRecord* pRecord);
  291. virtual BOOL Execute(CThreadRecord* pRecord);
  292. virtual BOOL IsSTA() {return FALSE;}
  293. virtual CExecRequest* SearchForSuitableRequest(CThreadRecord* pRecord);
  294. virtual void SitOutPenalty(long lRequestIndex);
  295. virtual DWORD CalcSitOutPenalty(long lRequestIndex);
  296. virtual void AdjustInitialPriority(CExecRequest* pRequest){}
  297. virtual void AdjustPriorityForPassing(CExecRequest* pRequest){}
  298. public:
  299. CExecQueue();
  300. ~CExecQueue();
  301. void AddRef() {InterlockedIncrement(&m_lRef);}
  302. void Release() {LONG lRet = InterlockedDecrement(&m_lRef); if(0 == lRet) delete this;}
  303. static DWORD GetTlsIndex();
  304. void Enter();
  305. void Leave();
  306. virtual HRESULT Enqueue(CExecRequest* pRequest, HANDLE* phWhenDone = NULL);
  307. HRESULT EnqueueWithoutSleep(CExecRequest* pRequest, HANDLE* phWhenDone = NULL );
  308. HRESULT EnqueueAndWait(CExecRequest* pRequest);
  309. virtual LPCWSTR GetType() {return L"";}
  310. void SetThreadLimits(long lMaxThreads, long lHiPriMaxThreads = -1,
  311. long lHiPriBound = 0);
  312. void SetIdleTimeout(DWORD dwTimeout) {m_dwTimeout = dwTimeout;}
  313. void SetOverflowIdleTimeout(DWORD dwTimeout)
  314. {m_dwOverflowTimeout = dwTimeout;}
  315. void SetRequestLimits(long lAbsoluteLimitCount,
  316. long lStartSlowdownCount = -1, long lOneSecondDelayCount = -1);
  317. void Shutdown();
  318. DWORD GetSitoutPenalty( void ) { return CalcSitOutPenalty( m_lNumRequests ); }
  319. static DWORD QueueWaitForSingleObject(HANDLE hHandle, DWORD dwWait);
  320. static DWORD QueueUnblockedWaitForSingleObject(HANDLE hHandle, DWORD dwWait);
  321. static BOOL IsSTAThread();
  322. };
  323. #endif