You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
842 lines
24 KiB
842 lines
24 KiB
//////////////////////////////////////////////////////////////////////
|
|
// File: StressInstance.cpp
|
|
//
|
|
// Copyright (c) 2001 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
// Purpose:
|
|
// StressInstance.cpp: interface for the StressInstance class.
|
|
// This class is used spawn and monitor instances of the stressEXE app
|
|
//
|
|
// History:
|
|
// 02/15/01 DennisCh Created
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Includes
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Win32 headers
|
|
//
|
|
|
|
//
|
|
// Project headers
|
|
//
|
|
#include "StressInstance.h"
|
|
#include "ServerCommands.h"
|
|
#include "NetworkTools.h"
|
|
#include "MemStats.h"
|
|
#include "debugger.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Globals and statics
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
extern ServerCommands g_objServerCommands; // Declared in WinHttpStressScheduler.cpp
|
|
extern HWND g_hWnd; // Declared in WinHttpStressScheduler.cpp
|
|
|
|
StressInstance *g_hThis; // the current StressInstance object. Used only in (friend) StressExe_TimerProc.
|
|
UINT_PTR g_uiStressExeTimerID; // ID for the timer that monitors the stressExe when it's spawned
|
|
|
|
// Forward function definitions
|
|
|
|
VOID
|
|
CALLBACK
|
|
StressExe_TimerProc(
|
|
HWND hwnd, // [IN] handle to window
|
|
UINT uMsg, // [IN] WM_TIMER message
|
|
UINT_PTR idEvent, // [IN] timer identifier
|
|
DWORD dwTime // [IN] current system time
|
|
);
|
|
|
|
DWORD
|
|
DebuggerCallbackProc(
|
|
DWORD dwFlags,
|
|
LPVOID lpIn,
|
|
LPTSTR lpszFutureString,
|
|
LPVOID lpFuturePointer
|
|
);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
|
// Construction/Destruction
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
StressInstance::StressInstance()
|
|
{
|
|
m_szStressExe_URL = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_PDB_URL = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_SYM_URL = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_FilePath = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_FileName = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_FilePathAndName = new TCHAR[MAX_STRESS_URL];
|
|
m_szStressExe_PageHeapCommandLine = new TCHAR[MAX_PATH];
|
|
m_szStressExe_UMDHCommandLine = new TCHAR[MAX_PATH];
|
|
m_szStressExe_MemDumpPath = new TCHAR[MAX_PATH];
|
|
|
|
ZeroMemory(m_szStressExe_URL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_PDB_URL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_SYM_URL, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_FilePath, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_FileName, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_FilePathAndName, MAX_STRESS_URL);
|
|
ZeroMemory(m_szStressExe_PageHeapCommandLine, MAX_PATH);
|
|
ZeroMemory(m_szStressExe_UMDHCommandLine, MAX_PATH);
|
|
ZeroMemory(m_szStressExe_MemDumpPath, MAX_PATH);
|
|
|
|
ZeroMemory(&m_piStressExeProcess, sizeof(PROCESS_INFORMATION));
|
|
|
|
m_hStressExe_ProcessExitEvent = NULL;
|
|
g_uiStressExeTimerID = 0;
|
|
|
|
m_objDebugger = NULL;
|
|
|
|
g_hThis = this;
|
|
}
|
|
|
|
|
|
StressInstance::~StressInstance()
|
|
{
|
|
// End any running tests
|
|
if (IsRunning(STRESSINSTANCE_STRESS_EXE_CLOSE_TIMEOUT))
|
|
StressInstance::End();
|
|
|
|
delete [] m_szStressExe_URL;
|
|
delete [] m_szStressExe_PDB_URL;
|
|
delete [] m_szStressExe_SYM_URL;
|
|
delete [] m_szStressExe_FilePath;
|
|
delete [] m_szStressExe_FileName;
|
|
delete [] m_szStressExe_FilePathAndName;
|
|
delete [] m_szStressExe_PageHeapCommandLine;
|
|
delete [] m_szStressExe_UMDHCommandLine;
|
|
delete [] m_szStressExe_MemDumpPath;
|
|
|
|
|
|
m_szStressExe_URL = NULL;
|
|
m_szStressExe_PDB_URL = NULL;
|
|
m_szStressExe_SYM_URL = NULL;
|
|
m_szStressExe_FilePath = NULL;
|
|
m_szStressExe_FileName = NULL;
|
|
m_szStressExe_FilePathAndName = NULL;
|
|
m_szStressExe_PageHeapCommandLine = NULL;
|
|
m_szStressExe_UMDHCommandLine = NULL;
|
|
m_szStressExe_MemDumpPath = NULL;
|
|
|
|
// close stressExe process handles
|
|
if (m_piStressExeProcess.hThread)
|
|
CloseHandle(m_piStressExeProcess.hThread);
|
|
|
|
if (m_piStressExeProcess.hProcess)
|
|
CloseHandle(m_piStressExeProcess.hProcess);
|
|
|
|
if (m_hStressExe_ProcessExitEvent)
|
|
CloseHandle(m_hStressExe_ProcessExitEvent);
|
|
|
|
m_piStressExeProcess.hThread = NULL;
|
|
m_piStressExeProcess.hProcess = NULL;
|
|
m_hStressExe_ProcessExitEvent = NULL;
|
|
|
|
// free debugger object
|
|
if (m_objDebugger)
|
|
{
|
|
delete m_objDebugger;
|
|
m_objDebugger = NULL;
|
|
}
|
|
|
|
g_hThis = NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Begin()
|
|
//
|
|
// Purpose:
|
|
// This method begins stress by downloading the stress EXE from
|
|
// m_szStressExe_URL and starts it in CDB.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
StressInstance::Begin()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
LPTSTR szCommandLine = new TCHAR[MAX_STRESS_URL*4];
|
|
LPTSTR szFileNameAndPath = new TCHAR[MAX_STRESS_URL*2];
|
|
DWORD dwCommandLineSize = MAX_STRESS_URL*4;
|
|
DWORD dwFileNameAndPathSize = MAX_STRESS_URL*2;
|
|
LPSTARTUPINFO pStartUpInfo = new STARTUPINFO;
|
|
|
|
|
|
// don't start if stress is already running or we don't have a FileName or Path.
|
|
if (IsRunning(5000) ||
|
|
0 >= _tcslen(m_szStressExe_FilePath) ||
|
|
0 >= _tcslen(m_szStressExe_FileName))
|
|
goto Exit;
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Download the stressExe and symbols.
|
|
// **
|
|
if (!DownloadStressExe())
|
|
{
|
|
bResult = FALSE;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Enable pageheap if needed
|
|
// **
|
|
if (0 < _tcsclen(m_szStressExe_PageHeapCommandLine))
|
|
{
|
|
if (!NetworkTools__PageHeap(TRUE, m_szStressExe_FileName, m_szStressExe_PageHeapCommandLine))
|
|
{
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "Pageheap failed when trying to enable.", NULL, Get_ID());
|
|
bResult = FALSE;
|
|
// goto Exit; don't need to exit when pageheap fails
|
|
}
|
|
else
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "Pageheap successfully enabled.", NULL, Get_ID());
|
|
}
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Create the stressExe process
|
|
// **
|
|
|
|
// build Remote/CDB/stressExe path
|
|
ZeroMemory(szCommandLine, dwCommandLineSize);
|
|
_stprintf(szCommandLine, STRESSINSTANCE_DEBUG_COMMANDLINE, m_szStressExe_FilePathAndName);
|
|
|
|
// startupInfo
|
|
ZeroMemory(pStartUpInfo, sizeof(STARTUPINFO));
|
|
pStartUpInfo->cb = sizeof(STARTUPINFO);
|
|
pStartUpInfo->dwFillAttribute = FOREGROUND_RED| BACKGROUND_RED| BACKGROUND_GREEN| BACKGROUND_BLUE; // red text on white background
|
|
pStartUpInfo->dwFlags = STARTF_USESHOWWINDOW;
|
|
pStartUpInfo->wShowWindow = SW_MINIMIZE;
|
|
|
|
|
|
// Create the stressExe process
|
|
bResult =
|
|
CreateProcess(
|
|
NULL,
|
|
m_szStressExe_FilePathAndName,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
CREATE_NEW_CONSOLE | CREATE_SEPARATE_WOW_VDM | NORMAL_PRIORITY_CLASS | CREATE_NEW_PROCESS_GROUP | CREATE_SUSPENDED,
|
|
NULL,
|
|
NULL,
|
|
pStartUpInfo,
|
|
&m_piStressExeProcess);
|
|
|
|
|
|
if (!bResult)
|
|
{
|
|
// stressExe failed to start
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Attach debugger to the process only if there isn't one
|
|
// **
|
|
|
|
// remove debugger if there is one
|
|
if (m_objDebugger)
|
|
{
|
|
delete m_objDebugger;
|
|
m_objDebugger = NULL;
|
|
}
|
|
|
|
// attach new debugger
|
|
Sleep(2000);
|
|
m_objDebugger = new Debugger(m_piStressExeProcess.dwProcessId, DebuggerCallbackProc);
|
|
m_objDebugger->Go();
|
|
|
|
ResumeThread(m_piStressExeProcess.hThread);
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Initialize dynamically named event objects.
|
|
// ** Set object access to ALL.
|
|
// **
|
|
|
|
// Create event object that'll be inherited by the stressExe process.
|
|
// StressScheduler will signal when it's time to close stressExe.
|
|
SECURITY_ATTRIBUTES securityAttributes;
|
|
PSECURITY_DESCRIPTOR pSD;
|
|
|
|
pSD = new SECURITY_DESCRIPTOR;
|
|
|
|
// Set a NULL security descriptor. This gives full access to handles when inherited
|
|
InitializeSecurityDescriptor(pSD, SECURITY_DESCRIPTOR_REVISION);
|
|
SetSecurityDescriptorDacl(pSD, TRUE, (PACL) NULL, FALSE);
|
|
|
|
securityAttributes.bInheritHandle = TRUE;
|
|
securityAttributes.lpSecurityDescriptor = pSD;
|
|
securityAttributes.nLength = sizeof(securityAttributes);
|
|
|
|
|
|
// The named event object names have the PID of the process appended to the end of the constants
|
|
// These strings are also created in the stressExe dynamically.
|
|
LPTSTR szExitProcessName;
|
|
LPTSTR szPID;
|
|
|
|
szExitProcessName = new TCHAR[MAX_PATH];
|
|
szPID = new TCHAR[16];
|
|
|
|
// Get the processID string
|
|
_itot(m_piStressExeProcess.dwProcessId, szPID, 10);
|
|
|
|
// build ExitProcess event object name
|
|
_tcscpy(szExitProcessName, STRESSINSTANCE_STRESS_EXE_EVENT_EXITPROCESS);
|
|
_tcscat(szExitProcessName, szPID);
|
|
|
|
if (m_hStressExe_ProcessExitEvent)
|
|
CloseHandle(m_hStressExe_ProcessExitEvent);
|
|
|
|
// this event is sent by us to stressExe when we want it to exit
|
|
// Signaled = tell stressExe to exit; Not-Signaled = stressExe can continue running
|
|
m_hStressExe_ProcessExitEvent = CreateEvent(
|
|
&securityAttributes,
|
|
FALSE, // manual reset
|
|
FALSE,
|
|
szExitProcessName);
|
|
|
|
|
|
delete [] szExitProcessName;
|
|
delete [] szPID;
|
|
delete [] pSD;
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Begin the stressExe memory monitoring timerproc
|
|
// **
|
|
if (g_uiStressExeTimerID)
|
|
{
|
|
// there shouldn't be a timer already going. If so, nuke it.
|
|
KillTimer(NULL, g_uiStressExeTimerID);
|
|
g_uiStressExeTimerID = 0;
|
|
}
|
|
|
|
// create a new timer object
|
|
g_uiStressExeTimerID =
|
|
SetTimer(
|
|
NULL,
|
|
0,
|
|
STRESSINSTANCE_MONITOR_EXE_TIME,
|
|
(TIMERPROC) StressExe_TimerProc);
|
|
|
|
|
|
|
|
// Notify the Command Server that stress has started
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_BEGIN, "This stressInstance has begun.", NULL, Get_ID());
|
|
|
|
Exit:
|
|
delete [] szCommandLine;
|
|
delete [] szFileNameAndPath;
|
|
delete [] pStartUpInfo;
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::End()
|
|
//
|
|
// Purpose:
|
|
// This method ends stress by sending a message
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::End()
|
|
{
|
|
// ******************************
|
|
// ******************************
|
|
// ** End the stressExe monitoring timerproc
|
|
if (g_uiStressExeTimerID)
|
|
KillTimer(NULL, g_uiStressExeTimerID);
|
|
|
|
|
|
// ******************************
|
|
// ******************************
|
|
// ** Tell stressExe to shut down.
|
|
SetEvent(m_hStressExe_ProcessExitEvent);
|
|
|
|
// give time for the stressExe to exit
|
|
Sleep(2000);
|
|
|
|
// close stressExe process handles
|
|
if (m_piStressExeProcess.hThread)
|
|
CloseHandle(m_piStressExeProcess.hThread);
|
|
|
|
if (m_piStressExeProcess.hProcess)
|
|
CloseHandle(m_piStressExeProcess.hProcess);
|
|
|
|
if (m_hStressExe_ProcessExitEvent)
|
|
CloseHandle(m_hStressExe_ProcessExitEvent);
|
|
|
|
m_piStressExeProcess.hThread = NULL;
|
|
m_piStressExeProcess.hProcess = NULL;
|
|
m_hStressExe_ProcessExitEvent = NULL;
|
|
|
|
|
|
// stop stressExe if it's still running
|
|
if (IsRunning(STRESSINSTANCE_STRESS_EXE_CLOSE_TIMEOUT))
|
|
{
|
|
// stressExe failed to signal that it exited.
|
|
// Bad stressExe, terminate the process.
|
|
BOOL temp = TerminateProcess(m_piStressExeProcess.hProcess, 0);
|
|
}
|
|
|
|
|
|
// ********************************
|
|
// ********************************
|
|
// ** Detach the debugger object
|
|
// **
|
|
|
|
// detaching the debugger will (read: should) stop the stressExe
|
|
if (m_objDebugger)
|
|
{
|
|
// ********************************
|
|
// ********************************
|
|
// ** Disable pageheap if needed
|
|
// **
|
|
NetworkTools__PageHeap(FALSE, m_szStressExe_FileName, NULL);
|
|
|
|
// let the Command Server know that stressExe has ended
|
|
// we send the message here because ServerCommands.cpp calls this too - even when
|
|
// there isn't a running test case.
|
|
// When the debugger object is valid, then we send the message - because it ensures that Begin() was called.
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_END, "This stressInstance has ended.", NULL, Get_ID());
|
|
|
|
delete m_objDebugger;
|
|
m_objDebugger = NULL;
|
|
}
|
|
|
|
ZeroMemory(&m_piStressExeProcess, sizeof(PROCESS_INFORMATION));
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Get_StressExeID()
|
|
//
|
|
// Purpose:
|
|
// Returns the stress instance's ID receivedfrom the server
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
DWORD
|
|
StressInstance::Get_ID()
|
|
{
|
|
return m_dwStressExe_ID;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Get_StressExeMemoryDumpPath()
|
|
//
|
|
// Purpose:
|
|
// Sets the URL of the memory dump path
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
LPTSTR
|
|
StressInstance::Get_StressExeMemoryDumpPath()
|
|
{
|
|
return m_szStressExe_MemDumpPath;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_StressExeMemoryDumpPath()
|
|
//
|
|
// Purpose:
|
|
// Sets the URL of the memory dump path
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_StressExeMemoryDumpPath(
|
|
LPTSTR szPath
|
|
)
|
|
{
|
|
_tcsncpy(m_szStressExe_MemDumpPath, szPath, MAX_PATH);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_StressExeURL(LPTSTR)
|
|
//
|
|
// Purpose:
|
|
// Sets the URL to download the stress EXE for this object.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_StressExeURL(
|
|
LPTSTR szBuffer // [IN] Buffer containing the URL to download the stressExe app
|
|
)
|
|
{
|
|
if (!szBuffer || (0 >= _tcslen(szBuffer)))
|
|
return;
|
|
|
|
_tcscpy(m_szStressExe_URL, szBuffer);
|
|
|
|
// Set the stressExe's filename
|
|
NetworkTools__GetFileNameFromURL(m_szStressExe_URL, m_szStressExe_FileName, MAX_STRESS_URL);
|
|
|
|
// Set the stressExe's default path to download to with trailing slash
|
|
GetCurrentDirectory(MAX_STRESS_URL, m_szStressExe_FilePath);
|
|
_tcscat(m_szStressExe_FilePath, _T("\\") STRESSINSTANCE_STRESS_EXE_DOWNLOAD_DIR _T("\\"));
|
|
|
|
// Set the full stressExe path + exe
|
|
_tcscpy(m_szStressExe_FilePathAndName, m_szStressExe_FilePath);
|
|
_tcscat(m_szStressExe_FilePathAndName, m_szStressExe_FileName);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_StressExePdbURL(LPTSTR)
|
|
//
|
|
// Purpose:
|
|
// Sets the URL to download the stress EXE's PDB file.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_StressExePdbURL(
|
|
LPTSTR szBuffer // [IN] Buffer containing the URL
|
|
)
|
|
{
|
|
if (!szBuffer || (0 >= _tcslen(szBuffer)))
|
|
return;
|
|
|
|
_tcscpy(m_szStressExe_PDB_URL, szBuffer);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_StressExeSymURL(LPTSTR)
|
|
//
|
|
// Purpose:
|
|
// Sets the URL to download the stress EXE's SYM file.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_StressExeSymURL(
|
|
LPTSTR szBuffer // [IN] Buffer containing the URL
|
|
)
|
|
{
|
|
if (!szBuffer || (0 >= _tcslen(szBuffer)))
|
|
return;
|
|
|
|
_tcscpy(m_szStressExe_SYM_URL, szBuffer);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_StressExeID(DWORD)
|
|
//
|
|
// Purpose:
|
|
// Sets the URL to download the stress EXE for this object.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_StressExeID(
|
|
DWORD dwID // [IN] ID from the stressAdmin DB uniquely identifying this stress EXE.
|
|
)
|
|
{
|
|
m_dwStressExe_ID = dwID;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_PageHeapCommands(LPCTSTR)
|
|
//
|
|
// Purpose:
|
|
// Sets the pageheap command line.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_PageHeapCommands(
|
|
LPCTSTR szCommandLine // [IN] Extra command line params for pageheap.
|
|
)
|
|
{
|
|
ZeroMemory(m_szStressExe_PageHeapCommandLine, MAX_PATH);
|
|
_tcsncpy(m_szStressExe_PageHeapCommandLine, szCommandLine, MAX_PATH-1);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::Set_UMDHCommands(LPCTSTR)
|
|
//
|
|
// Purpose:
|
|
// Sets the UMDH command line.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
StressInstance::Set_UMDHCommands(
|
|
LPCTSTR szCommandLine // [IN] Extra command line params for UMDH.
|
|
)
|
|
{
|
|
ZeroMemory(m_szStressExe_UMDHCommandLine, MAX_PATH);
|
|
_tcsncpy(m_szStressExe_UMDHCommandLine, szCommandLine, MAX_PATH-1);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::DownloadStressExe()
|
|
//
|
|
// Purpose:
|
|
// Downloads the stressExe app to the local machine.
|
|
// We create a directory of the stress exe name. For example,
|
|
// "http://hairball/files/stress1.exe" will be put in "stress1\stress1.exe"
|
|
// on the local machine. If the file is already there, it'll try to overwrite it.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL
|
|
StressInstance::DownloadStressExe()
|
|
{
|
|
BOOL bResult = TRUE;
|
|
LPTSTR szFileName = new TCHAR[MAX_PATH];
|
|
|
|
// Download the stressExe file
|
|
if (NetworkTools__URLDownloadToFile(m_szStressExe_URL, STRESSINSTANCE_STRESS_EXE_DOWNLOAD_DIR, m_szStressExe_FileName))
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "stress EXE file downloaded successfully.", NULL, Get_ID());
|
|
else
|
|
{
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "stress EXE file not downloaded.", NULL, Get_ID());
|
|
bResult = FALSE;
|
|
}
|
|
|
|
// Download PDB symbol file if there is one
|
|
if (NetworkTools__GetFileNameFromURL(m_szStressExe_PDB_URL, szFileName, MAX_PATH))
|
|
{
|
|
NetworkTools__URLDownloadToFile(m_szStressExe_PDB_URL, STRESSINSTANCE_STRESS_EXE_DOWNLOAD_DIR, szFileName);
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "stress PDB file downloaded successfully.", NULL, Get_ID());
|
|
}
|
|
else
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "stress PDB file not downloaded.", NULL, Get_ID());
|
|
|
|
// Download SYM symbol file if there is one
|
|
if (NetworkTools__GetFileNameFromURL(m_szStressExe_SYM_URL, szFileName, MAX_PATH))
|
|
{
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_SUCCESS, "stress SYM file downloaded successfully.", NULL, Get_ID());
|
|
NetworkTools__URLDownloadToFile(m_szStressExe_SYM_URL, STRESSINSTANCE_STRESS_EXE_DOWNLOAD_DIR, szFileName);
|
|
}
|
|
else
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_ERROR, "streses SYM file not downloaded.", NULL, Get_ID());
|
|
|
|
delete [] szFileName;
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressInstance::IsRunning()
|
|
//
|
|
// Purpose:
|
|
// Returns TRUE if this stressinstance is running. FALSE if not.
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
BOOL StressInstance::IsRunning(DWORD dwTimeOut)
|
|
{
|
|
BOOL bResult = FALSE;
|
|
HANDLE hStressExe = NULL;
|
|
|
|
hStressExe = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_piStressExeProcess.dwProcessId);
|
|
|
|
if (!hStressExe)
|
|
bResult = FALSE;
|
|
else
|
|
{
|
|
bResult = TRUE;
|
|
CloseHandle(hStressExe);
|
|
}
|
|
|
|
return bResult;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: StressExe_TimerProc(HWND, UINT, UINT_PTR, DWORD)
|
|
//
|
|
// Purpose:
|
|
// When this is called, we will check on the status of the
|
|
// stressExe process send the command server it's memory info
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
VOID
|
|
CALLBACK
|
|
StressExe_TimerProc(
|
|
HWND hwnd, // [IN] handle to window - should be NULL since we didn't specify one
|
|
UINT uMsg, // [IN] WM_TIMER message
|
|
UINT_PTR idEvent, // [IN] timer identifier
|
|
DWORD dwTime // [IN] current system time
|
|
)
|
|
{
|
|
// build directory to copy dump file
|
|
LPSTR szExeName = new CHAR[MAX_STRESS_URL];
|
|
|
|
|
|
if (!g_hThis)
|
|
goto Exit;
|
|
|
|
// ***********************************
|
|
// ***********************************
|
|
// ** Check that the stressExe is still running. If it isn't end this instance.
|
|
// **
|
|
if (!g_hThis->IsRunning(STRESSINSTANCE_STRESS_EXE_CLOSE_TIMEOUT))
|
|
{
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_INFORMATION, "This stress instance has exited prematurely.", NULL, g_hThis->Get_ID());
|
|
g_hThis->End();
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
ZeroMemory(szExeName, MAX_STRESS_URL);
|
|
|
|
// ******************************
|
|
// ** Remove the file extension of the stressExe name and send the system and process
|
|
// ** memory log to the command server
|
|
WideCharToMultiByte(
|
|
CP_ACP,
|
|
NULL,
|
|
g_hThis->m_szStressExe_FileName,
|
|
-1,
|
|
szExeName,
|
|
MAX_STRESS_URL,
|
|
NULL,
|
|
NULL);
|
|
|
|
MemStats__SendSystemMemoryLog(szExeName, g_hThis->m_piStressExeProcess.dwProcessId, g_hThis->Get_ID());
|
|
|
|
Exit:
|
|
delete [] szExeName;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Function: DebuggerCallbackProc(DWORD, LPVOID, LPTSTR, LPVOID)
|
|
//
|
|
// Purpose:
|
|
// Creates a memory dump on second change exceptions
|
|
//
|
|
////////////////////////////////////////////////////////////
|
|
DWORD DebuggerCallbackProc(
|
|
DWORD dwFlags,
|
|
LPVOID lpIn,
|
|
LPTSTR lpszFutureString,
|
|
LPVOID lpFuturePointer
|
|
)
|
|
{
|
|
//test callback for debugger lib
|
|
DWORD dwContinue = 0;
|
|
|
|
|
|
// ***********************************
|
|
// ***********************************
|
|
// ** Check that the stressExe is still running.
|
|
// **
|
|
if (!g_hThis || !g_hThis->IsRunning(STRESSINSTANCE_STRESS_EXE_CLOSE_TIMEOUT))
|
|
{
|
|
dwContinue = DEBUGGER_CONTINUE_STOP_DEBUGGING;
|
|
goto Exit;
|
|
}
|
|
|
|
|
|
switch (dwFlags)
|
|
{
|
|
case DEBUGGER_FIRST_CHANCE_EXCEPTION:
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_INFORMATION, "FIRST_CHANCE_EXCEPTION detected.", NULL, g_hThis->Get_ID());
|
|
//must use this to pass on first chance exceptions to the system
|
|
dwContinue = DEBUGGER_CONTINUE_UNHANDLED;
|
|
break;
|
|
|
|
case DEBUGGER_SECOND_CHANCE_EXCEPTION:
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_INFORMATION, "SECOND_CHANCE_EXCEPTION detected.", NULL, g_hThis->Get_ID());
|
|
|
|
// build directory to copy dump file
|
|
LPTSTR szPath;
|
|
LPTSTR szNum;
|
|
LPTSTR szMachineName;
|
|
|
|
szPath = new TCHAR[MAX_PATH * 2];
|
|
szNum = new TCHAR[100];
|
|
szMachineName = new TCHAR[MAX_PATH];
|
|
|
|
// ******************************
|
|
// create the directory STRESSINSTANCE_MEMORY_DUMP_PATH\<MachineName>
|
|
MultiByteToWideChar(
|
|
CP_ACP,
|
|
MB_PRECOMPOSED,
|
|
g_objServerCommands.Get_ClientMachineName(),
|
|
-1,
|
|
szMachineName,
|
|
MAX_PATH);
|
|
|
|
// if the server sent a vaild path then use it, else use the default memory dump path
|
|
if (0 < _tcslen(g_hThis->Get_StressExeMemoryDumpPath()))
|
|
_tcscpy(szPath, g_hThis->Get_StressExeMemoryDumpPath());
|
|
else
|
|
_tcscpy(szPath, STRESSINSTANCE_DEFAULT_MEMORY_DUMP_PATH);
|
|
|
|
// add the machine name to the end of the directory
|
|
_tcscat(szPath, szMachineName);
|
|
|
|
CreateDirectory(szPath, NULL);
|
|
|
|
// ******************************
|
|
// create the filename in form "<stressExeFileName>-<stressInstanceID>-<PID>.dmp"
|
|
_tcscat(szPath, _T("\\"));
|
|
|
|
_tcscat(szPath, g_hThis->m_szStressExe_FileName);
|
|
_tcscat(szPath, _T("-"));
|
|
|
|
_itot(g_hThis->Get_ID(), szNum, 10);
|
|
_tcscat(szPath, szNum);
|
|
_tcscat(szPath, _T("-"));
|
|
|
|
_itot(g_hThis->m_piStressExeProcess.dwProcessId, szNum, 10);
|
|
_tcscat(szPath, szNum);
|
|
_tcscat(szPath, _T(".dmp"));
|
|
|
|
//this creates a full user dump
|
|
g_hThis->m_objDebugger->CreateMiniDump(szPath, _T("This is a full user dump created by debugger.lib"), DEBUGGER_CREATE_FULL_MINI_DUMP);
|
|
|
|
delete [] szPath;
|
|
delete [] szNum;
|
|
delete [] szMachineName;
|
|
|
|
|
|
// let the Command Server know a dump file was created
|
|
NetworkTools__SendLog(FIELDNAME__LOGTYPE_DUMPFILE_CREATED, "User dump file was created.", NULL, g_hThis->Get_ID());
|
|
|
|
// stop the debugger
|
|
dwContinue = DEBUGGER_CONTINUE_STOP_DEBUGGING;
|
|
break;
|
|
|
|
case DEBUGGER_EXIT_PROCESS:
|
|
dwContinue = DEBUGGER_CONTINUE_STOP_DEBUGGING;
|
|
break;
|
|
|
|
default:
|
|
// let the Command Server know a dump file was created
|
|
break;
|
|
}
|
|
|
|
|
|
Exit:
|
|
return dwContinue;
|
|
}
|