📄 utils.cpp
字号:
// ==++==
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// ==--==
// =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+
//
// utils.cpp
//
// Utility routines for use in ConcRT.
//
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
#include "concrtinternal.h"
extern "C" IMAGE_DOS_HEADER __ImageBase;
#if _UMS_ADVANCED_DEBUG
//**************************************************
//
// Global operator overloads for UMS debugging
//
//**************************************************
void ValidateHeapCall()
{
if (UMS::Initialized())
{
UMSThreadProxy *pProxy = UMSThreadProxy::GetCurrent();
//
// Once a thread is transmogrified, it behaves as a truly external thread -- all validations are performed as such.
//
if (pProxy != NULL && !pProxy->IsTransmogrified())
{
CriticalRegionType type = pProxy->GetCriticalRegionType();
//
// Rules are more relaxed during shutdown when we're not responsible for scheduling anything. We need to be in a CR for various
// reasons, but heap allocations there won't hose us since there's nothing running.
//
bool validations = pProxy->IsShutdownValidations();
if (!validations)
{
ContextBase *pContext = SchedulerBase::FastCurrentContext();
if (pContext != NULL)
validations = pContext->IsShutdownValidations();
}
CORE_ASSERT(type != InsideHyperCriticalRegion || validations);
}
}
}
void *operator new(size_t size)
{
ValidateHeapCall();
return malloc(size);
}
void operator delete(void *pObj)
{
ValidateHeapCall();
free(pObj);
}
void *operator new[](size_t size)
{
ValidateHeapCall();
return malloc(size);
}
void operator delete[](void *pObj)
{
ValidateHeapCall();
free(pObj);
}
#endif // _UMS_ADVANCED_DEBUG
namespace Concurrency
{
namespace details
{
/// <summary>
/// Default method for yielding during a spin wait
/// </summary>
void __cdecl _UnderlyingYield()
{
// Performs a yield appropriate to the scheduler.
ContextBase *pCurrentContext = SchedulerBase::SafeFastCurrentContext();
if (pCurrentContext != NULL)
{
pCurrentContext->SpinYield();
}
else
{
SwitchToThread();
}
}
/// <summary>
/// Use Sleep(0) to do the yield.
/// </summary>
void __cdecl _Sleep0()
{
Sleep(0);
}
static bool g_TraceInitialized = false;
static int g_DesiredTraceLevel = 0;
static FILE* g_DebugOutFilePtr = stderr;
static int g_CommitFrequency = 50;
static unsigned __int64 g_TraceCount = 0;
void _HyperNonReentrantLock::_Acquire()
{
ContextBase::StaticEnterHyperCriticalRegion();
m_lock._Acquire();
}
bool _HyperNonReentrantLock::_TryAcquire()
{
ContextBase::StaticEnterHyperCriticalRegion();
bool lockAcquired = m_lock._TryAcquire();
if (!lockAcquired)
ContextBase::StaticExitHyperCriticalRegion();
return lockAcquired;
}
void _HyperNonReentrantLock::_Release()
{
m_lock._Release();
ContextBase::StaticExitHyperCriticalRegion();
}
void _CriticalNonReentrantLock::_Acquire()
{
ContextBase::StaticEnterCriticalRegion();
m_lock._Acquire();
}
bool _CriticalNonReentrantLock::_TryAcquire()
{
ContextBase::StaticEnterCriticalRegion();
bool lockAcquired = m_lock._TryAcquire();
if (!lockAcquired)
ContextBase::StaticExitCriticalRegion();
return lockAcquired;
}
void _CriticalNonReentrantLock::_Release()
{
m_lock._Release();
ContextBase::StaticExitCriticalRegion();
}
#if defined(CONCRT_TRACING)
static bool
IsWhitespace(
wchar_t wch
)
{
wchar_t buf[2];
buf[0] = wch;
buf[1] = 0;
WORD type;
#pragma warning(disable: 25028) // use of function or parameters passed to function 'GetStringTypeExW' need to be reviewed -- it has been reviewed
if (!GetStringTypeExW(LOCALE_USER_DEFAULT, CT_CTYPE1, buf, 1, &type)) {
return false;
}
#pragma warning(default: 25028)
return (type & C1_SPACE) != 0;
}
static wchar_t *
SkipWhitespace(
__out_ecount(count) wchar_t * ptr,
int count
)
{
int i = 0;
for (; i < count && ptr[i] != 0 && iswspace(ptr[i]); ++i)
;
return &ptr[i];
}
#endif
template<typename SignedInt, typename UnsignedInt, UnsignedInt ui_max>
static const wchar_t *
StringToInt(
const wchar_t * ptr,
SignedInt * pvalue
)
{
ASSERT(*ptr != L'\0');
bool negative;
if (*ptr == L'-') {
negative = true;
++ptr;
}
else {
negative = false;
if (*ptr == L'+') {
++ptr;
}
}
if (*ptr < L'0' || *ptr > L'9') {
// No number present (possibly just a sign)
return NULL;
}
UnsignedInt absval = 0;
do {
int digit = *ptr - L'0';
if (absval > ui_max / 10 ||
(absval == ui_max / 10 &&
digit > ui_max % 10))
{
// Unsigned overflow
return NULL;
}
absval = absval * 10 + digit;
++ptr;
} while (*ptr >= L'0' && *ptr <= L'9');
SignedInt result = static_cast<SignedInt>(absval);
if (negative) {
result = -result;
if (result > 0) {
// Signed underflow
return NULL;
}
}
else {
if (result < 0) {
// Signed overflow
return NULL;
}
}
*pvalue = result;
return ptr;
}
#if defined(CONCRT_TRACING)
static wchar_t * ReadEnvVar(const wchar_t * name, __out_ecount(maxlen) wchar_t * buffer, DWORD maxlen)
{
DWORD len = GetEnvironmentVariableW(name, buffer, maxlen);
if (len == 0) {
return NULL;
}
if (len >= MAX_PATH) {
// name too long, just ignore it
return NULL;
}
wchar_t * ptr = SkipWhitespace(buffer, maxlen);
if (*ptr == L'\0') {
return NULL;
}
wchar_t * endptr = ptr + lstrlenW(ptr);
ASSERT(*endptr == L'\0');
while (IsWhitespace(endptr[-1])) {
--endptr;
}
*endptr = L'\0';
ASSERT(*ptr != L'\0' && !IsWhitespace(*ptr));
return ptr;
}
static int ProcessTraceValue(const wchar_t * ptr)
{
int value;
ptr = StringToInt<int, unsigned int, UINT_MAX>(ptr, &value);
if (ptr == NULL || *ptr != L'\0') {
return 0;
}
return value;
}
#endif
void InitializeUtilityRoutines()
{
#if defined(CONCRT_TRACING)
if (g_TraceInitialized)
{
return;
}
else
{
g_TraceInitialized = true;
}
wchar_t buffer[MAX_PATH+1];
// bits to match TRACE arenas
const wchar_t * ptr = ReadEnvVar(L"CONCRT_TRACE", buffer, DIM(buffer));
if (ptr != NULL)
g_DesiredTraceLevel = ProcessTraceValue(buffer);
// when > 0, fflush every g_CommitFrequency TRACE statements, when <= 0 no flush
ptr = ReadEnvVar(L"CONCRT_COMMIT_FREQUENCY", buffer, DIM(buffer));
if (ptr != NULL)
g_CommitFrequency = ProcessTraceValue(buffer);
else
g_CommitFrequency = 1;
// when not set will go to debug output, else stdout, stderr or filename
const wchar_t* pwszOutputFile = ReadEnvVar(L"CONCRT_TRACE_OUTPUT", buffer, DIM(buffer));
if (pwszOutputFile != NULL)
{
if (wcsncmp(L"stdout", pwszOutputFile, MAX_PATH) == 0)
g_DebugOutFilePtr = stdout;
else if (wcsncmp(L"stderr", pwszOutputFile, MAX_PATH) == 0)
{
g_DebugOutFilePtr = stderr;
g_CommitFrequency = 0;
}
else
{
buffer[MAX_PATH] = 0;
errno_t errNo = 0;
if ((errNo = _wfopen_s(&g_DebugOutFilePtr, pwszOutputFile, L"w+tc")) != 0)
{
if (swprintf_s(buffer, MAX_PATH, L"Cannot open trace output: %S, errno=%d\n", pwszOutputFile, errNo) < 0)
// bad state -- try again w/o string
fprintf(stderr, "Cannot open trace output: errno=%d\n", errNo);
else
{
OutputDebugStringW(buffer);
fprintf(stderr, "Cannot open trace output: %S, errno=%d\n", pwszOutputFile, errNo);
}
// default to stderr
g_DebugOutFilePtr = stderr;
}
}
}
#endif
}
void _ConcRT_Assert(const char *value, const char* filename, int lineno)
{
const int size = 1024;
wchar_t buffer[size+1];
const ContextBase * pContext = SchedulerBase::SafeFastCurrentContext();
//
// If we're on the primary we don't want to execute any blocking APIs
//
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -