📄 utils.cpp
字号:
if (UMSSchedulingContext::OnPrimary())
{
DebugBreak();
return;
}
if (pContext != NULL && pContext->GetScheduler() != NULL) {
swprintf_s(buffer, size, L"[%d:%d:%d:%d(%d)] %S: !!!!!!!Assert Failed(%S: %d)\n",
pContext->GetVirtualProcessorId(),
pContext->GetId(),
pContext->GetScheduleGroupId(),
pContext->ScheduleGroupRefCount(),
GetCurrentThreadId(),
value,
filename,
lineno);
}
else
swprintf_s(buffer, size, L"[%d] %S: !!!!!!!Assert Failed(%S: %d)\n",
GetCurrentThreadId(),
value,
filename,
lineno);
buffer[1024] = 0;
fwprintf(g_DebugOutFilePtr, buffer);
fflush(g_DebugOutFilePtr);
OutputDebugStringW(buffer);
DebugBreak();
exit(-8);
}
void _ConcRT_CoreAssert(const char *value, const char* filename, int lineno)
{
//
// Nothing here can block in any way.
//
DebugBreak();
}
template <size_t size>
void
ConcRT_FillBuffer(
wchar_t (&buffer)[size],
const wchar_t * format,
va_list args
)
{
// Format the prefix giving the current context, thread, and vproc IDs
int lenPrefix = 0;
ContextBase * pContext = SchedulerBase::SafeFastCurrentContext();
if (pContext != NULL && pContext->GetScheduler() != NULL) {
lenPrefix = swprintf_s(buffer, size, L"[%d:%d:%d:%d(%d)] ",
pContext->GetVirtualProcessorId(),
pContext->GetId(),
pContext->GetScheduleGroupId(),
pContext->ScheduleGroupRefCount(),
GetCurrentThreadId());
if (lenPrefix < 0) {
// Error in swprintf_s, don't bother with a prefix
lenPrefix = 0;
}
}
// Format the trace message
vswprintf_s(buffer + lenPrefix,
DIM(buffer) - lenPrefix,
format, args);
// Append the trailing newline if missing
int lenBuffer = static_cast<int>(wcslen(buffer));
if (lenBuffer > 0 && buffer[lenBuffer - 1] != L'\n')
{
if (lenBuffer < DIM(buffer) - 1)
{
buffer[lenBuffer] = L'\n';
buffer[lenBuffer + 1] = L'\0';
}
else
{
buffer[lenBuffer - 1] = L'\n';
}
}
}
void
_ConcRT_DumpMessage(
const wchar_t * format,
...
)
{
wchar_t buffer[1024+1];
va_list args;
va_start(args, format);
ConcRT_FillBuffer(buffer, format, args);
va_end(args);
buffer[1024] = 0;
OutputDebugStringW(buffer);
fwprintf(stderr, buffer);
}
// Trace -- Used for tracing and debugging
void
_ConcRT_Trace(
int trace_level,
const wchar_t * format,
...
)
{
InitializeUtilityRoutines();
// Check if tracing is disabled
if ((g_DesiredTraceLevel & trace_level) == 0) {
return;
}
wchar_t buffer[1024+1];
va_list args;
va_start(args, format);
ConcRT_FillBuffer(buffer, format, args);
va_end(args);
buffer[1024] = 0;
if (g_DebugOutFilePtr != NULL)
{
fwprintf(g_DebugOutFilePtr, buffer);
if (g_CommitFrequency > 0 && (g_TraceCount++ % g_CommitFrequency) == 0)
fflush(g_DebugOutFilePtr);
}
else
{
OutputDebugStringW(buffer);
}
}
#if _UMSTRACE
void _ConcRT_VMTrace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data)
{
if (pVproc != NULL)
reinterpret_cast<VirtualProcessor *>(pVproc)->Trace(traceEvt, pCtx, pVproc, data);
}
void _ConcRT_CMTrace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data)
{
if (pCtx != NULL)
reinterpret_cast<InternalContextBase *>(pCtx)->Trace(traceEvt, pCtx, pVproc, data);
}
void _ConcRT_RVMTrace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data)
{
if (pVproc != NULL)
reinterpret_cast<UMSFreeVirtualProcessorRoot *>(pVproc)->Trace(traceEvt, pCtx, pVproc, data);
}
void _ConcRT_RPMTrace(int traceEvt, void *pCtx, void *pVproc, ULONG_PTR data)
{
if (pCtx != NULL)
reinterpret_cast<UMSThreadProxy *>(pCtx)->Trace(traceEvt, pCtx, pVproc, data);
}
#endif // _UMSTRACE
//
// _SpinLock
//
_CRTIMP _SpinLock::_SpinLock(volatile long& flag)
: _M_flag(flag)
{
if ( _InterlockedCompareExchange(&_M_flag, 1, 0) != 0 )
{
_SpinWaitBackoffNone spinWait;
do
{
spinWait._SpinOnce();
} while ( _InterlockedCompareExchange(&_M_flag, 1, 0) != 0 );
}
}
_CRTIMP _SpinLock::~_SpinLock()
{
_InterlockedExchange(&_M_flag, 0);
}
_CRTIMP unsigned long Log2(size_t n) {
unsigned long r;
#if defined(_M_X64)
_BitScanReverse64(&r, n);
#else
_BitScanReverse(&r, n);
#endif
return r;
}
// Globals used for ConcRT shutdown
volatile LONG LoadLibraryCount = 0;
HMODULE HostModule = NULL;
//
// Adds a reference on a DLL where ConcRT is hosted, if it is a DLL, otherwise does nothing.
// This is used to shutdown ConcRT on our own terms and not be forced into a difficult synchronous
// shutdown by user's call to FreeLibrary. Note that this does not matter if a process shutdown
// happens because all threads and ConcRT along with them are rudely terminated by the OS.
//
void ReferenceLoadLibrary()
{
HMODULE currentModuleHandle = (HMODULE) &__ImageBase;
HMODULE currentExeHandle = GetModuleHandle(NULL);
// Do this only if ConcRT is hosted inside a DLL
if (currentModuleHandle != currentExeHandle)
{
WCHAR wcDllPath[MAX_PATH];
if (GetModuleFileNameW(currentModuleHandle, wcDllPath, MAX_PATH))
{
HostModule = LoadLibraryW(wcDllPath);
}
else
{
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
}
}
//
// Adds a reference to a host module and then creates the thread. First reference is managed by LoadLibrary,
// and all subsequent ones are reference counted internally to avoid LoadLibrary call overhead.
//
HANDLE LoadLibraryAndCreateThread
(
LPSECURITY_ATTRIBUTES lpThreadAttributes,
SIZE_T dwStackSize,
LPTHREAD_START_ROUTINE lpStartAddress,
LPVOID lpParameter,
DWORD dwCreationFlags,
LPDWORD lpThreadId
)
{
// Make sure that library (DLL) is not unloaded while ConcRT threads are still running
if (InterlockedIncrement(&LoadLibraryCount) == 1)
{
ReferenceLoadLibrary();
SchedulerBase::ReferenceStaticOneShot();
}
HANDLE threadHandle = CreateThread(lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId);
// Make sure the background thread is properly created
if (threadHandle == NULL)
{
throw scheduler_resource_allocation_error(HRESULT_FROM_WIN32(GetLastError()));
}
return threadHandle;
}
//
// Removes a reference count on a host module and in the case of last reference frees the library.
//
void FreeLibraryAndDestroyThread(DWORD exitCode)
{
// If this is the last ConcRT thread leaving the process try to cleanup
if (InterlockedDecrement(&LoadLibraryCount) == 0)
{
SchedulerBase::CheckOneShotStaticDestruction();
// If this is a DLL release the last LoadLibrary reference
if (HostModule != NULL)
{
FreeLibraryAndExitThread(HostModule, exitCode);
}
}
}
// We will use the GS cookie as a starting point
extern "C" uintptr_t __security_cookie;
//
// Initializes the cookie used to encode global data
//
ULONG_PTR Security::InitializeCookie()
{
CORE_ASSERT(Security::s_initialized == 0);
Security::s_initialized = 1;
// Take advantage of ASLR and per-process cookie
ULONG_PTR cookie = (ULONG_PTR)::EncodePointer((PVOID)&Security::s_cookie);
// security cookie should be initialized before us.
cookie ^= (ULONG_PTR)__security_cookie;
// Add other randomization factors such as the thread creation time.
FILETIME creationTime;
FILETIME notused;
if (GetThreadTimes(GetCurrentThread(), &creationTime, ¬used, ¬used, ¬used))
{
#if defined(_WIN64)
ULARGE_INTEGER ul;
ul.LowPart = creationTime.dwLowDateTime;
ul.HighPart = creationTime.dwHighDateTime;
cookie ^= ul.QuadPart;
#else
cookie ^= creationTime.dwLowDateTime;
cookie ^= creationTime.dwHighDateTime;
#endif
}
return cookie;
}
//
// Encode the given pointer value
//
PVOID Security::EncodePointer(PVOID ptr)
{
CORE_ASSERT(Security::s_initialized != 0);
return (PVOID)((ULONG_PTR)(ptr) ^ Security::s_cookie);
}
//
// Decode the given pointer value
//
PVOID Security::DecodePointer(PVOID ptr)
{
return EncodePointer(ptr);
}
} // namespace details
} // namespace Concurrency
//
// ConcRT static cleanup:
//
extern "C"
void __cdecl _concrt_static_cleanup(void);
_CRTALLOC(".CRT$XPB") static _PVFV pterm = _concrt_static_cleanup;
extern "C"
void __cdecl _concrt_static_cleanup(void)
{
// Cleanup the TLS unless inside an EXE
if (HostModule != NULL)
{
SchedulerBase::CheckOneShotStaticDestruction();
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -