163 lines
3.9 KiB
C++
163 lines
3.9 KiB
C++
#pragma once
|
|
|
|
class CStressJobManager;
|
|
|
|
|
|
class CBarrier
|
|
{
|
|
CEvent m_hBarrierEvent;
|
|
LONG m_lBarrierSize;
|
|
LONG m_lWaitingThreads;
|
|
|
|
PRIVATIZE_COPY_CONSTRUCTORS(CBarrier)
|
|
|
|
public:
|
|
|
|
CBarrier() : m_lBarrierSize(0), m_lWaitingThreads(0) { }
|
|
|
|
//
|
|
// Start up, with the given barrier size and name (if any)
|
|
//
|
|
BOOL Initialize( DWORD lBarrierSize, PCWSTR pcwszBarrierName = NULL )
|
|
{
|
|
FN_PROLOG_WIN32
|
|
m_lBarrierSize = lBarrierSize;
|
|
m_lWaitingThreads = 0;
|
|
IFW32FALSE_EXIT(m_hBarrierEvent.Win32CreateEvent(TRUE, FALSE, pcwszBarrierName));
|
|
FN_EPILOG
|
|
}
|
|
|
|
//
|
|
// This thread is to join the barrier. It's possible that this call will be
|
|
// the one that "breaks" the barrier..
|
|
//
|
|
BOOL WaitForBarrier()
|
|
{
|
|
FN_PROLOG_WIN32
|
|
|
|
LONG LatestValue = ::InterlockedIncrement(&m_lWaitingThreads);
|
|
|
|
if ( LatestValue >= m_lBarrierSize )
|
|
{
|
|
IFW32FALSE_EXIT(::SetEvent(m_hBarrierEvent));
|
|
}
|
|
else
|
|
{
|
|
IFW32FALSE_EXIT(::WaitForSingleObject(m_hBarrierEvent, INFINITE) == WAIT_OBJECT_0);
|
|
}
|
|
|
|
FN_EPILOG
|
|
}
|
|
|
|
//
|
|
// In case someone wants to wait on us without actually joining in to count
|
|
// for breaking the barrier (why??)
|
|
//
|
|
BOOL WaitForBarrierNoJoin()
|
|
{
|
|
FN_PROLOG_WIN32
|
|
IFW32FALSE_EXIT(::WaitForSingleObject(m_hBarrierEvent, INFINITE) == WAIT_OBJECT_0);
|
|
FN_EPILOG
|
|
}
|
|
|
|
//
|
|
// A thread has a reason to break the barrier early? Fine, let them.
|
|
//
|
|
BOOL EarlyRelease()
|
|
{
|
|
FN_PROLOG_WIN32
|
|
IFW32FALSE_EXIT(::SetEvent(m_hBarrierEvent));
|
|
FN_EPILOG
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class CStressJobEntry
|
|
{
|
|
DWORD InternalThreadProc();
|
|
BOOL WaitForStartingGun();
|
|
|
|
PRIVATIZE_COPY_CONSTRUCTORS(CStressJobEntry);
|
|
|
|
public:
|
|
CDequeLinkage m_dlLinkage;
|
|
CThread m_hThread;
|
|
bool m_fStop;
|
|
ULONG m_ulRuns;
|
|
ULONG m_ulFailures;
|
|
DWORD m_dwSleepBetweenRuns;
|
|
CStringBuffer m_buffTestName;
|
|
CStringBuffer m_buffTestDirectory;
|
|
CStressJobManager *m_pManager;
|
|
|
|
//
|
|
// Override these three to provide functionality
|
|
//
|
|
virtual BOOL RunTest( bool &rfTestPasses ) = 0;
|
|
virtual BOOL SetupSelfForRun() = 0;
|
|
virtual BOOL Cleanup();
|
|
virtual BOOL LoadFromSettingsFile( PCWSTR pcwszSettingsFile );
|
|
|
|
//
|
|
// These are not to be overridden!
|
|
//
|
|
BOOL Stop( BOOL fWaitForCompletion = TRUE );
|
|
BOOL WaitForCompletion();
|
|
static DWORD ThreadProc( PVOID pv );
|
|
|
|
CStressJobEntry( CStressJobManager *pManager );
|
|
virtual ~CStressJobEntry();
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef CDeque<CStressJobEntry, offsetof(CStressJobEntry, m_dlLinkage)> CStressEntryDeque;
|
|
typedef CDequeIterator<CStressJobEntry, offsetof(CStressJobEntry, m_dlLinkage)> CStressEntryDequeIterator;
|
|
|
|
|
|
class CStressJobManager
|
|
{
|
|
PRIVATIZE_COPY_CONSTRUCTORS(CStressJobManager);
|
|
|
|
friend CStressJobEntry;
|
|
|
|
CEvent m_hStartingGunEvent;
|
|
ULONG m_ulThreadsCreated;
|
|
ULONG m_ulThreadsReady;
|
|
|
|
BOOL SignalAnotherJobReady();
|
|
BOOL SignalThreadWorking();
|
|
BOOL SignalThreadDone();
|
|
BOOL WaitForStartEvent();
|
|
|
|
public:
|
|
CStressEntryDeque m_JobsListed;
|
|
ULONG m_ulThreadsWorking;
|
|
|
|
BOOL LoadFromDirectory( PCWSTR pcwszDirectoryName, PULONG pulJobsFound = NULL );
|
|
BOOL CreateWorkerThreads( PULONG pulThreadsCreated = NULL );
|
|
BOOL StopJobs( BOOL fWithWaitForComplete = TRUE );
|
|
BOOL CleanupJobs();
|
|
BOOL StartJobs();
|
|
BOOL WaitForAllJobsComplete();
|
|
|
|
//
|
|
// This returns the directory name that the manager will use to find
|
|
// data files/directories.
|
|
//
|
|
virtual PCWSTR GetGroupName() = 0;
|
|
virtual PCWSTR GetIniFileName() = 0;
|
|
|
|
CStressJobManager();
|
|
~CStressJobManager();
|
|
|
|
protected:
|
|
virtual BOOL CreateJobEntry( CStressJobEntry* &pJobEntry ) = 0;
|
|
|
|
};
|
|
|
|
|