|
|
#include "stock.h"
#pragma hdrstop
#include "runtask.h"
#define SUPERCLASS
// #define TF_RUNTASK TF_GENERAL
#define TF_RUNTASK 0
// #define TF_RUNTASKV TF_CUSTOM1 // verbose version
#define TF_RUNTASKV 0
// constructor
CRunnableTask::CRunnableTask(DWORD dwFlags) { _lState = IRTIR_TASK_NOT_RUNNING; _dwFlags = dwFlags;
ASSERT(NULL == _hDone); if (_dwFlags & RTF_SUPPORTKILLSUSPEND) { // we signal this on suspend or kill
// Explicitly call the ANSI version so we don't need to worry
// about whether we're being built UNICODE and have to switch
// to a wrapper function...
_hDone = CreateEventA(NULL, TRUE, FALSE, NULL); }
#ifdef DEBUG
_dwTaskID = GetTickCount();
TraceMsg(TF_RUNTASK, "CRunnableTask (%#lx): creating task", _dwTaskID); #endif
_cRef = 1; }
// destructor
CRunnableTask::~CRunnableTask() { DEBUG_CODE( TraceMsg(TF_RUNTASK, "CRunnableTask (%#lx): deleting task", _dwTaskID); )
if (_hDone) CloseHandle(_hDone); }
STDMETHODIMP CRunnableTask::QueryInterface( REFIID riid, LPVOID * ppvObj ) { if ( ppvObj == NULL ) { return E_INVALIDARG; } if ( riid == IID_IRunnableTask ) { *ppvObj = SAFECAST( this, IRunnableTask *); AddRef(); } else return E_NOINTERFACE;
return NOERROR; }
STDMETHODIMP_(ULONG) CRunnableTask::AddRef() { return InterlockedIncrement(&_cRef); }
STDMETHODIMP_ (ULONG) CRunnableTask::Release() { AssertMsg( 0 != _cRef, TEXT("RefCount problem.") ); ULONG cRef = InterlockedDecrement(&_cRef); if ( 0 == cRef ) { delete this; } return cRef; }
/*----------------------------------------------------------
Purpose: IRunnableTask::Run method
This does a lot of the state-related work, and then calls the derived-class's RunRT() method. */ STDMETHODIMP CRunnableTask::Run(void) { HRESULT hr = E_FAIL;
// Are we already running?
if (_lState == IRTIR_TASK_RUNNING) { // Yes; nothing to do
hr = S_FALSE; } else if ( _lState == IRTIR_TASK_PENDING ) { hr = E_FAIL; } else if ( _lState == IRTIR_TASK_NOT_RUNNING ) { // Say we're running
LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_RUNNING); if ( lRes == IRTIR_TASK_PENDING ) { _lState = IRTIR_TASK_FINISHED; return NOERROR; }
if (_lState == IRTIR_TASK_RUNNING) { // Prepare to run
DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): initialize to run", _dwTaskID); ) hr = RunInitRT(); ASSERT(E_PENDING != hr); }
if (SUCCEEDED(hr)) { if (_lState == IRTIR_TASK_RUNNING) { // Continue to do the work
hr = InternalResumeRT(); } else if (_lState == IRTIR_TASK_SUSPENDED) { // it is possible that RunInitRT took a little longer to complete and our state changed
// from running to suspended with _hDone signaled, which would cause us to not call
// internal resume. We simulate internal resume here
if (_hDone) ResetEvent(_hDone); hr = E_PENDING; } }
if (FAILED(hr) && E_PENDING != hr) { DEBUG_CODE( TraceMsg(TF_WARNING, "CRunnableTask (%#lx): task failed to run: %#lx", _dwTaskID, hr); ) }
// Are we finished?
if (_lState != IRTIR_TASK_SUSPENDED || hr != E_PENDING) { // Yes
_lState = IRTIR_TASK_FINISHED; } } return hr; }
/*----------------------------------------------------------
Purpose: IRunnableTask::Kill method
*/ STDMETHODIMP CRunnableTask::Kill(BOOL fWait) { if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) ) return E_NOTIMPL; if (_lState != IRTIR_TASK_RUNNING) return S_FALSE;
DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): killing task", _dwTaskID); )
LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_PENDING); if (lRes == IRTIR_TASK_FINISHED) { DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); )
_lState = lRes; } else if (_hDone) { // signal the event it is likely to be waiting on
SetEvent(_hDone); }
return KillRT(fWait); }
/*----------------------------------------------------------
Purpose: IRunnableTask::Suspend method
*/ STDMETHODIMP CRunnableTask::Suspend( void ) { if ( !(_dwFlags & RTF_SUPPORTKILLSUSPEND) ) return E_NOTIMPL; if (_lState != IRTIR_TASK_RUNNING) return E_FAIL; DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): suspending task", _dwTaskID); ) LONG lRes = InterlockedExchange(&_lState, IRTIR_TASK_SUSPENDED);
if (IRTIR_TASK_FINISHED == lRes) { // we finished before we could suspend
DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): task already finished", _dwTaskID); ) _lState = lRes; return NOERROR; }
if (_hDone) SetEvent(_hDone);
return SuspendRT(); }
/*----------------------------------------------------------
Purpose: IRunnableTask::Resume method
*/ STDMETHODIMP CRunnableTask::Resume(void) { if (_lState != IRTIR_TASK_SUSPENDED) return E_FAIL;
DEBUG_CODE( TraceMsg(TF_RUNTASKV, "CRunnableTask (%#lx): resuming task", _dwTaskID); )
_lState = IRTIR_TASK_RUNNING; if (_hDone) ResetEvent(_hDone);
return ResumeRT(); }
/*----------------------------------------------------------
Purpose: IRunnableTask::IsRunning method
*/ STDMETHODIMP_( ULONG ) CRunnableTask:: IsRunning ( void ) { return _lState; }
|