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.

442 lines
11 KiB

  1. /************************************************************************
  2. Copyright (c) 2000 - 2000 Microsoft Corporation
  3. Module Name :
  4. tasksched.h
  5. Abstract :
  6. Header file for task manager classes and routines.
  7. Author :
  8. Revision History :
  9. ***********************************************************************/
  10. #pragma once
  11. #if !defined(__QMGR_TASKSCHEDULER_)
  12. #define __QMGR_TASKSCHEDULER__
  13. #include <set>
  14. #include <map>
  15. #include <clist.h>
  16. using namespace std;
  17. #define SYNCHRONIZED_READ
  18. #define SYNCHRONIZED_WRITE
  19. class TaskScheduler;
  20. class TaskSchedulerWorkItem;
  21. class TaskSchedulerWorkItemSorter;
  22. class SortedWorkItemList;
  23. enum TASK_SCHEDULER_WORK_ITEM_STATE
  24. {
  25. TASK_STATE_WAITING,
  26. TASK_STATE_READY,
  27. TASK_STATE_RUNNING,
  28. TASK_STATE_CANCELED,
  29. TASK_STATE_COMPLETE,
  30. TASK_STATE_NOTHING
  31. };
  32. class TaskSchedulerWorkItem :
  33. public IntrusiveList<TaskSchedulerWorkItem>::Link
  34. {
  35. private:
  36. FILETIME m_InsertionTime;
  37. FILETIME m_TimeToRun; // 0 if should run now.
  38. HANDLE m_CancelEvent; // Signaled on request to cancel.
  39. HANDLE m_ItemComplete; // Signaled on item complete or cancel.
  40. void * m_WorkGroup;
  41. TASK_SCHEDULER_WORK_ITEM_STATE m_State;
  42. public:
  43. SortedWorkItemList * m_Container;
  44. //--------------------------------------------------------------------
  45. TaskSchedulerWorkItem( FILETIME *pTimeToRun = NULL );
  46. virtual ~TaskSchedulerWorkItem();
  47. virtual void OnDispatch() = 0; // Called when work item is dispatched
  48. friend TaskScheduler;
  49. friend TaskSchedulerWorkItemSorter;
  50. void Serialize(
  51. HANDLE hFile
  52. );
  53. void Unserialize(
  54. HANDLE hFile
  55. );
  56. virtual SidHandle GetSid() = 0;
  57. };
  58. class TaskSchedulerWorkItemSorter
  59. {
  60. public:
  61. bool operator()(TaskSchedulerWorkItem *pA, TaskSchedulerWorkItem *pB ) const
  62. {
  63. // Convert all times to UINT64
  64. UINT64 TimeToRunA = FILETIMEToUINT64( pA->m_TimeToRun );
  65. UINT64 TimeToRunB = FILETIMEToUINT64( pB->m_TimeToRun );
  66. UINT64 InsertionTimeA = FILETIMEToUINT64( pA->m_InsertionTime );
  67. UINT64 InsertionTimeB = FILETIMEToUINT64( pB->m_InsertionTime );
  68. if ( TimeToRunA != TimeToRunB )
  69. return(TimeToRunA < TimeToRunB );
  70. if ( InsertionTimeA != InsertionTimeB )
  71. return(InsertionTimeA < InsertionTimeB);
  72. return pA < pB;
  73. }
  74. };
  75. class SortedWorkItemList : public IntrusiveList<TaskSchedulerWorkItem>
  76. {
  77. typedef IntrusiveList<TaskSchedulerWorkItem>::iterator iterator;
  78. TaskSchedulerWorkItemSorter m_sorter;
  79. public:
  80. void insert( TaskSchedulerWorkItem & val )
  81. {
  82. for (iterator iter=begin(); iter != end(); ++iter)
  83. {
  84. if ( false == m_sorter( &(*iter), &val ))
  85. {
  86. break;
  87. }
  88. }
  89. IntrusiveList<TaskSchedulerWorkItem>::insert( iter, val );
  90. val.m_Container = this;
  91. }
  92. size_t erase( TaskSchedulerWorkItem & val )
  93. {
  94. ASSERT( val.m_Container == NULL || val.m_Container == this );
  95. val.m_Container = NULL;
  96. return IntrusiveList<TaskSchedulerWorkItem>::erase( val );
  97. }
  98. };
  99. class TaskScheduler
  100. {
  101. public:
  102. TaskScheduler(); //Throws an HRESULT exception on error
  103. virtual ~TaskScheduler();
  104. // Handle which is signaled when a work item may be available.
  105. HANDLE GetWaitableObject();
  106. // Gets the current work item for the current thread.
  107. // Returns NULL if no work item is active.
  108. TaskSchedulerWorkItem* GetCurrentWorkItem();
  109. // Gets the cancel event for current work item, else return NULL
  110. HANDLE GetCancelEvent();
  111. // Returns true if the job assigned to the current thread
  112. // has a requested abort. Returns false if no job is assigned.
  113. bool PollAbort();
  114. // Gets a work item off the queue if available and dispatches it.
  115. void DispatchWorkItem();
  116. // returns true if the job completed before the cancel
  117. // This should not happen if both the thread that does the canceling
  118. // and the canceler thread are holdering the writer lock.
  119. // If the current thread is canceling the work item, the cancel is acknowledged immediatly.
  120. bool CancelWorkItem( TaskSchedulerWorkItem *pWorkItem );
  121. // Completes the current work item.
  122. void CompleteWorkItem();
  123. // Acknoledges a cancel of the current work item
  124. void AcknowledgeWorkItemCancel();
  125. void
  126. InsertDelayedWorkItem(
  127. TaskSchedulerWorkItem *pWorkItem,
  128. UINT64 Delay100Nsec
  129. );
  130. void RescheduleDelayedTask( TaskSchedulerWorkItem *pWorkItem, UINT64 Delay100Nsec );
  131. void InsertWorkItem( TaskSchedulerWorkItem *pWorkItem, FILETIME *pTimeToRun = NULL );
  132. bool IsWorkItemInScheduler( TaskSchedulerWorkItem *pWorkItem );
  133. // returns true if current job cancelled before lock acquire
  134. bool LockReader();
  135. void UnlockReader();
  136. // returns true if current job cancelled before lock acquire
  137. bool LockWriter();
  138. void UnlockWriter();
  139. bool IsWriter()
  140. {
  141. if (m_WriterOwner == GetCurrentThreadId())
  142. {
  143. return true;
  144. }
  145. return false;
  146. }
  147. void KillBackgroundTasks();
  148. private:
  149. static const size_t MAX_WORKGROUP_THREADS = 4;
  150. class TaskSchedulerWorkGroup
  151. {
  152. public:
  153. SidHandle m_Sid;
  154. SortedWorkItemList m_ReadyList;
  155. SortedWorkItemList m_RunningList;
  156. HANDLE m_ItemAvailableSemaphore;
  157. DWORD m_Threads;
  158. HANDLE m_Thread[MAX_WORKGROUP_THREADS];
  159. DWORD m_ThreadId[MAX_WORKGROUP_THREADS];
  160. LONG m_BusyThreads;
  161. TaskSchedulerWorkGroup( SidHandle Sid );
  162. ~TaskSchedulerWorkGroup();
  163. };
  164. bool m_bShouldDie;
  165. HANDLE m_SchedulerLock, m_WaitableTimer, m_ReaderLock, m_WriterSemaphore;
  166. LONG m_ReaderCount;
  167. DWORD m_WorkItemTLS;
  168. DWORD m_WriterOwner;
  169. SortedWorkItemList m_WaitingList;
  170. typedef map<SidHandle, TaskSchedulerWorkGroup*, CSidSorter> WorkGroupMapType;
  171. WorkGroupMapType m_WorkGroupMap;
  172. // Only used when creating a new background worker
  173. HANDLE m_WorkerInitialized;
  174. TaskSchedulerWorkGroup *m_NewWorkerGroup;
  175. void CompleteWorkItem( bool bCancel );
  176. void Reschedule();
  177. void AddItemToWorkGroup(
  178. SidHandle Sid,
  179. TaskSchedulerWorkItem *pWorkItem );
  180. static DWORD WorkGroupWorkerThunk( void *pContext );
  181. DWORD WorkGroupWorker( );
  182. };
  183. /////////////////////////////////////////////////////////////////////////////
  184. // Simple inlined functions
  185. /////////////////////////////////////////////////////////////////////////////
  186. inline HANDLE
  187. TaskScheduler::GetWaitableObject()
  188. {
  189. return m_WaitableTimer;
  190. }
  191. inline TaskSchedulerWorkItem*
  192. TaskScheduler::GetCurrentWorkItem()
  193. {
  194. return(TaskSchedulerWorkItem*)TlsGetValue( m_WorkItemTLS );
  195. }
  196. inline HANDLE
  197. TaskScheduler::GetCancelEvent()
  198. {
  199. TaskSchedulerWorkItem *pWorkItem = GetCurrentWorkItem();
  200. return pWorkItem ? pWorkItem->m_CancelEvent : NULL;
  201. }
  202. inline bool
  203. TaskScheduler::PollAbort()
  204. {
  205. return( WaitForSingleObject( GetCancelEvent(), 0 ) == WAIT_OBJECT_0 );
  206. }
  207. inline void
  208. TaskScheduler::CompleteWorkItem()
  209. {
  210. CompleteWorkItem(false);
  211. }
  212. inline void
  213. TaskScheduler::AcknowledgeWorkItemCancel()
  214. {
  215. ASSERT( PollAbort() );
  216. CompleteWorkItem(true);
  217. }
  218. class HoldReaderLock
  219. {
  220. TaskScheduler * const m_TaskScheduler;
  221. bool m_Taken;
  222. public:
  223. HoldReaderLock( TaskScheduler *pTaskScheduler ) :
  224. m_TaskScheduler( pTaskScheduler ),
  225. m_Taken( false )
  226. {
  227. if (false == m_TaskScheduler->IsWriter() )
  228. {
  229. RTL_VERIFY( !m_TaskScheduler->LockReader() );
  230. m_Taken = true;
  231. }
  232. }
  233. HoldReaderLock( TaskScheduler & TaskScheduler ) :
  234. m_TaskScheduler( &TaskScheduler ),
  235. m_Taken( false )
  236. {
  237. if (false == m_TaskScheduler->IsWriter() )
  238. {
  239. RTL_VERIFY( !m_TaskScheduler->LockReader() );
  240. m_Taken = true;
  241. }
  242. }
  243. ~HoldReaderLock()
  244. {
  245. if (m_Taken)
  246. {
  247. m_TaskScheduler->UnlockReader();
  248. }
  249. }
  250. };
  251. class HoldWriterLock
  252. {
  253. TaskScheduler * const m_TaskScheduler;
  254. bool m_Taken;
  255. public:
  256. HoldWriterLock( TaskScheduler *pTaskScheduler ) :
  257. m_TaskScheduler( pTaskScheduler ),
  258. m_Taken( false )
  259. {
  260. if (false == m_TaskScheduler->IsWriter() )
  261. {
  262. RTL_VERIFY( !m_TaskScheduler->LockWriter() );
  263. m_Taken = true;
  264. }
  265. }
  266. HoldWriterLock( TaskScheduler & TaskScheduler ) :
  267. m_TaskScheduler( &TaskScheduler ),
  268. m_Taken( false )
  269. {
  270. if (false == m_TaskScheduler->IsWriter() )
  271. {
  272. RTL_VERIFY( !m_TaskScheduler->LockWriter() );
  273. m_Taken = true;
  274. }
  275. }
  276. ~HoldWriterLock()
  277. {
  278. if (m_Taken)
  279. {
  280. m_TaskScheduler->UnlockWriter();
  281. }
  282. }
  283. };
  284. /*
  285. Boilerplate code to release and reclaim the write lock, throwing S_FALSE
  286. if the current workitem is cancelled. Use them like this:
  287. bool bNeedLock;
  288. try
  289. {
  290. ReleaseWriteLock( bNeedLock );
  291. code....
  292. ReclaimWriteLock( bNeedLock );
  293. return;
  294. }
  295. catch ( ComError err )
  296. {
  297. ReclaimWriteLock( bNeedLock );
  298. throw;
  299. }
  300. */
  301. void ReleaseWriteLock( bool & bNeedLock );
  302. void ReclaimWriteLock( bool & bNeedLock );
  303. //
  304. //
  305. //
  306. template<class T, DWORD LockFlags >
  307. class CLockedReadPointer
  308. {
  309. protected:
  310. const T * const m_Pointer;
  311. public:
  312. CLockedReadPointer( const T * Pointer) :
  313. m_Pointer(Pointer)
  314. {
  315. RTL_VERIFY( !g_Manager->LockReader() );
  316. }
  317. ~CLockedReadPointer()
  318. {
  319. g_Manager->UnlockReader();
  320. }
  321. HRESULT ValidateAccess()
  322. {
  323. return m_Pointer->CheckClientAccess(LockFlags);
  324. }
  325. const T * operator->() const { return m_Pointer; }
  326. };
  327. template<class T, DWORD LockFlags>
  328. class CLockedWritePointer
  329. {
  330. protected:
  331. T * const m_Pointer;
  332. public:
  333. CLockedWritePointer( T * Pointer ) :
  334. m_Pointer(Pointer)
  335. {
  336. RTL_VERIFY( !g_Manager->LockWriter() );
  337. }
  338. ~CLockedWritePointer()
  339. {
  340. g_Manager->UnlockWriter();
  341. }
  342. HRESULT ValidateAccess()
  343. {
  344. return m_Pointer->CheckClientAccess(LockFlags);
  345. }
  346. T * operator->() const { return m_Pointer; }
  347. };
  348. #endif //__QMGR_TASKSCHEDULER__