Counter Strike : Global Offensive Source Code
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.

460 lines
18 KiB

  1. //========= Copyright 1996-2004, Valve LLC, All rights reserved. ============
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================
  7. #ifndef GC_JOB_H
  8. #define GC_JOB_H
  9. #ifdef _WIN32
  10. #pragma once
  11. #endif
  12. #include "tier0/memdbgon.h"
  13. #include "tier1/functors.h"
  14. #include "workthreadpool.h"
  15. class GCConVar;
  16. namespace GCSDK
  17. {
  18. class CJobMgr;
  19. class CLock;
  20. class CJob;
  21. class IMsgNetPacket;
  22. // job creation function responsible for allocating the job of the specific type
  23. typedef CJob *(*JobCreationFunc_t)( void *pvServerParent, void * pvStartParam );
  24. // job routing function, which allows for controlling message routing through the system. The GCs that should have the message sent to it should be added to the vector. It is fine to add the actual self GC
  25. typedef void (*JobRoutingFunc_t)( CUtlVector< uint32 >& vecGCsToSendTo, IMsgNetPacket *pNetPacket );
  26. //-----------------------------------------------------------------------------
  27. // Purpose: static job information
  28. // contains information relevant to one type of CJob
  29. //-----------------------------------------------------------------------------
  30. struct JobType_t
  31. {
  32. const char *m_pchName; // name of this type of job
  33. MsgType_t m_eCreationMsg; // network message that creates this job
  34. uint32 m_nValidContexts; // a bit field indicating which contexts this message can be called from (i.e. from a server, or from a client, etc)
  35. JobCreationFunc_t m_pJobFactory; // virtual constructor
  36. JobRoutingFunc_t m_pJobRouter; // routing function for this job
  37. const GCConVar* m_pControlCV; // optional console variable that can be used to disable this message
  38. };
  39. //-----------------------------------------------------------------------------
  40. // Purpose: reason as to why the current job has yielded to the main thread (paused)
  41. // if this is updated, k_prgchJobPauseReason[] in job.cpp also needs to be updated
  42. //-----------------------------------------------------------------------------
  43. enum EJobPauseReason
  44. {
  45. k_EJobPauseReasonNone,
  46. k_EJobPauseReasonNotStarted,
  47. k_EJobPauseReasonNetworkMsg,
  48. k_EJobPauseReasonSleepForTime,
  49. k_EJobPauseReasonWaitingForLock,
  50. k_EJobPauseReasonYield,
  51. k_EJobPauseReasonSQL,
  52. k_EJobPauseReasonWorkItem,
  53. k_EJobPauseReasonCount
  54. };
  55. //-----------------------------------------------------------------------------
  56. // Purpose: contains information used to route a message to a job, or to
  57. // create a new job from that message type
  58. //-----------------------------------------------------------------------------
  59. struct JobMsgInfo_t
  60. {
  61. MsgType_t m_eMsg;
  62. JobID_t m_JobIDSource;
  63. JobID_t m_JobIDTarget;
  64. JobMsgInfo_t()
  65. {
  66. m_eMsg = (MsgType_t)0;
  67. m_JobIDSource = k_GIDNil;
  68. m_JobIDTarget = k_GIDNil;
  69. }
  70. JobMsgInfo_t( MsgType_t eMsg, JobID_t jobIDSource, JobID_t jobIDTarget )
  71. {
  72. m_eMsg = eMsg;
  73. m_JobIDSource = jobIDSource;
  74. m_JobIDTarget = jobIDTarget;
  75. }
  76. };
  77. typedef void (CJob::*JobThreadFunc_t)();
  78. #define BYieldingAcquireLock( lock ) _BYieldingAcquireLock( lock, __FILE__, __LINE__ )
  79. #define BAcquireLockImmediate( lock ) _BAcquireLockImmediate( lock, __FILE__, __LINE__ )
  80. #define ReleaseLock( lock ) _ReleaseLock( lock, false, __FILE__, __LINE__ )
  81. //-----------------------------------------------------------------------------
  82. // Purpose: A job is any server operation that requires state. Typically, we use jobs for
  83. // operations that need to pause waiting for responses from other servers. The
  84. // job object persists the state of the operation while it waits, and the reply
  85. // from the remote server re-activates the job.
  86. //-----------------------------------------------------------------------------
  87. class CJob
  88. {
  89. public:
  90. // Constructors & destructors, when overriding job name a static string pointer must be used
  91. explicit CJob( CJobMgr &jobMgr, char const *pchJobName = NULL );
  92. virtual ~CJob();
  93. // starts the job, storing off the network msg and calling it's Run() function
  94. void StartJobFromNetworkMsg( IMsgNetPacket *pNetPacket, const JobID_t &gidJobIDSrc, uint32 nContextMask );
  95. // accessors
  96. JobID_t GetJobID() const { return m_JobID; }
  97. // called to start a job. The default behavior of starting a job is to start it scheduled (i.e. delayed). This is largely deprecated, and the more explicit versions
  98. // below should be used instead
  99. void StartJob( void * pvStartParam );
  100. // schedules the job for execution, but does not interrupt the currently running job. Effectively starts the job on the yielding list as if it had immediately yielded
  101. // although is more efficient than actually doing so
  102. void StartJobDelayed( void * pvStartParam );
  103. // starts a job immediately, interrupting the current job if one is already running. This should only be used in special cases, and in a lot of ways should be considered
  104. // yielding in that another job can run and perform modifications, although the caller will receive attention back the first time that the inner job itself yields
  105. void StartJobImmediate( void * pvStartParam );
  106. // string name of the job
  107. const char *GetName() const;
  108. // return reason why we're paused
  109. EJobPauseReason GetPauseReason() const { return m_ePauseReason; }
  110. // string description of why we're paused
  111. const char *GetPauseReasonDescription() const;
  112. // return time at which this job was last paused or continued
  113. const CJobTime& GetTimeSwitched() const { return m_STimeSwitched; }
  114. // return microseconds run since we were last continued
  115. uint64 GetMicrosecondsRun() const { return m_FastTimerDelta.GetDurationInProgress().GetUlMicroseconds(); }
  116. bool BJobNeedsToHeartbeat() const { return ( m_STimeNextHeartbeat.CServerMicroSecsPassed() >= 0 ); }
  117. // --- locking pointers
  118. bool _BYieldingAcquireLock( CLock *pLock, const char *filename = "unknown", int line = 0 );
  119. bool _BAcquireLockImmediate( CLock *pLock, const char *filename = "unknown", int line = 0 );
  120. void _ReleaseLock( CLock *pLock, bool bForce = false, const char *filename = "unknown", int line = 0 );
  121. void ReleaseLocks();
  122. bool BJobHoldsLock( uint16 nType, uint64 nSubType ) const;
  123. bool BJobHoldsLock( const CLock* pLock ) const;
  124. /// If we hold any locks, spew about them and release them.
  125. /// This is useful for long running jobs, to make sure they don't leak
  126. /// locks that never get cleaned up
  127. void ShouldNotHoldAnyLocks();
  128. // --- general methods for waiting for events
  129. // Simple yield to other jobs until Run() called again
  130. bool BYield();
  131. // Yield IF JobMgr thinks we need to based on how long we've run and our priority
  132. bool BYieldIfNeeded( bool *pbYielded = NULL );
  133. // waits for a set amount of time
  134. bool BYieldingWaitTime( uint32 m_cMicrosecondsToSleep );
  135. bool BYieldingWaitOneFrame();
  136. // waits for another network msg, returning false if none returns
  137. bool BYieldingWaitForMsg( IMsgNetPacket **ppNetPacket );
  138. bool BYieldingWaitForMsg( CGCMsgBase *pMsg, MsgType_t eMsg );
  139. bool BYieldingWaitForMsg( CProtoBufMsgBase *pMsg, MsgType_t eMsg );
  140. // waits for another job(s) to complete
  141. bool BYieldingWaitForJob( JobID_t jobToWaitFor );
  142. bool BYieldingWaitForJobs( const CUtlVector<JobID_t> &vecJobsToWaitFor );
  143. #ifdef GC
  144. void SOVALIDATE_SetSteamID( const CSteamID steamID ) { m_SOCacheValidSteamID = steamID; }
  145. CSteamID SOVALIDATE_GetSteamID() const { return m_SOCacheValidSteamID; }
  146. void VALIDATE_SetJobAccessType( uint32 nAccess) { m_nGCJobAccessType = nAccess; }
  147. uint32 VALIDATE_GetJobAccessType() const { return m_nGCJobAccessType; }
  148. bool BYieldingWaitForMsg( CGCMsgBase *pMsg, MsgType_t eMsg, const CSteamID &expectedID );
  149. bool BYieldingWaitForMsg( CProtoBufMsgBase *pMsg, MsgType_t eMsg, const CSteamID &expectedID );
  150. bool BYieldingRunQuery( CGCSQLQueryGroup *pQueryGroup, ESchemaCatalog eSchemaCatalog );
  151. #endif
  152. void RecordWaitTimeout() { m_flags.m_bits.m_bWaitTimeout = true; }
  153. // wait for pending work items before deleting job
  154. void WaitForThreadFuncWorkItemBlocking();
  155. // waits for a work item completion callback
  156. // You can pass a string that describes what sort of work item you are waiting on.
  157. // WARNING: This function saves the pointer to the string, it doesn't copy the string
  158. bool BYieldingWaitForWorkItem( const char *pszWorkItemName = NULL );
  159. // adds this work item to threaded work pool and waits for it
  160. bool BYieldingWaitForThreadFuncWorkItem( CWorkItem * );
  161. // calls a local function in a thread, and yields until it's done
  162. bool BYieldingWaitForThreadFunc( CFunctor *jobFunctor );
  163. // creates a job
  164. template <typename JOB_TYPE, typename PARAM_TYPE>
  165. static JOB_TYPE *AllocateJob( PARAM_TYPE *pParam )
  166. {
  167. return new JOB_TYPE( pParam );
  168. }
  169. // delete a job (the job knows what allocator to use)
  170. static void DeleteJob( CJob *pJob );
  171. void SetStartParam( void * pvStartParam ) { Assert( NULL == m_pvStartParam ); m_pvStartParam = pvStartParam; }
  172. void SetFromFromMsg( bool bRunFromMsg ) { m_bRunFromMsg = true; }
  173. void AddPacketToList( IMsgNetPacket *pNetPacket, const JobID_t gidJobIDSrc );
  174. // marks a packet as being finished with, releases the packet and frees the memory
  175. void ReleaseNetPacket( IMsgNetPacket *pNetPacket );
  176. void EndPause( EJobPauseReason eExpectedState );
  177. // Generate an assertion in the coroutine of this job
  178. // (creating a minidump). Useful for inspecting stuck jobs
  179. void GenerateAssert( const char *pchMsg = NULL );
  180. //called to determine if the requested context is valid. If multiple contexts are provided, this will return true only if ALL the contexts are valid
  181. bool BHasContext( uint32 nContext ) const { return ( m_nContextMask & nContext ) == nContext; }
  182. uint32 GetContexts() const { return m_nContextMask; }
  183. //called to control the default behavior for starting jobs, immediate, or delayed
  184. static void SetStartDefaultJobsDelayed( bool bStartJobsDelayed ) { s_bStartDefaultJobsDelayed = bStartJobsDelayed; }
  185. // accessor to get access to the JobMgr from the server we belong to
  186. CJobMgr &GetJobMgr();
  187. protected:
  188. // main job implementation, in the coroutine. Every job must implement at least one of these methods.
  189. virtual bool BYieldingRunJob( void * pvStartParam ) { Assert( false ); return true; } // implement this if your job can be started directly
  190. virtual bool BYieldingRunJobFromMsg( IMsgNetPacket * pNetPacket ) { Assert( false ); return true; } // implement this if your job can be started by a network message
  191. // Can be overridden to return a different timeout per job class
  192. virtual uint32 CHeartbeatsBeforeTimeout();
  193. // Called by CJobMgr to send heartbeat message to our listeners during long operations
  194. void Heartbeat();
  195. uint32 m_bRunFromMsg:1,
  196. m_bWorkItemCanceled:1, // true if the work item we were waiting on was canceled
  197. m_bIsTest:1,
  198. m_bIsLongRunning:1;
  199. private:
  200. // starts the coroutine that activates the job
  201. void InitCoroutine();
  202. // continues the current job
  203. void Continue();
  204. // break into this coroutine - can only be called from OUTSIDE this coroutine
  205. void Debug();
  206. // pauses the current job - can only be called from inside a coroutine
  207. void Pause( EJobPauseReason eReason, const char *pszResourceName );
  208. static void BRunProxy( void *pvThis );
  209. JobID_t m_JobID; // Our unique identifier.
  210. HCoroutine m_hCoroutine;
  211. void * m_pvStartParam; // Start params for our job, if any
  212. // all these flags indicate some kind of failure and we will want to report them
  213. union {
  214. struct {
  215. uint32
  216. m_bJobFailed:1, // true if BYieldingRunJob returned false
  217. m_bLocksFailed:1,
  218. m_bLocksLongHeld:1,
  219. m_bLocksLongWait:1,
  220. m_bWaitTimeout:1,
  221. m_bLongInterYield:1,
  222. m_bTimeoutNetMsg:1,
  223. m_bTimeoutOther:1,
  224. m_uUnused:24;
  225. } m_bits;
  226. uint32 m_uFlags;
  227. } m_flags;
  228. int m_cLocksAttempted;
  229. int m_cLocksWaitedFor;
  230. EJobPauseReason m_ePauseReason;
  231. const char *m_pszPauseResourceName;
  232. MsgType_t m_unWaitMsgType;
  233. CJobTime m_STimeStarted; // time (frame) at which this job started
  234. CJobTime m_STimeSwitched; // time (frame) at which we were last paused or continued
  235. CJobTime m_STimeNextHeartbeat; // Time at which next heartbeat should be performed
  236. CFastTimer m_FastTimerDelta; // How much time we've been running for without yielding
  237. CCycleCount m_cyclecountTotal; // Total runtime
  238. uint32 m_nContextMask; // The context that this job was created in. Typically only used for message jobs to indicate the initiator of the message
  239. CJob *m_pJobPrev; // the job that launched us
  240. // lock manipulation
  241. void _SetLock( CLock *pLock, const char *filename, int line );
  242. void UnsetLock( CLock *pLock );
  243. void PassLockToJob( CJob *pNewJob, CLock *pLock );
  244. void OnLockDeleted( CLock *pLock );
  245. void AddJobToNotifyOnLockRelease( CJob *pJob );
  246. CUtlVectorFixedGrowable< CLock *, 2 > m_vecLocks;
  247. CLock *m_pWaitingOnLock; // lock we're waiting on, if any
  248. const char *m_pWaitingOnLockFilename;
  249. int m_waitingOnLockLine;
  250. CJob *m_pJobToNotifyOnLockRelease; // other job that wants this lock
  251. CWorkItem *m_pWaitingOnWorkItem; // set if job is waiting for this work item
  252. #ifdef GC
  253. //context flags indicating what this job can access. Temporary and only for validating access on the GC
  254. uint32 m_nGCJobAccessType;
  255. //the steam ID that we are stating is safe to access. This is temporary to validate jobs during the split of the GC
  256. CSteamID m_SOCacheValidSteamID;
  257. #endif
  258. CJobMgr &m_JobMgr; // our job manager
  259. CUtlVectorFixedGrowable< IMsgNetPacket *, 1 > m_vecNetPackets; // list of tcp packets currently held by this job (ie, needing release on job exit)
  260. // pointer to our own static job info
  261. struct JobType_t const *m_pJobType;
  262. // Name of the job for when it's not registered
  263. const char *m_pchJobName;
  264. // setting the job info
  265. friend void Job_SetJobType( CJob &job, const JobType_t *pJobType );
  266. friend class CJobMgr;
  267. friend class CLock;
  268. // used to store the memory allocation stack
  269. CUtlMemory< unsigned char > m_memAllocStack;
  270. static bool s_bStartDefaultJobsDelayed;
  271. };
  272. // Only one job can be running at a time. We keep a global accessor to it.
  273. extern CJob *g_pJobCur;
  274. inline CJob &GJobCur() { Assert( g_pJobCur != NULL ); return *g_pJobCur; }
  275. #define AssertRunningJob() { Assert( NULL != g_pJobCur ); }
  276. #define AssertRunningThisJob() { Assert( this == g_pJobCur ); }
  277. #define AssertNotRunningThisJob() { Assert( this != g_pJobCur ); }
  278. #define AssertNotRunningJob() { Assert( NULL == g_pJobCur ); }
  279. //-----------------------------------------------------------------------------
  280. // Purpose: simple locking class
  281. // add this object to any classes you want jobs to be able to lock
  282. //-----------------------------------------------------------------------------
  283. #if defined( GC )
  284. #include "tier0/memdbgoff.h"
  285. #endif
  286. class CLock
  287. {
  288. #if defined( GC )
  289. DECLARE_CLASS_MEMPOOL( CLock );
  290. #endif
  291. public:
  292. CLock( );
  293. ~CLock();
  294. bool BIsLocked() const { return m_pJob != NULL; }
  295. CJob *GetJobLocking() { return m_pJob; }
  296. CJob *GetJobWaitingQueueHead() { return m_pJobToNotifyOnLockRelease; }
  297. CJob *GetJobWaitingQueueTail() { return m_pJobWaitingQueueTail; }
  298. void AddToWaitingQueue( CJob *pJob );
  299. const char *GetName() const;
  300. void SetName( const char *pchName );
  301. int16 GetLockType() const { return m_nsLockType; }
  302. void SetLockType( int16 nsLockType ) { m_nsLockType = nsLockType; }
  303. uint64 GetLockSubType() const { return m_unLockSubType; }
  304. void SetLockSubType( uint64 unLockSubType ) { m_unLockSubType = unLockSubType; }
  305. int32 GetWaitingCount() const { return m_nWaitingCount; }
  306. int64 GetMicroSecondsSinceLock() const { return m_sTimeAcquired.CServerMicroSecsPassed(); }
  307. void IncrementReference();
  308. int DecrementReference();
  309. void ClearReference() { m_nRefCount = 0; }
  310. int32 GetReferenceCount() const { return m_nRefCount; }
  311. void Dump( const char *pszPrefix = "\t\t", int nPrintMax = 1, bool bPrintWaiting = true ) const;
  312. private:
  313. CJob *m_pJob; // the job that's currently locking us
  314. CJob *m_pJobToNotifyOnLockRelease; // Pointer to the first job waiting on us
  315. CJob *m_pJobWaitingQueueTail; // Pointer to the last job waiting on us
  316. const char *m_pchConstStr; // Prefix part of the lock's name
  317. int32 m_nRefCount; // # of times locked
  318. int32 m_nWaitingCount; // Count of jobs waiting on the lock
  319. CJobTime m_sTimeAcquired; // Time the lock was last locked
  320. uint64 m_unLockSubType;
  321. const char *m_pFilename; // Filename of the source file who acquired this lock
  322. int m_line; // Line number of the filename
  323. int16 m_nsLockType; // Lock priority for safely waiting on multiple locks
  324. friend class CJob;
  325. };
  326. #if defined( GC )
  327. #include "tier0/memdbgon.h"
  328. #endif
  329. //-----------------------------------------------------------------------------------------
  330. // An auto lock class which handles auto lifetime management of a lock
  331. //-----------------------------------------------------------------------------------------
  332. class CGCAutoLock
  333. {
  334. public:
  335. CGCAutoLock() : m_pLock( NULL ) {}
  336. CGCAutoLock( const CGCAutoLock& rhs ) { Acquire( rhs.m_pLock ); }
  337. ~CGCAutoLock() { Release(); }
  338. //determines if this lock is currently locked or not
  339. bool IsLocked() const { return ( m_pLock != NULL ); }
  340. //swaps two locks (faster than doing reassignments due to not needing all the reference counting)
  341. void Swap( CGCAutoLock& rhs ) { std::swap( m_pLock, rhs.m_pLock ); }
  342. CGCAutoLock& operator=( const CGCAutoLock& rhs );
  343. //called to acquire a lock (the odd naming convention is to match the macro format to automatically provide the file and line of the call site)
  344. bool _BYieldingAcquireLock( CLock& lock, const char* pszFile, uint32 nLine );
  345. //called to release the current lock
  346. void Release();
  347. private:
  348. void Acquire( CLock* pLock );
  349. CLock* m_pLock;
  350. };
  351. //-----------------------------------------------------------------------------
  352. // Purpose: Use these macros to declare blocks where it is unsafe to yield.
  353. // The job will assert if it pauses within the block
  354. //-----------------------------------------------------------------------------
  355. #define DO_NOT_YIELD_THIS_SCOPE() CDoNotYieldScopeImpl doNotYieldScope_##line( FILE_AND_LINE )
  356. #define BEGIN_DO_NOT_YIELD() CDoNotYieldScopeImpl::InternalPush( FILE_AND_LINE )
  357. #define END_DO_NOT_YIELD() CDoNotYieldScopeImpl::InternalPop()
  358. class CDoNotYieldScopeImpl
  359. {
  360. public:
  361. explicit CDoNotYieldScopeImpl( const char *pchLocation ) { InternalPush( pchLocation ); }
  362. ~CDoNotYieldScopeImpl() { InternalPop(); }
  363. static void InternalPush( const char *pchLocation );
  364. static void InternalPop();
  365. private:
  366. // Disallow these constructors and operators
  367. CDoNotYieldScopeImpl( const CDoNotYieldScopeImpl &that );
  368. CDoNotYieldScopeImpl &operator=( const CDoNotYieldScopeImpl &that );
  369. };
  370. } // namespace GCSDK
  371. #include "tier0/memdbgoff.h"
  372. #endif // GC_JOB_H