1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| #define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include "OnceAProcess.h"
#ifdef SANS_CRT
#include "TestSansCRT.h"
#define assert MY_ASSERT
#else
#include <assert.h>
#endif
/*
Do something once in a process
------------------------------ */
EXTERN_C LRESULT DoOnceAProcess(
LONG volatile * pbStartedDoing, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
LONG volatile * pbDone, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
ONCEAPROCESSCALLBACK proc, /*[in] Callback function, called once in the process. Must not be NULL.*/
LPARAM userData, /*[in/bypass] User parameter passed to the callback function.*/
LRESULT defReturnVal /*[in/bypass] Value to return if the function was NOT called.*/
) /*Returns the callback's return value, or defReturnVal.*/
{
static const LONG lTrue = TRUE;
static const LONG lFalse = FALSE;
LRESULT ret = defReturnVal;
if( ! *pbDone )
{
/* If not already started doing, do it.
Else, wait actively until done */
/* InterlockedCompareExchange() :
If *pbStartedDoing == lFalse, set it to lTrue; return the previous value of *pbStartedDoing. */
LONG alreadyStartedDoing = InterlockedCompareExchange(pbStartedDoing, lTrue, lFalse);
if(alreadyStartedDoing == lFalse)
{
ret = proc(userData);
*pbDone = lTrue;
}
else
{
while( ! (*pbDone) ) {}
}
}
/* Now, *pbDone can only be true:
Either it was already done, or it has just been done. */
assert(*pbDone);
return ret;
}
/* TLS slot initialization callback
-------------------------------- */
static LRESULT AllocTlsIndexToPtr(LPARAM parPdwTlsIndex)
{
HRESULT hrRet = S_OK;
DWORD * pdwTlsIndex = (DWORD*)parPdwTlsIndex;
DWORD tlsIndex;
assert(pdwTlsIndex!=NULL);
tlsIndex = TlsAlloc();
if(tlsIndex==TLS_OUT_OF_INDEXES)
{
/* Error: Get an error value from the Win32 error code. */
HRESULT hrError = HRESULT_FROM_WIN32(GetLastError());
if(SUCCEEDED(hrError))
hrError = E_UNEXPECTED;
assert(FAILED(hrError));
/* return it. */
hrRet = hrError;
}
*pdwTlsIndex = tlsIndex;
return (LRESULT)hrRet;
}
/* Allocate a Thread-Local Storage slot once in a process
------------------------------------------------------ */
EXTERN_C HRESULT AllocateTlsSlotOnce(
LONG volatile * pbStartedDoing, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
LONG volatile * pbDone, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
DWORD * pdwTlsIndex /*[out] Return the TLS slot here, leave untouched if already done.*/
) /*Returns S_FALSE if was already allocated.*/
{
assert(pbStartedDoing != NULL);
assert(pbDone != NULL);
assert(pdwTlsIndex != NULL);
return (HRESULT)DoOnceAProcess(pbStartedDoing, pbDone, AllocTlsIndexToPtr, (LPARAM)pdwTlsIndex, (LRESULT)S_FALSE);
}
/* Critical section initialization callback
---------------------------------------- */
static LRESULT InitializeCriticalSectionToPtr(LPARAM parPCrit)
{
HRESULT hrRet = S_OK;
LPCRITICAL_SECTION pCrit = (LPCRITICAL_SECTION)parPCrit;
assert(pCrit!=NULL);
#ifdef SANS_CRT
//No CRT means no exception handling : Just pray.
InitializeCriticalSection(pCrit);
#else
__try
{
InitializeCriticalSection(pCrit);
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
if(GetExceptionCode()==STATUS_NO_MEMORY)
hrRet = E_OUTOFMEMORY;
else
hrRet = E_UNEXPECTED;
}
#endif
return (LRESULT)hrRet;
}
/* Initialize a global critical section once in a process
------------------------------------------------------ */
EXTERN_C HRESULT InitializeCriticalSectionOnce(
LONG volatile * pbStartedDoing, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
LONG volatile * pbDone, /*[in/out] Ptr to a static variable. Must be initialized to (LONG)FALSE;*/
LPCRITICAL_SECTION pCrit /*[out] Ptr to the critical section to initialize.*/
) /*Returns S_FALSE if was already initialized.*/
{
assert(pbStartedDoing != NULL);
assert(pbDone != NULL);
assert(pCrit != NULL);
return (HRESULT)DoOnceAProcess(pbStartedDoing, pbDone, InitializeCriticalSectionToPtr, (LPARAM)pCrit, (LRESULT)S_FALSE);
} |
Partager