diff options
Diffstat (limited to 'network/trans/WFPSampler/lib/HelperFunctions_ThreadsAndEvents.cpp')
| -rw-r--r-- | network/trans/WFPSampler/lib/HelperFunctions_ThreadsAndEvents.cpp | 389 |
1 files changed, 389 insertions, 0 deletions
diff --git a/network/trans/WFPSampler/lib/HelperFunctions_ThreadsAndEvents.cpp b/network/trans/WFPSampler/lib/HelperFunctions_ThreadsAndEvents.cpp new file mode 100644 index 00000000..89c7a520 --- /dev/null +++ b/network/trans/WFPSampler/lib/HelperFunctions_ThreadsAndEvents.cpp @@ -0,0 +1,389 @@ +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// Copyright (c) 2012 Microsoft Corporation. All Rights Reserved. +// +// Module Name: +// HelperFunctions_ThreadsAndEvents.cpp +// +// Abstract: +// This module contains functions which functions which simplify threads and eventing. +// +// Naming Convention: +// +// <Scope><Module><Object><Action><Modifier> +// +// i.e. +// +// <Scope> +// { +// - Function is likely visible to other modules +// } +// <Module> +// { +// Hlpr - Function is from HelperFunctions_* Modules. +// } +// <Object> +// { +// Event - Function pertains to events. +// Thread - Function pertains to threads. +// } +// <Action> +// { +// Cleanup - +// Set - +// Start - +// Stop - +// Wait - +// } +// <Modifier> +// { +// ForCompletion - +// ForEvent - Function determines equality between values. +// } +// +// Private Functions: +// +// Public Functions: +// +// Author: +// Dusty Harper (DHarper) +// +// Revision History: +// +// [ Month ][Day] [Year] - [Revision]-[ Comments ] +// May 01, 2010 - 1.0 - Creation +// +//////////////////////////////////////////////////////////////////////////////////////////////////// + +#include "HelperFunctions_Include.h" /// . + +/** + @helper_function="HlprEventReset" + + Purpose: Sets the event to nonsignaled. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS685081.aspx <br> +*/ +VOID HlprEventReset(_In_opt_ HANDLE event) +{ + if(event) + ResetEvent(event); + + return; +} + + +/** + @helper_function="HlprEventSet" + + Purpose: Signals an event. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS686211.aspx <br> +*/ +VOID HlprEventSet(_In_opt_ HANDLE event) +{ + if(event) + SetEvent(event); + + return; +} + +/** + @helper_function="HlprThreadStart" + + Purpose: Generates a new thread. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS682396.aspx <br> + HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS682453.aspx <br> +*/ +_Success_(return == NO_ERROR) +UINT32 HlprThreadStart(_Inout_ THREAD_DATA* pThreadData, + _In_opt_ VOID* pData) /* 0 */ +{ + UINT32 status = NO_ERROR; + + if(pThreadData) + { + HlprThreadCleanup(pThreadData); + + if(pThreadData->threadStartRoutine) + { + pThreadData->threadStartEvent = CreateEvent(0, + TRUE, + FALSE, + 0); + + pThreadData->threadStopEvent = CreateEvent(0, + TRUE, + FALSE, + 0); + + pThreadData->threadContinueEvent = CreateEvent(0, + TRUE, + FALSE, + 0); + + pThreadData->thread = CreateThread(0, + 0, + (LPTHREAD_START_ROUTINE)pThreadData->threadStartRoutine, + pData ? pData : pThreadData, + 0, + (LPDWORD)&(pThreadData->threadId)); + + if(pThreadData->threadStartEvent && + pThreadData->threadStopEvent && + pThreadData->threadContinueEvent && + pThreadData->thread) + HlprThreadWaitForEvent(pThreadData->threadStartEvent, + pThreadData); + else + { + status = ERROR_GEN_FAILURE; + + HlprThreadCleanup(pThreadData); + + HlprLogError(L"HlprThreadStart() [status: %#x]", + status); + } + } + else + { + status = ERROR_INVALID_DATA; + + HlprLogError(L"HlprThreadStart() [status: %#x][pThreadData->threadStartRoutine: %#x]", + status, + pThreadData->threadStartRoutine); + } + } + else + { + status = ERROR_INVALID_PARAMETER; + + HlprLogError(L"HlprThreadStart() [status: %#x][pThread: %#x]", + status, + pThreadData); + } + + return status; +} + +/** + @helper_function="HlprThreadStop" + + Purpose: Signals a thread to stop and cleans it up. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS682396.aspx <br> <br> +*/ +_Success_(return == NO_ERROR) +UINT32 HlprThreadStop(_Inout_ THREAD_DATA* pThreadData) +{ + UINT32 status = NO_ERROR; + const UINT32 RETRY_ATTEMPTS = 5; + + if(pThreadData) + { + for(UINT32 i = 0; + status != WAIT_TIMEOUT && + i < RETRY_ATTEMPTS; + i++) + { + HlprEventSet(pThreadData->threadStopEvent); + + status = HlprThreadWaitForCompletion(pThreadData); + } + + HlprThreadCleanup(pThreadData); + } + + return status; +} + +/** + @helper_function="HlprThreadStop" + + Purpose: Signals a thread to stop and cleans it up, and frees any allocated memory. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_At_(*ppThreadData, _Pre_ _Notnull_) +_When_(return != NO_ERROR, _At_(*ppThreadData, _Post_ _Notnull_)) +_When_(return == NO_ERROR, _At_(*ppThreadData, _Post_ _Null_)) +_Success_(return == NO_ERROR && *ppThreadData == 0) +UINT32 HlprThreadStop(_Inout_ THREAD_DATA** ppThreadData) +{ + UINT32 status = NO_ERROR; + + if(ppThreadData) + { + status = HlprThreadStop(*ppThreadData); + if(status == NO_ERROR) + { + HLPR_DELETE(*ppThreadData) + } + } + + return status; +} + +/** + @helper_function="HlprThreadCleanup" + + Purpose: Cleans up a previously allocated thread. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS683190.aspx <br> + HTTP://MSDN.Microsoft.com/En-Us/Library/Windows/Desktop/MS686717.aspx <br> +*/ +VOID HlprThreadCleanup(_Inout_opt_ THREAD_DATA* pThreadData) +{ + if(pThreadData) + { + LPTHREAD_START_ROUTINE threadStartRoutine = pThreadData->threadStartRoutine; + UINT32 status = NO_ERROR; + + if(pThreadData->thread) + { + if(GetExitCodeThread(pThreadData->thread, + (DWORD*)&status)) + { + if(status == STILL_ACTIVE) + { + UINT64 timeAlpha = GetTickCount64(); + const UINT32 FOUR_MINUTES = 240000; + + for(UINT64 timeOmega = GetTickCount64(); + timeOmega - timeAlpha < FOUR_MINUTES; + timeOmega = GetTickCount64()) + { + HlprEventSet(pThreadData->threadStopEvent); + + status = HlprThreadWaitForCompletion(pThreadData); + if(status == NO_ERROR) + break; + } + + if(status != NO_ERROR) + { + HlprLogInfo(L"Possible Runaway Thread"); + +#pragma warning(push) +#pragma warning(disable: 6258) /// This is a last resort + + TerminateThread(pThreadData->thread, + ERROR_THREAD_WAS_SUSPENDED); + +#pragma warning(pop) + } + } + } + else + { + status = GetLastError(); + + HlprLogError(L"HlprThreadCleanup() [status:%#x]", + status); + } + } + + HLPR_CLOSE_HANDLE(pThreadData->threadStopEvent); + + HLPR_CLOSE_HANDLE(pThreadData->threadStartEvent); + + HLPR_CLOSE_HANDLE(pThreadData->threadContinueEvent); + + ZeroMemory(pThreadData, + sizeof(THREAD_DATA)); + + pThreadData->threadStartRoutine = threadStartRoutine; + } + + return; +} + +/** + @helper_function="HlprThreadWaitForCompletion" + + Purpose: Waits for a thread to complete. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_Success_(return == NO_ERROR) +UINT32 HlprThreadWaitForCompletion(_Inout_opt_ THREAD_DATA* pThreadData) +{ + UINT32 status = NO_ERROR; + + if(pThreadData) + { + HlprEventSet(pThreadData->threadStopEvent); + + status = HlprThreadWaitForEvent(pThreadData->thread, + pThreadData); + } + + return status; +} + +/** + @helper_function="HlprThreadWaitForEvent" + + Purpose: Waits for a particular event to be set within the thread. <br> + <br> + Notes: <br> + <br> + MSDN_Ref: <br> +*/ +_Success_(return == NO_ERROR) +UINT32 HlprThreadWaitForEvent(_In_ HANDLE eventHandle, + _In_ THREAD_DATA* pThreadData) +{ + UINT32 status = NO_ERROR; + const UINT32 RETRY_ATTEMPTS = 6; + WCHAR* pEventName = 0; + + if(eventHandle && + pThreadData) + { + if(eventHandle == pThreadData->threadContinueEvent) + pEventName = L"Continue Event"; + else if(eventHandle == pThreadData->threadStartEvent) + pEventName = L"Start Event"; + else if(eventHandle == pThreadData->threadStopEvent) + pEventName = L"Stop Event"; + else if(eventHandle == pThreadData->thread) + pEventName = L"Thread"; + + /// Try for 30 seconds before bailing + for(UINT32 i = 0; + WaitForSingleObject(eventHandle, + 5000) == WAIT_TIMEOUT; + i++) + { + HlprLogInfo(L"HlprThreadWaitForEvent() Waiting for %s ...", + pEventName); + + if(i == RETRY_ATTEMPTS - 1) + { + status = WAIT_TIMEOUT; + + HlprLogInfo(L"HlprThreadWaitForEvent() [status: %#x]"); + + break; + } + } + } + + return status; +} |
