source-engine/public/gcsdk/scheduledfunction.h

206 lines
5.8 KiB
C
Raw Normal View History

2020-04-22 16:56:21 +00:00
//====== Copyright (c), Valve Corporation, All rights reserved. =======
//
// Purpose: Provides a scheduled function manager that will bucket events into
// time chunks and execute them as time elapses
//
//=============================================================================
#ifndef SCHEDULEDFUNCTION_H
#define SCHEDULEDFUNCTION_H
#ifdef _WIN32
#pragma once
#endif
namespace GCSDK
{
//interface for events that can be scheduled to run on the GC base
class IGCScheduledFunction
{
public:
IGCScheduledFunction() : m_nAbsScheduleBucket( knInvalidBucket ) {}
virtual ~IGCScheduledFunction();
//called in response to our event time elapsing
virtual void OnEvent() = 0;
bool BIsScheduled() const { return m_nAbsScheduleBucket != IGCScheduledFunction::knInvalidBucket; }
private:
//the absolute bucket that we were scheduled in (or invalid). Used to enable deregistering
friend class CScheduledFunctionMgr;
uint32 m_nAbsScheduleBucket;
uint32 m_nLLIndex;
static const uint32 knInvalidBucket = ( uint32 )-1;
};
//utility for scheduling a global function
class CGlobalScheduledFunction :
public IGCScheduledFunction
{
public:
CGlobalScheduledFunction();
typedef void ( *func_t )();
void ScheduleMS( func_t pfn, uint32 nDelayMS );
void ScheduleSecond( func_t pfn, uint32 nDelaySecond );
void ScheduleMinute( func_t pfn, uint32 nDelayMinute );
void Cancel();
virtual void OnEvent() OVERRIDE;
private:
func_t m_pfn;
};
//the same as the above, but automatically deletes the object once the event is fired
class CGlobalScheduledFunctionAutoDelete :
public CGlobalScheduledFunction
{
public:
CGlobalScheduledFunctionAutoDelete() {}
virtual void OnEvent() OVERRIDE
{
CGlobalScheduledFunction::OnEvent();
delete this;
}
};
//utility for scheduling a member function
template< class T >
class CScheduledFunction :
public IGCScheduledFunction
{
public:
CScheduledFunction() : m_pObj( NULL ), m_pfn( NULL ) {}
typedef void ( T::*func_t )();
void ScheduleMS( T* pObj, func_t pfn, uint32 nDelayMS )
{
m_pObj = pObj;
m_pfn = pfn;
GScheduledFunctionMgr().ScheduleMS( this, nDelayMS );
}
void ScheduleSecond( T* pObj, func_t pfn, uint32 nDelaySecond )
{
m_pObj = pObj;
m_pfn = pfn;
GScheduledFunctionMgr().ScheduleSecond( this, nDelaySecond );
}
void ScheduleMinute( T* pObj, func_t pfn, uint32 nDelayMinute )
{
m_pObj = pObj;
m_pfn = pfn;
GScheduledFunctionMgr().ScheduleMinute( this, nDelayMinute );
}
void Cancel()
{
GScheduledFunctionMgr().Cancel( this );
}
virtual void OnEvent() OVERRIDE
{
( m_pObj->*m_pfn )();
}
private:
T* m_pObj;
func_t m_pfn;
};
//similar to the above, but auto deletes once the event is fired
template< class T >
class CScheduledFunctionAutoDelete :
public CScheduledFunction< T >
{
public:
typedef void ( T::*func_t )();
CScheduledFunctionAutoDelete() {}
CScheduledFunctionAutoDelete( T* pObj, func_t pfn, uint32 nDelayMS ) { Schedule( pObj, pfn, nDelayMS ); }
virtual void OnEvent() OVERRIDE
{
CScheduledFunction< T >::OnEvent();
delete this;
}
};
class CScheduledFunctionMgr
{
public:
CScheduledFunctionMgr();
//called to initialize the starting time for the scheduled function manager. It doesn't need to be globally absolute, just relative to the time values provided
//to the run function
void InitStartingTime();
//called to register a scheduled event for a certain period in the future, with the delay specified in milliseconds. This has resolution of an individual frame, and
//will unregister from any previously registered time slot
void ScheduleMS( IGCScheduledFunction* pEvent, uint32 nMSDelay );
//similar to the above, but instead of having frame resolution, this has second level resolution, and should be used for low granularity tasks
void ScheduleSecond( IGCScheduledFunction* pEvent, uint32 nSDelay );
//similar to the above but has minute level resolution which should be used for very low resolution tasks
void ScheduleMinute( IGCScheduledFunction* pEvent, uint32 nMinuteDelay );
//deregisters a previously registered event
void Cancel( IGCScheduledFunction* pEvent );
//called to run registered functions
void RunFunctions();
private:
//called internally by the other schedule functions to schedule the event at the specified resolution in our resolution array
void InternalSchedule( uint32 nResolution, IGCScheduledFunction* pEvent, uint32 nMSDelay );
//the list type that we store all of the entries in. We use a single list to avoid the overhead of so many lists
typedef CUtlLinkedList< IGCScheduledFunction*, uint32 > TScheduleList;
//all information tied to a specific resolution, including the time hash buckets, number of buckets, and which buckets it has executed
class CScheduleBucket
{
public:
CScheduleBucket();
~CScheduleBucket();
void Init( TScheduleList& MasterList, uint32 nNumBuckets, uint32 nMicroSPerBucket );
//maps a micro second time to a bucket time
uint32 GetAbsScheduleBucketIndex( uint64 nMicroSTime ) const { return ( uint32 )( nMicroSTime / m_nMicroSPerBucket ); }
//called to run registered functions
void RunFunctions( TScheduleList& MasterList, uint64 nMicroSTime );
//for each bucket, we insert a node into the master linked list, then our list runs from this node to the next empty node (or end) in the list
uint32* m_pBuckets;
//the number of buckets that we have
uint32 m_nNumBuckets;
//how many micro seconds each bucket represents
uint32 m_nMicroSPerBucket;
//the last bucket that we had executed
uint32 m_nAbsLastScheduleBucket;
};
//the list of all of our entries. We store bucket starts within here, and then insert the events in between them
TScheduleList m_ScheduleList;
//the list of resolutions that we have
CScheduleBucket m_Resolutions[ 3 ];
};
//global singleton access
CScheduledFunctionMgr& GScheduledFunctionMgr();
} //namespace GCSDK
#endif