//====== 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