/************************************************************************ Copyright (c) 2000 - 2000 Microsoft Corporation Module Name : tasksched.h Abstract : Header file for task manager classes and routines. Author : Revision History : ***********************************************************************/ #pragma once #if !defined(__QMGR_TASKSCHEDULER_) #define __QMGR_TASKSCHEDULER__ #include #include #include using namespace std; #define SYNCHRONIZED_READ #define SYNCHRONIZED_WRITE class TaskScheduler; class TaskSchedulerWorkItem; class TaskSchedulerWorkItemSorter; class SortedWorkItemList; enum TASK_SCHEDULER_WORK_ITEM_STATE { TASK_STATE_WAITING, TASK_STATE_READY, TASK_STATE_RUNNING, TASK_STATE_CANCELED, TASK_STATE_COMPLETE, TASK_STATE_NOTHING }; class TaskSchedulerWorkItem : public IntrusiveList::Link { private: FILETIME m_InsertionTime; FILETIME m_TimeToRun; // 0 if should run now. HANDLE m_CancelEvent; // Signaled on request to cancel. HANDLE m_ItemComplete; // Signaled on item complete. HANDLE m_ItemCanceled; // Signaled on item cancel. void * m_WorkGroup; TASK_SCHEDULER_WORK_ITEM_STATE m_State; public: SortedWorkItemList * m_Container; //-------------------------------------------------------------------- TaskSchedulerWorkItem( FILETIME *pTimeToRun = NULL ); virtual ~TaskSchedulerWorkItem(); virtual void OnDispatch() = 0; // Called when work item is dispatched friend TaskScheduler; friend TaskSchedulerWorkItemSorter; void Serialize( HANDLE hFile ); void Unserialize( HANDLE hFile ); virtual SidHandle GetSid() = 0; }; class TaskSchedulerWorkItemSorter { public: bool operator()(TaskSchedulerWorkItem *pA, TaskSchedulerWorkItem *pB ) const { // Convert all times to UINT64 UINT64 TimeToRunA = FILETIMEToUINT64( pA->m_TimeToRun ); UINT64 TimeToRunB = FILETIMEToUINT64( pB->m_TimeToRun ); UINT64 InsertionTimeA = FILETIMEToUINT64( pA->m_InsertionTime ); UINT64 InsertionTimeB = FILETIMEToUINT64( pB->m_InsertionTime ); if ( TimeToRunA != TimeToRunB ) return(TimeToRunA < TimeToRunB ); if ( InsertionTimeA != InsertionTimeB ) return(InsertionTimeA < InsertionTimeB); return pA < pB; } }; class SortedWorkItemList : public IntrusiveList { typedef IntrusiveList::iterator iterator; TaskSchedulerWorkItemSorter m_sorter; public: void insert( TaskSchedulerWorkItem & val ) { for (iterator iter=begin(); iter != end(); ++iter) { if ( false == m_sorter( &(*iter), &val )) { break; } } IntrusiveList::insert( iter, val ); val.m_Container = this; } size_t erase( TaskSchedulerWorkItem & val ) { ASSERT( val.m_Container == NULL || val.m_Container == this ); val.m_Container = NULL; return IntrusiveList::erase( val ); } }; class TaskScheduler { public: TaskScheduler(); //Throws an HRESULT exception on error virtual ~TaskScheduler(); // Handle which is signaled when a work item may be available. HANDLE GetWaitableObject(); // Gets the current work item for the current thread. // Returns NULL if no work item is active. TaskSchedulerWorkItem* GetCurrentWorkItem(); // Gets the cancel event for current work item, else return NULL HANDLE GetCancelEvent(); // Returns true if the job assigned to the current thread // has a requested abort. Returns false if no job is assigned. bool PollAbort(); // Gets a work item off the queue if available and dispatches it. void DispatchWorkItem(); // returns true if the job completed before the cancel // This should not happen if both the thread that does the canceling // and the canceler thread are holdering the writer lock. // If the current thread is canceling the work item, the cancel is acknowledged immediatly. bool CancelWorkItem( TaskSchedulerWorkItem *pWorkItem ); // Completes the current work item. void CompleteWorkItem(); // Acknoledges a cancel of the current work item void AcknowledgeWorkItemCancel(); void InsertDelayedWorkItem( TaskSchedulerWorkItem *pWorkItem, UINT64 Delay100Nsec ); void RescheduleDelayedTask( TaskSchedulerWorkItem *pWorkItem, UINT64 Delay100Nsec ); void InsertWorkItem( TaskSchedulerWorkItem *pWorkItem, FILETIME *pTimeToRun = NULL ); bool IsWorkItemInScheduler( TaskSchedulerWorkItem *pWorkItem ); // returns true if current job cancelled before lock acquire bool LockReader(); void UnlockReader(); // returns true if current job cancelled before lock acquire bool LockWriter(); void UnlockWriter(); bool IsWriter() { if (m_WriterOwner == GetCurrentThreadId()) { return true; } return false; } void KillBackgroundTasks(); private: static const size_t MAX_WORKGROUP_THREADS = 4; class TaskSchedulerWorkGroup { public: SidHandle m_Sid; SortedWorkItemList m_ReadyList; SortedWorkItemList m_RunningList; HANDLE m_ItemAvailableSemaphore; DWORD m_Threads; HANDLE m_Thread[MAX_WORKGROUP_THREADS]; DWORD m_ThreadId[MAX_WORKGROUP_THREADS]; LONG m_BusyThreads; TaskSchedulerWorkGroup( SidHandle Sid ); ~TaskSchedulerWorkGroup(); }; bool m_bShouldDie; HANDLE m_SchedulerLock, m_WaitableTimer, m_ReaderLock, m_WriterSemaphore; LONG m_ReaderCount; DWORD m_WorkItemTLS; DWORD m_WriterOwner; SortedWorkItemList m_WaitingList; typedef map WorkGroupMapType; WorkGroupMapType m_WorkGroupMap; // Only used when creating a new background worker HANDLE m_WorkerInitialized; TaskSchedulerWorkGroup *m_NewWorkerGroup; void CompleteWorkItem( bool bCancel ); void Reschedule(); void AddItemToWorkGroup( SidHandle Sid, TaskSchedulerWorkItem *pWorkItem ); static DWORD WorkGroupWorkerThunk( void *pContext ); DWORD WorkGroupWorker( ); }; ///////////////////////////////////////////////////////////////////////////// // Simple inlined functions ///////////////////////////////////////////////////////////////////////////// inline HANDLE TaskScheduler::GetWaitableObject() { return m_WaitableTimer; } inline TaskSchedulerWorkItem* TaskScheduler::GetCurrentWorkItem() { return(TaskSchedulerWorkItem*)TlsGetValue( m_WorkItemTLS ); } inline HANDLE TaskScheduler::GetCancelEvent() { TaskSchedulerWorkItem *pWorkItem = GetCurrentWorkItem(); return pWorkItem ? pWorkItem->m_CancelEvent : NULL; } inline bool TaskScheduler::PollAbort() { return( WaitForSingleObject( GetCancelEvent(), 0 ) == WAIT_OBJECT_0 ); } inline void TaskScheduler::CompleteWorkItem() { CompleteWorkItem(false); } inline void TaskScheduler::AcknowledgeWorkItemCancel() { ASSERT( PollAbort() ); CompleteWorkItem(true); } class HoldReaderLock { TaskScheduler * const m_TaskScheduler; bool m_Taken; public: HoldReaderLock( TaskScheduler *pTaskScheduler ) : m_TaskScheduler( pTaskScheduler ), m_Taken( false ) { if (false == m_TaskScheduler->IsWriter() ) { RTL_VERIFY( !m_TaskScheduler->LockReader() ); m_Taken = true; } } HoldReaderLock( TaskScheduler & TaskScheduler ) : m_TaskScheduler( &TaskScheduler ), m_Taken( false ) { if (false == m_TaskScheduler->IsWriter() ) { RTL_VERIFY( !m_TaskScheduler->LockReader() ); m_Taken = true; } } ~HoldReaderLock() { if (m_Taken) { m_TaskScheduler->UnlockReader(); } } }; class HoldWriterLock { TaskScheduler * const m_TaskScheduler; bool m_Taken; public: HoldWriterLock( TaskScheduler *pTaskScheduler ) : m_TaskScheduler( pTaskScheduler ), m_Taken( false ) { if (false == m_TaskScheduler->IsWriter() ) { RTL_VERIFY( !m_TaskScheduler->LockWriter() ); m_Taken = true; } } HoldWriterLock( TaskScheduler & TaskScheduler ) : m_TaskScheduler( &TaskScheduler ), m_Taken( false ) { if (false == m_TaskScheduler->IsWriter() ) { RTL_VERIFY( !m_TaskScheduler->LockWriter() ); m_Taken = true; } } ~HoldWriterLock() { if (m_Taken) { m_TaskScheduler->UnlockWriter(); } } }; template class CLockedReadPointer { protected: const T * const m_Pointer; public: CLockedReadPointer( const T * Pointer) : m_Pointer(Pointer) { RTL_VERIFY( !g_Manager->LockReader() ); } ~CLockedReadPointer() { g_Manager->UnlockReader(); } HRESULT ValidateAccess() { return m_Pointer->CheckClientAccess(LockFlags); } const T * operator->() const { return m_Pointer; } }; template class CLockedWritePointer { protected: T * const m_Pointer; public: CLockedWritePointer( T * Pointer ) : m_Pointer(Pointer) { RTL_VERIFY( !g_Manager->LockWriter() ); } ~CLockedWritePointer() { g_Manager->UnlockWriter(); } HRESULT ValidateAccess() { return m_Pointer->CheckClientAccess(LockFlags); } T * operator->() const { return m_Pointer; } }; #endif //__QMGR_TASKSCHEDULER__