#include "stdinc.h" #include "st.h" #include "stressharness.h" #define STRESSJOB_INI_SECTION_NAME (L"[StressJob]") #define STRESSJOB_INI_KEY_SLEEPTIME (L"SleepBetweenRuns") #define STRESSJOB_DEFAULT_SLEEP_TIME (50) CStressJobEntry::CStressJobEntry( CStressJobManager *pManager ) { this->m_dwSleepBetweenRuns = STRESSJOB_DEFAULT_SLEEP_TIME; this->m_fStop = false; this->m_pManager = pManager; this->m_ulFailures = this->m_ulRuns = 0; } BOOL CStressJobEntry::LoadFromSettingsFile( PCWSTR pcwszFileName ) { FN_PROLOG_WIN32 // // Right now, we only have one setting, in the [StressJob] section, the // time to sleep between runs. If it's not present, it defaults to // 50ms. // INT ulSleepTime = 0; IFW32FALSE_EXIT(SxspGetPrivateProfileIntW( STRESSJOB_INI_SECTION_NAME, STRESSJOB_INI_KEY_SLEEPTIME, STRESSJOB_DEFAULT_SLEEP_TIME, ulSleepTime, pcwszFileName)); this->m_dwSleepBetweenRuns = static_cast(ulSleepTime); FN_EPILOG } // // DNGN // CStressJobEntry::~CStressJobEntry() { FN_TRACE(); ASSERT(this->m_hThread == CThread::GetInvalidValue()); } BOOL CStressJobEntry::Stop( BOOL fWaitForCompletion ) { FN_PROLOG_WIN32 this->m_fStop = true; if ( fWaitForCompletion ) IFW32FALSE_EXIT(this->WaitForCompletion()); FN_EPILOG } BOOL CStressJobEntry::WaitForCompletion() { FN_PROLOG_WIN32 if ( m_hThread != m_hThread.GetInvalidValue() ) { IFW32FALSE_EXIT(WaitForSingleObject(m_hThread, INFINITE) == WAIT_OBJECT_0); } FN_EPILOG } BOOL CStressJobEntry::Cleanup() { FN_PROLOG_WIN32 if ( m_hThread != m_hThread.GetInvalidValue() ) { m_hThread.Win32Close(); m_hThread = m_hThread.GetInvalidValue(); } FN_EPILOG } BOOL CStressJobEntry::WaitForStartingGun() { FN_PROLOG_WIN32 ASSERT( m_pManager != NULL ); IFW32FALSE_EXIT(m_pManager->SignalAnotherJobReady()); IFW32FALSE_EXIT(m_pManager->WaitForStartEvent()); IFW32FALSE_EXIT(m_pManager->SignalThreadWorking()); FN_EPILOG } DWORD CStressJobEntry::ThreadProc( PVOID pv ) { FN_PROLOG_WIN32 CStressJobEntry *pEntry = reinterpret_cast(pv); PARAMETER_CHECK(pEntry != NULL); return pEntry->InternalThreadProc(); FN_EPILOG } DWORD CStressJobEntry::InternalThreadProc() { if (!this->WaitForStartingGun()) { const DWORD dwError = ::FusionpGetLastWin32Error(); ::ReportFailure("%ls:%ls failed waiting on starting event, error %ld", static_cast(m_pManager->GetGroupName()), static_cast(this->m_buffTestName), dwError); return 0; } if (!this->SetupSelfForRun()) { const DWORD dwError = ::FusionpGetLastWin32Error(); ReportFailure("%ls: test %ls failed to set itself up, error %ld", static_cast(m_pManager->GetGroupName()), static_cast(this->m_buffTestName), dwError); } else { while ( !m_fStop ) { bool fResult; if ( RunTest( fResult ) ) { const DWORD dwError = ::FusionpGetLastWin32Error(); wprintf(L"%ls: test %ls %ls, error %ld\n", static_cast(m_pManager->GetGroupName()), static_cast(this->m_buffTestName), fResult ? L"passes" : L"fails", dwError); } else { const DWORD dwError = ::FusionpGetLastWin32Error(); ReportFailure("%ls: test %ls failed to complete? Error %ld", static_cast(m_pManager->GetGroupName()), static_cast(this->m_buffTestName), dwError); } ::Sleep(this->m_dwSleepBetweenRuns); } } m_pManager->SignalThreadDone(); return 1; } BOOL CStressJobManager::SignalThreadWorking() { InterlockedIncrement((PLONG)&m_ulThreadsWorking); return TRUE; } BOOL CStressJobManager::SignalThreadDone() { InterlockedDecrement((PLONG)&m_ulThreadsWorking); return TRUE; } CStressJobManager::CStressJobManager() { if (!this->m_hStartingGunEvent.Win32CreateEvent(TRUE, FALSE)) { DebugBreak(); } m_ulThreadsCreated = 0; m_ulThreadsReady = 0; m_ulThreadsWorking = 0; } CStressJobManager::~CStressJobManager() { } BOOL CStressJobManager::StartJobs() { FN_PROLOG_WIN32 while ( m_ulThreadsReady != m_ulThreadsCreated ) ::Sleep(10); ASSERT(m_hStartingGunEvent != CEvent::GetInvalidValue()); IFW32FALSE_EXIT(SetEvent(m_hStartingGunEvent)); FN_EPILOG } BOOL CStressJobManager::CleanupJobs() { FN_PROLOG_WIN32 CStressEntryDequeIterator Iter(&this->m_JobsListed); for (Iter.Reset(); Iter.More(); Iter.Next()) { CStressJobEntry *pItem = Iter.Current(); pItem->Cleanup(); } m_JobsListed.ClearAndDeleteAll(); FN_EPILOG } BOOL CStressJobManager::StopJobs( BOOL fWithWaitForComplete ) { FN_PROLOG_WIN32 CStressEntryDequeIterator Iter(&this->m_JobsListed); for ( Iter.Reset(); Iter.More(); Iter.Next() ) { CStressJobEntry *pItem = Iter.Current(); pItem->Stop(fWithWaitForComplete); } FN_EPILOG } BOOL CStressJobManager::WaitForAllJobsComplete() { FN_PROLOG_WIN32 CStressEntryDequeIterator Iter(&this->m_JobsListed); for (Iter.Reset(); Iter.More(); Iter.Next()) { CStressJobEntry *pItem = Iter.Current(); pItem->WaitForCompletion(); } FN_EPILOG } BOOL CStressJobManager::CreateWorkerThreads( PULONG pulThreadsCreated ) { FN_PROLOG_WIN32 CStressEntryDequeIterator Iter(&this->m_JobsListed); INTERNAL_ERROR_CHECK( m_ulThreadsCreated == 0 ); if ( pulThreadsCreated ) *pulThreadsCreated = 0; m_ulThreadsCreated = 0; for ( Iter.Reset(); Iter.More(); Iter.Next() ) { CStressJobEntry *pType = Iter.Current(); IFW32FALSE_EXIT(pType->m_hThread.Win32CreateThread( pType->ThreadProc, pType )); this->m_ulThreadsCreated++; } if ( pulThreadsCreated ) *pulThreadsCreated = m_ulThreadsCreated; FN_EPILOG } BOOL CStressJobManager::SignalAnotherJobReady() { ::InterlockedIncrement((PLONG)&m_ulThreadsReady); return TRUE; } BOOL CStressJobManager::WaitForStartEvent() { return WaitForSingleObject( this->m_hStartingGunEvent, INFINITE ) == WAIT_OBJECT_0; } BOOL CStressJobManager::LoadFromDirectory( PCWSTR pcwszDirectoryName, PULONG pulJobsFound ) { FN_PROLOG_WIN32 CStringBuffer buffSearchString; CFindFile Finder; WIN32_FIND_DATAW FindData; PARAMETER_CHECK(pcwszDirectoryName); if ( pulJobsFound ) *pulJobsFound = 0; IFW32FALSE_EXIT(buffSearchString.Win32Assign(pcwszDirectoryName, ::wcslen(pcwszDirectoryName))); IFW32FALSE_EXIT(buffSearchString.Win32AppendPathElement(L"*", 1)); Finder = ::FindFirstFileW(buffSearchString, &FindData); if (Finder == INVALID_HANDLE_VALUE) { ::ReportFailure("No tests found in directory %ls", pcwszDirectoryName); FN_SUCCESSFUL_EXIT(); } IFW32FALSE_EXIT(buffSearchString.Win32RemoveLastPathElement()); do { if (FusionpIsDotOrDotDot(FindData.cFileName)) continue; CStringBuffer buffFoundName; CStressJobEntry *pNextEntry = NULL; IFW32FALSE_EXIT(buffFoundName.Win32Assign(buffSearchString)); IFW32FALSE_EXIT(buffFoundName.Win32AppendPathElement( FindData.cFileName, ::wcslen(FindData.cFileName))); // // Let's get ourselves another job entry // IFW32FALSE_EXIT(this->CreateJobEntry(pNextEntry)); INTERNAL_ERROR_CHECK(pNextEntry != NULL); // // Name and full path of test directory // IFW32FALSE_EXIT(pNextEntry->m_buffTestDirectory.Win32Assign(buffFoundName)); IFW32FALSE_EXIT(pNextEntry->m_buffTestName.Win32Assign( FindData.cFileName, ::wcslen(FindData.cFileName))); // // And now have it load settings // IFW32FALSE_EXIT(buffFoundName.Win32AppendPathElement( this->GetIniFileName(), ::wcslen(this->GetIniFileName()))); IFW32FALSE_EXIT(pNextEntry->LoadFromSettingsFile(buffFoundName)); // // So far, so good - add it to the list of created job entries // this->m_JobsListed.AddToTail(pNextEntry); pNextEntry = NULL; } while ( ::FindNextFileW(Finder, &FindData) ); if (::FusionpGetLastWin32Error() != ERROR_NO_MORE_FILES) goto Exit; // // Outward bound? // if ( pulJobsFound ) *pulJobsFound = static_cast(this->m_JobsListed.GetEntryCount()); FN_EPILOG }