1
0
mirror of https://github.com/alliedmodders/hl2sdk.git synced 2025-01-04 00:23:25 +08:00
hl2sdk/public/tier1/jobthread.h
2008-09-15 01:33:59 -05:00

261 lines
9.2 KiB
C++

//========== Copyright © 2005, Valve Corporation, All rights reserved. ========
//
// Purpose: A utility for a discrete job-oriented worker thread.
//
// The class CAsyncJobFuliller is both the job queue, and the
// worker thread. Except when the main thread attempts to
// synchronously execute a job, most of the inter-thread locking
// on the queue.
//
// The queue threading model uses a manual reset event for optimal
// throughput. Adding to the queue is guarded by a semaphore that
// will block the inserting thread if the queue has overflown.
// This prevents the worker thread from being starved out even if
// not running at a higher priority than the master thread.
//
// The thread function waits for jobs, services jobs, and manages
// communication between the worker and master threads. The nature
// of the work is opaque to the fulfiller.
//
// CAsyncJob instances actually do the work. The base class
// calls virtual methods for job primitives, so derivations don't
// need to worry about threading models. All of the variants of
// job and OS can be expressed in this hierarchy. Instances of
// CAsyncJob are the items placed in the queue, and by
// overriding the job primitives they are the manner by which
// users of the fulfiller control the state of the job.
//
//=============================================================================
#include <limits.h>
#include "tier0/threadtools.h"
#include "tier1/refcount.h"
#include "tier1/utllinkedlist.h"
#ifndef JOBTHREAD_H
#define JOBTHREAD_H
#ifdef AddJob // windows.h print function collisions
#undef AddJob
#undef GetJob
#endif
#if defined( _WIN32 )
#pragma once
#endif
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
class CAsyncJob;
//-----------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------
enum AsyncStatusEnum_t
{
// Use negative for errors
ASYNC_OK, // operation is successful
ASYNC_STATUS_PENDING, // file is properly queued, waiting for service
ASYNC_STATUS_INPROGRESS, // file is being accessed
ASYNC_STATUS_ABORTED, // file was aborted by caller
ASYNC_STATUS_UNSERVICED, // file is not yet queued
};
typedef int AsyncStatus_t;
enum AsyncJobFlags_t
{
AJF_IO = ( 1 << 0 ), // The job primarily blocks on IO or hardware
AJF_BOOST_THREAD = ( 1 << 1 ), // Up the thread priority to max allowed while processing task
};
enum AsyncJobPriority_t
{
AJP_LOW,
AJP_NORMAL,
AJP_HIGH
};
//-----------------------------------------------------------------------------
//
// CAsyncJobFuliller
//
//-----------------------------------------------------------------------------
//---------------------------------------------------------
// Messages supported through the CallWorker() method
//---------------------------------------------------------
enum AsyncFulfillerMessages_t
{
AF_EXIT, // Exit the thread
AF_SUSPEND, // Suspend after next operation
};
class CAsyncJobFuliller : public CWorkerThread
{
public:
CAsyncJobFuliller( int maxJobs );
CAsyncJobFuliller();
~CAsyncJobFuliller();
//-----------------------------------------------------
// Thread functions
//-----------------------------------------------------
bool Start( unsigned nBytesStack = 0 );
//-----------------------------------------------------
// Functions for any thread
//-----------------------------------------------------
unsigned GetJobCount() { AUTO_LOCK( m_mutex ); return m_queue.Count(); }
bool IsUsingSemaphore() { AUTO_LOCK( m_mutex ); return m_bUseSemaphore; }
//-----------------------------------------------------
// Pause/resume processing jobs
//-----------------------------------------------------
int SuspendExecution();
int ResumeExecution();
//-----------------------------------------------------
// Execute a job in the context of the worker thread
//-----------------------------------------------------
AsyncStatus_t ExecuteImmediate( CAsyncJob * );
//-----------------------------------------------------
// Add a job to the queue (master thread)
//-----------------------------------------------------
void AddJob( CAsyncJob * );
//-----------------------------------------------------
// Remove a job from the queue (master thread)
//-----------------------------------------------------
void ReprioritizedJob( CAsyncJob *p ) { if ( RemoveJob( p ) ) AddJob( p ); }
//-----------------------------------------------------
// Remove a job from the queue (master thread)
//-----------------------------------------------------
bool RemoveJob( CAsyncJob * );
//-----------------------------------------------------
// Bulk job manipulation (blocking)
//-----------------------------------------------------
int ExecuteAll() { return ExecuteToPriority( AJP_LOW ); }
int ExecuteToPriority( AsyncJobPriority_t toPriority );
int AbortAll();
//-----------------------------------------------------
// Queue lock
//-----------------------------------------------------
CThreadMutex &GetQueueLock() { return m_mutex; }
//-----------------------------------------------------
// Remove the next job from the queue (worker thread, or master when worker suspended)
//-----------------------------------------------------
CAsyncJob *GetJob();
//-----------------------------------------------------
// Raw access to queue. Should lock queue or suspend worker before using
//-----------------------------------------------------
CUtlLinkedList<CAsyncJob *> &AccessQueue() { return m_queue; }
protected:
//-----------------------------------------------------
// Thread functions
//-----------------------------------------------------
int Run();
#if defined( _WIN32 )
//-----------------------------------------------------
// Get handle to include in WaitForMultipleObjects wait list (worker thread)
//-----------------------------------------------------
HANDLE GetJobSignalHandle() { return m_JobSignal; }
#endif
private:
void WaitPut();
void ReleasePut();
CUtlLinkedList<CAsyncJob *> m_queue;
CThreadMutex m_mutex;
CThreadEvent m_JobSignal;
#ifdef _WIN32
CThreadSemaphore m_PutSemaphore;
#endif
bool m_bUseSemaphore;
int m_nSuspend;
};
//-----------------------------------------------------------------------------
// Class to combine the metadata for an operation and the ability to perform
// the operation
//-----------------------------------------------------------------------------
abstract_class CAsyncJob : public CRefCounted1<IRefCounted, CRefCountServiceMT>
{
public:
CAsyncJob( AsyncJobPriority_t priority = AJP_NORMAL )
: m_status( ASYNC_STATUS_UNSERVICED ),
m_priority( priority ),
m_queueID( -1 ),
m_pFulfiller( NULL )
{
}
//-----------------------------------------------------
// Priority (not thread safe)
//-----------------------------------------------------
void SetPriority( AsyncJobPriority_t priority ) { m_priority = priority; }
AsyncJobPriority_t GetPriority() const { return m_priority; }
//-----------------------------------------------------
// Fast queries
//-----------------------------------------------------
bool Executed() const { return ( m_status == ASYNC_OK ); }
bool IsFinished() const { return ( m_status != ASYNC_STATUS_PENDING && m_status != ASYNC_STATUS_INPROGRESS && m_status != ASYNC_STATUS_UNSERVICED ); }
AsyncStatus_t GetStatus() const { return m_status; }
//-----------------------------------------------------
// Try to acquire ownership (to satisfy). If you take the lock, you must either execute or abort.
//-----------------------------------------------------
bool TryLock() const { return m_mutex.TryLock(); }
void Lock() const { m_mutex.Lock(); }
void Unlock() const { m_mutex.Unlock(); }
//-----------------------------------------------------
// Perform the job
//-----------------------------------------------------
AsyncStatus_t Execute();
AsyncStatus_t TryExecute();
//-----------------------------------------------------
// Terminate the job, discard if partially or wholly fulfilled
//-----------------------------------------------------
AsyncStatus_t Abort( bool bDiscard = true );
virtual char const *Describe() { return "AsyncJob"; }
protected:
//-----------------------------------------------------
friend class CAsyncJobFuliller;
AsyncStatus_t m_status;
AsyncJobPriority_t m_priority;
int m_queueID;
CThreadMutex m_mutex;
CAsyncJobFuliller * m_pFulfiller;
private:
//-----------------------------------------------------
CAsyncJob( const CAsyncJob &fromRequest );
void operator=(const CAsyncJob &fromRequest );
virtual AsyncStatus_t DoExecute() = 0;
virtual AsyncStatus_t DoAbort( bool bDiscard ) { return ASYNC_STATUS_ABORTED; }
virtual void DoCleanup() {}
};
//-----------------------------------------------------------------------------
#endif // JOBTHREAD_H