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

/************************************************************************
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 <set>
#include <map>
#include <clist.h>
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<TaskSchedulerWorkItem>::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 or 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<TaskSchedulerWorkItem>
{
typedef IntrusiveList<TaskSchedulerWorkItem>::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<TaskSchedulerWorkItem>::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<TaskSchedulerWorkItem>::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<SidHandle, TaskSchedulerWorkGroup*, CSidSorter> 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();
}
}
};
/*
Boilerplate code to release and reclaim the write lock, throwing S_FALSE
if the current workitem is cancelled. Use them like this:
bool bNeedLock;
try
{
ReleaseWriteLock( bNeedLock );
code....
ReclaimWriteLock( bNeedLock );
return;
}
catch ( ComError err )
{
ReclaimWriteLock( bNeedLock );
throw;
}
*/
void ReleaseWriteLock( bool & bNeedLock );
void ReclaimWriteLock( bool & bNeedLock );
//
//
//
template<class T, DWORD LockFlags >
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 T, DWORD LockFlags>
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__