219 lines
4.4 KiB
C++
219 lines
4.4 KiB
C++
|
/*++
|
||
|
|
||
|
Copyright (c) 1994 Microsoft Corporation
|
||
|
All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
exec.hxx
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
Executes asynchronous commands. Layered on top of TThreadM.
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Albert Ting (AlbertT) 7-Nov-1994
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
--*/
|
||
|
|
||
|
#ifndef _EXEC_HXX
|
||
|
#define _EXEC_HXX
|
||
|
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
This module implements an asynchronous, pooled threads to
|
||
|
processes worker jobs.
|
||
|
|
||
|
class TJobUnit : public MExecWork {
|
||
|
...
|
||
|
}
|
||
|
|
||
|
gpExec->bJobAdd( pJobUnit, USER_SPECIFIED_BITFIELD );
|
||
|
|
||
|
//
|
||
|
// When thread is available to process job,
|
||
|
// pJobUnit->svExecute( USER_SPECIFIED_BITFIELD, ... )
|
||
|
// will be called.
|
||
|
//
|
||
|
|
||
|
Declare a class Work derived from the mix-in MExecWork. When
|
||
|
work needs to be done on an instantiation of Work, it is queued
|
||
|
and immediately returned. A DWORD bitfield--4 high bits are
|
||
|
predefined--indicates the type of work needed.
|
||
|
|
||
|
This DWORD should be a bitfield, so if there are multiple
|
||
|
bJobAdd requests and all threads are busy, these DWORDs are
|
||
|
OR'd together.
|
||
|
|
||
|
That is,
|
||
|
|
||
|
bJobAdd( pJobUnit, 0x1 );
|
||
|
bJobAdd( pJobUnit, 0x2 );
|
||
|
bJobAdd( pJobUnit, 0x4 );
|
||
|
bJobAdd( pJobUnit, 0x8 );
|
||
|
|
||
|
We will call svExecute with 0xf.
|
||
|
|
||
|
Two threads will never operate on one job simultaneously. This
|
||
|
is guarenteed by this library.
|
||
|
|
||
|
The worker routine is defined by the virtual function stExecute().
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
typedef enum _STATE_EXEC {
|
||
|
kExecUser = 0x08000000, // Here and below user may specify.
|
||
|
kExecRunNow = 0x10000000, // Ignore thread limit.
|
||
|
kExecExit = 0x20000000, // User requests the TExec exits.
|
||
|
kExecActive = 0x40000000, // Private: job is actively running.
|
||
|
kExecActiveReq = 0x80000000, // Private: job is queued.
|
||
|
|
||
|
kExecPrivate = kExecActive | kExecActiveReq,
|
||
|
kExecNoOutput = kExecPrivate | kExecRunNow
|
||
|
|
||
|
} STATE_EXEC;
|
||
|
|
||
|
|
||
|
class TExec;
|
||
|
|
||
|
class MExecWork {
|
||
|
friend TExec;
|
||
|
|
||
|
SIGNATURE( 'exwk' );
|
||
|
ALWAYS_VALID
|
||
|
SAFE_NEW
|
||
|
|
||
|
private:
|
||
|
|
||
|
DLINK( MExecWork, Work );
|
||
|
|
||
|
//
|
||
|
// Accessed by worker thread.
|
||
|
//
|
||
|
VAR( TState, State );
|
||
|
|
||
|
//
|
||
|
// StatePending is work that is pending (accumulated while the
|
||
|
// job is executing in a thread). The job at this stage is
|
||
|
// not in the queue.
|
||
|
//
|
||
|
VAR( TState, StatePending );
|
||
|
|
||
|
virtual
|
||
|
STATEVAR
|
||
|
svExecute(
|
||
|
STATEVAR StateVar
|
||
|
) = 0;
|
||
|
|
||
|
virtual
|
||
|
VOID
|
||
|
vExecFailedAddJob(
|
||
|
VOID
|
||
|
) = 0;
|
||
|
|
||
|
/********************************************************************
|
||
|
|
||
|
vExecExitComplete is called when a job completes and it is
|
||
|
pending deletion. This allows a client to allow all pending
|
||
|
work to complete before it deletes the object.
|
||
|
|
||
|
User adds job.
|
||
|
Job starts executing..,
|
||
|
User decides job should be deleted so adds EXEC_EXIT.
|
||
|
... job finally completes.
|
||
|
Library calls vExecExitComplete on job
|
||
|
Client can now delete work object in vExecExitComplete call.
|
||
|
|
||
|
Note that only jobs that are currently executing are allowed
|
||
|
to complete. Jobs that are queued to work will exit immediately.
|
||
|
|
||
|
********************************************************************/
|
||
|
|
||
|
virtual
|
||
|
VOID
|
||
|
vExecExitComplete(
|
||
|
VOID
|
||
|
) = 0;
|
||
|
};
|
||
|
|
||
|
|
||
|
class TExec : public TThreadM {
|
||
|
|
||
|
SIGNATURE( 'exec' );
|
||
|
SAFE_NEW
|
||
|
|
||
|
public:
|
||
|
|
||
|
TExec( MCritSec* pCritSec );
|
||
|
|
||
|
//
|
||
|
// Clients should use vDelete, _not_ ~TExec.
|
||
|
//
|
||
|
~TExec(
|
||
|
VOID
|
||
|
)
|
||
|
{ }
|
||
|
|
||
|
VOID
|
||
|
vDelete(
|
||
|
VOID
|
||
|
)
|
||
|
{
|
||
|
TThreadM::vDelete();
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
bValid(
|
||
|
VOID
|
||
|
) const
|
||
|
{
|
||
|
return TThreadM::bValid();
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
bJobAdd(
|
||
|
MExecWork* pExecWork,
|
||
|
STATEVAR StateVar
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
vJobDone(
|
||
|
MExecWork* pExecWork,
|
||
|
STATEVAR StateVar
|
||
|
);
|
||
|
|
||
|
STATEVAR
|
||
|
svClearPendingWork(
|
||
|
MExecWork* pExecWork
|
||
|
);
|
||
|
|
||
|
private:
|
||
|
|
||
|
DLINK_BASE( MExecWork, Work, Work );
|
||
|
MCritSec* _pCritSec;
|
||
|
|
||
|
//
|
||
|
// Virtual definitions for TThreadM.
|
||
|
//
|
||
|
PJOB
|
||
|
pThreadMJobNext(
|
||
|
VOID
|
||
|
);
|
||
|
VOID
|
||
|
vThreadMJobProcess(
|
||
|
PJOB pJob
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
bJobAddWorker(
|
||
|
MExecWork* pExecWork
|
||
|
);
|
||
|
};
|
||
|
|
||
|
#endif // ndef _EXEC_HXX
|
||
|
|