Source code of Windows XP (NT5)
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.

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