|
|
/*++
Copyright (c) 1996-1999 Microsoft Corporation
Module Name : sched.hxx
Abstract: This module defines the data structures for scheduler module.
Author:
Murali R. Krishnan ( MuraliK ) 16-Sept-1996 George V. Reilly (GeorgeRe) May-1999
Project:
Internet Server DLL
Revision History:
--*/
# ifndef _SCHED_HXX_
# define _SCHED_HXX_
/************************************************************
* Include Headers ************************************************************/
# include "acache.hxx"
# include <lstentry.h>
# include <process.h>
# include <new.h>
// little-endian signatures
#define SIGNATURE_SCHED_ITEM ((DWORD) 'TICS')
#define SIGNATURE_SCHED_ITEM_FREE ((DWORD) 'xICS')
#define SIGNATURE_SCHEDDATA ((DWORD) 'DSCS')
#define SIGNATURE_SCHEDDATA_FREE ((DWORD) 'xSCS')
#define SIGNATURE_THREADDATA ((DWORD) 'DTCS')
#define SIGNATURE_THREADDATA_FREE ((DWORD) 'xTCS')
//
// Global definitions
//
#define NUM_SCHEDULE_THREADS_PWS 1
#define NUM_SCHEDULE_THREADS_NTS 2
#define MAX_THREADS (MAXIMUM_WAIT_OBJECTS/4)
// #define MAX_THREADS 4
/************************************************************
* Forward references ************************************************************/
class SCHED_ITEM; class CSchedData; class CThreadData;
unsigned __stdcall SchedulerWorkerThread( void* pvParam );
BOOL SchedulerInitialize( VOID ); VOID SchedulerTerminate( VOID );
/************************************************************
* Type Definitions ************************************************************/
// the state of scheduled item
enum SCHED_ITEM_STATE { SI_ERROR = 0, SI_IDLE, SI_ACTIVE, SI_ACTIVE_PERIODIC, SI_CALLBACK_PERIODIC, SI_TO_BE_DELETED,
SI_MAX_ITEMS };
// various scheduler operations
enum SCHED_OPS { SI_OP_ADD = 0, SI_OP_ADD_PERIODIC, SI_OP_CALLBACK, SI_OP_DELETE,
SI_OP_MAX };
extern SCHED_ITEM_STATE rg_NextState[][SI_MAX_ITEMS];
# include <pshpack8.h>
//
// SCHED_ITEM
//
//
class SCHED_ITEM { public:
SCHED_ITEM( PFN_SCHED_CALLBACK pfnCallback, PVOID pContext, DWORD msecTime) : _pfnCallback ( pfnCallback ), _pContext ( pContext ), _dwSerialNumber ( NewSerialNumber() ), _msecInterval ( msecTime ), _Signature ( SIGNATURE_SCHED_ITEM ), _siState ( SI_IDLE ), _dwCallbackThreadId ( 0 ), _hCallbackEvent ( NULL ), _lEventRefCount ( 0 ) { CalcExpiresTime(); }
~SCHED_ITEM( VOID ) { DBG_ASSERT( _lEventRefCount == 0 ); DBG_ASSERT( _hCallbackEvent == NULL ); DBG_ASSERT( _ListEntry.Flink == NULL );
_Signature = SIGNATURE_SCHED_ITEM_FREE; }
BOOL CheckSignature( VOID ) const { return (_Signature == SIGNATURE_SCHED_ITEM); }
VOID CalcExpiresTime(VOID) { _msecExpires = GetCurrentTimeInMilliseconds() + _msecInterval; }
VOID ChangeTimeInterval( DWORD msecNewTime) { _msecInterval = msecNewTime; }
enum { SERIAL_NUM_INITIAL_VALUE = 1, SERIAL_NUM_INCREMENT = 2, // ensures that it will never wrap to 0,
// which is considered an invalid value
};
// There's an extremely small possibility that in a very long-running
// service, the counter will wrap and regenerate a cookie that matches
// the one belonging to a long-lived periodic work item. We don't care.
static DWORD NewSerialNumber() { return InterlockedExchangeAdd(&sm_lSerialNumber, SERIAL_NUM_INCREMENT); }
LONG AddEvent() { // AddEvent() is always called when the list is locked
// no need for Interlocked operations
if (!_hCallbackEvent) _hCallbackEvent = IIS_CREATE_EVENT( "SCHED_ITEM::_hCallbackEvent", this, TRUE, FALSE );
if (_hCallbackEvent) _lEventRefCount++; return _lEventRefCount; }
LONG WaitForEventAndRelease() { DBG_ASSERT(_hCallbackEvent); WaitForSingleObject(_hCallbackEvent, INFINITE);
// could be called from multiple threads
// need for Interlock operations
LONG lRefs = InterlockedDecrement(&_lEventRefCount); DBG_ASSERT(lRefs >= 0); if (lRefs == 0) { CloseHandle(_hCallbackEvent); _hCallbackEvent = NULL; }
return lRefs; }
BOOL FInsideCallbackOnOtherThread() const { return (_dwCallbackThreadId != 0) && (_dwCallbackThreadId != GetCurrentThreadId()); }
public: DWORD _Signature; DWORD _dwSerialNumber; CListEntry _ListEntry; __int64 _msecExpires; PFN_SCHED_CALLBACK _pfnCallback; PVOID _pContext; DWORD _msecInterval;
SCHED_ITEM_STATE _siState;
DWORD _dwCallbackThreadId; HANDLE _hCallbackEvent; LONG _lEventRefCount;
// Used as identification cookie for removing items
static LONG sm_lSerialNumber; }; // class SCHED_ITEM
# include <poppack.h>
//
// CSchedData: manages all the scheduler work items
//
class CSchedData { public: CSchedData() : m_dwSignature(SIGNATURE_SCHEDDATA), m_nID(InterlockedIncrement(&sm_nID)), m_hevtNotify(NULL), m_cThreads(0), m_cRefs(1), // last reference Release'd in Terminate
m_fShutdown(FALSE), m_pachSchedItems(NULL) { ALLOC_CACHE_CONFIGURATION acConfig = { 1, 30, sizeof(SCHED_ITEM)}; m_pachSchedItems = new ALLOC_CACHE_HANDLER( "SchedItems", &acConfig);
m_hevtNotify = IIS_CREATE_EVENT("CSchedData", this, FALSE, // auto-reset
FALSE); // initially non-signalled
sm_lstSchedulers.InsertTail(&m_leGlobalList); }
~CSchedData();
bool IsValid() const { return (m_pachSchedItems != NULL && m_hevtNotify != NULL && CheckSignature()); }
bool CheckSignature() const { return (m_dwSignature == SIGNATURE_SCHEDDATA); }
LONG Release() { LONG l = InterlockedDecrement(&m_cRefs); if (l == 0) delete this; return l; }
SCHED_ITEM* const NewSchedItem( PFN_SCHED_CALLBACK pfnCallback, PVOID pContext, DWORD msecTime) { DBG_ASSERT(m_pachSchedItems != NULL);
// placement new, using the allocator
LPBYTE pbsi = static_cast<LPBYTE>(m_pachSchedItems->Alloc()); if (pbsi == NULL) return NULL; InterlockedIncrement(&m_cRefs); SCHED_ITEM* psi = new (pbsi) SCHED_ITEM(pfnCallback, pContext, msecTime); return psi; }
void DeleteSchedItem( SCHED_ITEM* const psi) { DBG_ASSERT(m_pachSchedItems != NULL); DBG_ASSERT(psi != NULL);
psi->~SCHED_ITEM(); // placement destruction
m_pachSchedItems->Free(psi); Release(); }
// The global scheduler object
static CSchedData* const Scheduler() { DBG_ASSERT( sm_psd != NULL ); DBG_ASSERT( sm_psd->m_dwSignature == SIGNATURE_SCHEDDATA ); return sm_psd; }
void LockItems() { m_lstItems.Lock(); }
void UnlockItems() { m_lstItems.Unlock(); }
VOID InsertIntoWorkItemList(SCHED_ITEM* psi);
SCHED_ITEM* FindSchedulerItem(DWORD dwCookie);
void Terminate();
public: DWORD m_dwSignature; const LONG m_nID; CLockedDoubleList m_lstItems; // list of SCHED_ITEMs
CLockedDoubleList m_lstThreads; // list of CThreadDatas
CLockedDoubleList m_lstDeadThreads; // list of dead CThreadDatas
LONG m_cThreads; // #worker threads
LONG m_cRefs; // outstanding references
HANDLE m_hevtNotify; // Notify worker threads
BOOL m_fShutdown; ALLOC_CACHE_HANDLER* m_pachSchedItems; // SCHED_ITEM allocator
CListEntry m_leGlobalList;
static CSchedData* sm_psd; static CLockedDoubleList sm_lstSchedulers; static LONG sm_nID; };
//
// CThreadData: describes a worker thread
//
class CThreadData { public: CThreadData( CSchedData* psdOwner) : m_dwSignature(SIGNATURE_THREADDATA), m_nID(InterlockedIncrement(&sm_nID)), m_psdOwner(psdOwner), m_hevtShutdown(NULL), m_hThreadSelf(NULL) { unsigned idThread;
m_hevtShutdown = IIS_CREATE_EVENT("CThreadData", this, FALSE, // auto-reset
FALSE); // initially non-signalled
if (m_hevtShutdown != NULL) m_hThreadSelf = (HANDLE) _beginthreadex( NULL, 0, SchedulerWorkerThread, this, CREATE_SUSPENDED, &idThread ); psdOwner->m_lstThreads.InsertTail(&m_leThreads); InterlockedIncrement(&psdOwner->m_cThreads); InterlockedIncrement(&psdOwner->m_cRefs); }
~CThreadData() { CloseHandle(m_hThreadSelf); CloseHandle(m_hevtShutdown); m_psdOwner->m_lstDeadThreads.RemoveEntry(&m_leThreads); m_dwSignature = SIGNATURE_THREADDATA_FREE; }
void Release() { InterlockedDecrement(&m_psdOwner->m_cThreads); m_psdOwner->m_lstThreads.RemoveEntry(&m_leThreads); m_psdOwner->m_lstDeadThreads.InsertTail(&m_leThreads); m_psdOwner->Release(); } bool IsValid() const { return (m_hevtShutdown != NULL && m_hThreadSelf != NULL && CheckSignature()); }
bool CheckSignature() const { return (m_dwSignature == SIGNATURE_THREADDATA); }
public: DWORD m_dwSignature; const LONG m_nID; CSchedData* m_psdOwner; HANDLE m_hevtShutdown; HANDLE m_hThreadSelf; CListEntry m_leThreads;
static LONG sm_nID; };
# endif // _SCHED_HXX_
/************************ End of File ***********************/
|