Remove more unused things from CryCommon and CrySystem. (#709)

Lots of unrelated removals, I basically tried to remove everything exposed via gEnv that isn't used anymore, and following the threads found a few other things to remove also.
This commit is contained in:
bosnichd
2021-05-12 08:30:15 -06:00
committed by GitHub
parent f9fb61cc5d
commit 7cec2d8b07
198 changed files with 29 additions and 28558 deletions
+1 -3
View File
@@ -1044,11 +1044,9 @@ void CSystem::AutoDetectSpec(const bool detectResolution)
unsigned int numSysCores(1), numProcCores(1);
Win32SysInspect::GetNumCPUCores(numSysCores, numProcCores);
CryLogAlways("--- Number of available cores: %d (out of %d)", numProcCores, numSysCores);
const int numLogicalProcs = gEnv->pi.numLogicalProcessors;
CryLogAlways("--- Number of logical processors: %d", numLogicalProcs);
// get CPU rating
const int cpuRating = numLogicalProcs >= 8 ? 3 : (numLogicalProcs >= 6 ? 2 : 1);
const int cpuRating = numProcCores >= 4 ? 3 : (numProcCores >= 3 ? 2 : 1);
// get GPU info
unsigned int gpuVendorId(0), gpuDeviceId(0), totVidMem(0);
-2
View File
@@ -89,7 +89,6 @@ ly_add_target(
Legacy::CrySystem.Static
AZ::AzCore
Legacy::CryCommon
Legacy::CryCommon.EngineSettings.Static
)
################################################################################
@@ -109,7 +108,6 @@ if(PAL_TRAIT_BUILD_TESTS_SUPPORTED)
PRIVATE
AZ::AzTest
Legacy::CryCommon
Legacy::CryCommon.EngineSettings.Static
Legacy::CrySystem.Static
AZ::AzFramework
)
@@ -87,14 +87,6 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename)
filename = PathUtil::ReplaceExtension(filename, "cfg");
}
#if defined(CVARS_WHITELIST)
bool ignoreWhitelist = true;
if (_stricmp(sFilename, "autoexec.cfg") == 0)
{
ignoreWhitelist = false;
}
#endif // defined(CVARS_WHITELIST)
//////////////////////////////////////////////////////////////////////////
CCryFile file;
@@ -179,18 +171,9 @@ bool CConsoleBatchFile::ExecuteConfigFile(const char* sFilename)
continue;
}
#if defined(CVARS_WHITELIST)
if (ignoreWhitelist || (gEnv->pSystem->GetCVarsWhiteList() && gEnv->pSystem->GetCVarsWhiteList()->IsWhiteListed(strLine, false)))
#endif // defined(CVARS_WHITELIST)
{
m_pConsole->ExecuteString(strLine);
}
#if defined(CVARS_WHITELIST)
else if (gEnv->IsDedicated())
{
gEnv->pSystem->GetILog()->LogError("Failed to execute command: '%s' as it is not whitelisted\n", strLine.c_str());
}
#endif // defined(CVARS_WHITELIST)
}
// See above
// ((CXConsole*)m_pConsole)->SetStatus(bConsoleStatus);
@@ -117,7 +117,6 @@ struct IRenderer;
struct ISystem;
struct ITimer;
struct IFFont;
struct IKeyboard;
struct ICVar;
struct IConsole;
struct IProcess;
@@ -1,259 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
//////////////////////////////////////////////////////////////////////////
// NOTE: INTERNAL HEADER NOT FOR PUBLIC USE
// This header should only be include by SystemThreading.cpp only
// It provides an interface for PThread intrinsics
// It's only client should be CThreadManager which should manage all thread interaction
#if !defined(INCLUDED_FROM_SYSTEM_THREADING_CPP)
# error "CRYTEK INTERNAL HEADER. ONLY INCLUDE FROM SYSTEMTHRADING.CPP."
#endif
//////////////////////////////////////////////////////////////////////////
#define DEFAULT_THREAD_STACK_SIZE_KB 0
#define CRY_PTHREAD_THREAD_NAME_MAX 16
//////////////////////////////////////////////////////////////////////////
// THREAD CREATION AND MANAGMENT
//////////////////////////////////////////////////////////////////////////
namespace CryThreadUtil
{
// Define type for platform specific thread handle
typedef pthread_t TThreadHandle;
struct SThreadCreationDesc
{
// Define platform specific thread entry function functor type
typedef void* (* EntryFunc)(void*);
const char* szThreadName;
EntryFunc fpEntryFunc;
void* pArgList;
uint32 nStackSizeInBytes;
};
//////////////////////////////////////////////////////////////////////////
TThreadHandle CryGetCurrentThreadHandle()
{
return (TThreadHandle)pthread_self();
}
//////////////////////////////////////////////////////////////////////////
// Note: Handle must be closed lated via CryCloseThreadHandle()
TThreadHandle CryDuplicateThreadHandle(const TThreadHandle& hThreadHandle)
{
// Do not do anything
// If you add a new platform which duplicates handles make sure to mirror the change in CryCloseThreadHandle(..)
return hThreadHandle;
}
//////////////////////////////////////////////////////////////////////////
void CryCloseThreadHandle(TThreadHandle& hThreadHandle)
{
pthread_detach(hThreadHandle);
}
//////////////////////////////////////////////////////////////////////////
threadID CryGetCurrentThreadId()
{
return threadID(pthread_self());
}
//////////////////////////////////////////////////////////////////////////
threadID CryGetThreadId(TThreadHandle hThreadHandle)
{
return threadID(hThreadHandle);
}
//////////////////////////////////////////////////////////////////////////
// Note: On OSX the thread name can only be set by the thread itself.
void CrySetThreadName(TThreadHandle pThreadHandle, const char* sThreadName)
{
char threadName[CRY_PTHREAD_THREAD_NAME_MAX];
if (!cry_strcpy(threadName, sThreadName))
{
CryLog("<ThreadInfo> CrySetThreadName: input thread name '%s' truncated to '%s'", sThreadName, threadName);
}
#if AZ_TRAIT_OS_PLATFORM_APPLE
// On OSX the thread name can only be set by the thread itself.
assert(pthread_equal(pthread_self(), (pthread_t )pThreadHandle));
if (pthread_setname_np(threadName) != 0)
#else
if (pthread_setname_np(pThreadHandle, threadName) != 0)
#endif
{
switch (errno)
{
case ERANGE:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadName: Unable to rename thread \"%s\". Error Msg: \"Name to long. Exceeds %d bytes.\"", sThreadName, CRY_PTHREAD_THREAD_NAME_MAX);
break;
default:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadName: Unsupported error code: %i", errno);
break;
}
}
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadAffinityMask(TThreadHandle pThreadHandle, DWORD dwAffinityMask)
{
#if defined(AZ_PLATFORM_ANDROID)
// Not supported on ANDROID
// Alternative solution
// Watch out that android will clear the mask after a core has been switched off hence loosing the affinity mask setting!
// http://stackoverflow.com/questions/16319725/android-set-thread-affinity
#elif AZ_TRAIT_OS_PLATFORM_APPLE
# pragma message "Warning: <ThreadInfo> CrySetThreadAffinityMask not implemented for platform"
// Implementation details can be found here
// https://developer.apple.com/library/mac/releasenotes/Performance/RN-AffinityAPI/
#else
cpu_set_t cpu_mask;
CPU_ZERO(&cpu_mask);
for (int cpu = 0; cpu < sizeof(cpu_mask) * 8; ++cpu)
{
if (dwAffinityMask & (1 << cpu))
{
CPU_SET(cpu, &cpu_mask);
}
}
if (sched_setaffinity(0, sizeof(cpu_mask), &cpu_mask) != 0)
{
switch (errno)
{
case EFAULT:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: Supplied memory address was invalid.");
break;
case EINVAL:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The affinity bit mask [%u] contains no processors that are currently physically on the system and permitted to the process .", dwAffinityMask);
break;
case EPERM:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The calling process does not have appropriate privileges. Mask [%u].", dwAffinityMask);
break;
case ESRCH:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: The process whose ID is pid could not be found.");
break;
default:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> CrySetThreadAffinityMask: Unsupported error code: %i", errno);
break;
}
}
#endif
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadPriority(TThreadHandle pThreadHandle, DWORD dwPriority)
{
int policy;
struct sched_param param;
pthread_getschedparam(pThreadHandle, &policy, &param);
param.sched_priority = sched_get_priority_max(dwPriority);
pthread_setschedparam(pThreadHandle, policy, &param);
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadPriorityBoost(TThreadHandle pThreadHandle, bool bEnabled)
{
// Not supported
}
//////////////////////////////////////////////////////////////////////////
bool CryCreateThread(TThreadHandle* pThreadHandle, const SThreadCreationDesc& threadDesc)
{
uint32 nStackSize = threadDesc.nStackSizeInBytes != 0 ? threadDesc.nStackSizeInBytes : DEFAULT_THREAD_STACK_SIZE_KB * 1024;
assert(pThreadHandle != reinterpret_cast<TThreadHandle*>(THREADID_NULL));
pthread_attr_t threadAttr;
sched_param schedParam;
pthread_attr_init(&threadAttr);
pthread_attr_setdetachstate(&threadAttr, PTHREAD_CREATE_JOINABLE);
pthread_attr_setstacksize(&threadAttr, nStackSize);
const int err = pthread_create(
pThreadHandle,
&threadAttr,
threadDesc.fpEntryFunc,
threadDesc.pArgList);
// Handle error on thread creation
switch (err)
{
case 0:
// No error
break;
case EAGAIN:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"Insufficient resources to create another thread, or a system-imposed limit on the number of threads was encountered.\"", threadDesc.szThreadName);
return false;
case EINVAL:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"Invalid attribute setting for thread creation.\"", threadDesc.szThreadName);
return false;
case EPERM:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Error Msg: \"No permission to set the scheduling policy and parameters specified in attribute setting\"", threadDesc.szThreadName);
return false;
default:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". Unknown error message. Error code %i", threadDesc.szThreadName, err);
break;
}
// Print info to log
CryComment("<ThreadInfo>: New thread \"%s\" | StackSize: %u(KB)", threadDesc.szThreadName, threadDesc.nStackSizeInBytes / 1024);
return true;
}
//////////////////////////////////////////////////////////////////////////
void CryThreadExitCall()
{
// Notes on: pthread_exit
// A thread that was create with pthread_create implicitly calls pthread_exit when the thread returns from its start routine (the function that was first called after a thread was created).
// pthread_exit(NULL);
}
}
//////////////////////////////////////////////////////////////////////////
// FLOATING POINT EXCEPTIONS
//////////////////////////////////////////////////////////////////////////
namespace CryThreadUtil
{
///////////////////////////////////////////////////////////////////////////
void EnableFloatExceptions(EFPE_Severity eFPESeverity)
{
// TODO:
// Not implemented
// for potential implementation see http://linux.die.net/man/3/feenableexcept
}
//////////////////////////////////////////////////////////////////////////
void EnableFloatExceptions(threadID nThreadId, EFPE_Severity eFPESeverity)
{
// TODO:
// Not implemented
// for potential implementation see http://linux.die.net/man/3/feenableexcept
}
//////////////////////////////////////////////////////////////////////////
uint GetFloatingPointExceptionMask()
{
// Not implemented
return ~0;
}
//////////////////////////////////////////////////////////////////////////
void SetFloatingPointExceptionMask(uint nMask)
{
// Not implemented
}
}
@@ -1,432 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
//////////////////////////////////////////////////////////////////////////
// NOTE: INTERNAL HEADER NOT FOR PUBLIC USE
// This header should only be include by SystemThreading.cpp only
// It provides an interface for WinApi intrinsics
// It's only client should be CThreadManager which should manage all thread interaction
#pragma once
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define CRYTHREADUTIL_WIN32_THREAD_H_SECTION_1 1
#define CRYTHREADUTIL_WIN32_THREAD_H_SECTION_2 2
#endif
#if !defined(INCLUDED_FROM_SYSTEM_THREADING_CPP)
# error "CRYTEK INTERNAL HEADER. ONLY INCLUDE FROM SYSTEMTHRADING.CPP."
#endif
//////////////////////////////////////////////////////////////////////////
#define DEFAULT_THREAD_STACK_SIZE_KB 0
// Returns the last Win32 error, in string format. Returns an empty string if there is no error.
static string GetLastErrorAsString()
{
// Get the error message, if any.
DWORD errorMessageID = GetLastError();
if (errorMessageID == 0)
{
return "";
}
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION CRYTHREADUTIL_WIN32_THREAD_H_SECTION_1
#include AZ_RESTRICTED_FILE(CryThreadUtil_win32_thread_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
LPSTR messageBuffer = nullptr;
size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), messageBuffer, 0, NULL);
string message(messageBuffer, size);
// Free the buffer.
LocalFree(messageBuffer);
return message;
#endif
}
//////////////////////////////////////////////////////////////////////////
// THREAD CREATION AND MANAGMENT
//////////////////////////////////////////////////////////////////////////
namespace CryThreadUtil
{
// Define type for platform specific thread handle
typedef THREAD_HANDLE TThreadHandle;
struct SThreadCreationDesc
{
// Define platform specific thread entry function functor type
typedef unsigned int(_stdcall * EntryFunc)(void*);
const char* szThreadName;
EntryFunc fpEntryFunc;
void* pArgList;
uint32 nStackSizeInBytes;
};
//////////////////////////////////////////////////////////////////////////
TThreadHandle CryGetCurrentThreadHandle()
{
return GetCurrentThread(); // most likely returns pseudo handle (0xfffffffe)
}
//////////////////////////////////////////////////////////////////////////
// Note: Handle must be closed lated via CryCloseThreadHandle()
TThreadHandle CryDuplicateThreadHandle(const TThreadHandle& hThreadHandle)
{
// NOTES:
// GetCurrentThread() may return a psydo handle to the current thread
// to avoid going into the slower kernel mode.
// Hence the handle is useless when being used from an other thread.
// - GetCurrentThread() -> 0xfffffffe
// - GetCurrentProcess() -> 0xffffffff
HANDLE hRealHandle = 0;
DuplicateHandle(GetCurrentProcess(), // Source Process Handle.
hThreadHandle, // Source Handle to dup.
GetCurrentProcess(), // Target Process Handle.
&hRealHandle, // Target Handle pointer.
0, // Options flag.
TRUE, // Inheritable flag
DUPLICATE_SAME_ACCESS); // Options
return (TThreadHandle)hRealHandle;
}
//////////////////////////////////////////////////////////////////////////
void CryCloseThreadHandle(TThreadHandle& hThreadHandle)
{
if (hThreadHandle)
{
CloseHandle(hThreadHandle);
}
}
//////////////////////////////////////////////////////////////////////////
threadID CryGetCurrentThreadId()
{
return GetCurrentThreadId();
}
//////////////////////////////////////////////////////////////////////////
threadID CryGetThreadId(TThreadHandle hThreadHandle)
{
return GetThreadId(hThreadHandle);
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadName(TThreadHandle pThreadHandle, const char* sThreadName)
{
const DWORD MS_VC_EXCEPTION = 0x406D1388;
struct SThreadNameDesc
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
};
SThreadNameDesc info;
info.dwType = 0x1000;
info.szName = sThreadName;
info.dwThreadID = GetThreadId(pThreadHandle);
info.dwFlags = 0;
AZ_PUSH_DISABLE_WARNING(6312 6322, "-Wunknown-warning-option")
// warning C6312: Possible infinite loop: use of the constant EXCEPTION_CONTINUE_EXECUTION in the exception-filter expression of a try-except
// warning C6322: empty _except block
__try
{
// Raise exception to set thread name for attached debugger
RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR*)&info);
}
__except (GetExceptionCode() == MS_VC_EXCEPTION ? EXCEPTION_CONTINUE_EXECUTION : EXCEPTION_EXECUTE_HANDLER)
{
}
AZ_POP_DISABLE_WARNING
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadAffinityMask(TThreadHandle pThreadHandle, DWORD dwAffinityMask)
{
SetThreadAffinityMask(pThreadHandle, dwAffinityMask);
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadPriority(TThreadHandle pThreadHandle, DWORD dwPriority)
{
if (!SetThreadPriority(pThreadHandle, dwPriority))
{
string errMsg = GetLastErrorAsString();
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to set thread priority. System Error Msg: \"%s\"", errMsg.c_str());
return;
}
}
//////////////////////////////////////////////////////////////////////////
void CrySetThreadPriorityBoost(TThreadHandle pThreadHandle, bool bEnabled)
{
SetThreadPriorityBoost(pThreadHandle, !bEnabled);
}
//////////////////////////////////////////////////////////////////////////
bool CryCreateThread(TThreadHandle* pThreadHandle, const SThreadCreationDesc& threadDesc)
{
const uint32 nStackSize = threadDesc.nStackSizeInBytes != 0 ? threadDesc.nStackSizeInBytes : DEFAULT_THREAD_STACK_SIZE_KB * 1024;
// Create thread
unsigned int threadId = 0;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION CRYTHREADUTIL_WIN32_THREAD_H_SECTION_2
#include AZ_RESTRICTED_FILE(CryThreadUtil_win32_thread_h)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
*pThreadHandle = (void*)_beginthreadex(NULL, nStackSize, threadDesc.fpEntryFunc, threadDesc.pArgList, CREATE_SUSPENDED, &threadId);
#endif
if (!(*pThreadHandle))
{
string errMsg = GetLastErrorAsString();
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Unable to create thread \"%s\". System Error Msg: \"%s\"", threadDesc.szThreadName, errMsg.c_str());
return false;
}
// Start thread
ResumeThread(*pThreadHandle);
// Print info to log
CryComment("<ThreadInfo>: New thread \"%s\" | StackSize: %u(KB)", threadDesc.szThreadName, threadDesc.nStackSizeInBytes / 1024);
return true;
}
//////////////////////////////////////////////////////////////////////////
void CryThreadExitCall()
{
// Note on: ExitThread() (from MSDN)
// ExitThread is the preferred method of exiting a thread in C code.
// However, in C++ code, the thread is exited before any destructor can be called or any other automatic cleanup can be performed.
// Therefore, in C++ code, you should return from your thread function.
}
}
//////////////////////////////////////////////////////////////////////////
// FLOATING POINT EXCEPTIONS
//////////////////////////////////////////////////////////////////////////
namespace CryThreadUtil
{
///////////////////////////////////////////////////////////////////////////
void EnableFloatExceptions([[maybe_unused]] EFPE_Severity eFPESeverity)
{
AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
// Optimization
// Enable DAZ/FZ
// Denormals Are Zeros
// Flush-to-Zero
_controlfp(_DN_FLUSH, _MCW_DN);
_mm_setcsr(_mm_getcsr() | _MM_FLUSH_ZERO_ON);
#ifndef _RELEASE
if (eFPESeverity == eFPE_None)
{
// mask all floating exceptions off.
_controlfp(_MCW_EM, _MCW_EM);
_mm_setcsr(_mm_getcsr() | _MM_MASK_MASK);
}
else
{
// Clear pending exceptions
_fpreset();
if (eFPESeverity == eFPE_Basic)
{
// Enable:
// - _EM_ZERODIVIDE
// - _EM_INVALID
//
// Disable:
// - _EM_DENORMAL
// - _EM_OVERFLOW
// - _EM_UNDERFLOW
// - _EM_INEXACT
_controlfp(_EM_INEXACT | _EM_DENORMAL | _EM_UNDERFLOW | _EM_OVERFLOW, _MCW_EM);
_mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | (_MM_MASK_DENORM | _MM_MASK_INEXACT | _MM_MASK_UNDERFLOW | _MM_MASK_OVERFLOW));
//_mm_setcsr(_mm_getcsr() & ~0x280);
}
if (eFPESeverity == eFPE_All)
{
// Enable:
// - _EM_ZERODIVIDE
// - _EM_INVALID
// - _EM_UNDERFLOW
// - _EM_OVERFLOW
//
// Disable:
// - _EM_INEXACT
// - _EM_DENORMAL
_controlfp(_EM_INEXACT | _EM_DENORMAL, _MCW_EM);
_mm_setcsr((_mm_getcsr() & ~_MM_MASK_MASK) | (_MM_MASK_INEXACT | _MM_MASK_DENORM));
}
}
#endif // _RELEASE
AZ_POP_DISABLE_WARNING
}
//////////////////////////////////////////////////////////////////////////
void EnableFloatExceptions(threadID nThreadId, EFPE_Severity eFPESeverity)
{
if (eFPESeverity >= eFPE_LastEntry)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Floating Point Exception (FPE) severity is out of range. (%i)", eFPESeverity);
}
// Check if the thread ID matches the current thread
if (nThreadId == 0 || nThreadId == CryGetCurrentThreadId())
{
EnableFloatExceptions(eFPESeverity);
return;
}
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, true, nThreadId);
if (hThread == 0)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Unable to open thread. %p", hThread);
return;
}
SuspendThread(hThread);
CONTEXT ctx;
memset(&ctx, 0, sizeof(ctx));
ctx.ContextFlags = CONTEXT_ALL;
if (GetThreadContext(hThread, &ctx) == 0)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Unable to get thread context");
ResumeThread(hThread);
CloseHandle(hThread);
return;
}
#ifdef PLATFORM_64BIT
//////////////////////////////////////////////////////////////////////////
// Note:
// DO NOT USE ctx.FltSave.MxCsr ... SetThreadContext() will copy the value of ctx.MxCsr into it
//////////////////////////////////////////////////////////////////////////
DWORD& floatMxCsr = ctx.MxCsr; // Hold FPE Mask and Status for MMX (SSE) floating point registers
WORD& floatControlWord = ctx.FltSave.ControlWord; // Hold FPE Mask for floating point registers
#ifndef _RELEASE
WORD& floatStatuslWord = ctx.FltSave.StatusWord; // Holds FPE Status for floating point registers
#endif
#else
DWORD& floatMxCsr = *(DWORD*)(&ctx.ExtendedRegisters[24]); // Hold FPE Mask and Status for MMX (SSE) floating point registers
DWORD& floatControlWord = ctx.FloatSave.ControlWord; // Hold FPE Mask for floating point registers
DWORD& floatStatuslWord = ctx.FloatSave.StatusWord; // Holds FPE Status for floating point registers
#endif
// Flush-To-Zero Mode
// Two conditions must be met for FTZ processing to occur:
// - The FTZ bit (bit 15) in the MXCSR register must be masked (value = 1).
// - The underflow exception (bit 11) needs to be masked (value = 1).
// Set flush mode to zero mode
floatControlWord = (floatControlWord & ~_MCW_DN) | _DN_FLUSH;
floatMxCsr = (floatMxCsr & ~_MM_FLUSH_ZERO_MASK) | (_MM_FLUSH_ZERO_ON);
#ifndef _RELEASE
// Reset FPE bits
floatControlWord = floatControlWord | _MCW_EM;
floatMxCsr = floatMxCsr | _MM_MASK_MASK;
// Clear pending exceptions
floatStatuslWord = floatStatuslWord & ~(_SW_INEXACT | _SW_UNDERFLOW | _SW_OVERFLOW | _SW_ZERODIVIDE | _SW_INVALID | _SW_DENORMAL);
floatMxCsr = floatMxCsr & ~(_MM_EXCEPT_INEXACT | _MM_EXCEPT_UNDERFLOW | _MM_EXCEPT_OVERFLOW | _MM_EXCEPT_DIV_ZERO | _MM_EXCEPT_INVALID | _MM_EXCEPT_DENORM);
if (eFPESeverity == eFPE_Basic)
{
// Enable:
// - _EM_ZERODIVIDE
// - _EM_INVALID
//
// Disable:
// - _EM_DENORMAL
// - _EM_OVERFLOW
// - _EM_UNDERFLOW
// - _EM_INEXACT
floatControlWord = (floatControlWord & ~_MCW_EM) | (_EM_DENORMAL | _EM_INEXACT | EM_UNDERFLOW | _EM_OVERFLOW);
floatMxCsr = (floatMxCsr & ~_MM_MASK_MASK) | (_MM_MASK_DENORM | _MM_MASK_INEXACT | _MM_MASK_UNDERFLOW | _MM_MASK_OVERFLOW);
}
if (eFPESeverity == eFPE_All)
{
// Enable:
// - _EM_ZERODIVIDE
// - _EM_INVALID
// - _EM_UNDERFLOW
// - _EM_OVERFLOW
//
// Disable:
// - _EM_INEXACT
// - _EM_DENORMAL
floatControlWord = (floatControlWord & ~_MCW_EM) | (_EM_INEXACT | _EM_DENORMAL);
floatMxCsr = (floatMxCsr & ~_MM_MASK_MASK) | (_MM_MASK_INEXACT | _MM_MASK_DENORM);
}
#endif
ctx.ContextFlags = CONTEXT_ALL;
if (SetThreadContext(hThread, &ctx) == 0)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Error setting ThreadContext for ThreadID: %u", nThreadId);
ResumeThread(hThread);
CloseHandle(hThread);
return;
}
ResumeThread(hThread);
CloseHandle(hThread);
}
//////////////////////////////////////////////////////////////////////////
uint GetFloatingPointExceptionMask()
{
uint nMask = 0;
_clearfp();
_controlfp_s(&nMask, 0, 0);
return nMask;
}
//////////////////////////////////////////////////////////////////////////
void SetFloatingPointExceptionMask(uint nMask)
{
uint temp = 0;
_clearfp();
const unsigned int kAllowedBits = _MCW_DN | _MCW_EM | _MCW_RC;
_controlfp_s(&temp, nMask, kAllowedBits);
}
}
-926
View File
@@ -1,926 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "DebugCallStack.h"
#if defined(WIN32) || defined(WIN64)
#include <IConsole.h>
#include <CryPath.h>
#include <Pak/CryPakUtils.h>
#include "System.h"
#include <AzCore/Debug/StackTracer.h>
#include <AzCore/Debug/EventTraceDrillerBus.h>
#include "resource.h"
__pragma(comment(lib, "version.lib"))
//! Needs one external of DLL handle.
extern HMODULE gDLLHandle;
#include <DbgHelp.h>
#define MAX_PATH_LENGTH 1024
#define MAX_SYMBOL_LENGTH 512
static HWND hwndException = 0;
static bool g_bUserDialog = true; // true=on crash show dialog box, false=supress user interaction
static int PrintException(EXCEPTION_POINTERS* pex);
static bool IsFloatingPointException(EXCEPTION_POINTERS* pex);
extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers);
extern LONG WINAPI CryEngineExceptionFilterMiniDump(struct _EXCEPTION_POINTERS* pExceptionPointers, const char* szDumpPath, MINIDUMP_TYPE mdumpValue);
//=============================================================================
CONTEXT CaptureCurrentContext()
{
CONTEXT context;
memset(&context, 0, sizeof(context));
context.ContextFlags = CONTEXT_FULL;
RtlCaptureContext(&context);
return context;
}
LONG __stdcall CryUnhandledExceptionHandler(EXCEPTION_POINTERS* pex)
{
return DebugCallStack::instance()->handleException(pex);
}
BOOL CALLBACK EnumModules(
PCSTR ModuleName,
DWORD64 BaseOfDll,
PVOID UserContext)
{
DebugCallStack::TModules& modules = *static_cast<DebugCallStack::TModules*>(UserContext);
modules[(void*)BaseOfDll] = ModuleName;
return TRUE;
}
//=============================================================================
// Class Statics
//=============================================================================
// Return single instance of class.
IDebugCallStack* IDebugCallStack::instance()
{
static DebugCallStack sInstance;
return &sInstance;
}
//------------------------------------------------------------------------------------------------------------------------
// Sets up the symbols for functions in the debug file.
//------------------------------------------------------------------------------------------------------------------------
DebugCallStack::DebugCallStack()
: prevExceptionHandler(0)
, m_pSystem(0)
, m_nSkipNumFunctions(0)
, m_bCrash(false)
, m_szBugMessage(NULL)
{
}
DebugCallStack::~DebugCallStack()
{
}
void DebugCallStack::RemoveOldFiles()
{
RemoveFile("error.log");
RemoveFile("error.bmp");
RemoveFile("error.dmp");
}
void DebugCallStack::RemoveFile(const char* szFileName)
{
FILE* pFile = nullptr;
azfopen(&pFile, szFileName, "r");
const bool bFileExists = (pFile != NULL);
if (bFileExists)
{
fclose(pFile);
WriteLineToLog("Removing file \"%s\"...", szFileName);
if (remove(szFileName) == 0)
{
WriteLineToLog("File successfully removed.");
}
else
{
WriteLineToLog("Couldn't remove file!");
}
}
}
void DebugCallStack::installErrorHandler(ISystem* pSystem)
{
m_pSystem = pSystem;
prevExceptionHandler = (void*)SetUnhandledExceptionFilter(CryUnhandledExceptionHandler);
}
//////////////////////////////////////////////////////////////////////////
void DebugCallStack::SetUserDialogEnable(const bool bUserDialogEnable)
{
g_bUserDialog = bUserDialogEnable;
}
DWORD g_idDebugThreads[10];
const char* g_nameDebugThreads[10];
int g_nDebugThreads = 0;
volatile int g_lockThreadDumpList = 0;
void MarkThisThreadForDebugging(const char* name)
{
EBUS_EVENT(AZ::Debug::EventTraceDrillerSetupBus, SetThreadName, AZStd::this_thread::get_id(), name);
WriteLock lock(g_lockThreadDumpList);
DWORD id = GetCurrentThreadId();
if (g_nDebugThreads == sizeof(g_idDebugThreads) / sizeof(g_idDebugThreads[0]))
{
return;
}
for (int i = 0; i < g_nDebugThreads; i++)
{
if (g_idDebugThreads[i] == id)
{
return;
}
}
g_nameDebugThreads[g_nDebugThreads] = name;
g_idDebugThreads[g_nDebugThreads++] = id;
((CSystem*)gEnv->pSystem)->EnableFloatExceptions(g_cvars.sys_float_exceptions);
}
void UnmarkThisThreadFromDebugging()
{
WriteLock lock(g_lockThreadDumpList);
DWORD id = GetCurrentThreadId();
for (int i = g_nDebugThreads - 1; i >= 0; i--)
{
if (g_idDebugThreads[i] == id)
{
memmove(g_idDebugThreads + i, g_idDebugThreads + i + 1, (g_nDebugThreads - 1 - i) * sizeof(g_idDebugThreads[0]));
memmove(g_nameDebugThreads + i, g_nameDebugThreads + i + 1, (g_nDebugThreads - 1 - i) * sizeof(g_nameDebugThreads[0]));
--g_nDebugThreads;
}
}
}
extern int prev_sys_float_exceptions;
void UpdateFPExceptionsMaskForThreads()
{
int mask = -iszero(g_cvars.sys_float_exceptions);
CONTEXT ctx;
for (int i = 0; i < g_nDebugThreads; i++)
{
if (g_idDebugThreads[i] != GetCurrentThreadId())
{
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, g_idDebugThreads[i]);
ctx.ContextFlags = CONTEXT_ALL;
SuspendThread(hThread);
GetThreadContext(hThread, &ctx);
#ifndef WIN64
(ctx.FloatSave.ControlWord |= 7) &= ~5 | mask;
(*(WORD*)(ctx.ExtendedRegisters + 24) |= 0x280) &= ~0x280 | mask;
#else
(ctx.FltSave.ControlWord |= 7) &= ~5 | mask;
(ctx.FltSave.MxCsr |= 0x280) &= ~0x280 | mask;
#endif
SetThreadContext(hThread, &ctx);
ResumeThread(hThread);
}
}
}
//////////////////////////////////////////////////////////////////////////
int DebugCallStack::handleException(EXCEPTION_POINTERS* exception_pointer)
{
if (gEnv == NULL)
{
return EXCEPTION_EXECUTE_HANDLER;
}
ResetFPU(exception_pointer);
prev_sys_float_exceptions = 0;
const int cached_sys_float_exceptions = g_cvars.sys_float_exceptions;
((CSystem*)gEnv->pSystem)->EnableFloatExceptions(0);
if (g_cvars.sys_WER)
{
gEnv->pLog->FlushAndClose();
return CryEngineExceptionFilterWER(exception_pointer);
}
if (g_cvars.sys_no_crash_dialog)
{
DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX);
}
m_bCrash = true;
if (g_cvars.sys_no_crash_dialog)
{
DWORD dwMode = SetErrorMode(SEM_NOGPFAULTERRORBOX);
SetErrorMode(dwMode | SEM_NOGPFAULTERRORBOX);
}
static bool firstTime = true;
if (g_cvars.sys_dump_aux_threads)
{
for (int i = 0; i < g_nDebugThreads; i++)
{
if (g_idDebugThreads[i] != GetCurrentThreadId())
{
SuspendThread(OpenThread(THREAD_ALL_ACCESS, TRUE, g_idDebugThreads[i]));
}
}
}
// uninstall our exception handler.
SetUnhandledExceptionFilter((LPTOP_LEVEL_EXCEPTION_FILTER)prevExceptionHandler);
if (!firstTime)
{
WriteLineToLog("Critical Exception! Called Multiple Times!");
gEnv->pLog->FlushAndClose();
// Exception called more then once.
return EXCEPTION_EXECUTE_HANDLER;
}
// Print exception info:
{
char excCode[80];
char excAddr[80];
WriteLineToLog("<CRITICAL EXCEPTION>");
sprintf_s(excAddr, "0x%04X:0x%p", exception_pointer->ContextRecord->SegCs, exception_pointer->ExceptionRecord->ExceptionAddress);
sprintf_s(excCode, "0x%08X", exception_pointer->ExceptionRecord->ExceptionCode);
WriteLineToLog("Exception: %s, at Address: %s", excCode, excAddr);
{
IMemoryManager::SProcessMemInfo memInfo;
if (gEnv->pSystem->GetIMemoryManager()->GetProcessMemInfo(memInfo))
{
uint32 nMemUsage = (uint32)(memInfo.PagefileUsage / (1024 * 1024));
WriteLineToLog("Virtual memory usage: %dMb", nMemUsage);
}
gEnv->szDebugStatus[SSystemGlobalEnvironment::MAX_DEBUG_STRING_LENGTH - 1] = '\0';
WriteLineToLog("Debug Status: %s", gEnv->szDebugStatus);
}
}
firstTime = false;
const int ret = SubmitBug(exception_pointer);
if (ret != IDB_IGNORE)
{
CryEngineExceptionFilterWER(exception_pointer);
}
gEnv->pLog->FlushAndClose();
if (exception_pointer->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
{
// This is non continuable exception. abort application now.
exit(exception_pointer->ExceptionRecord->ExceptionCode);
}
//typedef long (__stdcall *ExceptionFunc)(EXCEPTION_POINTERS*);
//ExceptionFunc prevFunc = (ExceptionFunc)prevExceptionHandler;
//return prevFunc( (EXCEPTION_POINTERS*)exception_pointer );
if (ret == IDB_EXIT)
{
// Immediate exit.
// on windows, exit() and _exit() do all sorts of things, unfortuantely
// TerminateProcess is the only way to die.
TerminateProcess(GetCurrentProcess(), exception_pointer->ExceptionRecord->ExceptionCode); // we crashed, so don't return a zero exit code!
// on linux based systems, _exit will not call ATEXIT and other things, which makes it more suitable for termination in an emergency such
// as an unhandled exception.
// however, this function is a windows exception handler.
}
else if (ret == IDB_IGNORE)
{
#ifndef WIN64
exception_pointer->ContextRecord->FloatSave.StatusWord &= ~31;
exception_pointer->ContextRecord->FloatSave.ControlWord |= 7;
(*(WORD*)(exception_pointer->ContextRecord->ExtendedRegisters + 24) &= 31) |= 0x1F80;
#else
exception_pointer->ContextRecord->FltSave.StatusWord &= ~31;
exception_pointer->ContextRecord->FltSave.ControlWord |= 7;
(exception_pointer->ContextRecord->FltSave.MxCsr &= 31) |= 0x1F80;
#endif
firstTime = true;
prevExceptionHandler = (void*)SetUnhandledExceptionFilter(CryUnhandledExceptionHandler);
g_cvars.sys_float_exceptions = cached_sys_float_exceptions;
((CSystem*)gEnv->pSystem)->EnableFloatExceptions(g_cvars.sys_float_exceptions);
return EXCEPTION_CONTINUE_EXECUTION;
}
// Continue;
return EXCEPTION_EXECUTE_HANDLER;
}
void DebugCallStack::ReportBug(const char* szErrorMessage)
{
WriteLineToLog("Reporting bug: %s", szErrorMessage);
m_szBugMessage = szErrorMessage;
m_context = CaptureCurrentContext();
SubmitBug(NULL);
m_szBugMessage = NULL;
}
void DebugCallStack::dumpCallStack(std::vector<string>& funcs)
{
WriteLineToLog("=============================================================================");
int len = (int)funcs.size();
for (int i = 0; i < len; i++)
{
const char* str = funcs[i].c_str();
WriteLineToLog("%2d) %s", len - i, str);
}
WriteLineToLog("=============================================================================");
}
//////////////////////////////////////////////////////////////////////////
void DebugCallStack::LogExceptionInfo(EXCEPTION_POINTERS* pex)
{
string path("");
if ((gEnv) && (gEnv->pFileIO))
{
const char* logAlias = gEnv->pFileIO->GetAlias("@log@");
if (!logAlias)
{
logAlias = gEnv->pFileIO->GetAlias("@root@");
}
if (logAlias)
{
path = logAlias;
path += "/";
}
}
string fileName = path;
fileName += "error.log";
struct stat fileInfo;
string timeStamp;
string backupPath;
if (gEnv->IsDedicated())
{
backupPath = PathUtil::ToUnixPath(PathUtil::AddSlash(path + "DumpBackups"));
gEnv->pFileIO->CreatePath(backupPath.c_str());
if (stat(fileName.c_str(), &fileInfo) == 0)
{
// Backup log
tm creationTime;
localtime_s(&creationTime, &fileInfo.st_mtime);
char tempBuffer[32];
strftime(tempBuffer, sizeof(tempBuffer), "%d %b %Y (%H %M %S)", &creationTime);
timeStamp = tempBuffer;
string backupFileName = backupPath + timeStamp + " error.log";
CopyFile(fileName.c_str(), backupFileName.c_str(), true);
}
}
FILE* f = nullptr;
azfopen(&f, fileName.c_str(), "wt");
CDebugAllowFileAccess ignoreInvalidFileAccess;
static char errorString[s_iCallStackSize];
errorString[0] = 0;
// Time and Version.
char versionbuf[1024];
azstrcpy(versionbuf, AZ_ARRAY_SIZE(versionbuf), "");
PutVersion(versionbuf, AZ_ARRAY_SIZE(versionbuf));
cry_strcat(errorString, versionbuf);
cry_strcat(errorString, "\n");
char excCode[MAX_WARNING_LENGTH];
char excAddr[80];
char desc[1024];
char excDesc[MAX_WARNING_LENGTH];
// make sure the mouse cursor is visible
ShowCursor(TRUE);
const char* excName;
if (m_bIsFatalError || !pex)
{
const char* const szMessage = m_bIsFatalError ? s_szFatalErrorCode : m_szBugMessage;
excName = szMessage;
cry_strcpy(excCode, szMessage);
cry_strcpy(excAddr, "");
cry_strcpy(desc, "");
cry_strcpy(m_excModule, "");
cry_strcpy(excDesc, szMessage);
}
else
{
sprintf_s(excAddr, "0x%04X:0x%p", pex->ContextRecord->SegCs, pex->ExceptionRecord->ExceptionAddress);
sprintf_s(excCode, "0x%08X", pex->ExceptionRecord->ExceptionCode);
excName = TranslateExceptionCode(pex->ExceptionRecord->ExceptionCode);
cry_strcpy(desc, "");
sprintf_s(excDesc, "%s\r\n%s", excName, desc);
if (pex->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
{
if (pex->ExceptionRecord->NumberParameters > 1)
{
ULONG_PTR iswrite = pex->ExceptionRecord->ExceptionInformation[0];
DWORD64 accessAddr = pex->ExceptionRecord->ExceptionInformation[1];
if (iswrite)
{
sprintf_s(desc, "Attempt to write data to address 0x%08llu\r\nThe memory could not be \"written\"", accessAddr);
}
else
{
sprintf_s(desc, "Attempt to read from address 0x%08llu\r\nThe memory could not be \"read\"", accessAddr);
}
}
}
}
WriteLineToLog("Exception Code: %s", excCode);
WriteLineToLog("Exception Addr: %s", excAddr);
WriteLineToLog("Exception Module: %s", m_excModule);
WriteLineToLog("Exception Name : %s", excName);
WriteLineToLog("Exception Description: %s", desc);
cry_strcpy(m_excDesc, excDesc);
cry_strcpy(m_excAddr, excAddr);
cry_strcpy(m_excCode, excCode);
char errs[32768];
sprintf_s(errs, "Exception Code: %s\nException Addr: %s\nException Module: %s\nException Description: %s, %s\n",
excCode, excAddr, m_excModule, excName, desc);
IMemoryManager::SProcessMemInfo memInfo;
if (gEnv->pSystem->GetIMemoryManager()->GetProcessMemInfo(memInfo))
{
char memoryString[256];
double MB = 1024 * 1024;
sprintf_s(memoryString, "Memory in use: %3.1fMB\n", (double)(memInfo.PagefileUsage) / MB);
cry_strcat(errs, memoryString);
}
{
const int tempStringSize = 256;
char tempString[tempStringSize];
gEnv->szDebugStatus[SSystemGlobalEnvironment::MAX_DEBUG_STRING_LENGTH - 1] = '\0';
sprintf_s(tempString, tempStringSize, "Debug Status: %s\n", gEnv->szDebugStatus);
cry_strcat(errs, tempString);
sprintf_s(tempString, tempStringSize, "Out of Memory: %d\n", gEnv->bIsOutOfMemory);
cry_strcat(errs, tempString);
}
cry_strcat(errs, "\nCall Stack Trace:\n");
std::vector<string> funcs;
if (gEnv->bIsOutOfMemory)
{
cry_strcat(errs, "1) OUT_OF_MEMORY()\n");
}
else
{
AZ::Debug::StackFrame frames[25];
AZ::Debug::SymbolStorage::StackLine lines[AZ_ARRAY_SIZE(frames)];
unsigned int numFrames = AZ::Debug::StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), 3);
if (numFrames)
{
AZ::Debug::SymbolStorage::DecodeFrames(frames, numFrames, lines);
for (unsigned int i = 0; i < numFrames; i++)
{
funcs.push_back(lines[i]);
}
}
dumpCallStack(funcs);
// Fill call stack.
char str[s_iCallStackSize];
cry_strcpy(str, "");
for (unsigned int i = 0; i < funcs.size(); i++)
{
char temp[s_iCallStackSize];
sprintf_s(temp, "%2zd) %s", funcs.size() - i, (const char*)funcs[i].c_str());
cry_strcat(str, temp);
cry_strcat(str, "\r\n");
cry_strcat(errs, temp);
cry_strcat(errs, "\n");
}
cry_strcpy(m_excCallstack, str);
}
cry_strcat(errorString, errs);
if (f)
{
fwrite(errorString, strlen(errorString), 1, f);
if (!gEnv->bIsOutOfMemory)
{
if (g_cvars.sys_dump_aux_threads)
{
for (int i = 0; i < g_nDebugThreads; i++)
{
if (g_idDebugThreads[i] != GetCurrentThreadId())
{
fprintf(f, "\n\nSuspended thread (%s):\n", g_nameDebugThreads[i]);
HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, TRUE, g_idDebugThreads[i]);
// mirrors the AZ::Debug::Trace::PrintCallstack() functionality, but prints to a file
{
AZ::Debug::StackFrame frames[10];
// Without StackFrame explicit alignment frames array is aligned to 4 bytes
// which causes the stack tracing to fail.
AZ::Debug::SymbolStorage::StackLine lines[AZ_ARRAY_SIZE(frames)];
unsigned int numFrames = AZ::Debug::StackRecorder::Record(frames, AZ_ARRAY_SIZE(frames), 0, hThread);
if (numFrames)
{
AZ::Debug::SymbolStorage::DecodeFrames(frames, numFrames, lines);
for (unsigned int i2 = 0; i2 < numFrames; ++i2)
{
fprintf(f, "%2d) %s\n", numFrames - i2, lines[i2]);
}
}
}
ResumeThread(hThread);
}
}
}
}
fflush(f);
fclose(f);
}
if (pex)
{
MINIDUMP_TYPE mdumpValue;
bool bDump = true;
switch (g_cvars.sys_dump_type)
{
case 0:
bDump = false;
break;
case 1:
mdumpValue = MiniDumpNormal;
break;
case 2:
mdumpValue = (MINIDUMP_TYPE)(MiniDumpWithIndirectlyReferencedMemory | MiniDumpWithDataSegs);
break;
case 3:
mdumpValue = MiniDumpWithFullMemory;
break;
default:
mdumpValue = (MINIDUMP_TYPE)g_cvars.sys_dump_type;
break;
}
if (bDump)
{
fileName = path + "error.dmp";
if (gEnv->IsDedicated() && stat(fileName.c_str(), &fileInfo) == 0)
{
// Backup dump (use timestamp from error.log if available)
if (timeStamp.empty())
{
tm creationTime;
localtime_s(&creationTime, &fileInfo.st_mtime);
char tempBuffer[32];
strftime(tempBuffer, sizeof(tempBuffer), "%d %b %Y (%H %M %S)", &creationTime);
timeStamp = tempBuffer;
}
string backupFileName = backupPath + timeStamp + " error.dmp";
CopyFile(fileName.c_str(), backupFileName.c_str(), true);
}
CryEngineExceptionFilterMiniDump(pex, fileName.c_str(), mdumpValue);
}
}
//if no crash dialog don't even submit the bug
if (m_postBackupProcess && g_cvars.sys_no_crash_dialog == 0 && g_bUserDialog)
{
m_postBackupProcess();
}
else
{
// lawsonn: Disabling the JIRA-based crash reporter for now
// we'll need to deal with it our own way, pending QA.
// if you're customizing the engine this is also your opportunity to deal with it.
if (g_cvars.sys_no_crash_dialog != 0 || !g_bUserDialog)
{
// ------------ place custom crash handler here ---------------------
// it should launch an executable!
/// by this time, error.bmp will be in the engine root folder
// error.log and error.dmp will also be present in the engine root folder
// if your error dumper wants those, it should zip them up and send them or offer to do so.
// ------------------------------------------------------------------
}
}
const bool bQuitting = !gEnv || !gEnv->pSystem || gEnv->pSystem->IsQuitting();
//[AlexMcC|16.04.10] When the engine is shutting down, MessageBox doesn't display a box
// and immediately returns IDYES. Avoid this by just not trying to save if we're quitting.
// Don't ask to save if this isn't a real crash (a real crash has exception pointers)
if (g_cvars.sys_no_crash_dialog == 0 && g_bUserDialog && gEnv->IsEditor() && !bQuitting && pex)
{
BackupCurrentLevel();
const INT_PTR res = DialogBoxParam(gDLLHandle, MAKEINTRESOURCE(IDD_CONFIRM_SAVE_LEVEL), NULL, DebugCallStack::ConfirmSaveDialogProc, NULL);
if (res == IDB_CONFIRM_SAVE)
{
if (SaveCurrentLevel())
{
MessageBox(NULL, "Level has been successfully saved!\r\nPress Ok to terminate Editor.", "Save", MB_OK);
}
else
{
MessageBox(NULL, "Error saving level.\r\nPress Ok to terminate Editor.", "Save", MB_OK | MB_ICONWARNING);
}
}
}
if (g_cvars.sys_no_crash_dialog != 0 || !g_bUserDialog)
{
// terminate immediately - since we're in a crash, there is no point unwinding stack, we've already done access violation or worse.
// calling exit will only cause further death down the line...
TerminateProcess(GetCurrentProcess(), pex->ExceptionRecord->ExceptionCode);
}
}
INT_PTR CALLBACK DebugCallStack::ExceptionDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static EXCEPTION_POINTERS* pex;
static char errorString[32768] = "";
switch (message)
{
case WM_INITDIALOG:
{
pex = (EXCEPTION_POINTERS*)lParam;
HWND h;
if (pex->ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
{
// Disable continue button for non continuable exceptions.
//h = GetDlgItem( hwndDlg,IDB_CONTINUE );
//if (h) EnableWindow( h,FALSE );
}
DebugCallStack* pDCS = static_cast<DebugCallStack*>(DebugCallStack::instance());
h = GetDlgItem(hwndDlg, IDC_EXCEPTION_DESC);
if (h)
{
SendMessage(h, EM_REPLACESEL, FALSE, (LONG_PTR)pDCS->m_excDesc);
}
h = GetDlgItem(hwndDlg, IDC_EXCEPTION_CODE);
if (h)
{
SendMessage(h, EM_REPLACESEL, FALSE, (LONG_PTR)pDCS->m_excCode);
}
h = GetDlgItem(hwndDlg, IDC_EXCEPTION_MODULE);
if (h)
{
SendMessage(h, EM_REPLACESEL, FALSE, (LONG_PTR)pDCS->m_excModule);
}
h = GetDlgItem(hwndDlg, IDC_EXCEPTION_ADDRESS);
if (h)
{
SendMessage(h, EM_REPLACESEL, FALSE, (LONG_PTR)pDCS->m_excAddr);
}
// Fill call stack.
HWND callStack = GetDlgItem(hwndDlg, IDC_CALLSTACK);
if (callStack)
{
SendMessage(callStack, WM_SETTEXT, FALSE, (LPARAM)pDCS->m_excCallstack);
}
if (hwndException)
{
DestroyWindow(hwndException);
hwndException = 0;
}
if (IsFloatingPointException(pex))
{
EnableWindow(GetDlgItem(hwndDlg, IDB_IGNORE), TRUE);
}
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDB_EXIT:
case IDB_IGNORE:
// Fall through.
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
return FALSE;
}
INT_PTR CALLBACK DebugCallStack::ConfirmSaveDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, [[maybe_unused]] LPARAM lParam)
{
switch (message)
{
case WM_INITDIALOG:
{
// The user might be holding down the spacebar while the engine crashes.
// If we don't remove keyboard focus from this dialog, the keypress will
// press the default button before the dialog actually appears, even if
// the user has already released the key, which is bad.
SetFocus(NULL);
} break;
case WM_COMMAND:
{
switch (LOWORD(wParam))
{
case IDB_CONFIRM_SAVE: // Fall through
case IDB_DONT_SAVE:
{
EndDialog(hwndDlg, wParam);
return TRUE;
}
}
} break;
}
return FALSE;
}
bool DebugCallStack::BackupCurrentLevel()
{
CSystem* pSystem = static_cast<CSystem*>(m_pSystem);
if (pSystem && pSystem->GetUserCallback())
{
return pSystem->GetUserCallback()->OnBackupDocument();
}
return false;
}
bool DebugCallStack::SaveCurrentLevel()
{
CSystem* pSystem = static_cast<CSystem*>(m_pSystem);
if (pSystem && pSystem->GetUserCallback())
{
return pSystem->GetUserCallback()->OnSaveDocument();
}
return false;
}
int DebugCallStack::SubmitBug(EXCEPTION_POINTERS* exception_pointer)
{
int ret = IDB_EXIT;
assert(!hwndException);
RemoveOldFiles();
AZ::Debug::Trace::PrintCallstack("", 2);
LogExceptionInfo(exception_pointer);
if (IsFloatingPointException(exception_pointer))
{
//! Print exception dialog.
ret = PrintException(exception_pointer);
}
return ret;
}
void DebugCallStack::ResetFPU(EXCEPTION_POINTERS* pex)
{
if (IsFloatingPointException(pex))
{
// How to reset FPU: http://www.experts-exchange.com/Programming/System/Windows__Programming/Q_10310953.html
_clearfp();
#ifndef WIN64
pex->ContextRecord->FloatSave.ControlWord |= 0x2F;
pex->ContextRecord->FloatSave.StatusWord &= ~0x8080;
#endif
}
}
string DebugCallStack::GetModuleNameForAddr(void* addr)
{
if (m_modules.empty())
{
return "[unknown]";
}
if (addr < m_modules.begin()->first)
{
return "[unknown]";
}
TModules::const_iterator it = m_modules.begin();
TModules::const_iterator end = m_modules.end();
for (; ++it != end; )
{
if (addr < it->first)
{
return (--it)->second;
}
}
//if address is higher than the last module, we simply assume it is in the last module.
return m_modules.rbegin()->second;
}
void DebugCallStack::GetProcNameForAddr(void* addr, string& procName, void*& baseAddr, string& filename, int& line)
{
AZ::Debug::SymbolStorage::StackLine func, file, module;
AZ::Debug::SymbolStorage::FindFunctionFromIP(addr, &func, &file, &module, line, baseAddr);
procName = func;
filename = file;
}
string DebugCallStack::GetCurrentFilename()
{
char fullpath[MAX_PATH_LENGTH + 1];
GetModuleFileName(NULL, fullpath, MAX_PATH_LENGTH);
return fullpath;
}
static bool IsFloatingPointException(EXCEPTION_POINTERS* pex)
{
if (!pex)
{
return false;
}
DWORD exceptionCode = pex->ExceptionRecord->ExceptionCode;
switch (exceptionCode)
{
case EXCEPTION_FLT_DENORMAL_OPERAND:
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
case EXCEPTION_FLT_INEXACT_RESULT:
case EXCEPTION_FLT_INVALID_OPERATION:
case EXCEPTION_FLT_OVERFLOW:
case EXCEPTION_FLT_UNDERFLOW:
case STATUS_FLOAT_MULTIPLE_FAULTS:
case STATUS_FLOAT_MULTIPLE_TRAPS:
return true;
default:
return false;
}
}
int DebugCallStack::PrintException(EXCEPTION_POINTERS* exception_pointer)
{
return (int)DialogBoxParam(gDLLHandle, MAKEINTRESOURCE(IDD_CRITICAL_ERROR), NULL, DebugCallStack::ExceptionDialogProc, (LPARAM)exception_pointer);
}
#else
void MarkThisThreadForDebugging(const char*) {}
void UnmarkThisThreadFromDebugging() {}
void UpdateFPExceptionsMaskForThreads() {}
#endif //WIN32
-95
View File
@@ -1,95 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_DEBUGCALLSTACK_H
#define CRYINCLUDE_CRYSYSTEM_DEBUGCALLSTACK_H
#pragma once
#include "IDebugCallStack.h"
#if defined (WIN32) || defined (WIN64)
//! Limits the maximal number of functions in call stack.
const int MAX_DEBUG_STACK_ENTRIES_FILE_DUMP = 12;
struct ISystem;
//!============================================================================
//!
//! DebugCallStack class, capture call stack information from symbol files.
//!
//!============================================================================
class DebugCallStack
: public IDebugCallStack
{
public:
DebugCallStack();
virtual ~DebugCallStack();
ISystem* GetSystem() { return m_pSystem; };
virtual string GetModuleNameForAddr(void* addr);
virtual void GetProcNameForAddr(void* addr, string& procName, void*& baseAddr, string& filename, int& line);
virtual string GetCurrentFilename();
void installErrorHandler(ISystem* pSystem);
virtual int handleException(EXCEPTION_POINTERS* exception_pointer);
virtual void ReportBug(const char*);
void dumpCallStack(std::vector<string>& functions);
void SetUserDialogEnable(const bool bUserDialogEnable);
typedef std::map<void*, string> TModules;
protected:
static void RemoveOldFiles();
static void RemoveFile(const char* szFileName);
static int PrintException(EXCEPTION_POINTERS* exception_pointer);
static INT_PTR CALLBACK ExceptionDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
static INT_PTR CALLBACK ConfirmSaveDialogProc(HWND hwndDlg, UINT message, WPARAM wParam, LPARAM lParam);
void LogExceptionInfo(EXCEPTION_POINTERS* exception_pointer);
bool BackupCurrentLevel();
bool SaveCurrentLevel();
int SubmitBug(EXCEPTION_POINTERS* exception_pointer);
void ResetFPU(EXCEPTION_POINTERS* pex);
static const int s_iCallStackSize = 32768;
char m_excLine[256];
char m_excModule[128];
char m_excDesc[MAX_WARNING_LENGTH];
char m_excCode[MAX_WARNING_LENGTH];
char m_excAddr[80];
char m_excCallstack[s_iCallStackSize];
void* prevExceptionHandler;
bool m_bCrash;
const char* m_szBugMessage;
ISystem* m_pSystem;
int m_nSkipNumFunctions;
CONTEXT m_context;
TModules m_modules;
};
#endif //WIN32
#endif // CRYINCLUDE_CRYSYSTEM_DEBUGCALLSTACK_H
-36
View File
@@ -14,7 +14,6 @@
#include "CrySystem_precompiled.h"
#include "System.h"
#include <AZCrySystemInitLogSink.h>
#include "DebugCallStack.h"
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
@@ -72,10 +71,6 @@ public:
{
switch (event)
{
case ESYSTEM_EVENT_LEVEL_UNLOAD:
gEnv->pSystem->SetThreadState(ESubsys_Physics, false);
break;
case ESYSTEM_EVENT_LEVEL_LOAD_START:
case ESYSTEM_EVENT_LEVEL_LOAD_END:
{
@@ -87,7 +82,6 @@ public:
{
CryCleanup();
STLALLOCATOR_CLEANUP;
gEnv->pSystem->SetThreadState(ESubsys_Physics, true);
break;
}
}
@@ -135,21 +129,6 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar
startupParams.pUserCallback->OnSystemConnect(pSystem);
}
// Environment Variable to signal we don't want to override our exception handler - our crash report system will set this
auto envVar = AZ::Environment::FindVariable<bool>("ExceptionHandlerIsSet");
bool handlerIsSet = (envVar && *envVar);
if (!startupParams.bMinimal && !handlerIsSet) // in minimal mode, we want to crash when we crash!
{
#if defined(WIN32)
// Install exception handler in Release modes.
((DebugCallStack*)IDebugCallStack::instance())->installErrorHandler(pSystem);
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION DLLMAIN_CPP_SECTION_3
#include AZ_RESTRICTED_FILE(DllMain_cpp)
#endif
}
bool retVal = false;
{
AZ::Debug::StartupLogSinkReporter<AZ::Debug::CrySystemInitLogSink> initLogSink;
@@ -171,20 +150,5 @@ CRYSYSTEM_API ISystem* CreateSystemInterface(const SSystemInitParams& startupPar
return pSystem;
}
CRYSYSTEM_API void WINAPI CryInstallUnhandledExceptionHandler()
{
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION DLLMAIN_CPP_SECTION_4
#include AZ_RESTRICTED_FILE(DllMain_cpp)
#endif
}
#if defined(ENABLE_PROFILING_CODE) && !defined(LINUX) && !defined(APPLE)
CRYSYSTEM_API void CryInstallPostExceptionHandler(void (* PostExceptionHandlerCallback)())
{
return IDebugCallStack::instance()->FileCreationCallback(PostExceptionHandlerCallback);
}
#endif
};
@@ -1,278 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : A multiplatform base class for handling errors and collecting call stacks
#include "CrySystem_precompiled.h"
#include "IDebugCallStack.h"
#include <Pak/CryPakUtils.h>
#include "System.h"
#include <AzFramework/IO/FileOperations.h>
#include <AzCore/NativeUI/NativeUIRequests.h>
#include <AzCore/StringFunc/StringFunc.h>
#include <AzCore/Utils/Utils.h>
//#if !defined(LINUX)
#include <ISystem.h>
const char* const IDebugCallStack::s_szFatalErrorCode = "FATAL_ERROR";
IDebugCallStack::IDebugCallStack()
: m_bIsFatalError(false)
, m_postBackupProcess(0)
, m_memAllocFileHandle(AZ::IO::InvalidHandle)
{
}
IDebugCallStack::~IDebugCallStack()
{
StopMemLog();
}
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_SINGLETON
IDebugCallStack* IDebugCallStack::instance()
{
static IDebugCallStack sInstance;
return &sInstance;
}
#endif
void IDebugCallStack::FileCreationCallback(void (* postBackupProcess)())
{
m_postBackupProcess = postBackupProcess;
}
//////////////////////////////////////////////////////////////////////////
void IDebugCallStack::LogCallstack()
{
AZ::Debug::Trace::PrintCallstack("", 2);
}
const char* IDebugCallStack::TranslateExceptionCode(DWORD dwExcept)
{
switch (dwExcept)
{
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_TRANSLATE
case EXCEPTION_ACCESS_VIOLATION:
return "EXCEPTION_ACCESS_VIOLATION";
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
return "EXCEPTION_DATATYPE_MISALIGNMENT";
break;
case EXCEPTION_BREAKPOINT:
return "EXCEPTION_BREAKPOINT";
break;
case EXCEPTION_SINGLE_STEP:
return "EXCEPTION_SINGLE_STEP";
break;
case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED";
break;
case EXCEPTION_FLT_DENORMAL_OPERAND:
return "EXCEPTION_FLT_DENORMAL_OPERAND";
break;
case EXCEPTION_FLT_DIVIDE_BY_ZERO:
return "EXCEPTION_FLT_DIVIDE_BY_ZERO";
break;
case EXCEPTION_FLT_INEXACT_RESULT:
return "EXCEPTION_FLT_INEXACT_RESULT";
break;
case EXCEPTION_FLT_INVALID_OPERATION:
return "EXCEPTION_FLT_INVALID_OPERATION";
break;
case EXCEPTION_FLT_OVERFLOW:
return "EXCEPTION_FLT_OVERFLOW";
break;
case EXCEPTION_FLT_STACK_CHECK:
return "EXCEPTION_FLT_STACK_CHECK";
break;
case EXCEPTION_FLT_UNDERFLOW:
return "EXCEPTION_FLT_UNDERFLOW";
break;
case EXCEPTION_INT_DIVIDE_BY_ZERO:
return "EXCEPTION_INT_DIVIDE_BY_ZERO";
break;
case EXCEPTION_INT_OVERFLOW:
return "EXCEPTION_INT_OVERFLOW";
break;
case EXCEPTION_PRIV_INSTRUCTION:
return "EXCEPTION_PRIV_INSTRUCTION";
break;
case EXCEPTION_IN_PAGE_ERROR:
return "EXCEPTION_IN_PAGE_ERROR";
break;
case EXCEPTION_ILLEGAL_INSTRUCTION:
return "EXCEPTION_ILLEGAL_INSTRUCTION";
break;
case EXCEPTION_NONCONTINUABLE_EXCEPTION:
return "EXCEPTION_NONCONTINUABLE_EXCEPTION";
break;
case EXCEPTION_STACK_OVERFLOW:
return "EXCEPTION_STACK_OVERFLOW";
break;
case EXCEPTION_INVALID_DISPOSITION:
return "EXCEPTION_INVALID_DISPOSITION";
break;
case EXCEPTION_GUARD_PAGE:
return "EXCEPTION_GUARD_PAGE";
break;
case EXCEPTION_INVALID_HANDLE:
return "EXCEPTION_INVALID_HANDLE";
break;
//case EXCEPTION_POSSIBLE_DEADLOCK: return "EXCEPTION_POSSIBLE_DEADLOCK"; break ;
case STATUS_FLOAT_MULTIPLE_FAULTS:
return "STATUS_FLOAT_MULTIPLE_FAULTS";
break;
case STATUS_FLOAT_MULTIPLE_TRAPS:
return "STATUS_FLOAT_MULTIPLE_TRAPS";
break;
#endif
default:
return "Unknown";
break;
}
}
void IDebugCallStack::PutVersion(char* str, size_t length)
{
AZ_PUSH_DISABLE_WARNING(4996, "-Wunknown-warning-option")
if (!gEnv || !gEnv->pSystem)
{
return;
}
char sFileVersion[128];
gEnv->pSystem->GetFileVersion().ToString(sFileVersion, sizeof(sFileVersion));
char sProductVersion[128];
gEnv->pSystem->GetProductVersion().ToString(sProductVersion, sizeof(sFileVersion));
//! Get time.
time_t ltime;
time(&ltime);
tm* today = localtime(&ltime);
char s[1024];
//! Use strftime to build a customized time string.
strftime(s, 128, "Logged at %#c\n", today);
azstrcat(str, length, s);
sprintf_s(s, "FileVersion: %s\n", sFileVersion);
azstrcat(str, length, s);
sprintf_s(s, "ProductVersion: %s\n", sProductVersion);
azstrcat(str, length, s);
if (gEnv->pLog)
{
const char* logfile = gEnv->pLog->GetFileName();
if (logfile)
{
sprintf (s, "LogFile: %s\n", logfile);
azstrcat(str, length, s);
}
}
AZ::IO::FixedMaxPathString projectPath = AZ::Utils::GetProjectPath();
azstrcat(str, length, "ProjectDir: ");
azstrcat(str, length, projectPath.c_str());
azstrcat(str, length, "\n");
#if AZ_LEGACY_CRYSYSTEM_TRAIT_DEBUGCALLSTACK_APPEND_MODULENAME
GetModuleFileNameA(NULL, s, sizeof(s));
// Log EXE filename only if possible (not full EXE path which could contain sensitive info)
AZStd::string exeName;
if (AZ::StringFunc::Path::GetFullFileName(s, exeName))
{
azstrcat(str, length, "Executable: ");
azstrcat(str, length, exeName.c_str());
# ifdef AZ_DEBUG_BUILD
azstrcat(str, length, " (debug: yes");
# else
azstrcat(str, length, " (debug: no");
# endif
}
#endif
AZ_POP_DISABLE_WARNING
}
//Crash the application, in this way the debug callstack routine will be called and it will create all the necessary files (error.log, dump, and eventually screenshot)
void IDebugCallStack::FatalError(const char* description)
{
m_bIsFatalError = true;
WriteLineToLog(description);
#ifndef _RELEASE
bool bShowDebugScreen = g_cvars.sys_no_crash_dialog == 0;
// showing the debug screen is not safe when not called from mainthread
// it normally leads to a infinity recursion followed by a stack overflow, preventing
// useful call stacks, thus they are disabled
bShowDebugScreen = bShowDebugScreen && gEnv->mMainThreadId == CryGetCurrentThreadId();
if (bShowDebugScreen)
{
EBUS_EVENT(AZ::NativeUI::NativeUIRequestBus, DisplayOkDialog, "Open 3D Engine Fatal Error", description, false);
}
#endif
#if defined(WIN32) || !defined(_RELEASE)
int* p = 0x0;
PREFAST_SUPPRESS_WARNING(6011) * p = 1; // we're intentionally crashing here
#endif
}
void IDebugCallStack::WriteLineToLog(const char* format, ...)
{
CDebugAllowFileAccess allowFileAccess;
va_list ArgList;
char szBuffer[MAX_WARNING_LENGTH];
va_start(ArgList, format);
vsnprintf_s(szBuffer, sizeof(szBuffer), sizeof(szBuffer) - 1, format, ArgList);
cry_strcat(szBuffer, "\n");
szBuffer[sizeof(szBuffer) - 1] = '\0';
va_end(ArgList);
AZ::IO::HandleType fileHandle = AZ::IO::InvalidHandle;
AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\error.log", AZ::IO::GetOpenModeFromStringMode("a+t"), fileHandle);
if (fileHandle != AZ::IO::InvalidHandle)
{
AZ::IO::FileIOBase::GetDirectInstance()->Write(fileHandle, szBuffer, strlen(szBuffer));
AZ::IO::FileIOBase::GetDirectInstance()->Flush(fileHandle);
AZ::IO::FileIOBase::GetDirectInstance()->Close(fileHandle);
}
}
//////////////////////////////////////////////////////////////////////////
void IDebugCallStack::StartMemLog()
{
AZ::IO::FileIOBase::GetDirectInstance()->Open("@Log@\\memallocfile.log", AZ::IO::OpenMode::ModeWrite, m_memAllocFileHandle);
assert(m_memAllocFileHandle != AZ::IO::InvalidHandle);
}
//////////////////////////////////////////////////////////////////////////
void IDebugCallStack::StopMemLog()
{
if (m_memAllocFileHandle != AZ::IO::InvalidHandle)
{
AZ::IO::FileIOBase::GetDirectInstance()->Close(m_memAllocFileHandle);
m_memAllocFileHandle = AZ::IO::InvalidHandle;
}
}
//#endif //!defined(LINUX)
@@ -1,90 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : A multiplatform base class for handling errors and collecting call stacks
#ifndef CRYINCLUDE_CRYSYSTEM_IDEBUGCALLSTACK_H
#define CRYINCLUDE_CRYSYSTEM_IDEBUGCALLSTACK_H
#pragma once
#include "System.h"
#if AZ_LEGACY_CRYSYSTEM_TRAIT_FORWARD_EXCEPTION_POINTERS
struct EXCEPTION_POINTERS;
#endif
//! Limits the maximal number of functions in call stack.
enum
{
MAX_DEBUG_STACK_ENTRIES = 80
};
class IDebugCallStack
{
public:
// Returns single instance of DebugStack
static IDebugCallStack* instance();
virtual int handleException([[maybe_unused]] EXCEPTION_POINTERS* exception_pointer){return 0; }
// returns the module name of a given address
virtual string GetModuleNameForAddr([[maybe_unused]] void* addr) { return "[unknown]"; }
// returns the function name of a given address together with source file and line number (if available) of a given address
virtual void GetProcNameForAddr(void* addr, string& procName, void*& baseAddr, string& filename, int& line)
{
filename = "[unknown]";
line = 0;
baseAddr = addr;
#if defined(PLATFORM_64BIT)
procName.Format("[%016llX]", addr);
#else
procName.Format("[%08X]", addr);
#endif
}
// returns current filename
virtual string GetCurrentFilename() { return "[unknown]"; }
//! Dumps Current Call Stack to log.
virtual void LogCallstack();
//triggers a fatal error, so the DebugCallstack can create the error.log and terminate the application
void FatalError(const char*);
//Reports a bug and continues execution
virtual void ReportBug(const char*) {}
virtual void FileCreationCallback(void (* postBackupProcess)());
static void WriteLineToLog(const char* format, ...);
virtual void StartMemLog();
virtual void StopMemLog();
protected:
IDebugCallStack();
virtual ~IDebugCallStack();
static const char* TranslateExceptionCode(DWORD dwExcept);
static void PutVersion(char* str, size_t length);
bool m_bIsFatalError;
static const char* const s_szFatalErrorCode;
void (* m_postBackupProcess)();
AZ::IO::HandleType m_memAllocFileHandle;
};
#endif // CRYINCLUDE_CRYSYSTEM_IDEBUGCALLSTACK_H
@@ -1,59 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
struct SThreadConfig
{
enum eThreadParamFlag
{
eThreadParamFlag_ThreadName = BIT(0),
eThreadParamFlag_StackSize = BIT(1),
eThreadParamFlag_Affinity = BIT(2),
eThreadParamFlag_Priority = BIT(3),
eThreadParamFlag_PriorityBoost = BIT(4),
};
typedef uint32 TThreadParamFlag;
const char* szThreadName;
uint32 stackSizeBytes;
uint32 affinityFlag;
int32 priority;
bool bDisablePriorityBoost;
TThreadParamFlag paramActivityFlag;
};
class IThreadConfigManager
{
public:
virtual ~IThreadConfigManager()
{
}
//! Called once during System startup.
//! Loads the thread configuration for the executing platform from file.
virtual bool LoadConfig(const char* pcPath) = 0;
//! Returns true if a config has been loaded.
virtual bool ConfigLoaded() const = 0;
//! Gets the thread configuration for the specified thread on the active platform.
//! If no matching config is found a default configuration is returned (which does not have the same name as the search string).
virtual const SThreadConfig* GetThreadConfig(const char* sThreadName, ...) = 0;
virtual const SThreadConfig* GetDefaultThreadConfig() const = 0;
//! Dump a detailed description of the thread startup configurations for this platform to the log file.
virtual void DumpThreadConfigurationsToLog() = 0;
};
@@ -17,7 +17,6 @@
#include "LevelSystem.h"
#include <IAudioSystem.h>
#include "IMovieSystem.h"
#include "IMaterialEffects.h"
#include <IResourceManager.h>
#include <ILocalizationManager.h>
#include "CryPath.h"
@@ -648,20 +647,6 @@ ILevel* CLevelSystem::LoadLevelInternal(const char* _levelName)
AZStd::string levelPath(pLevelInfo->GetPath());
/*
ICVar *pFileCache = gEnv->pConsole->GetCVar("sys_FileCache"); CRY_ASSERT(pFileCache);
if(pFileCache->GetIVal())
{
if(pPak->OpenPack("",pLevelInfo->GetPath()+string("/FileCache.dat")))
gEnv->pLog->Log("FileCache.dat loaded");
else
gEnv->pLog->Log("FileCache.dat not loaded");
}
*/
m_pSystem->SetThreadState(ESubsys_Physics, false);
ICVar* pSpamDelay = gEnv->pConsole->GetCVar("log_SpamDelay");
float spamDelay = 0.0f;
if (pSpamDelay)
@@ -768,8 +753,6 @@ ILevel* CLevelSystem::LoadLevelInternal(const char* _levelName)
gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_START, 0, 0);
m_pSystem->SetThreadState(ESubsys_Physics, true);
return m_pCurrentLevel;
}
@@ -247,8 +247,6 @@ namespace LegacyLevelSystem
auto pPak = gEnv->pCryPak;
m_pSystem->SetThreadState(ESubsys_Physics, false);
ICVar* pSpamDelay = gEnv->pConsole->GetCVar("log_SpamDelay");
float spamDelay = 0.0f;
if (pSpamDelay)
@@ -343,8 +341,6 @@ namespace LegacyLevelSystem
gEnv->pSystem->GetISystemEventDispatcher()->OnSystemEvent(ESYSTEM_EVENT_LEVEL_PRECACHE_START, 0, 0);
m_pSystem->SetThreadState(ESubsys_Physics, true);
return true;
}
+1 -9
View File
@@ -920,13 +920,7 @@ bool CLog::LogToMainThread(const char* szString, ELogType logType, bool bAdd, SL
msg.bAdd = bAdd;
msg.destination = destination;
msg.logType = logType;
// don't try to store the log message for later in case of out of memory, since then its very likely that this allocation
// also fails and results in a stack overflow. This way we should at least get a out of memory on-screen message instead of
// a not obvious crash
if ((gEnv) && (gEnv->bIsOutOfMemory == false))
{
m_threadSafeMsgQueue.push(msg);
}
m_threadSafeMsgQueue.push(msg);
return true;
}
return false;
@@ -1448,8 +1442,6 @@ void CLog::UpdateLoadingScreen(const char* szFormat, ...)
if (CryGetCurrentThreadId() == m_nMainThreadId)
{
((CSystem*)m_pSystem)->UpdateLoadingScreen();
#ifndef LINUX
// Take this opportunity to update streaming engine.
if (IStreamEngine* pStreamEngine = GetISystem()->GetStreamEngine())
File diff suppressed because it is too large Load Diff
@@ -1,293 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_NOTIFICATIONNETWORK_H
#define CRYINCLUDE_CRYSYSTEM_NOTIFICATIONNETWORK_H
#pragma once
#include <IConsole.h>
#include <INotificationNetwork.h>
#include <CryThread.h>
#include <AzCore/Socket/AzSocket_fwd.h>
class CNotificationNetwork;
namespace NotificationNetwork {
// Constants
static const uint32 NN_PACKET_HEADER_LENGTH = 2 * sizeof(uint32) + NN_CHANNEL_NAME_LENGTH_MAX;
static const uint32 NN_PACKET_HEADER_OFFSET_MESSAGE = 0;
static const uint32 NN_PACKET_HEADER_OFFSET_DATA_LENGTH = sizeof(uint32);
static const uint32 NN_PACKET_HEADER_OFFSET_CHANNEL = sizeof(uint32) + sizeof(uint32);
static const char* NN_THREAD_NAME = "NotificationNetwork";
enum EMessage
{
eMessage_DataTransfer = 0xbada2217,
eMessage_ChannelRegister = 0xab4eda30,
eMessage_ChannelUnregister = 0xfa4e3423,
};
// Classes
struct CChannel
{
public:
static bool IsNameValid(const char* name);
public:
CChannel();
CChannel(const char* name);
~CChannel();
public:
void WriteToPacketHeader(void* pPacket) const;
void ReadFromPacketHeader(void* pPacket);
public:
bool operator ==(const CChannel& channel) const;
bool operator !=(const CChannel& channel) const;
private:
char m_name[NN_CHANNEL_NAME_LENGTH_MAX];
};
// TEMP
struct SBuffer
{
uint8* pData;
uint32 length;
CChannel channel;
};
class CListeners
{
public:
CListeners();
~CListeners();
public:
size_t Count() { return m_listeners.size(); }
size_t Count(const CChannel& channel);
CChannel& Channel(size_t index) { return m_listeners[index].second; }
CChannel* Channel(INotificationNetworkListener* pListener);
bool Bind(const CChannel& channel, INotificationNetworkListener* pListener);
bool Remove(INotificationNetworkListener* pListener);
void NotificationPush(const SBuffer& buffer);
void NotificationsProcess();
private:
std::vector< std::pair<INotificationNetworkListener*, CChannel> > m_listeners;
std::queue<SBuffer> m_notifications[2];
std::queue<SBuffer>* m_pNotificationWrite;
std::queue<SBuffer>* m_pNotificationRead;
CryCriticalSection m_notificationCriticalSection;
};
class CConnectionBase
{
public:
CConnectionBase(CNotificationNetwork* pNotificationNetwork);
virtual ~CConnectionBase();
public:
AZSOCKET CreateSocket();
bool Connect(const char* address, uint16 port);
AZSOCKET GetSocket() { return m_socket; }
bool Validate();
bool SendNotification(const CChannel& channel, const void* pBuffer, size_t length);
bool Receive(CListeners& listeners);
bool GetIsConnectedFlag();
bool GetIsFailedToConnectFlag() const;
protected:
CNotificationNetwork* GetNotificationNetwork() { return m_pNotificationNetwork; }
void SetAddress(const char* address, uint16 port);
void SetSocket(AZSOCKET sock) { m_socket = sock; }
bool Send(const void* pBuffer, size_t length);
bool SendMessage(EMessage eMessage, const CChannel& channel, uint32 data);
bool Select_Internal();
void CloseSocket_Internal();
virtual bool OnConnect([[maybe_unused]] bool bConnectionResult) { return true; }
virtual bool OnDisconnect() {return true; }
virtual bool OnMessage([[maybe_unused]] EMessage eMessage, [[maybe_unused]] const CChannel& channel) { return false; }
private:
bool ReceiveMessage(CListeners& listeners);
bool ReceiveNotification(CListeners& listeners);
protected:
CNotificationNetwork* m_pNotificationNetwork;
char m_address[16];
uint16 m_port;
AZSOCKET m_socket;
uint8 m_bufferHeader[NN_PACKET_HEADER_LENGTH];
SBuffer m_buffer;
uint32 m_dataLeft;
volatile bool m_boIsConnected;
volatile bool m_boIsFailedToConnect;
};
class CClient
: public CConnectionBase
, public INotificationNetworkClient
{
public:
typedef std::vector<INotificationNetworkConnectionCallback*> TDNotificationNetworkConnectionCallbacks;
static CClient* Create(CNotificationNetwork* pNotificationNetwork, const char* address, uint16 port);
static CClient* Create(CNotificationNetwork* pNotificationNetwork);
private:
CClient(CNotificationNetwork* pNotificationNetwork);
~CClient();
public:
bool Receive() { return CConnectionBase::Receive(m_listeners); }
void Update();
// CConnectionBase
public:
virtual bool OnConnect(bool bConnectionResult);
virtual bool OnDisconnect();
virtual bool OnMessage(EMessage eMessage, const CChannel& channel);
// INotificationNetworkClient
public:
bool Connect(const char* address, uint16 port);
void Release() { delete this; }
virtual bool ListenerBind(const char* channelName, INotificationNetworkListener* pListener);
virtual bool ListenerRemove(INotificationNetworkListener* pListener);
virtual bool Send(const char* channelName, const void* pBuffer, size_t length);
virtual bool IsConnected() {return CConnectionBase::GetIsConnectedFlag(); }
virtual bool IsFailedToConnect() const{return CConnectionBase::GetIsFailedToConnectFlag(); }
virtual bool RegisterCallbackListener(INotificationNetworkConnectionCallback* pConnectionCallback);
virtual bool UnregisterCallbackListener(INotificationNetworkConnectionCallback* pConnectionCallback);
private:
CListeners m_listeners;
TDNotificationNetworkConnectionCallbacks m_cNotificationNetworkConnectionCallbacks;
CryCriticalSection m_stConnectionCallbacksLock;
};
} // namespace NotificationNetwork
class CNotificationNetwork
: public INotificationNetwork
{
private:
class CConnection
: public NotificationNetwork::CConnectionBase
{
public:
CConnection(CNotificationNetwork* pNotificationNetwork, AZSOCKET sock);
virtual ~CConnection();
public:
bool IsListening(const NotificationNetwork::CChannel& channel);
// CConnectionBase
protected:
virtual bool OnMessage(NotificationNetwork::EMessage eMessage, const NotificationNetwork::CChannel& channel);
private:
std::vector<NotificationNetwork::CChannel> m_listeningChannels;
};
class CThread
: public CryThread<CThread>
{
public:
CThread();
~CThread();
public:
bool Begin(CNotificationNetwork* pNotificationNetwork);
void End();
// CryRunnable
public:
virtual void Run();
private:
CNotificationNetwork* m_pNotificationNetwork;
bool m_bRun;
} m_thread;
public:
static CNotificationNetwork* Create();
public:
CNotificationNetwork();
~CNotificationNetwork();
public:
void ReleaseClients(NotificationNetwork::CClient* pClient);
private:
void ProcessSockets();
// INotificationNetwork
public:
virtual void Release() { delete this; }
virtual INotificationNetworkClient* CreateClient();
virtual INotificationNetworkClient* Connect(const char* address, uint16 port);
virtual size_t GetConnectionCount(const char* channelName);
virtual void Update();
virtual bool ListenerBind(const char* channelName, INotificationNetworkListener* pListener);
virtual bool ListenerRemove(INotificationNetworkListener* pListener);
virtual uint32 Send(const char* channelName, const void* pBuffer, size_t length);
private:
AZSOCKET m_socket;
std::vector<CConnection*> m_connections;
std::vector<NotificationNetwork::CClient*> m_clients;
NotificationNetwork::CListeners m_listeners;
CryCriticalSection m_clientsCriticalSection;
};
#endif // CRYINCLUDE_CRYSYSTEM_NOTIFICATIONNETWORK_H
@@ -1,134 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "ProfileLogSystem.h"
//////////////////////////////////////////////////////////////////////////
// class CLogElement
//////////////////////////////////////////////////////////////////////////
CLogElement::CLogElement()
: m_pParent (NULL)
, m_time (0)
{
}
CLogElement::CLogElement(CLogElement* pParent)
: m_pParent (pParent)
, m_time (0)
{
}
CLogElement::CLogElement(CLogElement* pParent, const char* name, const char* message)
: m_pParent (pParent)
, m_strName (name)
, m_strMessage(message)
, m_time (0)
{
}
void CLogElement::Flush(stack_string& indent)
{
if (m_logElements.empty())
{
CryLog("%s%s [%.3f ms] %s", indent.c_str(), m_strName.c_str(), m_time, m_strMessage.c_str());
return;
}
CryLog("%s+%s [%.3f ms] %s", indent.c_str(), m_strName.c_str(), m_time, m_strMessage.c_str());
indent += " ";
for (std::list<CLogElement>::iterator it = m_logElements.begin(); it != m_logElements.end(); ++it)
{
(*it).Flush(indent);
}
indent.erase(0, 2);
CryLog("%s-%s", indent.c_str(), m_strName.c_str());
}
ILogElement* CLogElement::Log(const char* name, const char* message)
{
m_logElements.push_back(CLogElement(this));
m_logElements.back().m_strName = name;
m_logElements.back().m_strMessage = message;
return &m_logElements.back();
}
ILogElement* CLogElement::SetTime(float time)
{
m_time = time;
return m_pParent;
}
void CLogElement::Clear()
{
m_logElements.resize(0);
}
//////////////////////////////////////////////////////////////////////////
// class CProfileLogSystem
//////////////////////////////////////////////////////////////////////////
CProfileLogSystem::CProfileLogSystem()
: m_rootElelent(NULL)
, m_pLastElelent(NULL)
{
}
CProfileLogSystem::~CProfileLogSystem()
{
}
ILogElement* CProfileLogSystem::Log(const char* name, const char* message)
{
if (m_pLastElelent)
{
m_pLastElelent = m_pLastElelent->Log(name, message);
}
else
{
m_rootElelent.Clear();
m_rootElelent.SetName(name);
m_rootElelent.SetMessage(message);
m_pLastElelent = &m_rootElelent;
}
return m_pLastElelent;
}
void CProfileLogSystem::SetTime(ILogElement* pElement, float time)
{
if (pElement == NULL)
{
return;
}
m_pLastElelent = pElement->SetTime(time);
if (m_pLastElelent)
{
return;
}
stack_string indent;
m_rootElelent.Flush(indent);
m_rootElelent.Clear();
}
void CProfileLogSystem::Release()
{
delete this;
}
@@ -1,74 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Implementation of the IProfileLogSystem interface, which is used to
// save hierarchical log with SHierProfileLogItem
#ifndef CRYINCLUDE_CRYSYSTEM_PROFILELOGSYSTEM_H
#define CRYINCLUDE_CRYSYSTEM_PROFILELOGSYSTEM_H
#pragma once
#include "ProfileLog.h"
class CLogElement
: public ILogElement
{
public:
CLogElement();
CLogElement(CLogElement* pParent);
CLogElement(CLogElement* pParent, const char* name, const char* message);
virtual ILogElement* Log (const char* name, const char* message);
virtual ILogElement* SetTime (float time);
virtual void Flush (stack_string& indent);
void Clear ();
inline void SetName(const char* name)
{
m_strName = name;
}
inline void SetMessage(const char* message)
{
m_strMessage = message;
}
private:
string m_strName;
string m_strMessage;
float m_time; // milliSeconds
CLogElement* m_pParent;
std::list<CLogElement> m_logElements;
};
class CProfileLogSystem
: public IProfileLogSystem
{
public:
CProfileLogSystem();
~CProfileLogSystem();
virtual ILogElement* Log (const char* name, const char* message);
virtual void SetTime (ILogElement* pElement, float time);
virtual void Release ();
private:
CLogElement m_rootElelent;
ILogElement* m_pLastElelent;
};
#endif // CRYINCLUDE_CRYSYSTEM_PROFILELOGSYSTEM_H
+2 -9
View File
@@ -699,7 +699,7 @@ void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_P
if (g_cvars.archiveVars.nLoadCache)
{
//Load the frontend common mode switch pak, this can considerably reduce the time spent switching especially from disc
if (!gEnv->bMultiplayer && LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
if (LoadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP) == false)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "Could not load %s during init. This file can significantly reduce frontend loading times.\n", FRONTEND_COMMON_PAK_FILENAME_SP);
}
@@ -710,14 +710,7 @@ void CResourceManager::OnSystemEvent(ESystemEvent event, [[maybe_unused]] UINT_P
case ESYSTEM_EVENT_LEVEL_LOAD_PREPARE:
{
if (!gEnv->bMultiplayer)
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
}
else
{
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_MP, FRONTEND_COMMON_LIST_FILENAME "_mp");
}
UnloadMenuCommonPak(FRONTEND_COMMON_PAK_FILENAME_SP, FRONTEND_COMMON_LIST_FILENAME "_sp");
m_bLevelTransitioning = !m_sLevelName.empty();
@@ -1,787 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#ifdef SOFTCODE_SYSTEM_ENABLED
#ifndef SOFTCODE_ENABLED
// Even if this module isn't built with SC enabled, if the SC system is enabled we define
// it for this compilation unit to ensure we use the correct versions of the IType* interfaces.
#define SOFTCODE_ENABLED
#endif
#include "SoftCodeMgr.h"
#include <IConsole.h>
#include <CryLibrary.h>
#include <CryPath.h>
#include <AzCore/std/functional.h> // for function<> in find files
// This should resolve to "GetTypeLibrary" but we export by ordinal to avoid overheads on 360
// and keep everything consistent.
static const char* DLL_GETTYPELIBRARY = (LPCSTR)1;
struct CInstanceData
{
CInstanceData(void* pInstance, size_t memberCount)
: m_pOldInstance(pInstance)
, m_pNewInstance()
{
m_members.resize(memberCount);
}
~CInstanceData()
{
// Delete all members
for (TMemberVec::iterator iter(m_members.begin());
iter != m_members.end();
++iter)
{
// TODO: Safe cross module? Same allocator? Use a Destroy() method?
delete *iter;
}
}
void* Instance() { return m_pOldInstance; }
void AddMember(size_t index, IExchangeValue& value)
{
// TODO: Add support for members with same name at different hierarchy levels
assert(m_members[index] == NULL);
assert(index != ~0);
// Support expansion of m_members during while resolving members
if (index >= m_members.size())
{
m_members.resize(index + 1);
}
m_members[index] = value.Clone();
}
IExchangeValue* GetMember(size_t index) const
{
assert(index < m_members.size());
return m_members[index];
}
void SetNewInstance(void* pNewInstance) { m_pNewInstance = pNewInstance; }
void* m_pOldInstance;
void* m_pNewInstance;
typedef std::vector<IExchangeValue*> TMemberVec;
TMemberVec m_members;
};
class CExchanger
: public IExchanger
{
public:
CExchanger()
: m_pInstanceData()
, m_instanceIndex(~0)
, m_state(eState_ResolvingMembers)
{}
virtual ~CExchanger()
{
DestroyInstanceData();
}
virtual bool IsLoading() const { return m_state >= eState_WritingNewMembers; }
virtual size_t InstanceCount() const { return m_instances.size(); }
virtual bool BeginInstance(void* pInstance)
{
if (IsLoading())
{
if (++m_instanceIndex < m_instances.size())
{
m_pInstanceData = m_instances[m_instanceIndex];
m_pInstanceData->SetNewInstance(pInstance);
}
else
{
m_pInstanceData = NULL;
}
}
else // Reading/resolving members
{
m_instanceIndex = m_instances.size();
m_pInstanceData = new CInstanceData(pInstance, m_memberMap.size());
m_instances.push_back(m_pInstanceData);
}
return m_pInstanceData != NULL;
}
virtual bool SetValue(const char* name, IExchangeValue& value)
{
assert(!IsLoading());
const size_t index = FindMemberIndex(name);
const bool consumingValue = index != ~0;
if (consumingValue)
{
m_pInstanceData->AddMember(index, value);
}
return consumingValue;
}
virtual IExchangeValue* GetValue(const char* name, void* pTarget, size_t targetSize)
{
assert(IsLoading());
const size_t index = FindMemberIndex(name);
// If member resolved (may not be if restoring to old instances)
if (index != ~0)
{
// If member data available (may not be if member is new)
if (IExchangeValue* pValue = m_pInstanceData->GetMember(index))
{
if (pValue->GetSizeOf() == targetSize)
{
return pValue;
}
else // Member size mismatch
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING,
"SoftCode: Member %s of instance %p has changed size (old: %d new: %d), setting to default value.",
name, m_pInstanceData->Instance(), (int)pValue->GetSizeOf(), (int)targetSize);
}
}
else // Member unknown
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING,
"SoftCode: Member %s (of instance %p) appears to be new.",
name, m_pInstanceData->Instance());
// TODO: Could attempt to validate against a known wipe pattern ie. 0xfefefefe
// This could catch most uninitialized variables...
if (targetSize <= sizeof(void*))
{
switch (targetSize)
{
case 1:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "\tLeaving as: %d", *reinterpret_cast<char*>(pTarget));
break;
case 2:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "\tLeaving as: %04x", *reinterpret_cast<short*>(pTarget));
break;
case 4:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "\tLeaving as: %08x", *reinterpret_cast<int*>(pTarget));
break;
case 8:
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "\tLeaving as: %llx", *reinterpret_cast<long long*>(pTarget));
break;
}
}
}
}
// Indicate value should be default constructed
return NULL;
}
// Used once required members have been established, members not already
// encountered will be ignored.
void LockMemberSet()
{
assert(m_state == eState_ResolvingMembers);
DestroyInstanceData();
m_state = eState_ReadingOldMembers;
}
// Rewinds instance data and prepare for loading
void RewindForLoading()
{
assert(m_state == eState_ReadingOldMembers);
m_pInstanceData = NULL;
m_instanceIndex = ~0;
m_state = eState_WritingNewMembers;
}
// Rewinds instance data to prepare to restore old members (UNDO)
void RewindForRestore()
{
assert(m_state == eState_WritingNewMembers);
m_pInstanceData = NULL;
m_instanceIndex = ~0;
m_state = eState_RestoringOldMembers;
}
void NotifyListenerOfReplacements(ISoftCodeListener* pListener)
{
for (TInstanceVec::const_iterator iter(m_instances.begin()); iter != m_instances.end(); ++iter)
{
CInstanceData* pInstanceData = *iter;
pListener->InstanceReplaced(pInstanceData->m_pOldInstance, pInstanceData->m_pNewInstance);
}
}
private:
void DestroyInstanceData()
{
m_pInstanceData = NULL;
m_instanceIndex = ~0;
for (TInstanceVec::iterator iter(m_instances.begin()); iter != m_instances.end(); ++iter)
{
delete *iter;
}
m_instances.resize(0);
}
inline size_t FindMemberIndex(const string& memberName)
{
size_t index = ~0;
// If needed members have been resolved
if (m_state != eState_ResolvingMembers)
{
TMemberMap::const_iterator iter(m_memberMap.find(memberName));
if (iter != m_memberMap.end())
{
index = iter->second;
}
}
else // Add this member to the map with a new index
{
// Ensure there's no member name duplicates
assert(m_memberMap.find(memberName) == m_memberMap.end());
// A new entry
index = m_memberMap.size();
size_t& newIndex = m_memberMap[memberName];
newIndex = index;
}
return index;
}
private:
CInstanceData* m_pInstanceData;
size_t m_instanceIndex;
typedef std::vector<CInstanceData*> TInstanceVec;
TInstanceVec m_instances;
// Maps instance members to offsets in instance member vectors
typedef std::map<string, size_t> TMemberMap;
TMemberMap m_memberMap;
enum EState
{
eState_ResolvingMembers = 0, // Record new member names as found
eState_ReadingOldMembers, // Scrape requested member data from old instances
eState_WritingNewMembers, // Write old member data to new instances
eState_RestoringOldMembers, // Restore scraped values to old instances (UNDO)
};
EState m_state;
};
// ----
DynamicTypeLibrary::DynamicTypeLibrary(const char* name)
: m_name(name)
, m_listeners(1)
{}
const char* DynamicTypeLibrary::GetName()
{
return m_name;
}
void* DynamicTypeLibrary::CreateInstanceVoid(const char* typeName)
{
TTypeMap::const_iterator typeIter(m_types.find(typeName));
if (typeIter != m_types.end())
{
ITypeRegistrar* pRegistrar = typeIter->second;
return pRegistrar->CreateInstance();
}
return NULL;
}
void DynamicTypeLibrary::SetOverride(ITypeLibrary* /*pOverrideLib*/)
{
CryFatalError("Unsupported: Attempting to SetOverride on a DynamicTypeLibrary!");
}
size_t DynamicTypeLibrary::GetTypes([[maybe_unused]] ITypeRegistrar** ppRegistrar, [[maybe_unused]] size_t& count) const
{
CryFatalError("Unsupported: Attempting to GetTypes on a DynamicTypeLibrary!");
return 0;
}
void DynamicTypeLibrary::AddListener(const char* libraryName, ISoftCodeListener* pListener, const char* listenerName)
{
// This DynamicTypeLibrary could have been created by this listener request
// So ensure we have a name...!
if (!m_name)
{
m_name = libraryName;
}
m_listeners.Add(pListener, listenerName);
}
void DynamicTypeLibrary::RemoveListener(ISoftCodeListener* pListener)
{
m_listeners.Remove(pListener);
}
void DynamicTypeLibrary::IntegrateLibrary(ITypeLibrary* pLib, bool isDefault)
{
typedef std::vector<ITypeRegistrar*> TTypeVec;
// Resolve our name if we haven't already
if (!m_name)
{
m_name = pLib->GetName();
}
// Override the new lib immediately
pLib->SetOverride(this);
// Query the new library for its types
size_t typeCount = 0;
pLib->GetTypes(NULL, typeCount);
if (typeCount > 0)
{
TTypeVec typeVec;
typeVec.resize(typeCount);
pLib->GetTypes(&(typeVec.front()), typeCount);
if (!isDefault)
{
CryLogAlways("SoftCode: Integrating %d new types defined in %s...", (int)typeCount, m_name);
}
// Attempt to integrate each type found
for (TTypeVec::iterator typeIter(typeVec.begin()); typeIter != typeVec.end(); ++typeIter)
{
IntegrateType(*typeIter, isDefault);
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "SoftCode: New %s library has no registered types. Nothing to integrate.", pLib->GetName());
}
}
ITypeRegistrar* DynamicTypeLibrary::FindTypeForInstance(void* pInstance) const
{
for (TTypeMap::const_iterator iter(m_types.begin()); iter != m_types.end(); ++iter)
{
ITypeRegistrar* pType = iter->second;
if (pType->HasInstance(pInstance))
{
return pType;
}
}
return NULL;
}
void DynamicTypeLibrary::IntegrateType(ITypeRegistrar* pType, bool isDefault)
{
const char* typeName = pType->GetName();
// If there's an existing registrar
ITypeRegistrar* pExistingType = m_types[typeName];
assert(pExistingType != pType); // Sanity check
// If the new type is the default (built-in) type but it's already been overridden
if (isDefault && pExistingType)
{
return; // Nothing to do
}
// TODO: Inform listeners that there's a new library available
// and ask if we should use it immediately or defer
CExchanger exchanger;
// If the type can be safely created, visited and destroyed
if (EvaluateType(pType, exchanger))
{
// Override the type
m_types[typeName] = pType;
if (!isDefault)
{
CryLogAlways("SoftCode: Overridden %s in library %s", typeName, m_name);
}
const size_t instanceCount = (pExistingType) ? pExistingType->InstanceCount() : 0;
// If there are any existing instances
if (instanceCount > 0)
{
CryLogAlways("SoftCode: Attempting to exchange %d %s instances to the new version...", (int)instanceCount, typeName);
// Read instance members for type (removes data for resolved members)
if (pExistingType->ExchangeInstances(exchanger))
{
exchanger.RewindForLoading();
// Write instance members for type
if (pType->ExchangeInstances(exchanger))
{
// Success! Tell the listeners to fix up their pointers
for (TListeners::Notifier notifier(m_listeners); notifier.IsValid(); notifier.Next())
{
exchanger.NotifyListenerOfReplacements(*notifier);
}
CryLogAlways("SoftCode: %d %s instances successfully overridden to latest!", (int)instanceCount, typeName);
// Clean up old instances
if (!pExistingType->DestroyInstances())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "SoftCode: Failed to destroy old instances of type %s - leak probable.", typeName);
}
}
else // Failed to create & write into new instances
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to create and write into new instances of %s. Attempting restore of old instances...", typeName);
if (!pType->DestroyInstances())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "SoftCode: Failed to destroy new instances of type %s - leak probable.", typeName);
}
// Restore the original type library as the active one
m_types[typeName] = pExistingType;
// Attempt to restore the old instances with their original data
exchanger.RewindForRestore();
if (pExistingType->ExchangeInstances(exchanger))
{
CryLogAlways("SoftCode: Type %s in library %s successfully restored to previous revision!", typeName, m_name);
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Restore of old %s instances failed. State now undefined!", typeName);
}
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to read members on %s", typeName);
}
}
}
}
bool DynamicTypeLibrary::EvaluateType(ITypeRegistrar* pType, CExchanger& exchanger)
{
// Try a full object life-time with a single instance of the
// new type before attempting a member exchange. This also allow the
// exchanger to determine the required members to be removed from the
// old instances.
bool testPassed = false;
// Create a single test instance of the type
if (pType->CreateInstance())
{
// Read the instance members (also prepares the exchanger member set)
if (pType->ExchangeInstances(exchanger))
{
// Destroy the old instance
if (pType->DestroyInstances())
{
// Indicate required members are now resolved
exchanger.LockMemberSet();
testPassed = true;
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to destroy test instance of type: %s. New type will be skipped.", pType->GetName());
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to read members in test instance of type: %s. New type will be skipped.", pType->GetName());
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to create test instance of type: %s. New type will be skipped.", pType->GetName());
}
return testPassed;
}
// ----
// The export we expect to find in the SoftCode modules
typedef ITypeLibrary* (__stdcall * TGetTypeLibraryFcn)();
static void SoftCode_UpdateCmd([[maybe_unused]] IConsoleCmdArgs* pArgs)
{
gEnv->pSoftCodeMgr->LoadNewModules();
}
static int g_autoUpdatePeriod = 0;
SoftCodeMgr::SoftCodeMgr()
{
REGISTER_CVAR2("sc_autoupdate", &g_autoUpdatePeriod, 5, VF_CHEAT, "Set the auto-update poll period for new SoftCode modules. Set to zero to disable");
REGISTER_COMMAND("sc_update", reinterpret_cast<ConsoleCommandFunc>(&SoftCode_UpdateCmd), VF_CHEAT, "Loads any new SoftCode modules");
// Clear out any old modules
{
typedef std::vector<string> TStringVec;
TStringVec filePaths;
if (FindSoftCodeFiles("*", filePaths) > 0)
{
for (TStringVec::const_iterator iter(filePaths.begin()); iter != filePaths.end(); ++iter)
{
if (!DeleteFile(iter->c_str()))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "SoftCode: Failed to clean %s", iter->c_str());
}
}
}
}
}
SoftCodeMgr::~SoftCodeMgr()
{
if (gEnv->pConsole)
{
gEnv->pConsole->RemoveCommand("sc_update");
gEnv->pConsole->UnregisterVariable("sc_autoupdate");
}
}
// Used to register built-in libraries on first use
void SoftCodeMgr::RegisterLibrary(ITypeLibrary* pDefaultLib)
{
DynamicTypeLibrary& typeLib = m_libraryMap[pDefaultLib->GetName()];
typeLib.IntegrateLibrary(pDefaultLib, true);
}
// Look for new SoftCode modules and load them, adding their types to the registry
void SoftCodeMgr::LoadNewModules()
{
typedef std::vector<string> TStringVec;
typedef TStringVec::const_iterator TModuleIter;
TStringVec modulePaths;
// Find modules
FindSoftCodeFiles("*.dll", modulePaths);
for (TModuleIter libIter(modulePaths.begin()); libIter != modulePaths.end(); ++libIter)
{
const char* moduleName = libIter->c_str();
LoadModule(moduleName);
}
}
void SoftCodeMgr::AddListener(const char* libraryName, ISoftCodeListener* pListener, const char* listenerName)
{
// Find an existing lib or create a new one to add the listener to
DynamicTypeLibrary& lib = m_libraryMap[libraryName];
lib.AddListener(libraryName, pListener, listenerName);
}
void SoftCodeMgr::RemoveListener(const char* libraryName, ISoftCodeListener* pListener)
{
TLibMap::iterator iter(m_libraryMap.find(libraryName));
if (iter != m_libraryMap.end())
{
iter->second.RemoveListener(pListener);
}
}
// To be called regularly to poll for library updates
void SoftCodeMgr::PollForNewModules()
{
if (g_autoUpdatePeriod > 0)
{
const CTimeValue frameStartTime(gEnv->pTimer->GetFrameStartTime(ITimer::ETIMER_UI));
if (m_nextAutoCheckTime <= frameStartTime)
{
m_nextAutoCheckTime.SetSeconds((int64)g_autoUpdatePeriod);
m_nextAutoCheckTime += frameStartTime;
// Attempt to find and load any new modules
LoadNewModules();
}
}
}
namespace
{
// Util
class InstanceFixup
: public ISoftCodeListener
{
public:
InstanceFixup(void* pOldInstance)
: m_pOldInstance(pOldInstance)
, m_pNewInstance() {}
virtual void InstanceReplaced(void* pOldInstance, void* pNewInstance)
{
if (m_pOldInstance == pOldInstance)
{
m_pNewInstance = pNewInstance;
}
}
void* NewInstance() const { return m_pNewInstance; }
private:
void* m_pOldInstance;
void* m_pNewInstance;
};
}
// Stops thread execution until a new SoftCode module is available
void* SoftCodeMgr::WaitForUpdate(void* pInstance)
{
DynamicTypeLibrary* pOwningLib = NULL;
ITypeRegistrar* pOldType = NULL;
// Find existing instance
for (TLibMap::iterator libIter(m_libraryMap.begin()); libIter != m_libraryMap.end(); ++libIter)
{
DynamicTypeLibrary& lib = libIter->second;
if (ITypeRegistrar* pType = lib.FindTypeForInstance(pInstance))
{
pOwningLib = &lib;
pOldType = pType;
break;
}
}
if (!pOwningLib)
{
CryFatalError("SoftCode: Attempting to wait for update on an unknown instance!");
return NULL;
}
InstanceFixup instanceFixup(pInstance);
pOwningLib->AddListener(pOwningLib->GetName(), &instanceFixup, "InstanceFixup");
while (true)
{
// Find and load new modules
LoadNewModules();
// Got a new instance?
if (instanceFixup.NewInstance())
{
break;
}
// Wait for a new module
CryLogAlways("SoftCode: Pausing execution until class %s in %s library is updated...", pOldType->GetName(), pOwningLib->GetName());
__debugbreak(); // Stopped here? Check your log!
}
pOwningLib->RemoveListener(&instanceFixup);
return instanceFixup.NewInstance();
}
bool SoftCodeMgr::LoadModule(const char* moduleName)
{
bool success = false;
// If module not yet loaded
if (m_loadedSet.find(moduleName) == m_loadedSet.end())
{
m_loadedSet.insert(moduleName);
CryLogAlways("SoftCode: Found new module %s, attempting to load...", moduleName);
HMODULE hModule = CryLoadLibrary(moduleName);
if (hModule)
{
TGetTypeLibraryFcn pGetTypeLibraryFcn = reinterpret_cast<TGetTypeLibraryFcn>(GetProcAddress(hModule, DLL_GETTYPELIBRARY));
if (pGetTypeLibraryFcn)
{
// Add to list of loaded libs & override any earlier TypeLibraries already registered
ITypeLibrary* pTypeLibrary = pGetTypeLibraryFcn();
if (pTypeLibrary)
{
const char* libraryName = pTypeLibrary->GetName();
m_libraryMap[libraryName].IntegrateLibrary(pTypeLibrary, false);
CryLogAlways("SoftCode: Loaded new type library \"%s\" from module %s.", libraryName, moduleName);
success = true;
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to resolve GetTypeLibrary() export in: %s (error: %x)", moduleName, GetLastError());
}
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "Failed to load: %s (error: %x)", moduleName, GetLastError());
}
}
return success;
}
size_t SoftCodeMgr::FindSoftCodeFiles(const string& searchName, std::vector<string>& foundPaths) const
{
foundPaths.clear();
stack_string scSoftCodeDir;
TCHAR modulePath[MAX_PATH];
GetModuleFileName(NULL, modulePath, sizeof(modulePath));
scSoftCodeDir = PathUtil::GetParentDirectory(modulePath);
scSoftCodeDir += "\\SoftCode\\";
gEnv->pFileIO->FindFiles(scSoftCodeDir.c_str(), searchName, [&](const char* filePath) -> bool
{
if (!gEnv->pFileIO->IsDirectory(filePath) && !gEnv->pFileIO->IsReadOnly(filePath))
{
foundPaths.push_back(filePath);
}
// Keep asking for more files, no early out
return true;
});
// Sort the paths into name order
std::sort(foundPaths.begin(), foundPaths.end());
return foundPaths.size();
}
#endif // SOFTCODE_ENABLED
@@ -1,111 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_SOFTCODE_SOFTCODEMGR_H
#define CRYINCLUDE_CRYSYSTEM_SOFTCODE_SOFTCODEMGR_H
#pragma once
#include <CryListenerSet.h>
#include "ISoftCodeMgr.h"
struct ITypeLibrary;
struct ITypeRegistrar;
class CExchanger;
// Internal: Performs the dynamic type management needed for SoftCoding
class DynamicTypeLibrary
: public ITypeLibrary
{
public:
DynamicTypeLibrary(const char* name = NULL);
// ITypeLibrary impl.
virtual const char* GetName();
virtual void* CreateInstanceVoid(const char* typeName);
virtual void SetOverride(ITypeLibrary* pOverrideLib);
virtual size_t GetTypes(ITypeRegistrar** ppRegistrar, size_t& count) const;
void AddListener(const char* libraryName, ISoftCodeListener* pListener, const char* listenerName);
void RemoveListener(ISoftCodeListener* pListener);
// Attempts to add the library types the active set
void IntegrateLibrary(ITypeLibrary* pLib, bool isDefault);
ITypeRegistrar* FindTypeForInstance(void* pInstance) const;
private:
// Attempts to add the type the active set
void IntegrateType(ITypeRegistrar* pType, bool isDefault);
// Ensure the type can be safely created, visited, destroyed and prep exchanger
bool EvaluateType(ITypeRegistrar* pType, CExchanger& exchanger);
private:
typedef std::vector<ITypeLibrary*> TLibVec;
typedef std::map<string, ITypeRegistrar*> TTypeMap;
typedef CListenerSet<ISoftCodeListener*> TListeners;
// The current set of active types
std::map<string, ITypeRegistrar*> m_types;
// Current set of loaded libraries
TLibVec m_history;
// Set of listeners to SC changes
TListeners m_listeners;
const char* m_name; // Supplied by the first real library that registers
};
// Implements the global singleton responsible for SoftCode management
class SoftCodeMgr
: public ISoftCodeMgr
{
public:
SoftCodeMgr();
virtual ~SoftCodeMgr();
// Used to register built-in libraries on first use
virtual void RegisterLibrary(ITypeLibrary* pLib);
// Look for new SoftCode modules and load them, adding their types to the registry
virtual void LoadNewModules();
virtual void AddListener(const char* libraryName, ISoftCodeListener* pListener, const char* listenerName);
virtual void RemoveListener(const char* libraryName, ISoftCodeListener* pListener);
// To be called regularly to poll for library updates
virtual void PollForNewModules();
// Stops thread execution until a new SoftCode module is available
virtual void* WaitForUpdate(void* pInstance);
private:
bool LoadModule(const char* moduleName);
size_t FindSoftCodeFiles(const string& searchName, std::vector<string>& foundPaths) const;
private:
typedef std::map<string, DynamicTypeLibrary> TLibMap;
typedef std::set<string> TLoadedLibSet;
// Records the history for each TypeLibrary keyed by library name
TLibMap m_libraryMap;
// Records the library files already loaded
TLoadedLibSet m_loadedSet;
// Used to determine when the next auto-update will occur
CTimeValue m_nextAutoCheckTime;
};
#endif // CRYINCLUDE_CRYSYSTEM_SOFTCODE_SOFTCODEMGR_H
-562
View File
@@ -124,8 +124,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include <ILog.h>
#include <IAudioSystem.h>
#include <IProcess.h>
#include <INotificationNetwork.h>
#include <ISoftCodeMgr.h>
#include <LyShine/ILyShine.h>
#include <LoadScreenBus.h>
@@ -133,8 +131,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include <AzFramework/Archive/Archive.h>
#include "XConsole.h"
#include "Log.h"
#include "NotificationNetwork.h"
#include "ProfileLog.h"
#include "XML/xml.h"
#include "XML/ReadWriteXMLSink.h"
@@ -148,7 +144,6 @@ LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#include "ServerThrottle.h"
#include "ResourceManager.h"
#include "HMDBus.h"
#include <IThreadManager.h>
#include "IZLibCompressor.h"
#include "IZlibDecompressor.h"
@@ -267,22 +262,6 @@ namespace
}
#endif
#if defined(CVARS_WHITELIST)
struct SCVarsWhitelistConfigSink
: public ILoadConfigurationEntrySink
{
virtual void OnLoadConfigurationEntry(const char* szKey, const char* szValue, const char* szGroup)
{
ICVarsWhitelist* pCVarsWhitelist = gEnv->pSystem->GetCVarsWhiteList();
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(szKey, false) : true;
if (whitelisted)
{
gEnv->pConsole->LoadConfigVar(szKey, szValue);
}
}
} g_CVarsWhitelistConfigSink;
#endif // defined(CVARS_WHITELIST)
/////////////////////////////////////////////////////////////////////////////////
// System Implementation.
//////////////////////////////////////////////////////////////////////////
@@ -322,27 +301,13 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_env.pSystem = this;
m_env.pTimer = &m_Time;
m_env.pNameTable = &m_nameTable;
m_env.bServer = false;
m_env.bMultiplayer = false;
m_env.bHostMigrating = false;
m_env.bIgnoreAllAsserts = false;
m_env.bNoAssertDialog = false;
m_env.bTesting = false;
m_env.pSharedEnvironment = pSharedEnvironment;
m_env.SetFMVIsPlaying(false);
m_env.SetCutsceneIsPlaying(false);
m_env.szDebugStatus[0] = '\0';
#if !defined(CONSOLE)
m_env.SetIsClient(false);
#endif
//////////////////////////////////////////////////////////////////////////
m_pStreamEngine = NULL;
m_PhysThread = 0;
m_pIFont = NULL;
m_pIFontUi = NULL;
@@ -370,7 +335,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_pILZ4Decompressor = NULL;
m_pIZStdDecompressor = nullptr;
m_pLocalizationManager = NULL;
m_sys_physics_CPU = 0;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(System_cpp)
@@ -378,15 +342,9 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_sys_min_step = 0;
m_sys_max_step = 0;
m_pNotificationNetwork = NULL;
m_cvAIUpdate = NULL;
m_pUserCallback = NULL;
#if defined(CVARS_WHITELIST)
m_pCVarsWhitelist = NULL;
m_pCVarsWhitelistConfigSink = &g_CVarsWhitelistConfigSink;
#endif // defined(CVARS_WHITELIST)
m_sys_memory_debug = NULL;
m_sysWarnings = NULL;
m_sysKeyboard = NULL;
@@ -409,13 +367,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_bNoCrashDialog = false;
m_bNoErrorReportWindow = false;
#ifndef _RELEASE
m_checkpointLoadCount = 0;
m_loadOrigin = eLLO_Unknown;
m_hasJustResumed = false;
m_expectingMapCommand = false;
#endif
m_pCVarQuit = NULL;
m_bForceNonDevMode = false;
@@ -429,13 +380,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_nServerConfigSpec = CONFIG_VERYHIGH_SPEC;
m_nMaxConfigSpec = CONFIG_VERYHIGH_SPEC;
//m_hPhysicsThread = INVALID_HANDLE_VALUE;
//m_hPhysicsActive = INVALID_HANDLE_VALUE;
//m_bStopPhysics = 0;
//m_bPhysicsActive = 0;
m_pProgressListener = 0;
m_bPaused = false;
m_bNoUpdate = false;
m_nUpdateCounter = 0;
@@ -444,12 +388,9 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
m_pXMLUtils = new CXmlUtils(this);
m_pMemoryManager = CryGetIMemoryManager();
m_pThreadTaskManager = new CThreadTaskManager;
m_pResourceManager = new CResourceManager;
m_pTextModeConsole = NULL;
InitThreadSystem();
g_pPakHeap = new CMTSafeHeap;
if (!AZ::AllocatorInstance<AZ::OSAllocator>::IsReady())
@@ -464,7 +405,6 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
AZ::Debug::Trace::Instance().Init();
}
m_UpdateTimesIdx = 0U;
m_bNeedDoWorkDuringOcclusionChecks = false;
m_eRuntimeState = ESYSTEM_EVENT_LEVEL_UNLOAD;
@@ -478,15 +418,12 @@ CSystem::CSystem(SharedEnvironmentInstance* pSharedEnvironment)
#endif
m_ConfigPlatform = CONFIG_INVALID_PLATFORM;
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusConnect();
}
/////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////
CSystem::~CSystem()
{
AzFramework::Terrain::TerrainDataNotificationBus::Handler::BusDisconnect();
ShutDown();
#if AZ_LEGACY_CRYSYSTEM_TRAIT_USE_MESSAGE_HANDLER
@@ -496,16 +433,8 @@ CSystem::~CSystem()
CRY_ASSERT(m_windowMessageHandlers.empty() && "There exists a dangling window message handler somewhere");
SAFE_DELETE(m_pXMLUtils);
SAFE_DELETE(m_pThreadTaskManager);
SAFE_DELETE(m_pResourceManager);
SAFE_DELETE(m_pSystemEventDispatcher);
// SAFE_DELETE(m_pMemoryManager);
if (gEnv && gEnv->pThreadManager)
{
gEnv->pThreadManager->UnRegisterThirdPartyThread("Main");
}
ShutDownThreadSystem();
SAFE_DELETE(g_pPakHeap);
@@ -617,8 +546,6 @@ void CSystem::ShutDown()
SAFE_DELETE(m_pTextModeConsole);
KillPhysicsThread();
if (m_sys_firstlaunch)
{
m_sys_firstlaunch->Set("0");
@@ -664,8 +591,6 @@ void CSystem::ShutDown()
gEnv->pLyShine = nullptr;
}
SAFE_DELETE(m_env.pResourceCompilerHelper);
SAFE_RELEASE(m_env.pMovieSystem);
SAFE_RELEASE(m_env.pLyShine);
SAFE_RELEASE(m_env.pCryFont);
@@ -706,7 +631,6 @@ void CSystem::ShutDown()
SAFE_RELEASE(m_sys_GraphicsQuality);
SAFE_RELEASE(m_sys_firstlaunch);
SAFE_RELEASE(m_sys_enable_budgetmonitoring);
SAFE_RELEASE(m_sys_physics_CPU);
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_3
@@ -716,9 +640,6 @@ void CSystem::ShutDown()
SAFE_RELEASE(m_sys_min_step);
SAFE_RELEASE(m_sys_max_step);
SAFE_RELEASE(m_pNotificationNetwork);
SAFE_DELETE(m_env.pSoftCodeMgr);
SAFE_DELETE(m_pDefaultValidator);
m_pValidator = nullptr;
@@ -743,7 +664,6 @@ void CSystem::ShutDown()
SAFE_RELEASE(m_env.pConsole);
// Log must be last thing released.
SAFE_RELEASE(m_env.pProfileLogSystem);
if (m_env.pLog)
{
m_env.pLog->FlushAndClose();
@@ -752,10 +672,6 @@ void CSystem::ShutDown()
ShutdownFileSystem();
#if defined(MAP_LOADING_SLICING)
delete gEnv->pSystemScheduler;
#endif // defined(MAP_LOADING_SLICING)
ShutdownModuleLibraries();
EBUS_EVENT(CrySystemEventBus, OnCrySystemPostShutdown);
@@ -841,273 +757,6 @@ ISystem* CSystem::GetCrySystem()
return this;
}
//////////////////////////////////////////////////////////////////////////
// Physics thread task
//////////////////////////////////////////////////////////////////////////
class CPhysicsThreadTask
: public IThreadTask
{
public:
CPhysicsThreadTask()
{
m_bStopRequested = 0;
m_bIsActive = 0;
m_stepRequested = 0;
m_bProcessing = 0;
m_doZeroStep = 0;
m_lastStepTimeTaken = 0U;
m_lastWaitTimeTaken = 0U;
}
//////////////////////////////////////////////////////////////////////////
// IThreadTask implementation.
//////////////////////////////////////////////////////////////////////////
virtual void OnUpdate()
{
Run();
// At the end.. delete the task
delete this;
}
virtual void Stop()
{
Cancel();
}
virtual SThreadTaskInfo* GetTaskInfo() { return &m_TaskInfo; }
//////////////////////////////////////////////////////////////////////////
virtual void Run()
{
m_bStopRequested = 0;
m_bIsActive = 1;
float step, timeTaken, kSlowdown = 1.0f;
int nSlowFrames = 0;
int64 timeStart;
#ifdef ENABLE_LW_PROFILERS
LARGE_INTEGER stepStart, stepEnd;
#endif
LARGE_INTEGER waitStart, waitEnd;
MarkThisThreadForDebugging("Physics");
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_5
#include AZ_RESTRICTED_FILE(System_cpp)
#endif
while (true)
{
QueryPerformanceCounter(&waitStart);
m_FrameEvent.Wait(); // Wait untill new frame
QueryPerformanceCounter(&waitEnd);
m_lastWaitTimeTaken = waitEnd.QuadPart - waitStart.QuadPart;
if (m_bStopRequested)
{
UnmarkThisThreadFromDebugging();
return;
}
bool stepped = false;
#ifdef ENABLE_LW_PROFILERS
QueryPerformanceCounter(&stepStart);
#endif
while ((step = m_stepRequested) > 0 || m_doZeroStep)
{
stepped = true;
m_stepRequested = 0;
m_bProcessing = 1;
m_doZeroStep = 0;
if (kSlowdown != 1.0f)
{
step = max(1, FtoI(step * kSlowdown * 50 - 0.5f)) * 0.02f;
}
timeStart = CryGetTicks();
timeTaken = gEnv->pTimer->TicksToSeconds(CryGetTicks() - timeStart);
if (timeTaken > step * 0.9f)
{
if (++nSlowFrames > 5)
{
kSlowdown = step * 0.9f / timeTaken;
}
}
else
{
kSlowdown = 1.0f, nSlowFrames = 0;
}
m_bProcessing = 0;
//int timeSleep = (int)((m_timeTarget-gEnv->pTimer->GetAsyncTime()).GetMilliSeconds()*0.9f);
//Sleep(max(0,timeSleep));
}
if (!stepped)
{
Sleep(0);
}
m_FrameDone.Set();
#ifdef ENABLE_LW_PROFILERS
QueryPerformanceCounter(&stepEnd);
m_lastStepTimeTaken = stepEnd.QuadPart - stepStart.QuadPart;
#endif
}
}
virtual void Cancel()
{
Pause();
m_bStopRequested = 1;
m_FrameEvent.Set();
m_bIsActive = 0;
}
int Pause()
{
if (m_bIsActive)
{
AZ_PROFILE_FUNCTION_STALL(AZ::Debug::ProfileCategory::System);
m_bIsActive = 0;
while (m_bProcessing)
{
;
}
return 1;
}
return 0;
}
int Resume()
{
if (!m_bIsActive)
{
m_bIsActive = 1;
return 1;
}
return 0;
}
int IsActive() { return m_bIsActive; }
int RequestStep(float dt)
{
if (m_bIsActive && dt > FLT_EPSILON)
{
m_stepRequested += dt;
if (dt <= 0.0f)
{
m_doZeroStep = 1;
}
m_FrameEvent.Set();
}
return m_bProcessing;
}
float GetRequestedStep() { return m_stepRequested; }
uint64 LastStepTaken() const
{
return m_lastStepTimeTaken;
}
uint64 LastWaitTime() const
{
return m_lastWaitTimeTaken;
}
void EnsureStepDone()
{
FRAME_PROFILER("SysUpdate:PhysicsEnsureDone", gEnv->pSystem, PROFILE_SYSTEM);
if (m_bIsActive)
{
while (m_stepRequested > 0.0f || m_bProcessing)
{
m_FrameDone.Wait();
}
}
}
protected:
volatile int m_bStopRequested;
volatile int m_bIsActive;
volatile float m_stepRequested;
volatile int m_bProcessing;
volatile int m_doZeroStep;
volatile uint64 m_lastStepTimeTaken;
volatile uint64 m_lastWaitTimeTaken;
CryEvent m_FrameEvent;
CryEvent m_FrameDone;
SThreadTaskInfo m_TaskInfo;
};
void CSystem::CreatePhysicsThread()
{
if (!m_PhysThread)
{
//////////////////////////////////////////////////////////////////////////
SThreadTaskParams threadParams;
threadParams.name = "Physics";
threadParams.nFlags = THREAD_TASK_BLOCKING;
threadParams.nStackSizeKB = PHYSICS_STACK_SIZE >> 10;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_CPP_SECTION_6
#include AZ_RESTRICTED_FILE(System_cpp)
#endif
{
m_PhysThread = new CPhysicsThreadTask;
GetIThreadTaskManager()->RegisterTask(m_PhysThread, threadParams);
}
}
}
void CSystem::KillPhysicsThread()
{
if (m_PhysThread)
{
GetIThreadTaskManager()->UnregisterTask(m_PhysThread);
m_PhysThread = 0;
}
}
///////////////////////////////////////////////////////////////////////////
// AzFramework::Terrain::TerrainDataNotificationBus START
void CSystem::OnTerrainDataCreateBegin()
{
KillPhysicsThread();
}
void CSystem::OnTerrainDataDestroyBegin()
{
OnTerrainDataCreateBegin();
}
// AzFramework::Terrain::TerrainDataNotificationBus END
///////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
int CSystem::SetThreadState(ESubsystem subsys, bool bActive)
{
switch (subsys)
{
case ESubsys_Physics:
{
if (m_PhysThread)
{
return bActive ? ((CPhysicsThreadTask*)m_PhysThread)->Resume() : ((CPhysicsThreadTask*)m_PhysThread)->Pause();
}
}
break;
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CSystem::SleepIfInactive()
{
// ProcessSleep()
if (m_bDedicatedServer || m_bEditor || gEnv->bMultiplayer)
{
return;
}
}
//////////////////////////////////////////////////////////////////////////
void CSystem::SleepIfNeeded()
{
@@ -1180,11 +829,7 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
// do the dedicated sleep earlier than the frame profiler to avoid having it counted
if (gEnv->IsDedicated())
{
#if defined(MAP_LOADING_SLICING)
gEnv->pSystemScheduler->SchedulingSleepIfNeeded();
#else
SleepIfNeeded();
#endif // defined(MAP_LOADING_SLICING)
}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
@@ -1199,9 +844,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
m_nUpdateCounter++;
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
// Check if game needs to be sleeping when not active.
SleepIfInactive();
if (m_pUserCallback)
{
m_pUserCallback->OnUpdate();
@@ -1216,7 +858,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
prev_sys_float_exceptions = g_cvars.sys_float_exceptions;
EnableFloatExceptions(g_cvars.sys_float_exceptions);
UpdateFPExceptionsMaskForThreads();
}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
//////////////////////////////////////////////////////////////////////////
@@ -1263,13 +904,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
}
#endif //PROFILE_WITH_VTUNE
#ifdef SOFTCODE_SYSTEM_ENABLED
if (m_env.pSoftCodeMgr)
{
m_env.pSoftCodeMgr->PollForNewModules();
}
#endif
if (m_pStreamEngine)
{
FRAME_PROFILER("StreamEngine::Update()", this, PROFILE_SYSTEM);
@@ -1290,7 +924,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
if (m_sysNoUpdate && m_sysNoUpdate->GetIVal())
{
bNoUpdate = true;
updateFlags = ESYSUPDATE_IGNORE_PHYSICS;
}
m_bNoUpdate = bNoUpdate;
@@ -1373,16 +1006,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
return false;
}
#ifndef EXCLUDE_UPDATE_ON_CONSOLE
//////////////////////////////////////////////////////////////////////
//update notification network system
if (m_pNotificationNetwork)
{
FRAME_PROFILER("SysUpdate:NotificationNetwork", this, PROFILE_SYSTEM);
m_pNotificationNetwork->Update();
}
#endif //EXCLUDE_UPDATE_ON_CONSOLE
//////////////////////////////////////////////////////////////////////
//update sound system Part 1 if in Editor / in Game Mode Viewsystem updates the Listeners
if (!m_env.IsEditorGameMode())
@@ -1401,15 +1024,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
}
}
//////////////////////////////////////////////////////////////////////////
// Update Threads Task Manager.
//////////////////////////////////////////////////////////////////////////
if (m_pThreadTaskManager)
{
FRAME_PROFILER("SysUpdate:ThreadTaskManager", this, PROFILE_SYSTEM);
m_pThreadTaskManager->OnUpdate();
}
//////////////////////////////////////////////////////////////////////////
// Update Resource Manager.
//////////////////////////////////////////////////////////////////////////
@@ -1418,77 +1032,6 @@ bool CSystem::UpdatePreTickBus(int updateFlags, int nPauseMode)
m_pResourceManager->Update();
}
//////////////////////////////////////////////////////////////////////
// update physic system
//static float time_zero = 0;
if (m_sys_physics_CPU->GetIVal() > 0 && !gEnv->IsDedicated())
{
CreatePhysicsThread();
}
else
{
KillPhysicsThread();
}
static int g_iPausedPhys = 0;
CPhysicsThreadTask* pPhysicsThreadTask = ((CPhysicsThreadTask*)m_PhysThread);
if (!pPhysicsThreadTask)
{
FRAME_PROFILER_LEGACYONLY("SysUpdate:AllAIAndPhysics", this, PROFILE_SYSTEM);
AZ_TRACE_METHOD_NAME("SysUpdate::AllAIAndPhysics");
//////////////////////////////////////////////////////////////////////
// update entity system (a little bit) before physics
if (nPauseMode != 1)
{
if (!bNoUpdate)
{
EBUS_EVENT(CrySystemEventBus, OnCrySystemPrePhysicsUpdate);
}
}
// intermingle physics/AI updates so that if we get a big timestep (frame rate glitch etc) the
// AI gets to steer entities before they travel over cliffs etc.
const float maxTimeStep = 0.25f;
int maxSteps = 1;
//float fCurTime = m_Time.GetCurrTime();
float timeToDo = m_Time.GetFrameTime();//fCurTime - fPrevTime;
if (m_env.bMultiplayer)
{
timeToDo = m_Time.GetRealFrameTime();
}
while (timeToDo > 0.0001f && maxSteps-- > 0)
{
float thisStep = min(maxTimeStep, timeToDo);
timeToDo -= thisStep;
EBUS_EVENT(CrySystemEventBus, OnCrySystemPostPhysicsUpdate);
}
}
else
{
// In multithreaded physics mode, post physics fires after physics events are dispatched on the main thread.
EBUS_EVENT(CrySystemEventBus, OnCrySystemPostPhysicsUpdate);
//////////////////////////////////////////////////////////////////////
// update entity system (a little bit) before physics
if (nPauseMode != 1)
{
if (!bNoUpdate)
{
EBUS_EVENT(CrySystemEventBus, OnCrySystemPrePhysicsUpdate);
}
}
}
// Use UI timer for CryMovie, because it should not be affected by pausing game time
const float fMovieFrameTime = m_Time.GetFrameTime(ITimer::ETIMER_UI);
@@ -1550,8 +1093,6 @@ bool CSystem::UpdatePostTickBus(int updateFlags, int /*nPauseMode*/)
m_updateTimes.push_back(std::make_pair(cur_time, updateTime));
}
UpdateUpdateTimes();
{
FRAME_PROFILER("SysUpdate - SystemEventDispatcher::Update", this, PROFILE_SYSTEM);
m_pSystemEventDispatcher->Update();
@@ -1890,12 +1431,6 @@ ILocalizationManager* CSystem::GetLocalizationManager()
return m_pLocalizationManager;
}
//////////////////////////////////////////////////////////////////////////
IThreadTaskManager* CSystem::GetIThreadTaskManager()
{
return m_pThreadTaskManager;
}
//////////////////////////////////////////////////////////////////////////
IResourceManager* CSystem::GetIResourceManager()
{
@@ -1960,10 +1495,6 @@ void CSystem::ExecuteCommandLine(bool deferred)
if (pCmd->GetType() == eCLAT_Post)
{
string sLine = pCmd->GetName();
#if defined(CVARS_WHITELIST)
if (!GetCVarsWhiteList() || GetCVarsWhiteList()->IsWhiteListed(sLine, false))
#endif
{
if (pCmd->GetValue())
{
@@ -1973,12 +1504,6 @@ void CSystem::ExecuteCommandLine(bool deferred)
GetILog()->Log("Executing command from command line: \n%s\n", sLine.c_str()); // - the actual command might be executed much later (e.g. level load pause)
GetIConsole()->ExecuteString(sLine.c_str(), false, deferred);
}
#if defined(CVARS_WHITELIST)
else if (gEnv->IsDedicated())
{
GetILog()->LogError("Failed to execute command: '%s' as it is not whitelisted\n", sLine.c_str());
}
#endif
}
}
@@ -2078,93 +1603,6 @@ void CProfilingSystem::VTunePause()
#endif
}
//////////////////////////////////////////////////////////////////////////
sUpdateTimes& CSystem::GetCurrentUpdateTimeStats()
{
return m_UpdateTimes[m_UpdateTimesIdx];
}
//////////////////////////////////////////////////////////////////////////
const sUpdateTimes* CSystem::GetUpdateTimeStats(uint32& index, uint32& num)
{
index = m_UpdateTimesIdx;
num = NUM_UPDATE_TIMES;
return m_UpdateTimes;
}
void CSystem::UpdateUpdateTimes()
{
sUpdateTimes& sample = m_UpdateTimes[m_UpdateTimesIdx];
if (m_PhysThread)
{
static uint64 lastPhysTime = 0U;
static uint64 lastMainTime = 0U;
static uint64 lastYields = 0U;
static uint64 lastPhysWait = 0U;
uint64 physTime = 0, mainTime = 0;
uint32 yields = 0;
physTime = ((CPhysicsThreadTask*)m_PhysThread)->LastStepTaken();
mainTime = CryGetTicks() - lastMainTime;
lastMainTime = mainTime;
lastPhysWait = ((CPhysicsThreadTask*)m_PhysThread)->LastWaitTime();
sample.PhysStepTime = physTime;
sample.SysUpdateTime = mainTime;
sample.PhysYields = yields;
sample.physWaitTime = lastPhysWait;
}
++m_UpdateTimesIdx;
if (m_UpdateTimesIdx >= NUM_UPDATE_TIMES)
{
m_UpdateTimesIdx = 0;
}
}
#ifndef _RELEASE
void CSystem::GetCheckpointData(ICheckpointData& data)
{
data.m_totalLoads = m_checkpointLoadCount;
data.m_loadOrigin = m_loadOrigin;
}
void CSystem::IncreaseCheckpointLoadCount()
{
if (!m_hasJustResumed)
{
++m_checkpointLoadCount;
}
m_hasJustResumed = false;
}
void CSystem::SetLoadOrigin(LevelLoadOrigin origin)
{
switch (origin)
{
case eLLO_NewLevel: // Intentional fall through
case eLLO_Level2Level:
m_expectingMapCommand = true;
break;
case eLLO_Resumed:
m_hasJustResumed = true;
break;
case eLLO_MapCmd:
if (m_expectingMapCommand)
{
// We knew a map command was coming, so don't process this.
m_expectingMapCommand = false;
return;
}
break;
}
m_loadOrigin = origin;
m_checkpointLoadCount = 0;
}
#endif
bool CSystem::SteamInit()
{
#if USE_STEAM
-95
View File
@@ -26,14 +26,12 @@
#include "MTSafeAllocator.h"
#include "CPUDetect.h"
#include <AzFramework/Archive/ArchiveVars.h>
#include "ThreadTask.h"
#include "RenderBus.h"
#include <LoadScreenBus.h>
#include <ThermalInfo.h>
#include <AzCore/Module/DynamicModuleHandle.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
namespace AzFramework
{
@@ -44,7 +42,6 @@ struct IConsoleCmdArgs;
class CServerThrottle;
struct IZLibCompressor;
class CWatchdogThread;
class CThreadManager;
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
@@ -183,8 +180,6 @@ class CThreadManager;
#include "CryLibrary.h"
#endif
#define NUM_UPDATE_TIMES (128U)
#ifdef WIN32
typedef void* WIN_HMODULE;
#else
@@ -241,7 +236,6 @@ struct SSystemCVars
int sys_WER;
int sys_dump_type;
int sys_ai;
int sys_physics;
int sys_entitysystem;
int sys_trackview;
int sys_vtune;
@@ -342,7 +336,6 @@ class CSystem
, public IWindowMessageHandler
, public AZ::RenderNotificationsBus::Handler
, public CrySystemRequestBus::Handler
, private AzFramework::Terrain::TerrainDataNotificationBus::Handler
{
public:
@@ -397,20 +390,8 @@ public:
ISystem* GetCrySystem() override;
////////////////////////////////////////////////////////////////////////
//! Update screen during loading.
void UpdateLoadingScreen();
//! Update screen and call some important tick functions during loading.
void SynchronousLoadingTick(const char* pFunc, int line);
uint32 GetUsedMemory();
#ifndef _RELEASE
virtual void GetCheckpointData(ICheckpointData& data);
virtual void IncreaseCheckpointLoadCount();
virtual void SetLoadOrigin(LevelLoadOrigin origin);
#endif
virtual bool SteamInit();
void Relaunch(bool bRelaunch);
@@ -425,8 +406,6 @@ public:
virtual const char* GetUserName();
virtual int GetApplicationInstance();
int GetApplicationLogInstance(const char* logFilePath) override;
virtual sUpdateTimes& GetCurrentUpdateTimeStats();
virtual const sUpdateTimes* GetUpdateTimeStats(uint32&, uint32&);
ITimer* GetITimer(){ return m_env.pTimer; }
AZ::IO::IArchive* GetIPak() { return m_env.pCryPak; };
@@ -434,7 +413,6 @@ public:
IRemoteConsole* GetIRemoteConsole();
IMovieSystem* GetIMovieSystem() { return m_env.pMovieSystem; };
IMemoryManager* GetIMemoryManager(){ return m_pMemoryManager; }
IThreadManager* GetIThreadManager() override {return m_env.pThreadManager; }
ICryFont* GetICryFont(){ return m_env.pCryFont; }
ILog* GetILog(){ return m_env.pLog; }
ICmdLine* GetICmdLine(){ return m_pCmdLine; }
@@ -444,11 +422,8 @@ public:
IViewSystem* GetIViewSystem();
ILevelSystem* GetILevelSystem();
ISystemEventDispatcher* GetISystemEventDispatcher() { return m_pSystemEventDispatcher; }
IThreadTaskManager* GetIThreadTaskManager();
IResourceManager* GetIResourceManager();
ITextModeConsole* GetITextModeConsole();
IVisualLog* GetIVisualLog() { return m_env.pVisualLog; }
INotificationNetwork* GetINotificationNetwork() { return m_pNotificationNetwork; }
IProfilingSystem* GetIProfilingSystem() { return &m_ProfilingSystem; }
IZLibCompressor* GetIZLibCompressor() { return m_pIZLibCompressor; }
IZLibDecompressor* GetIZLibDecompressor() { return m_pIZLibDecompressor; }
@@ -459,19 +434,6 @@ public:
CPNoise3* GetNoiseGen();
virtual uint64 GetUpdateCounter() { return m_nUpdateCounter; };
virtual void SetLoadingProgressListener(ILoadingProgressListener* pLoadingProgressListener)
{
m_pProgressListener = pLoadingProgressListener;
};
virtual ILoadingProgressListener* GetLoadingProgressListener() const
{
return m_pProgressListener;
};
void SetIMaterialEffects(IMaterialEffects* pMaterialEffects) { m_env.pMaterialEffects = pMaterialEffects; }
void SetIOpticsManager(IOpticsManager* pOpticsManager) { m_env.pOpticsManager = pOpticsManager; }
void SetIVisualLog(IVisualLog* pVisualLog) { m_env.pVisualLog = pVisualLog; }
void DetectGameFolderAccessRights();
virtual void ExecuteCommandLine(bool deferred=true);
@@ -554,12 +516,6 @@ public:
//! Return pointer to user defined callback.
ISystemUserCallback* GetUserCallback() const { return m_pUserCallback; };
#if defined(CVARS_WHITELIST)
virtual ICVarsWhitelist* GetCVarsWhiteList() const { return m_pCVarsWhitelist; };
virtual ILoadConfigurationEntrySink* GetCVarsWhiteListConfigSink() const { return m_pCVarsWhitelistConfigSink; }
#else
virtual ILoadConfigurationEntrySink* GetCVarsWhiteListConfigSink() const { return nullptr; }
#endif // defined(CVARS_WHITELIST)
//////////////////////////////////////////////////////////////////////////
virtual void SaveConfiguration();
@@ -571,7 +527,6 @@ public:
virtual void SetConfigPlatform(ESystemConfigPlatform platform);
//////////////////////////////////////////////////////////////////////////
virtual int SetThreadState(ESubsystem subsys, bool bActive);
virtual bool IsPaused() const { return m_bPaused; };
virtual ILocalizationManager* GetLocalizationManager();
@@ -608,8 +563,6 @@ private:
// Release all resources.
void ShutDown();
void SleepIfInactive();
bool LoadEngineDLLs();
//! @name Initialization routines
@@ -623,12 +576,6 @@ private:
//@}
//////////////////////////////////////////////////////////////////////////
// Threading functions.
//////////////////////////////////////////////////////////////////////////
void InitThreadSystem();
void ShutDownThreadSystem();
//////////////////////////////////////////////////////////////////////////
// Helper functions.
//////////////////////////////////////////////////////////////////////////
@@ -645,9 +592,6 @@ private:
void LogBuildInfo();
void SetDevMode(bool bEnable);
void CreatePhysicsThread();
void KillPhysicsThread();
#ifndef _RELEASE
static void SystemVersionChanged(ICVar* pCVar);
#endif // #ifndef _RELEASE
@@ -676,7 +620,6 @@ public:
virtual bool GetForceNonDevMode() const;
virtual bool WasInDevMode() const { return m_bWasInDevMode; };
virtual bool IsDevMode() const { return m_bInDevMode && !GetForceNonDevMode(); }
virtual bool IsMinimalMode() const { return m_bMinimal; }
virtual bool IsMODValid(const char* szMODName) const
{
if (!szMODName || strstr(szMODName, ".") || strstr(szMODName, "\\"))
@@ -727,7 +670,6 @@ private: // ------------------------------------------------------
bool m_bRelaunch; //!< relaunching the app or not (true beforerelaunch)
int m_iLoadingMode; //!< Game is loading w/o changing context (0 not, 1 quickloading, 2 full loading)
bool m_bTestMode; //!< If running in testing mode.
bool m_bMinimal; //!< If running in 'minimal mode'.
bool m_bEditor; //!< If running in Editor.
bool m_bNoCrashDialog;
bool m_bNoErrorReportWindow;
@@ -742,16 +684,6 @@ private: // ------------------------------------------------------
SDefaultValidator* m_pDefaultValidator; //!<
CCpuFeatures* m_pCpu; //!< CPU features
int m_ttMemStatSS; //!< Time to memstat screenshot
string m_szCmdLine;
int m_iTraceAllocations;
#ifndef _RELEASE
int m_checkpointLoadCount;// Total times game has loaded from a checkpoint
LevelLoadOrigin m_loadOrigin; // Where the load was initiated from
bool m_hasJustResumed; // Has resume game just been called
bool m_expectingMapCommand;
#endif
bool m_bDrawConsole; //!< Set to true if OK to draw the console.
bool m_bDrawUI; //!< Set to true if OK to draw UI.
@@ -867,8 +799,6 @@ private: // ------------------------------------------------------
ICVar* m_sys_asset_processor;
ICVar* m_sys_load_files_to_memory;
ICVar* m_sys_physics_CPU;
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEM_H_SECTION_4
#include AZ_RESTRICTED_FILE(System_h)
@@ -891,15 +821,6 @@ private: // ------------------------------------------------------
//! User define callback for system events.
ISystemUserCallback* m_pUserCallback;
#if defined(CVARS_WHITELIST)
//////////////////////////////////////////////////////////////////////////
//! User define callback for whitelisting cvars
ICVarsWhitelist* m_pCVarsWhitelist;
ILoadConfigurationEntrySink* m_pCVarsWhitelistConfigSink;
#endif // defined(CVARS_WHITELIST)
//int m_nCurrentLogVerbosity;
SFileVersion m_fileVersion;
SFileVersion m_productVersion;
SFileVersion m_buildVersion;
@@ -910,8 +831,6 @@ private: // ------------------------------------------------------
// Name table.
CNameTable m_nameTable;
IThreadTask* m_PhysThread;
ESystemConfigSpec m_nServerConfigSpec;
ESystemConfigSpec m_nMaxConfigSpec;
ESystemConfigPlatform m_ConfigPlatform;
@@ -919,8 +838,6 @@ private: // ------------------------------------------------------
std::unique_ptr<CServerThrottle> m_pServerThrottle;
CProfilingSystem m_ProfilingSystem;
sUpdateTimes m_UpdateTimes[NUM_UPDATE_TIMES];
uint32 m_UpdateTimesIdx;
// Pause mode.
bool m_bPaused;
@@ -991,26 +908,14 @@ private:
ESystemGlobalState m_systemGlobalState;
static const char* GetSystemGlobalStateName(const ESystemGlobalState systemGlobalState);
///////////////////////////////////////////////////////////////////////////
// AzFramework::Terrain::TerrainDataNotificationBus START
void OnTerrainDataCreateBegin() override;
void OnTerrainDataDestroyBegin() override;
// AzFramework::Terrain::TerrainDataNotificationBus END
///////////////////////////////////////////////////////////////////////////
public:
void InitLocalization();
void UpdateUpdateTimes();
protected: // -------------------------------------------------------------
ILoadingProgressListener* m_pProgressListener;
CCmdLine* m_pCmdLine;
CThreadManager* m_pThreadManager;
CThreadTaskManager* m_pThreadTaskManager;
class CResourceManager* m_pResourceManager;
ITextModeConsole* m_pTextModeConsole;
INotificationNetwork* m_pNotificationNetwork;
string m_currentLanguageAudio;
string m_systemConfigName; // computed from system_(hardwareplatform)_(assetsPlatform) - eg, system_android_es3.cfg or system_android_opengl.cfg or system_windows_pc.cfg
+10 -154
View File
@@ -35,13 +35,9 @@
#define SYSTEMINIT_CPP_SECTION_17 17
#endif
#if defined(MAP_LOADING_SLICING)
#include "SystemScheduler.h"
#endif // defined(MAP_LOADING_SLICING)
#include "CryLibrary.h"
#include "CryPath.h"
#include <StringUtils.h>
#include <IThreadManager.h>
#include <AzFramework/Input/Devices/Mouse/InputDeviceMouse.h>
#include <AzFramework/IO/LocalFileIO.h>
@@ -103,16 +99,12 @@
#include "PhysRenderer.h"
#include "LocalizedStringManager.h"
#include "SystemEventDispatcher.h"
#include "ThreadConfigManager.h"
#include "Validator.h"
#include "ServerThrottle.h"
#include "SystemCFG.h"
#include "AutoDetectSpec.h"
#include "ResourceManager.h"
#include "MTSafeAllocator.h"
#include "NotificationNetwork.h"
#include "ProfileLogSystem.h"
#include "SoftCode/SoftCodeMgr.h"
#include "ZLibCompressor.h"
#include "ZLibDecompressor.h"
#include "ZStdDecompressor.h"
@@ -146,8 +138,6 @@
#include "MobileDetectSpec.h"
#endif
#include "IDebugCallStack.h"
#include "WindowsConsole.h"
#if defined(EXTERNAL_CRASH_REPORTING)
@@ -163,11 +153,6 @@
# include <AzFramework/Network/AssetProcessorConnection.h>
#endif
// if we enable the built-in local version instead of remote:
#if defined(CRY_ENABLE_RC_HELPER)
#include "ResourceCompilerHelper.h"
#endif
#ifdef WIN32
extern LONG WINAPI CryEngineExceptionFilterWER(struct _EXCEPTION_POINTERS* pExceptionPointers);
#endif
@@ -400,26 +385,20 @@ struct SysSpecOverrideSink
}
else
{
// This could bypass the restricted/whitelisted cvar checks that exist elsewhere depending on
// This could bypass the restricted cvar checks that exist elsewhere depending on
// the calling code so we also need check here before setting.
bool isConst = pCvar->IsConstCVar();
bool isCheat = ((pCvar->GetFlags() & (VF_CHEAT | VF_CHEAT_NOCHECK | VF_CHEAT_ALWAYS_CHECK)) != 0);
bool isReadOnly = ((pCvar->GetFlags() & VF_READONLY) != 0);
bool isDeprecated = ((pCvar->GetFlags() & VF_DEPRECATED) != 0);
bool allowApplyCvar = true;
bool whitelisted = true;
#if defined CVARS_WHITELIST
ICVarsWhitelist* cvarWhitelist = gEnv->pSystem->GetCVarsWhiteList();
whitelisted = cvarWhitelist ? cvarWhitelist->IsWhiteListed(szKey, true) : true;
#endif
if ((isConst || isCheat || isReadOnly) || isDeprecated)
{
allowApplyCvar = !isDeprecated && (gEnv->pSystem->IsDevMode()) || (gEnv->IsEditor());
}
if ((allowApplyCvar && whitelisted) || ALLOW_CONST_CVAR_MODIFICATIONS)
if ((allowApplyCvar) || ALLOW_CONST_CVAR_MODIFICATIONS)
{
applyCvar = true;
}
@@ -1028,7 +1007,6 @@ bool CSystem::InitFileSystem()
// get the DirectInstance FileIOBase which should be the AZ::LocalFileIO
m_env.pFileIO = AZ::IO::FileIOBase::GetDirectInstance();
m_env.pResourceCompilerHelper = nullptr;
m_env.pCryPak = AZ::Interface<AZ::IO::IArchive>::Get();
m_env.pFileIO = AZ::IO::FileIOBase::GetInstance();
@@ -1107,8 +1085,7 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
{
LOADING_TIME_PROFILE_SECTION;
{
ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetCVarsWhiteListConfigSink();
LoadConfiguration(m_systemConfigName.c_str(), pCVarsWhiteListConfigSink);
LoadConfiguration(m_systemConfigName.c_str());
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Loading system configuration from %s...", m_systemConfigName.c_str());
}
@@ -1118,13 +1095,6 @@ bool CSystem::InitFileSystem_LoadEngineFolders(const SSystemInitParams&)
GetISystem()->SetConfigPlatform(GetDevicePlatform());
#if defined(CRY_ENABLE_RC_HELPER)
if (!m_env.pResourceCompilerHelper)
{
m_env.pResourceCompilerHelper = new CResourceCompilerHelper();
}
#endif
auto projectPath = AZ::Utils::GetProjectPath();
AZ_Printf(AZ_TRACE_SYSTEM_WINDOW, "Project Path: %s\n", projectPath.empty() ? "None specified" : projectPath.c_str());
@@ -1179,7 +1149,6 @@ bool CSystem::InitAudioSystem(const SSystemInitParams& initParams)
bool useRealAudioSystem = false;
if (!initParams.bPreview
&& !initParams.bMinimal
&& !m_bDedicatedServer
&& m_sys_audio_disable->GetIVal() == 0)
{
@@ -1672,12 +1641,8 @@ bool CSystem::Init(const SSystemInitParams& startupParams)
gEnv->mMainThreadId = GetCurrentThreadId(); //Set this ASAP on startup
InlineInitializationProcessing("CSystem::Init start");
m_szCmdLine = startupParams.szSystemCmdLine;
m_env.szCmdLine = m_szCmdLine.c_str();
m_env.bTesting = startupParams.bTesting;
m_env.bNoAssertDialog = startupParams.bTesting;
m_env.bNoRandomSeed = startupParams.bNoRandom;
m_env.bNoAssertDialog = false;
m_bNoCrashDialog = gEnv->IsDedicated();
@@ -1754,16 +1719,10 @@ AZ_POP_DISABLE_WARNING
m_bPreviewMode = startupParams.bPreview;
m_bTestMode = startupParams.bTestMode;
m_pUserCallback = startupParams.pUserCallback;
m_bMinimal = startupParams.bMinimal;
#if defined(CVARS_WHITELIST)
m_pCVarsWhitelist = startupParams.pCVarsWhitelist;
#endif // defined(CVARS_WHITELIST)
m_bDedicatedServer = startupParams.bDedicatedServer;
m_currentLanguageAudio = "";
memcpy(gEnv->pProtectedFunctions, startupParams.pProtectedFunctions, sizeof(startupParams.pProtectedFunctions));
#if !defined(CONSOLE)
m_env.SetIsEditor(m_bEditor);
m_env.SetIsEditorGameMode(false);
@@ -1771,7 +1730,6 @@ AZ_POP_DISABLE_WARNING
#endif
m_env.SetToolMode(startupParams.bToolMode);
m_env.bIsOutOfMemory = false;
if (m_bEditor)
{
@@ -1935,23 +1893,6 @@ AZ_POP_DISABLE_WARNING
// so we log this immediately after setting the log filename
LogVersion();
//here we should be good to ask Crypak to do something
// Initialise after pLog and CPU feature initialization
// AND after console creation (Editor only)
// May need access to engine folder .pak files
gEnv->pThreadManager->GetThreadConfigManager()->LoadConfig("config/engine_core.thread_config");
if (m_bEditor)
{
gEnv->pThreadManager->GetThreadConfigManager()->LoadConfig("config/engine_sandbox.thread_config");
}
// Setup main thread
void* pThreadHandle = 0; // Let system figure out thread handle
gEnv->pThreadManager->RegisterThirdPartyThread(pThreadHandle, "Main");
m_env.pProfileLogSystem = new CProfileLogSystem();
bool devModeEnable = true;
#if defined(_RELEASE)
@@ -1967,22 +1908,6 @@ AZ_POP_DISABLE_WARNING
SetDevMode(devModeEnable);
//////////////////////////////////////////////////////////////////////////
// CREATE NOTIFICATION NETWORK
//////////////////////////////////////////////////////////////////////////
m_pNotificationNetwork = nullptr;
#ifndef _RELEASE
#ifndef LINUX
if (!startupParams.bMinimal)
{
m_pNotificationNetwork = CNotificationNetwork::Create();
}
#endif//LINUX
#endif // _RELEASE
InlineInitializationProcessing("CSystem::Init NotificationNetwork");
//////////////////////////////////////////////////////////////////////////
// CREATE CONSOLE
//////////////////////////////////////////////////////////////////////////
@@ -2051,8 +1976,6 @@ AZ_POP_DISABLE_WARNING
// CPU features detection.
m_pCpu = new CCpuFeatures;
m_pCpu->Detect();
m_env.pi.numCoresAvailableToProcess = m_pCpu->GetCPUCount();
m_env.pi.numLogicalProcessors = m_pCpu->GetLogicalCPUCount();
// Check hard minimum CPU requirements
if (!CheckCPURequirements(m_pCpu, this))
@@ -2102,17 +2025,15 @@ AZ_POP_DISABLE_WARNING
}
{
ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetCVarsWhiteListConfigSink();
// We have to load this file again since first time we did it without devmode
LoadConfiguration(m_systemConfigName.c_str(), pCVarsWhiteListConfigSink);
LoadConfiguration(m_systemConfigName.c_str());
// Optional user defined overrides
LoadConfiguration("user.cfg", pCVarsWhiteListConfigSink);
LoadConfiguration("user.cfg");
#if defined(ENABLE_STATS_AGENT)
if (m_pCmdLine->FindArg(eCLAT_Pre, "useamblecfg"))
{
LoadConfiguration("amble.cfg", pCVarsWhiteListConfigSink);
LoadConfiguration("amble.cfg");
}
#endif
}
@@ -2159,7 +2080,7 @@ AZ_POP_DISABLE_WARNING
InlineInitializationProcessing("CSystem::Init LoadConfigurations");
#ifdef WIN32
if ((g_cvars.sys_WER) && (!startupParams.bMinimal))
if ((g_cvars.sys_WER))
{
SetUnhandledExceptionFilter(CryEngineExceptionFilterWER);
}
@@ -2169,7 +2090,6 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// Localization
//////////////////////////////////////////////////////////////////////////
if (!startupParams.bMinimal)
{
InitLocalization();
}
@@ -2187,7 +2107,6 @@ AZ_POP_DISABLE_WARNING
//////////////////////////////////////////////////////////////////////////
// AUDIO
//////////////////////////////////////////////////////////////////////////
if (!startupParams.bMinimal)
{
if (InitAudioSystem(startupParams))
{
@@ -2210,12 +2129,6 @@ AZ_POP_DISABLE_WARNING
m_pUserCallback->OnInitProgress("First time asset processing - may take a minute...");
}
#ifdef SOFTCODE_SYSTEM_ENABLED
m_env.pSoftCodeMgr = new SoftCodeMgr();
#else
m_env.pSoftCodeMgr = nullptr;
#endif
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
// System cursor
@@ -2225,8 +2138,7 @@ AZ_POP_DISABLE_WARNING
// - System cursor has to be enabled manually by the Game if needed; the custom UiCursor will typically be used instead
if (!gEnv->IsDedicated() &&
!gEnv->IsEditor() &&
!startupParams.bTesting)
!gEnv->IsEditor())
{
AzFramework::InputSystemCursorRequestBus::Event(AzFramework::InputDeviceMouse::Id,
&AzFramework::InputSystemCursorRequests::SetSystemCursorState,
@@ -2322,27 +2234,6 @@ AZ_POP_DISABLE_WARNING
InlineInitializationProcessing("CSystem::Init ZStdDecompressor");
//////////////////////////////////////////////////////////////////////////
// Initialize task threads.
//////////////////////////////////////////////////////////////////////////
{
m_pThreadTaskManager->InitThreads();
SetAffinity();
AZ_Assert(CryMemory::IsHeapValid(), "CryMemory heap must be valid before initializing VTune.");
if (strstr(startupParams.szSystemCmdLine, "-VTUNE") != 0 || g_cvars.sys_vtune != 0)
{
if (!InitVTuneProfiler())
{
return false;
}
}
}
InlineInitializationProcessing("CSystem::Init InitTaskThreads");
if (m_env.pLyShine)
{
m_env.pLyShine->PostInit();
@@ -2366,8 +2257,6 @@ AZ_POP_DISABLE_WARNING
}
}
EnableFloatExceptions(g_cvars.sys_float_exceptions);
MarkThisThreadForDebugging("Main");
}
InlineInitializationProcessing("CSystem::Init End");
@@ -2422,8 +2311,7 @@ static void LoadConfigurationCmd(IConsoleCmdArgs* pParams)
return;
}
ILoadConfigurationEntrySink* pCVarsWhiteListConfigSink = GetISystem()->GetCVarsWhiteListConfigSink();
GetISystem()->LoadConfiguration(string("Config/") + pParams->GetArg(1), pCVarsWhiteListConfigSink);
GetISystem()->LoadConfiguration(string("Config/") + pParams->GetArg(1));
}
@@ -2648,20 +2536,6 @@ void CmdDrillToFile(IConsoleCmdArgs* pArgs)
}
}
void ChangeLogAllocations(ICVar* pVal)
{
g_iTraceAllocations = pVal->GetIVal();
if (g_iTraceAllocations == 2)
{
IDebugCallStack::instance()->StartMemLog();
}
else
{
IDebugCallStack::instance()->StopMemLog();
}
}
//////////////////////////////////////////////////////////////////////////
void CSystem::CreateSystemVars()
{
@@ -2719,9 +2593,6 @@ void CSystem::CreateSystemVars()
m_cvAIUpdate = REGISTER_INT("ai_NoUpdate", 0, VF_CHEAT, "Disables AI system update when 1");
m_iTraceAllocations = g_iTraceAllocations;
REGISTER_CVAR2_CB("sys_logallocations", &m_iTraceAllocations, m_iTraceAllocations, VF_DUMPTODISK, "Save allocation call stack", ChangeLogAllocations);
m_cvMemStats = REGISTER_INT("MemStats", 0, 0,
"0/x=refresh rate in milliseconds\n"
"Use 1000 to switch on and 0 to switch off\n"
@@ -2860,16 +2731,6 @@ void CSystem::CreateSystemVars()
m_sys_TaskThread_CPU[5] = REGISTER_INT("sys_TaskThread5_CPU", 1, 0,
"Specifies the physical CPU index taskthread5 will run on");
//if physics thread is excluded all locks inside are mapped to NO_LOCK
//var must be not visible to accidentally get enabled
#if defined(EXCLUDE_PHYSICS_THREAD)
m_sys_physics_CPU = REGISTER_INT("sys_physics_CPU_disabled", 0, 0,
"Specifies the physical CPU index physics will run on");
#else
m_sys_physics_CPU = REGISTER_INT("sys_physics_CPU", 1, 0,
"Specifies the physical CPU index physics will run on");
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMINIT_CPP_SECTION_12
#include AZ_RESTRICTED_FILE(SystemInit_cpp)
@@ -3033,7 +2894,6 @@ void CSystem::CreateSystemVars()
"0=off / 1=enabled");
*/
REGISTER_CVAR2("sys_AI", &g_cvars.sys_ai, 1, 0, "Enables AI Update");
REGISTER_CVAR2("sys_physics", &g_cvars.sys_physics, 1, 0, "Enables Physics Update");
REGISTER_CVAR2("sys_entities", &g_cvars.sys_entitysystem, 1, 0, "Enables Entities Update");
REGISTER_CVAR2("sys_trackview", &g_cvars.sys_trackview, 1, 0, "Enables TrackView Update");
@@ -3068,10 +2928,6 @@ void CSystem::CreateSystemVars()
REGISTER_STRING("dlc_directory", "", 0, "Holds the path to the directory where DLC should be installed to and read from");
#if defined(MAP_LOADING_SLICING)
CreateSystemScheduler(this);
#endif // defined(MAP_LOADING_SLICING)
#if defined(WIN32) || defined(WIN64)
REGISTER_INT("sys_screensaver_allowed", 0, VF_NULL, "Specifies if screen saver is allowed to start up while the game is running.");
#endif
-48
View File
@@ -39,8 +39,6 @@
#include <ILevelSystem.h>
#include <LyShine/ILyShine.h>
#include "ThreadInfo.h"
#include <LoadScreenBus.h>
#if defined(AZ_RESTRICTED_PLATFORM)
@@ -90,52 +88,6 @@ void CSystem::OnScene3DEnd()
}
}
//! Update screen and call some important tick functions during loading.
void CSystem::SynchronousLoadingTick([[maybe_unused]] const char* pFunc, [[maybe_unused]] int line)
{
LOADING_TIME_PROFILE_SECTION;
if (gEnv && gEnv->bMultiplayer && !gEnv->IsEditor())
{
//UpdateLoadingScreen currently contains a couple of tick functions that need to be called regularly during the synchronous level loading,
//when the usual engine and game ticks are suspended.
UpdateLoadingScreen();
#if defined(MAP_LOADING_SLICING)
GetISystemScheduler()->SliceAndSleep(pFunc, line);
#endif
}
}
//////////////////////////////////////////////////////////////////////////
void CSystem::UpdateLoadingScreen()
{
// Do not update the network thread from here - it will cause context corruption - use the NetworkStallTicker thread system
if (GetCurrentThreadId() != gEnv->mMainThreadId)
{
return;
}
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMRENDERER_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(SystemRender_cpp)
#endif
#if AZ_LOADSCREENCOMPONENT_ENABLED
EBUS_EVENT(LoadScreenBus, UpdateAndRender);
#endif // if AZ_LOADSCREENCOMPONENT_ENABLED
if (!m_bEditor && !IsQuitting())
{
if (m_pProgressListener)
{
m_pProgressListener->OnLoadingProgress(0);
}
}
}
//////////////////////////////////////////////////////////////////////////
void CSystem::DisplayErrorMessage(const char* acMessage,
@@ -1,211 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
// Description : Implementation of the CSystemScheduler class
#include "CrySystem_precompiled.h"
#include "ProjectDefines.h"
#if defined(MAP_LOADING_SLICING)
#include "SystemScheduler.h"
#include "MiniQueue.h"
#include "ClientHandler.h"
#include "ServerHandler.h"
void CreateSystemScheduler(CSystem* pSystem)
{
gEnv->pSystemScheduler = new CSystemScheduler(pSystem);
}
CSystemScheduler::CSystemScheduler(CSystem* pSystem)
: m_pSystem(pSystem)
, m_lastSliceCheckTime(0.0f)
, m_sliceLoadingRef(0)
{
int defaultSchedulingMode = 0;
if (gEnv->IsDedicated())
{
defaultSchedulingMode = 2;
}
m_svSchedulingMode = REGISTER_INT("sv_scheduling", defaultSchedulingMode, 0, "Scheduling mode\n"
" 0: Normal mode\n"
" 1: Client\n"
" 2: Server\n");
m_svSchedulingBucket = REGISTER_INT("sv_schedulingBucket", 0, 0, "Scheduling bucket\n");
m_svSchedulingAffinity = REGISTER_INT("sv_SchedulingAffinity", 0, 0, "Scheduling affinity\n");
m_svSchedulingClientTimeout = REGISTER_INT("sv_schedulingClientTimeout", 1000, 0, "Client wait server\n");
m_svSchedulingServerTimeout = REGISTER_INT("sv_schedulingServerTimeout", 100, 0, "Server wait server\n");
#if defined(MAP_LOADING_SLICING)
m_svSliceLoadEnable = REGISTER_INT("sv_sliceLoadEnable", 1, 0, "Enable/disable slice loading logic\n");
;
m_svSliceLoadBudget = REGISTER_INT("sv_sliceLoadBudget", 10, 0, "Slice budget\n");
;
m_svSliceLoadLogging = REGISTER_INT("sv_sliceLoadLogging", 0, 0, "Enable/disable slice loading logging\n");
#endif
m_pLastSliceName = "INACTIVE";
m_lastSliceLine = 0;
}
CSystemScheduler::~CSystemScheduler(void)
{
}
void CSystemScheduler::SliceLoadingBegin()
{
m_lastSliceCheckTime = gEnv->pTimer->GetAsyncTime();
m_sliceLoadingRef++;
m_pLastSliceName = "START";
m_lastSliceLine = 0;
}
void CSystemScheduler::SliceLoadingEnd()
{
m_sliceLoadingRef--;
m_pLastSliceName = "INACTIVE";
m_lastSliceLine = 0;
}
void CSystemScheduler::SliceAndSleep(const char* sliceName, int line)
{
#if defined(MAP_LOADING_SLICING)
if (!gEnv->IsDedicated())
{
return;
}
if (!m_sliceLoadingRef)
{
return;
}
if (!m_svSliceLoadEnable->GetIVal())
{
return;
}
SchedulingModeUpdate();
CTimeValue currTime = gEnv->pTimer->GetAsyncTime();
float sliceBudget = CLAMP(m_svSliceLoadBudget->GetFVal(), 0, 1000.0f / m_pSystem->GetDedicatedMaxRate()->GetFVal());
bool doSleep = true;
if ((currTime - m_pSystem->GetLastTickTime()).GetMilliSeconds() < sliceBudget)
{
m_lastSliceCheckTime = currTime;
doSleep = false;
}
if (doSleep)
{
if (m_svSliceLoadLogging->GetIVal())
{
float diff = (currTime - m_lastSliceCheckTime).GetMilliSeconds();
if (diff > sliceBudget)
{
CryLogAlways("[SliceAndSleep]: Interval between slice [%s:%i] and [%s:%i] was [%f] out of budget [%f]", m_pLastSliceName, m_lastSliceLine, sliceName, line, diff, sliceBudget);
}
}
m_pSystem->SleepIfNeeded();
}
m_pLastSliceName = sliceName;
m_lastSliceLine = line;
#endif
}
void CSystemScheduler::SchedulingSleepIfNeeded()
{
if (!gEnv->IsDedicated())
{
return;
}
SchedulingModeUpdate();
m_pSystem->SleepIfNeeded();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Scheduling mode routines
//
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
//
// Scheduling mode update logic
//
///////////////////////////////////////////////////////////////////////////////////////////////////
void CSystemScheduler::SchedulingModeUpdate()
{
static std::unique_ptr<ClientHandler> m_client;
static std::unique_ptr<ServerHandler> m_server;
if (int scheduling = m_svSchedulingMode->GetIVal())
{
if (scheduling == 1) //client
{
if (!m_client.get())
{
m_server.reset();
m_client.reset(new ClientHandler(m_svSchedulingBucket->GetString(), m_svSchedulingAffinity->GetIVal(), m_svSchedulingClientTimeout->GetIVal()));
}
if (m_client->Sync())
{
return;
}
}
else if (scheduling == 2) //server
{
if (!m_server.get())
{
m_client.reset();
m_server.reset(new ServerHandler(m_svSchedulingBucket->GetString(), m_svSchedulingAffinity->GetIVal(), m_svSchedulingServerTimeout->GetIVal()));
}
if (m_server->Sync())
{
return;
}
}
}
else
{
m_client.reset();
m_server.reset();
}
}
#endif // defined(MAP_LOADING_SLICING)
extern "C" void SliceAndSleep(const char* pFunc, int line)
{
if (GetISystemScheduler())
{
GetISystemScheduler()->SliceAndSleep(pFunc, line);
}
}
@@ -1,63 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_SYSTEMSCHEDULER_H
#define CRYINCLUDE_CRYSYSTEM_SYSTEMSCHEDULER_H
#pragma once
#include "System.h"
#include <ISystemScheduler.h>
class CSystemScheduler
: public ISystemScheduler
{
public:
CSystemScheduler(CSystem* pSystem);
virtual ~CSystemScheduler(void);
// ISystemScheduler
virtual void SliceAndSleep(const char* sliceName, int line);
virtual void SliceLoadingBegin();
virtual void SliceLoadingEnd();
virtual void SchedulingSleepIfNeeded(void);
// ~ISystemScheduler
protected:
void SchedulingModeUpdate(void);
private:
CSystem* m_pSystem;
ICVar* m_svSchedulingAffinity;
ICVar* m_svSchedulingClientTimeout;
ICVar* m_svSchedulingServerTimeout;
ICVar* m_svSchedulingBucket;
ICVar* m_svSchedulingMode;
ICVar* m_svSliceLoadEnable;
ICVar* m_svSliceLoadBudget;
ICVar* m_svSliceLoadLogging;
CTimeValue m_lastSliceCheckTime;
int m_sliceLoadingRef;
const char* m_pLastSliceName;
int m_lastSliceLine;
};
// Summary:
// Creates the system scheduler interface.
void CreateSystemScheduler(CSystem* pSystem);
#endif // CRYINCLUDE_CRYSYSTEM_SYSTEMSCHEDULER_H
@@ -1,697 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "System.h"
#include "ThreadConfigManager.h"
#include "IThreadManager.h"
#include <CryCustomTypes.h>
#include "CryUtils.h"
#define INCLUDED_FROM_SYSTEM_THREADING_CPP
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define SYSTEMTHREADING_CPP_SECTION_1 1
#define SYSTEMTHREADING_CPP_SECTION_2 2
#define SYSTEMTHREADING_CPP_SECTION_3 3
#endif
#if defined(WIN32) || defined(WIN64)
#include "CryThreadUtil_win32_thread.h"
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMTHREADING_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(SystemThreading_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
#include "CryThreadUtil_pthread.h"
#endif
#undef INCLUDED_FROM_SYSTEM_THREADING_CPP
//////////////////////////////////////////////////////////////////////////
static void ApplyThreadConfig(CryThreadUtil::TThreadHandle pThreadHandle, const SThreadConfig& rThreadDesc)
{
// Apply config
if (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_ThreadName)
{
CryThreadUtil::CrySetThreadName(pThreadHandle, rThreadDesc.szThreadName);
}
if (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_Affinity)
{
CryThreadUtil::CrySetThreadAffinityMask(pThreadHandle, rThreadDesc.affinityFlag);
}
if (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_Priority)
{
CryThreadUtil::CrySetThreadPriority(pThreadHandle, rThreadDesc.priority);
}
if (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_PriorityBoost)
{
CryThreadUtil::CrySetThreadPriorityBoost(pThreadHandle, !rThreadDesc.bDisablePriorityBoost);
}
CryComment("<ThreadInfo> Configured thread \"%s\" %s | AffinityMask: %u %s | Priority: %i %s | PriorityBoost: %s %s",
rThreadDesc.szThreadName, (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_ThreadName) ? "" : "(ignored)",
rThreadDesc.affinityFlag, (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_Affinity) ? "" : "(ignored)",
rThreadDesc.priority, (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_Priority) ? "" : "(ignored)",
!rThreadDesc.bDisablePriorityBoost ? "enabled" : "disabled", (rThreadDesc.paramActivityFlag & SThreadConfig::eThreadParamFlag_PriorityBoost) ? "" : "(ignored)");
}
//////////////////////////////////////////////////////////////////////////
struct SThreadMetaData
: public CMultiThreadRefCount
{
SThreadMetaData()
: m_pThreadTask(0)
, m_threadHandle(0)
, m_threadId(0)
, m_threadName("Cry_UnnamedThread")
, m_isRunning(false)
{
}
IThread* m_pThreadTask; // Pointer to thread task to be executed
CThreadManager* m_pThreadMngr; // Pointer to thread manager
CryThreadUtil::TThreadHandle m_threadHandle; // Thread handle
threadID m_threadId; // The active threadId, 0 = Invalid Id
CryMutex m_threadExitMutex; // Mutex used to safeguard thread exit condition signaling
CryConditionVariable m_threadExitCondition; // Signaled when the thread is about to exit
CryFixedStringT<THREAD_NAME_LENGTH_MAX> m_threadName; // Thread name
volatile bool m_isRunning; // Indicates the thread is not ready to exit yet
};
//////////////////////////////////////////////////////////////////////////
class CThreadManager
: public IThreadManager
{
public:
// <interfuscator:shuffle>
virtual ~CThreadManager()
{
}
virtual bool SpawnThread(IThread* pThread, const char* sThreadName, ...) override;
virtual bool JoinThread(IThread* pThreadTask, EJoinMode eJoinMode) override;
virtual bool RegisterThirdPartyThread(void* pThreadHandle, const char* sThreadName, ...) override;
virtual bool UnRegisterThirdPartyThread(const char* sThreadName, ...) override;
virtual const char* GetThreadName(threadID nThreadId) override;
virtual threadID GetThreadId(const char* sThreadName, ...) override;
virtual void ForEachOtherThread(IThreadManager::ThreadModifFunction fpThreadModiFunction, void* pFuncData = 0) override;
virtual void EnableFloatExceptions(EFPE_Severity eFPESeverity, threadID nThreadId = 0) override;
virtual void EnableFloatExceptionsForEachOtherThread(EFPE_Severity eFPESeverity) override;
virtual uint GetFloatingPointExceptionMask() override;
virtual void SetFloatingPointExceptionMask(uint nMask) override;
IThreadConfigManager* GetThreadConfigManager() override
{
return &m_threadConfigManager;
}
// </interfuscator:shuffle>
private:
#if defined(WIN32) || defined(WIN64)
static unsigned __stdcall RunThread(void* thisPtr);
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMTHREADING_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(SystemThreading_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
static void* RunThread(void* thisPtr);
#endif
private:
bool UnregisterThread(IThread* pThreadTask);
bool SpawnThreadImpl(IThread* pThread, const char* sThreadName);
bool RegisterThirdPartyThreadImpl(CryThreadUtil::TThreadHandle pThreadHandle, const char* sThreadName);
bool UnRegisterThirdPartyThreadImpl(const char* sThreadName);
threadID GetThreadIdImpl(const char* sThreadName);
private:
// Note: Guard SThreadMetaData with a _smart_ptr and lock to ensure that a thread waiting to be signaled by another still
// has access to valid SThreadMetaData even though the other thread terminated and as a result unregistered itself from the CThreadManager.
// An example would be the join method. Where one thread waits on a signal from an other thread to terminate and release its SThreadMetaData,
// sharing the same SThreadMetaData condition variable.
typedef std::map<IThread*, _smart_ptr<SThreadMetaData> > SpawnedThreadMap;
typedef std::map<IThread*, _smart_ptr<SThreadMetaData> >::iterator SpawnedThreadMapIter;
typedef std::map<IThread*, _smart_ptr<SThreadMetaData> >::const_iterator SpawnedThreadMapConstIter;
typedef std::pair<IThread*, _smart_ptr<SThreadMetaData> > ThreadMapPair;
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, _smart_ptr<SThreadMetaData> > SpawnedThirdPartyThreadMap;
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, _smart_ptr<SThreadMetaData> >::iterator SpawnedThirdPartyThreadMapIter;
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, _smart_ptr<SThreadMetaData> >::const_iterator SpawnedThirdPartyThreadMapConstIter;
typedef std::pair<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, _smart_ptr<SThreadMetaData> > ThirdPartyThreadMapPair;
CryCriticalSection m_spawnedThreadsLock; // Use lock for the rare occasion a thread is created/destroyed
SpawnedThreadMap m_spawnedThreads; // Holds information of all spawned threads (through this system)
CryCriticalSection m_spawnedThirdPartyThreadsLock; // Use lock for the rare occasion a thread is created/destroyed
SpawnedThirdPartyThreadMap m_spawnedThirdPartyThread; // Holds information of all registered 3rd party threads (through this system)
CThreadConfigManager m_threadConfigManager;
};
//////////////////////////////////////////////////////////////////////////
#if defined(WIN32) || defined(WIN64)
unsigned __stdcall CThreadManager::RunThread(void* thisPtr)
#define AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMTHREADING_CPP_SECTION_3
#include AZ_RESTRICTED_FILE(SystemThreading_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#else
void* CThreadManager::RunThread(void* thisPtr)
#endif
{
// Check that we are not spawning a thread before gEnv->pSystem has been set
// Otherwise we cannot enable floating point exceptions
if (!gEnv || !gEnv->pSystem)
{
CryFatalError("[Error]: CThreadManager::RunThread requires gEnv->pSystem to be initialized.");
}
IThreadConfigManager* pThreadConfigMngr = gEnv->pThreadManager->GetThreadConfigManager();
SThreadMetaData* pThreadData = reinterpret_cast<SThreadMetaData*>(thisPtr);
pThreadData->m_threadId = CryThreadUtil::CryGetCurrentThreadId();
// Apply config
const SThreadConfig* pThreadConfig = pThreadConfigMngr->GetThreadConfig(pThreadData->m_threadName.c_str());
ApplyThreadConfig(pThreadData->m_threadHandle, *pThreadConfig);
// Config not found, append thread name with no config tag
if (pThreadConfig == pThreadConfigMngr->GetDefaultThreadConfig())
{
CryFixedStringT<THREAD_NAME_LENGTH_MAX> tmpString(pThreadData->m_threadName);
const char* cNoConfigAppendix = "(NoCfgFound)";
int nNumCharsToReplace = strlen(cNoConfigAppendix);
// Replace thread name ending
if (pThreadData->m_threadName.size() > THREAD_NAME_LENGTH_MAX - nNumCharsToReplace)
{
tmpString.replace(THREAD_NAME_LENGTH_MAX - nNumCharsToReplace, nNumCharsToReplace, cNoConfigAppendix, nNumCharsToReplace);
}
else
{
tmpString.append(cNoConfigAppendix);
}
// Print to log
if (pThreadConfigMngr->ConfigLoaded())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> No Thread config found for thread %s using ... default config.", pThreadData->m_threadName.c_str());
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo> Thread config not loaded yet. Hence no thread config was found for thread %s ... using default config.", pThreadData->m_threadName.c_str());
}
// Rename Thread
CryThreadUtil::CrySetThreadName(pThreadData->m_threadHandle, tmpString.c_str());
}
// Enable FPEs
gEnv->pThreadManager->EnableFloatExceptions((EFPE_Severity)g_cvars.sys_float_exceptions);
// Execute thread code
pThreadData->m_pThreadTask->ThreadEntry();
// Disable FPEs
gEnv->pThreadManager->EnableFloatExceptions(eFPE_None);
// Signal imminent thread end
pThreadData->m_threadExitMutex.Lock();
pThreadData->m_isRunning = false;
pThreadData->m_threadExitCondition.Notify();
pThreadData->m_threadExitMutex.Unlock();
// Unregister thread
// Note: Unregister after m_threadExitCondition.Notify() to ensure pThreadData is still valid
pThreadData->m_pThreadMngr->UnregisterThread(pThreadData->m_pThreadTask);
CryThreadUtil::CryThreadExitCall();
return NULL;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::JoinThread(IThread* pThreadTask, EJoinMode eJoinMode)
{
// Get thread object
_smart_ptr<SThreadMetaData> pThreadImpl = 0;
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapIter res = m_spawnedThreads.find(pThreadTask);
if (res == m_spawnedThreads.end())
{
// Thread has already finished and unregistered itself.
// As it is complete we cannot wait for it.
// Hence return true.
return true;
}
pThreadImpl = res->second; // Keep object alive
}
// On try join, exit if the thread is not in a state to exit
if (eJoinMode == eJM_TryJoin && pThreadImpl->m_isRunning)
{
return false;
}
// Wait for completion of the target thread exit condition
pThreadImpl->m_threadExitMutex.Lock();
while (pThreadImpl->m_isRunning)
{
pThreadImpl->m_threadExitCondition.Wait(pThreadImpl->m_threadExitMutex);
}
pThreadImpl->m_threadExitMutex.Unlock();
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::UnregisterThread(IThread* pThreadTask)
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapIter res = m_spawnedThreads.find(pThreadTask);
if (res == m_spawnedThreads.end())
{
// Duplicate thread deletion
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: UnregisterThread: Unable to unregister thread. Thread name could not be found. Double deletion? IThread pointer: %p", pThreadTask);
return false;
}
m_spawnedThreads.erase(res);
return true;
}
//////////////////////////////////////////////////////////////////////////
const char* CThreadManager::GetThreadName(threadID nThreadId)
{
// Loop over internally spawned threads
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapConstIter iter = m_spawnedThreads.begin();
SpawnedThreadMapConstIter iterEnd = m_spawnedThreads.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadId == nThreadId)
{
return iter->second->m_threadName.c_str();
}
}
}
// Loop over third party threads
{
AUTO_LOCK(m_spawnedThirdPartyThreadsLock);
SpawnedThirdPartyThreadMapConstIter iter = m_spawnedThirdPartyThread.begin();
SpawnedThirdPartyThreadMapConstIter iterEnd = m_spawnedThirdPartyThread.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadId == nThreadId)
{
return iter->second->m_threadName.c_str();
}
}
}
return "";
}
//////////////////////////////////////////////////////////////////////////
void CThreadManager::ForEachOtherThread(IThreadManager::ThreadModifFunction fpThreadModiFunction, void* pFuncData)
{
threadID nCurThreadId = CryThreadUtil::CryGetCurrentThreadId();
// Loop over internally spawned threads
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapConstIter iter = m_spawnedThreads.begin();
SpawnedThreadMapConstIter iterEnd = m_spawnedThreads.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadId != nCurThreadId)
{
fpThreadModiFunction(iter->second->m_threadId, pFuncData);
}
}
}
// Loop over third party threads
{
AUTO_LOCK(m_spawnedThirdPartyThreadsLock);
SpawnedThirdPartyThreadMapConstIter iter = m_spawnedThirdPartyThread.begin();
SpawnedThirdPartyThreadMapConstIter iterEnd = m_spawnedThirdPartyThread.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadId != nCurThreadId)
{
fpThreadModiFunction(iter->second->m_threadId, pFuncData);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::SpawnThread(IThread* pThreadTask, const char* sThreadName, ...)
{
va_list args;
va_start(args, sThreadName);
// Format thread name
char strThreadName[THREAD_NAME_LENGTH_MAX];
const int cNumCharsNeeded = azvsnprintf(strThreadName, CRY_ARRAY_COUNT(strThreadName), sThreadName, args);
if (cNumCharsNeeded > THREAD_NAME_LENGTH_MAX - 1 || cNumCharsNeeded < 0)
{
strThreadName[THREAD_NAME_LENGTH_MAX - 1] = '\0'; // The WinApi only null terminates if strLen < bufSize
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: ThreadName \"%s\" has been truncated. Max characters allowed: %i. ", strThreadName, THREAD_NAME_LENGTH_MAX - 1);
}
// Spawn thread
bool ret = SpawnThreadImpl(pThreadTask, strThreadName);
if (!ret)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: CSystem::SpawnThread error spawning thread: \"%s\" ", strThreadName);
}
va_end(args);
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::SpawnThreadImpl(IThread* pThreadTask, const char* sThreadName)
{
if (pThreadTask == NULL)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_ERROR, "<ThreadInfo>: SpawnThread '%s' ThreadTask is NULL : ignoring", sThreadName);
return false;
}
// Init thread meta data
SThreadMetaData* pThreadMetaData = new SThreadMetaData();
pThreadMetaData->m_pThreadTask = pThreadTask;
pThreadMetaData->m_pThreadMngr = this;
pThreadMetaData->m_threadName = sThreadName;
// Add thread to map
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapIter res = m_spawnedThreads.find(pThreadTask);
if (res != m_spawnedThreads.end())
{
// Thread with same name already spawned
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: SpawnThread: Thread \"%s\" already exists.", sThreadName);
delete pThreadMetaData;
return false;
}
// Insert thread data
m_spawnedThreads.insert(ThreadMapPair(pThreadTask, pThreadMetaData));
}
// Load config if we can and if no config has been defined to be loaded
const SThreadConfig* pThreadConfig = gEnv->pThreadManager->GetThreadConfigManager()->GetThreadConfig(sThreadName);
// Create thread description
CryThreadUtil::SThreadCreationDesc desc = {sThreadName, RunThread, pThreadMetaData, pThreadConfig->paramActivityFlag & SThreadConfig::eThreadParamFlag_StackSize ? pThreadConfig->stackSizeBytes : 0};
// Spawn new thread
pThreadMetaData->m_isRunning = CryThreadUtil::CryCreateThread(&(pThreadMetaData->m_threadHandle), desc);
// Validate thread creation
if (!pThreadMetaData->m_isRunning)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: SpawnThread: Could not spawn thread \"%s\" .", sThreadName);
// Remove thread from map (also releases SThreadMetaData _smart_ptr)
m_spawnedThreads.erase(m_spawnedThreads.find(pThreadTask));
return false;
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::RegisterThirdPartyThread(void* pThreadHandle, const char* sThreadName, ...)
{
if (!pThreadHandle)
{
pThreadHandle = reinterpret_cast<void*>(CryThreadUtil::CryGetCurrentThreadHandle());
}
va_list args;
va_start(args, sThreadName);
// Format thread name
char strThreadName[THREAD_NAME_LENGTH_MAX];
const int cNumCharsNeeded = azvsnprintf(strThreadName, CRY_ARRAY_COUNT(strThreadName), sThreadName, args);
if (cNumCharsNeeded > THREAD_NAME_LENGTH_MAX - 1)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: ThreadName \"%s\" has been truncated. Max characters allowed: %i. ", strThreadName, THREAD_NAME_LENGTH_MAX - 1);
}
// Register 3rd party thread
bool ret = RegisterThirdPartyThreadImpl(reinterpret_cast<CryThreadUtil::TThreadHandle>(pThreadHandle), strThreadName);
va_end(args);
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::RegisterThirdPartyThreadImpl(CryThreadUtil::TThreadHandle threadHandle, const char* sThreadName)
{
if (strcmp(sThreadName, "") == 0)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: CThreadManager::RegisterThirdPartyThread error registering third party thread. No name provided.");
return false;
}
// Init thread meta data
SThreadMetaData* pThreadMetaData = new SThreadMetaData();
pThreadMetaData->m_pThreadTask = 0;
pThreadMetaData->m_pThreadMngr = this;
pThreadMetaData->m_threadName = sThreadName;
pThreadMetaData->m_threadHandle = CryThreadUtil::CryDuplicateThreadHandle(threadHandle); // Ensure that we are not storing a pseudo handle
pThreadMetaData->m_threadId = CryThreadUtil::CryGetThreadId(pThreadMetaData->m_threadHandle);
{
AUTO_LOCK(m_spawnedThirdPartyThreadsLock);
// Check for duplicate
SpawnedThirdPartyThreadMapConstIter res = m_spawnedThirdPartyThread.find(sThreadName);
if (res != m_spawnedThirdPartyThread.end())
{
CryFatalError("CThreadManager::RegisterThirdPartyThread - Unable to register thread \"%s\""
"because another third party thread with the same name \"%s\" has already been registered with ThreadHandle: %p",
sThreadName, res->second->m_threadName.c_str(), reinterpret_cast<void*>(threadHandle));
delete pThreadMetaData;
return false;
}
// Insert thread data
m_spawnedThirdPartyThread.insert(ThirdPartyThreadMapPair(pThreadMetaData->m_threadName.c_str(), pThreadMetaData));
}
// Get thread config
const SThreadConfig* pThreadConfig = gEnv->pThreadManager->GetThreadConfigManager()->GetThreadConfig(sThreadName);
// Apply config (if not default config)
if (strcmp(pThreadConfig->szThreadName, sThreadName) == 0)
{
ApplyThreadConfig(threadHandle, *pThreadConfig);
}
// Update FP exception mask for 3rd party thread
if (pThreadMetaData->m_threadId)
{
CryThreadUtil::EnableFloatExceptions(pThreadMetaData->m_threadId, (EFPE_Severity)g_cvars.sys_float_exceptions);
}
return true;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::UnRegisterThirdPartyThread(const char* sThreadName, ...)
{
va_list args;
va_start(args, sThreadName);
// Format thread name
char strThreadName[THREAD_NAME_LENGTH_MAX];
const int cNumCharsNeeded = azvsnprintf(strThreadName, CRY_ARRAY_COUNT(strThreadName), sThreadName, args);
if (cNumCharsNeeded > THREAD_NAME_LENGTH_MAX - 1)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: ThreadName \"%s\" has been truncated. Max characters allowed: %i. ", strThreadName, THREAD_NAME_LENGTH_MAX - 1);
}
// Unregister 3rd party thread
bool ret = UnRegisterThirdPartyThreadImpl(strThreadName);
va_end(args);
return ret;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadManager::UnRegisterThirdPartyThreadImpl(const char* sThreadName)
{
AUTO_LOCK(m_spawnedThirdPartyThreadsLock);
SpawnedThirdPartyThreadMapIter res = m_spawnedThirdPartyThread.find(sThreadName);
if (res == m_spawnedThirdPartyThread.end())
{
// Duplicate thread deletion
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: UnRegisterThirdPartyThread: Unable to unregister thread. Thread name \"%s\" could not be found. Double deletion? ", sThreadName);
return false;
}
// Close thread handle
CryThreadUtil::CryCloseThreadHandle(res->second->m_threadHandle);
// Delete reference from container
m_spawnedThirdPartyThread.erase(res);
return true;
}
//////////////////////////////////////////////////////////////////////////
threadID CThreadManager::GetThreadId(const char* sThreadName, ...)
{
va_list args;
va_start(args, sThreadName);
// Format thread name
char strThreadName[THREAD_NAME_LENGTH_MAX];
const int cNumCharsNeeded = azvsnprintf(strThreadName, CRY_ARRAY_COUNT(strThreadName), sThreadName, args);
if (cNumCharsNeeded > THREAD_NAME_LENGTH_MAX - 1)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: ThreadName \"%s\" has been truncated. Max characters allowed: %i. ", strThreadName, THREAD_NAME_LENGTH_MAX - 1);
}
// Get thread name
threadID ret = GetThreadIdImpl(strThreadName);
va_end(args);
return ret;
}
//////////////////////////////////////////////////////////////////////////
threadID CThreadManager::GetThreadIdImpl(const char* sThreadName)
{
// Loop over internally spawned threads
{
AUTO_LOCK(m_spawnedThreadsLock);
SpawnedThreadMapConstIter iter = m_spawnedThreads.begin();
SpawnedThreadMapConstIter iterEnd = m_spawnedThreads.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadName.compare(sThreadName) == 0)
{
return iter->second->m_threadId;
}
}
}
// Loop over third party threads
{
AUTO_LOCK(m_spawnedThirdPartyThreadsLock);
SpawnedThirdPartyThreadMapConstIter iter = m_spawnedThirdPartyThread.begin();
SpawnedThirdPartyThreadMapConstIter iterEnd = m_spawnedThirdPartyThread.end();
for (; iter != iterEnd; ++iter)
{
if (iter->second->m_threadName.compare(sThreadName) == 0)
{
return iter->second->m_threadId;
}
}
}
return 0;
}
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
static void EnableFPExceptionsForThread(threadID nThreadId, void* pData)
{
EFPE_Severity eFPESeverity = *(EFPE_Severity*)pData;
CryThreadUtil::EnableFloatExceptions(nThreadId, eFPESeverity);
}
//////////////////////////////////////////////////////////////////////////
void CThreadManager::EnableFloatExceptions(EFPE_Severity eFPESeverity, threadID nThreadId /*=0*/)
{
CryThreadUtil::EnableFloatExceptions(nThreadId, eFPESeverity);
}
//////////////////////////////////////////////////////////////////////////
void CThreadManager::EnableFloatExceptionsForEachOtherThread(EFPE_Severity eFPESeverity)
{
ForEachOtherThread(EnableFPExceptionsForThread, &eFPESeverity);
}
//////////////////////////////////////////////////////////////////////////
uint CThreadManager::GetFloatingPointExceptionMask()
{
return CryThreadUtil::GetFloatingPointExceptionMask();
}
//////////////////////////////////////////////////////////////////////////
void CThreadManager::SetFloatingPointExceptionMask(uint nMask)
{
CryThreadUtil::SetFloatingPointExceptionMask(nMask);
}
//////////////////////////////////////////////////////////////////////////
void CSystem::InitThreadSystem()
{
m_pThreadManager = new CThreadManager();
m_env.pThreadManager = m_pThreadManager;
}
//////////////////////////////////////////////////////////////////////////
void CSystem::ShutDownThreadSystem()
{
SAFE_DELETE(m_pThreadManager);
}
-15
View File
@@ -46,8 +46,6 @@
#include <shlobj.h>
#endif
#include "IDebugCallStack.h"
#if defined(APPLE) || defined(LINUX)
#include <pwd.h>
#endif
@@ -752,13 +750,6 @@ void CSystem::FatalError(const char* format, ...)
}
// Dump callstack.
#endif
#if defined (WIN32)
//Triggers a fatal error, so the DebugCallstack can create the error.log and terminate the application
IDebugCallStack::instance()->FatalError(szBuffer);
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION SYSTEMWIN32_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(SystemWin32_cpp)
#endif
CryDebugBreak();
@@ -800,8 +791,6 @@ void CSystem::ReportBug([[maybe_unused]] const char* format, ...)
va_start(ArgList, format);
azvsnprintf(szBuffer + strlen(sPrefix), MAX_WARNING_LENGTH - strlen(sPrefix), format, ArgList);
va_end(ArgList);
IDebugCallStack::instance()->ReportBug(szBuffer);
#endif
}
@@ -910,10 +899,6 @@ void CSystem::LogSystemInfo()
OSVERSIONINFO OSVerInfo;
OSVerInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
// log Windows type
Win32SysInspect::GetOS(m_env.pi.winVer, m_env.pi.win64Bit, szBuffer, sizeof(szBuffer));
CryLogAlways(szBuffer);
// log system language
GetLocaleInfo(LOCALE_SYSTEM_DEFAULT, LOCALE_SENGLANGUAGE, szLanguageBuffer, sizeof(szLanguageBuffer));
azsprintf(szBuffer, "System language: %s", szLanguageBuffer);
@@ -1,577 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "ThreadConfigManager.h"
#include "IConsole.h"
#include "System.h"
#include <StringUtils.h>
#include <CryCustomTypes.h>
#include "CryUtils.h"
namespace
{
const char* sCurThreadConfigFilename = "";
const uint32 sPlausibleStackSizeLimitKB = (1024 * 100); // 100mb
}
//////////////////////////////////////////////////////////////////////////
CThreadConfigManager::CThreadConfigManager()
{
m_defaultConfig.szThreadName = "CryThread_Unnamed";
m_defaultConfig.stackSizeBytes = 0;
m_defaultConfig.affinityFlag = -1;
m_defaultConfig.priority = THREAD_PRIORITY_NORMAL;
m_defaultConfig.bDisablePriorityBoost = false;
m_defaultConfig.paramActivityFlag = (SThreadConfig::TThreadParamFlag)~0;
}
//////////////////////////////////////////////////////////////////////////
const SThreadConfig* CThreadConfigManager::GetThreadConfig(const char* szThreadName, ...)
{
va_list args;
va_start(args, szThreadName);
// Format thread name
char strThreadName[THREAD_NAME_LENGTH_MAX];
const int cNumCharsNeeded = azvsnprintf(strThreadName, CRY_ARRAY_COUNT(strThreadName), szThreadName, args);
if (cNumCharsNeeded > THREAD_NAME_LENGTH_MAX - 1)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: ThreadName \"%s\" has been truncated. Max characters allowed: %i. ", strThreadName, THREAD_NAME_LENGTH_MAX - 1);
}
// Get Thread Config
const SThreadConfig* retThreasdConfig = GetThreadConfigImpl(strThreadName);
va_end(args);
return retThreasdConfig;
}
//////////////////////////////////////////////////////////////////////////
const SThreadConfig* CThreadConfigManager::GetThreadConfigImpl(const char* szThreadName)
{
// Get thread config for platform
ThreadConfigMapConstIter threatRet = m_threadConfig.find(CryFixedStringT<THREAD_NAME_LENGTH_MAX>(szThreadName));
if (threatRet == m_threadConfig.end())
{
// Search in wildcard setups
ThreadConfigMapConstIter wildCardIter = m_wildcardThreadConfig.begin();
ThreadConfigMapConstIter wildCardIterEnd = m_wildcardThreadConfig.end();
for (; wildCardIter != wildCardIterEnd; ++wildCardIter)
{
if (CryStringUtils::MatchWildcard(szThreadName, wildCardIter->second.szThreadName))
{
// Store new thread config
SThreadConfig threadConfig = wildCardIter->second;
std::pair<ThreadConfigMapIter, bool> res;
res = m_threadConfig.insert(ThreadConfigMapPair(CryFixedStringT<THREAD_NAME_LENGTH_MAX>(szThreadName), threadConfig));
// Store name (ref to key)
SThreadConfig& rMapThreadConfig = res.first->second;
rMapThreadConfig.szThreadName = res.first->first.c_str();
// Return new thread config
return &res.first->second;
}
}
// Failure case, no match found
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadInfo>: Unable to find config for thread:%s", szThreadName);
return &m_defaultConfig;
}
// Return thread config
return &threatRet->second;
}
//////////////////////////////////////////////////////////////////////////
const SThreadConfig* CThreadConfigManager::GetDefaultThreadConfig() const
{
return &m_defaultConfig;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadConfigManager::LoadConfig(const char* pcPath)
{
// Adjust filename for OnDisk or in .pak file loading
char szFullPathBuf[AZ::IO::IArchive::MaxPath];
gEnv->pCryPak->AdjustFileName(pcPath, szFullPathBuf, AZ_ARRAY_SIZE(szFullPathBuf), 0);
// Open file
XmlNodeRef xmlRoot = GetISystem()->LoadXmlFromFile(szFullPathBuf);
if (!xmlRoot)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: File \"%s\" not found!", pcPath);
return false;
}
// Load config for active platform
sCurThreadConfigFilename = pcPath;
const char* strPlatformId = IdentifyPlatform();
CryFixedStringT<32> tmpPlatformStr;
bool retValue = false;
// Try load common platform settings
tmpPlatformStr.Format("%s_Common", strPlatformId);
LoadPlatformConfig(xmlRoot, tmpPlatformStr.c_str());
#if defined(CRY_PLATFORM_DESKTOP)
// Handle PC specifically as we do not know the core setup of the executing machine.
// Try and find the next power of 2 core setup. Otherwise fallback to a lower power of 2 core setup spec
// Try and load next pow of 2 setup for active pc core configuration
const unsigned int numCPUs = ((CSystem*)GetISystem())->GetCPUFeatures()->GetLogicalCPUCount();
uint32 i = numCPUs;
for (; i > 0; --i)
{
tmpPlatformStr.Format("%s_%i", strPlatformId, i);
retValue = LoadPlatformConfig(xmlRoot, tmpPlatformStr.c_str());
if (retValue)
{
break;
}
}
if (retValue && i != numCPUs)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: (%s: %u core) Unable to find platform config \"%s\". Next valid config found was %s_%u.",
strPlatformId, numCPUs, tmpPlatformStr.c_str(), strPlatformId, i);
}
#else
tmpPlatformStr.Format("%s", strPlatformId);
retValue = LoadPlatformConfig(xmlRoot, strPlatformId);
#endif
// Print out info
if (retValue)
{
CryLogAlways("<ThreadConfigInfo>: Thread profile loaded: \"%s\" (%s) ", tmpPlatformStr.c_str(), pcPath);
}
else
{
// Could not find any matching platform
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: Active platform identifier string \"%s\" not found in config \"%s\".", strPlatformId, sCurThreadConfigFilename);
}
sCurThreadConfigFilename = "";
return retValue;
}
//////////////////////////////////////////////////////////////////////////
bool CThreadConfigManager::ConfigLoaded() const
{
return !m_threadConfig.empty();
}
//////////////////////////////////////////////////////////////////////////
bool CThreadConfigManager::LoadPlatformConfig(const XmlNodeRef& rXmlRoot, const char* sPlatformId)
{
// Validate node
if (!rXmlRoot->isTag("ThreadConfig"))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: Unable to find root xml node \"ThreadConfig\"");
return false;
}
// Find active platform
const uint32 numPlatforms = rXmlRoot->getChildCount();
for (uint32 i = 0; i < numPlatforms; ++i)
{
const XmlNodeRef xmlPlatformNode = rXmlRoot->getChild(i);
// Is platform node
if (!xmlPlatformNode->isTag("Platform"))
{
continue;
}
// Is has Name attribute
if (!xmlPlatformNode->haveAttr("Name"))
{
continue;
}
// Is platform of interest
const char* platformName = xmlPlatformNode->getAttr("Name");
if (_stricmp(sPlatformId, platformName) == 0)
{
// Load platform
LoadThreadDefaultConfig(xmlPlatformNode);
LoadPlatformThreadConfigs(xmlPlatformNode);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadPlatformThreadConfigs(const XmlNodeRef& rXmlPlatformRef)
{
// Get thread configurations for active platform
const uint32 numThreads = rXmlPlatformRef->getChildCount();
for (uint32 j = 0; j < numThreads; ++j)
{
const XmlNodeRef xmlThreadNode = rXmlPlatformRef->getChild(j);
if (!xmlThreadNode->isTag("Thread"))
{
continue;
}
// Ensure thread config has name
if (!xmlThreadNode->haveAttr("Name"))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Thread node without \"name\" attribute encountered.");
continue;
}
// Load thread config
SThreadConfig loadedThreadConfig = SThreadConfig(m_defaultConfig);
LoadThreadConfig(xmlThreadNode, loadedThreadConfig);
// Get thread name and check if it contains wildcard characters
const char* szThreadName = xmlThreadNode->getAttr("Name");
bool bWildCard = strchr(szThreadName, '*') ? true : false;
ThreadConfigMap& threadConfig = bWildCard ? m_wildcardThreadConfig : m_threadConfig;
// Check for duplicate and override it with new config if found
if (threadConfig.find(szThreadName) != threadConfig.end())
{
CryLogAlways("<ThreadConfigInfo>: [XML Parsing] Thread with name \"%s\" already loaded. Overriding with new configuration", szThreadName);
threadConfig[szThreadName] = loadedThreadConfig;
continue;
}
// Store new thread config
std::pair<ThreadConfigMapIter, bool> res;
res = threadConfig.insert(ThreadConfigMapPair(CryFixedStringT<THREAD_NAME_LENGTH_MAX>(szThreadName), loadedThreadConfig));
// Store name (ref to key)
SThreadConfig& rMapThreadConfig = res.first->second;
rMapThreadConfig.szThreadName = res.first->first.c_str();
}
}
//////////////////////////////////////////////////////////////////////////
bool CThreadConfigManager::LoadThreadDefaultConfig(const XmlNodeRef& rXmlPlatformRef)
{
// Find default thread config node
const uint32 numNodes = rXmlPlatformRef->getChildCount();
for (uint32 j = 0; j < numNodes; ++j)
{
const XmlNodeRef xmlNode = rXmlPlatformRef->getChild(j);
// Load default config
if (xmlNode->isTag("ThreadDefault"))
{
LoadThreadConfig(xmlNode, m_defaultConfig);
return true;
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadAffinity(const XmlNodeRef& rXmlThreadRef, uint32& rAffinity, SThreadConfig::TThreadParamFlag& rParamActivityFlag)
{
const char* szValidCharacters = "-,0123456789";
uint32 affinity = 0;
// Validate node
if (!rXmlThreadRef->haveAttr("Affinity"))
{
return;
}
// Validate token
CryFixedStringT<32> affinityRawStr(rXmlThreadRef->getAttr("Affinity"));
if (affinityRawStr.empty())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Empty attribute \"Affinity\" encountered");
return;
}
if (affinityRawStr.compareNoCase("ignore") == 0)
{
// Param is inactive, clear bit
rParamActivityFlag &= ~SThreadConfig::eThreadParamFlag_Affinity;
return;
}
CryFixedStringT<32>::size_type nPos = affinityRawStr.find_first_not_of(" -,0123456789");
if (nPos != CryFixedStringT<32>::npos)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING,
"<ThreadConfigInfo>: [XML Parsing] Invalid character \"%c\" encountered in \"Affinity\" attribute. Valid characters:\"%s\" Offending token:\"%s\"", affinityRawStr.at(nPos),
szValidCharacters, affinityRawStr.c_str());
return;
}
// Tokenize comma separated string
int pos = 0;
CryFixedStringT<32> affnityTokStr = affinityRawStr.Tokenize(",", pos);
while (!affnityTokStr.empty())
{
affnityTokStr.Trim();
long affinityId = strtol(affnityTokStr.c_str(), NULL, 10);
if (affinityId == LONG_MAX || affinityId == LONG_MIN)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Unknown value \"%s\" encountered for attribute \"Affinity\"", affnityTokStr.c_str());
return;
}
// Allow scheduler to pick thread
if (affinityId == -1)
{
affinity = ~0;
break;
}
// Set affinity bit
affinity |= BIT(affinityId);
// Move to next token
affnityTokStr = affinityRawStr.Tokenize(",", pos);
}
// Set affinity reference
rAffinity = affinity;
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadPriority(const XmlNodeRef& rXmlThreadRef, int32& rPriority, SThreadConfig::TThreadParamFlag& rParamActivityFlag)
{
const char* szValidCharacters = "-,0123456789";
// Validate node
if (!rXmlThreadRef->haveAttr("Priority"))
{
return;
}
// Validate token
CryFixedStringT<32> threadPrioStr(rXmlThreadRef->getAttr("Priority"));
threadPrioStr.Trim();
if (threadPrioStr.empty())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Empty attribute \"Priority\" encountered");
return;
}
if (threadPrioStr.compareNoCase("ignore") == 0)
{
// Param is inactive, clear bit
rParamActivityFlag &= ~SThreadConfig::eThreadParamFlag_Priority;
return;
}
// Test for character string (no numbers allowed)
if (threadPrioStr.find_first_of(szValidCharacters) == CryFixedStringT<32>::npos)
{
threadPrioStr.MakeLower();
// Set priority
if (threadPrioStr.compare("below_normal") == 0)
{
rPriority = THREAD_PRIORITY_BELOW_NORMAL;
}
else if (threadPrioStr.compare("normal") == 0)
{
rPriority = THREAD_PRIORITY_NORMAL;
}
else if (threadPrioStr.compare("above_normal") == 0)
{
rPriority = THREAD_PRIORITY_ABOVE_NORMAL;
}
else if (threadPrioStr.compare("idle") == 0)
{
rPriority = THREAD_PRIORITY_IDLE;
}
else if (threadPrioStr.compare("lowest") == 0)
{
rPriority = THREAD_PRIORITY_LOWEST;
}
else if (threadPrioStr.compare("highest") == 0)
{
rPriority = THREAD_PRIORITY_HIGHEST;
}
else if (threadPrioStr.compare("time_critical") == 0)
{
rPriority = THREAD_PRIORITY_TIME_CRITICAL;
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Platform unsupported value \"%s\" encountered for attribute \"Priority\"", threadPrioStr.c_str());
return;
}
}
// Test for number string (no alphabetical characters allowed)
else if (threadPrioStr.find_first_not_of(szValidCharacters) == CryFixedStringT<32>::npos)
{
long numValue = strtol(threadPrioStr.c_str(), NULL, 10);
if (numValue == LONG_MAX || numValue == LONG_MIN)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Unsupported number type \"%s\" for for attribute \"Priority\"", threadPrioStr.c_str());
return;
}
// Set priority
rPriority = numValue;
}
else
{
// String contains characters and numbers
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Unsupported type \"%s\" encountered for attribute \"Priority\". Token containers numbers and characters", threadPrioStr.c_str());
return;
}
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadDisablePriorityBoost(const XmlNodeRef& rXmlThreadRef, bool& rPriorityBoost, SThreadConfig::TThreadParamFlag& rParamActivityFlag)
{
// Validate node
if (!rXmlThreadRef->haveAttr("DisablePriorityBoost"))
{
return;
}
// Extract bool info
CryFixedStringT<16> sAttribToken(rXmlThreadRef->getAttr("DisablePriorityBoost"));
sAttribToken.Trim();
sAttribToken.MakeLower();
if (sAttribToken.compare("ignore") == 0)
{
// Param is inactive, clear bit
rParamActivityFlag &= ~SThreadConfig::eThreadParamFlag_PriorityBoost;
return;
}
else if (sAttribToken.compare("true") == 0 || sAttribToken.compare("1") == 0)
{
rPriorityBoost = true;
}
else if (sAttribToken.compare("false") == 0 || sAttribToken.compare("0") == 0)
{
rPriorityBoost = false;
}
else
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Unsupported bool type \"%s\" encountered for attribute \"DisablePriorityBoost\"",
rXmlThreadRef->getAttr("DisablePriorityBoost"));
return;
}
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadStackSize(const XmlNodeRef& rXmlThreadRef, uint32& rStackSize, SThreadConfig::TThreadParamFlag& rParamActivityFlag)
{
const char* sValidCharacters = "0123456789";
if (rXmlThreadRef->haveAttr("StackSizeKB"))
{
// Read stack size
CryFixedStringT<32> stackSize(rXmlThreadRef->getAttr("StackSizeKB"));
// Validate stack size
if (stackSize.empty())
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Empty attribute \"StackSize\" encountered");
return;
}
else if (stackSize.compareNoCase("ignore") == 0)
{
// Param is inactive, clear bit
rParamActivityFlag &= ~SThreadConfig::eThreadParamFlag_StackSize;
return;
}
else if (stackSize.find_first_not_of(sValidCharacters) == CryFixedStringT<32>::npos)
{
// Convert string to long
long stackSizeVal = strtol(stackSize.c_str(), NULL, 10);
if (stackSizeVal == LONG_MAX || stackSizeVal == LONG_MIN)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] Invalid number for \"StackSize\" encountered. \"%s\"", stackSize.c_str());
return;
}
else if (stackSizeVal <= 0 || stackSizeVal > sPlausibleStackSizeLimitKB)
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "<ThreadConfigInfo>: [XML Parsing] \"StackSize\" value not plausible \"%" PRId64 "KB\"", (int64)stackSizeVal);
return;
}
// Set stack size
rStackSize = stackSizeVal * 1024; // Convert to bytes
}
}
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::LoadThreadConfig(const XmlNodeRef& rXmlThreadRef, SThreadConfig& rThreadConfig)
{
LoadAffinity(rXmlThreadRef, rThreadConfig.affinityFlag, rThreadConfig.paramActivityFlag);
LoadPriority(rXmlThreadRef, rThreadConfig.priority, rThreadConfig.paramActivityFlag);
LoadDisablePriorityBoost(rXmlThreadRef, rThreadConfig.bDisablePriorityBoost, rThreadConfig.paramActivityFlag);
LoadStackSize(rXmlThreadRef, rThreadConfig.stackSizeBytes, rThreadConfig.paramActivityFlag);
}
//////////////////////////////////////////////////////////////////////////
const char* CThreadConfigManager::IdentifyPlatform()
{
#if defined(AZ_RESTRICTED_PLATFORM)
#include AZ_RESTRICTED_FILE(ThreadConfigManager_cpp)
#endif
#if defined(AZ_RESTRICTED_SECTION_IMPLEMENTED)
#undef AZ_RESTRICTED_SECTION_IMPLEMENTED
#elif defined(ANDROID)
return "android";
#elif defined(LINUX)
return "linux";
#elif defined(APPLE)
return "mac";
#elif defined(WIN32) || defined(WIN64)
return "pc";
#else
#error "Undefined platform"
#endif
}
//////////////////////////////////////////////////////////////////////////
void CThreadConfigManager::DumpThreadConfigurationsToLog()
{
#if !defined(RELEASE)
// Print header
CryLogAlways("== Thread Startup Config List (\"%s\") ==", IdentifyPlatform());
// Print loaded default config
CryLogAlways(" (Default) 1. \"%s\" (StackSize:%uKB | Affinity:%u | Priority:%i | PriorityBoost:\"%s\")", m_defaultConfig.szThreadName, m_defaultConfig.stackSizeBytes / 1024,
m_defaultConfig.affinityFlag, m_defaultConfig.priority, m_defaultConfig.bDisablePriorityBoost ? "disabled" : "enabled");
// Print loaded thread configs
int listItemCounter = 1;
ThreadConfigMapConstIter iter = m_threadConfig.begin();
ThreadConfigMapConstIter iterEnd = m_threadConfig.end();
for (; iter != iterEnd; ++iter)
{
const SThreadConfig& threadConfig = iter->second;
CryLogAlways("%3d.\"%s\" %s (StackSize:%uKB %s | Affinity:%u %s | Priority:%i %s | PriorityBoost:\"%s\" %s)", ++listItemCounter,
threadConfig.szThreadName, (threadConfig.paramActivityFlag & SThreadConfig::eThreadParamFlag_ThreadName) ? "" : "(ignored)",
threadConfig.stackSizeBytes / 1024u, (threadConfig.paramActivityFlag & SThreadConfig::eThreadParamFlag_StackSize) ? "" : "(ignored)",
threadConfig.affinityFlag, (threadConfig.paramActivityFlag & SThreadConfig::eThreadParamFlag_Affinity) ? "" : "(ignored)",
threadConfig.priority, (threadConfig.paramActivityFlag & SThreadConfig::eThreadParamFlag_Priority) ? "" : "(ignored)",
!threadConfig.bDisablePriorityBoost ? "enabled" : "disabled", (threadConfig.paramActivityFlag & SThreadConfig::eThreadParamFlag_PriorityBoost) ? "" : "(ignored)");
}
#endif
}
@@ -1,137 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#pragma once
#include <map>
#include "IThreadConfigManager.h"
/*
ThreadConfigManager:
Loads a thread configuration from an xml file and stores them.
== XML File Layout and Rules: ===
= Platform names =
(case insensitive)
"ANDROID"
"PC"
"MAC"
etc.
= Basic Layout =
<ThreadConfig>
<Platform name="XXX">
<ThreadDefault Affinity="XX" Priority="XX" StackSizeKB="XX">
<Thread name ="A" Affinity="XX" Priority="XX" StackSizeKB="XX">
<Thread name ="B" Affinity="XX" >
...
</Platform>
<Platform name="YYY">
...
</Platform>
</ThreadConfig>
= Parser Order for Platform =
1. PlatformName_Common (valid for all potential platform configurations. Can be overridden by concert platform configuration)
2. PlatformName or PlatformName_X (for platforms with unknown CPU count where X is the number of potential cores. The equal or next lower matching configuration for the identified core count at runtime will be taken)
Note: Overriding of thread configuration by later parsed configuration allowed.
= <ThreadDefault> and <Thread> XML attributes =
!!!
Note: Use "ignore" as value if you do not want the thread system to set the value specifically!
If a value is not defines the <ThreadDefault> value of the parameter will be used.
This is useful when dealing with 3rdParty threads where you are not in control of the parameter setup.
!!!
Name:
"x" (string) : Name of thread
"x*y" (string) : Name of thread with wildcard character
Affinity:
"-1" : Put SW thread affinity in the hands of the scheduler - (default) -
"x" : Run thread on specified core
"x, y, ..." : Run thread on specified cores
Priority:
"idle" : Hint to CryEngine to run thread with pre-set priority
"below_normal" : Hint to CryEngine to run thread with pre-set priority
"normal" : Hint to CryEngine to run thread with pre-set priority - (default) -
"above_normal" : Hint to CryEngine to run thread with pre-set priority
"highest" : Hint to CryEngine to run thread with pre-set priority
"time_critical" : Hint to CryEngine to run thread with pre-set priority
"x" (number) : User defined thread priority number
StackSizeKB:
"0" : Let platform decide on the stack size - (default) -
"x" : Create thread with "x" KB of stack size
DisablePriorityBoost:
"true" : Disable priority boosting - (default) -
"false" : Enable priority boosting
*/
class CThreadConfigManager
: public IThreadConfigManager
{
public:
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, SThreadConfig> ThreadConfigMap;
typedef std::pair<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, SThreadConfig> ThreadConfigMapPair;
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, SThreadConfig>::iterator ThreadConfigMapIter;
typedef std::map<CryFixedStringT<THREAD_NAME_LENGTH_MAX>, SThreadConfig>::const_iterator ThreadConfigMapConstIter;
public:
CThreadConfigManager();
~CThreadConfigManager()
{
}
// Called once during System startup.
// Loads the thread configuration for the executing platform from file.
virtual bool LoadConfig(const char* pcPath) override;
// Returns true if a config has been loaded
virtual bool ConfigLoaded() const override;
// Gets the thread configuration for the specified thread on the active platform.
// If no matching config is found a default configuration is returned
// (which does not have the same name as the search string).
virtual const SThreadConfig* GetThreadConfig(const char* sThreadName, ...) override;
virtual const SThreadConfig* GetDefaultThreadConfig() const override;
virtual void DumpThreadConfigurationsToLog() override;
private:
const char* IdentifyPlatform();
const SThreadConfig* GetThreadConfigImpl(const char* cThreadName);
bool LoadPlatformConfig(const XmlNodeRef& rXmlRoot, const char* sPlatformId);
void LoadPlatformThreadConfigs(const XmlNodeRef& rXmlPlatformRef);
bool LoadThreadDefaultConfig(const XmlNodeRef& rXmlPlatformRef);
void LoadThreadConfig(const XmlNodeRef& rXmlThreadRef, SThreadConfig& rThreadConfig);
void LoadAffinity(const XmlNodeRef& rXmlThreadRef, uint32& rAffinity, SThreadConfig::TThreadParamFlag& rParamActivityFlag);
void LoadPriority(const XmlNodeRef& rXmlThreadRef, int32& rPriority, SThreadConfig::TThreadParamFlag& rParamActivityFlag);
void LoadDisablePriorityBoost(const XmlNodeRef& rXmlThreadRef, bool& rPriorityBoost, SThreadConfig::TThreadParamFlag& rParamActivityFlag);
void LoadStackSize(const XmlNodeRef& rXmlThreadRef, uint32& rStackSize, SThreadConfig::TThreadParamFlag& rParamActivityFlag);
private:
ThreadConfigMap m_threadConfig; // Note: The map key is referenced by as const char* by the value's storage class. Other containers may not support this behaviour as they will re-allocate memory as they grow/shrink.
ThreadConfigMap m_wildcardThreadConfig;
SThreadConfig m_defaultConfig;
};
-123
View File
@@ -1,123 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#include "CrySystem_precompiled.h"
#include "ThreadInfo.h"
#include "System.h"
////////////////////////////////////////////////////////////////////////////
#if defined(AZ_RESTRICTED_PLATFORM)
#undef AZ_RESTRICTED_SECTION
#define THREADINFO_CPP_SECTION_1 1
#define THREADINFO_CPP_SECTION_2 2
#endif
#if defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION THREADINFO_CPP_SECTION_1
#include AZ_RESTRICTED_FILE(ThreadInfo_cpp)
#endif
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
#if AZ_LEGACY_CRYSYSTEM_TRAIT_THREADINFO_WINDOWS_STYLE
////////////////////////////////////////////////////////////////////////////
void SThreadInfo::GetCurrentThreads(TThreadInfo& threadsOut)
{
HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
DWORD currProcessId = GetCurrentProcessId();
if (h != INVALID_HANDLE_VALUE)
{
THREADENTRY32 te;
te.dwSize = sizeof(te);
if (Thread32First(h, &te))
{
do
{
if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID))
{
if (te.th32OwnerProcessID == currProcessId)
{
threadsOut[te.th32ThreadID] = CryThreadGetName(te.th32ThreadID);
}
}
te.dwSize = sizeof(te);
} while (Thread32Next(h, &te));
}
CloseHandle(h);
}
}
////////////////////////////////////////////////////////////////////////////
void SThreadInfo::OpenThreadHandles(TThreads& threadsOut, const TThreadIds& threadIds /* = TThreadIds()*/, bool ignoreCurrThread /* = true*/)
{
TThreadIds threadids = threadIds;
if (threadids.empty())
{
TThreadInfo threads;
GetCurrentThreads(threads);
DWORD currThreadId = GetCurrentThreadId();
for (TThreadInfo::iterator it = threads.begin(), end = threads.end(); it != end; ++it)
{
if (!ignoreCurrThread || it->first != currThreadId)
{
threadids.push_back(it->first);
}
}
}
for (TThreadIds::iterator it = threadids.begin(), end = threadids.end(); it != end; ++it)
{
SThreadHandle thread;
thread.Id = *it;
thread.Handle = OpenThread(THREAD_ALL_ACCESS, FALSE, *it);
threadsOut.push_back(thread);
}
}
////////////////////////////////////////////////////////////////////////////
void SThreadInfo::CloseThreadHandles(const TThreads& threads)
{
for (TThreads::const_iterator it = threads.begin(), end = threads.end(); it != end; ++it)
{
CloseHandle(it->Handle);
}
}
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////
#elif defined(AZ_RESTRICTED_PLATFORM)
#define AZ_RESTRICTED_SECTION THREADINFO_CPP_SECTION_2
#include AZ_RESTRICTED_FILE(ThreadInfo_cpp)
#elif defined(LINUX) || defined(APPLE)
void SThreadInfo::GetCurrentThreads(TThreadInfo& threadsOut)
{
assert(false); // not implemented!
}
////////////////////////////////////////////////////////////////////////////
void SThreadInfo::OpenThreadHandles(TThreads& threadsOut, const TThreadIds& threadIds /* = TThreadIds()*/, bool ignoreCurrThread /* = true*/)
{
assert(false); // not implemented!
}
////////////////////////////////////////////////////////////////////////////
void SThreadInfo::CloseThreadHandles(const TThreads& threads)
{
assert(false); // not implemented!
}
////////////////////////////////////////////////////////////////////////////
#endif
-43
View File
@@ -1,43 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_THREADINFO_H
#define CRYINCLUDE_CRYSYSTEM_THREADINFO_H
#pragma once
struct SThreadInfo
{
public:
struct SThreadHandle
{
HANDLE Handle;
uint32 Id;
};
typedef std::vector<uint32> TThreadIds;
typedef std::vector<SThreadHandle> TThreads;
typedef std::map<uint32, string> TThreadInfo;
// returns thread info
static void GetCurrentThreads(TThreadInfo& threadsOut);
// fills threadsOut vector with thread handles of given thread ids; if threadIds vector is emtpy it fills all running threads
// if ignoreCurrThread is true it will not return the current thread
static void OpenThreadHandles(TThreads& threadsOut, const TThreadIds& threadIds = TThreadIds(), bool ignoreCurrThread = true);
// closes thread handles; should be called whenever GetCurrentThreads was called!
static void CloseThreadHandles(const TThreads& threads);
};
#endif // CRYINCLUDE_CRYSYSTEM_THREADINFO_H
File diff suppressed because it is too large Load Diff
-181
View File
@@ -1,181 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
// Original file Copyright Crytek GMBH or its affiliates, used under license.
#ifndef CRYINCLUDE_CRYSYSTEM_THREADTASK_H
#define CRYINCLUDE_CRYSYSTEM_THREADTASK_H
#pragma once
#include <IThreadTask.h>
#include <CryThread.h>
#include <MultiThread_Containers.h>
#define MAIN_THREAD_INDEX 0
class CThreadTask_Thread;
void MarkThisThreadForDebugging(const char* name);
void UnmarkThisThreadFromDebugging();
void UpdateFPExceptionsMaskForThreads();
class CThreadTaskManager;
///
struct IThreadTaskRunnable
{
virtual ~IThreadTaskRunnable(){}
virtual void Run() = 0;
virtual void Cancel() = 0;
};
//////////////////////////////////////////////////////////////////////////
class CThreadTask_Thread
: public CryThread<IThreadTaskRunnable>
, public IThreadTask_Thread
{
protected:
void Init();
public:
CThreadTask_Thread(CThreadTaskManager* pTaskMgr, const char* sName, int nThreadIndex, int nProcessor, int nThreadPriority, ThreadPoolHandle poolHandle = -1);
~CThreadTask_Thread();
// see IThreadTaskRunnable, CryThread<>
void Run() override;
void Cancel() override;
// see CryThread<>
void Terminate() override;
// IThreadTask_Thread
void AddTask(SThreadTaskInfo* pTaskInfo) override;
void RemoveTask(SThreadTaskInfo* pTaskInfo) override;
void RemoveAllTasks() override;
void SingleUpdate() override;
void ChangeProcessor(int nProcessor);
public:
CThreadTaskManager* m_pTaskManager;
string m_sThreadName;
int m_nThreadIndex; // -1 means the thread is blocking
int m_nProcessor;
int m_nThreadPriority;
THREAD_HANDLE m_hThreadHandle;
// Tasks running on this thread.
typedef CryMT::CLocklessPointerQueue<SThreadTaskInfo, stl::STLGlobalAllocator<SThreadTaskInfo> > Tasks;
Tasks tasks;
// The task is being processing now
SThreadTaskInfo* m_pProcessingTask;
CryEvent m_waitForTasks;
// Set to true when thread must stop.
volatile bool bStopThread;
volatile bool bRunning;
// handle of threads pool which this thread belongs to(if any)
ThreadPoolHandle m_poolHandle;
};
//////////////////////////////////////////////////////////////////////////
class CThreadTaskManager
: public IThreadTaskManager
{
private:
typedef std::vector<CThreadTask_Thread*, stl::STLGlobalAllocator<CThreadTask_Thread*> > Threads;
// note: this struct is auxilary and NOT thread-safe
// it is only for internal use inside the task manager
struct CThreadsPool
{
ThreadPoolHandle m_hHandle;
Threads m_Threads;
ThreadPoolDesc m_pDescription;
const bool SetAffinity(const ThreadPoolAffinityMask AffinityMask);
const bool operator < (const CThreadsPool& p) const { return m_hHandle < p.m_hHandle; }
const bool operator == (const CThreadsPool& p) const { return m_hHandle == p.m_hHandle; }
};
typedef std::vector<CThreadsPool> ThreadsPools;
public:
CThreadTaskManager();
~CThreadTaskManager();
void InitThreads();
void CloseThreads();
void StopAllThreads();
//////////////////////////////////////////////////////////////////////////
// IThreadTaskManager
//////////////////////////////////////////////////////////////////////////
virtual void RegisterTask(IThreadTask* pTask, const SThreadTaskParams& options);
virtual void UnregisterTask(IThreadTask* pTask);
virtual void SetMaxThreadCount(int nMaxThreads);
virtual void SetThreadName(threadID dwThreadId, const char* sThreadName);
virtual const char* GetThreadName(threadID dwThreadId);
virtual threadID GetThreadByName(const char* sThreadName);
// Thread pool framework
virtual ThreadPoolHandle CreateThreadsPool(const ThreadPoolDesc& desc);
virtual const bool DestroyThreadsPool(const ThreadPoolHandle& handle);
virtual const bool GetThreadsPoolDesc(const ThreadPoolHandle handle, ThreadPoolDesc* pDesc) const;
virtual const bool SetThreadsPoolAffinity(const ThreadPoolHandle handle, const ThreadPoolAffinityMask AffinityMask);
virtual void MarkThisThreadForDebugging(const char* name, bool bDump);
//////////////////////////////////////////////////////////////////////////
// This is on update function of the main thread.
void OnUpdate();
void AddSystemThread(threadID nThreadId);
void RemoveSystemThread(threadID nThreadId);
// Balancing tasks in the pool between threads
void BalanceThreadsPool(const ThreadPoolHandle& handle);
void BalanceThreadInPool(CThreadTask_Thread* pFreeThread, Threads* pThreads = NULL);
private:
void ScheduleTask(SThreadTaskInfo* pTaskInfo);
void RescheduleTasks();
private:
// User created threads pools
mutable CryReadModifyLock m_threadsPoolsLock;
ThreadsPools m_threadsPools;
// Physical threads available to system.
Threads m_threads;
// Threads with single blocking task attached.
Threads m_blockingThreads;
typedef CryMT::CLocklessPointerQueue<SThreadTaskInfo> Tasks;
Tasks m_unassignedTasks;
mutable CryCriticalSection m_threadNameLock;
mutable CryCriticalSection m_threadRemove;
typedef std::map<threadID, string> ThreadNames;
ThreadNames m_threadNames;
mutable CryCriticalSection m_systemThreadsLock;
std::vector<threadID> m_systemThreads;
// Max threads that can be executed at same time.
int m_nMaxThreads;
};
#endif // CRYINCLUDE_CRYSYSTEM_THREADTASK_H
@@ -1,46 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "CrySystem_precompiled.h"
#include <AzTest/AzTest.h>
#include <Cry_Math.h>
namespace UnitTest
{
class CryMathTestFixture
: public ::testing::Test
{};
#if AZ_TRAIT_DISABLE_FAILED_MATH_TESTS
TEST_F(CryMathTestFixture, DISABLED_InverserSqrt_HasAtLeast22BitsOfAccuracy)
#else
TEST_F(CryMathTestFixture, InverserSqrt_HasAtLeast22BitsOfAccuracy)
#endif
{
float testFloat(0.336950600);
const float result = isqrt_safe_tpl(testFloat * testFloat);
const float epsilon = 0.00001f;
EXPECT_NEAR(2.96779, result, epsilon);
}
#if AZ_TRAIT_DISABLE_FAILED_MATH_TESTS
TEST_F(CryMathTestFixture, DISABLED_SimdSqrt_HasAtLeast23BitsOfAccuracy)
#else
TEST_F(CryMathTestFixture, SimdSqrt_HasAtLeast23BitsOfAccuracy)
#endif
{
float testFloat(3434.34839439);
const float result = sqrt_tpl(testFloat);
const float epsilon = 0.00001f;
EXPECT_NEAR(58.60331, result, epsilon);
}
}
@@ -1,141 +0,0 @@
/*
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
* its licensors.
*
* For complete copyright and license terms please see the LICENSE at the root of this
* distribution (the "License"). All use of this software is governed by the License,
* or, if provided, by the license below or the license accompanying this file. Do not
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
*/
#include "CrySystem_precompiled.h"
#include <AzTest/AzTest.h>
#include <AzCore/UnitTest/UnitTest.h>
#include <AzCore/Component/ComponentApplication.h>
#include <AzCore/IO/SystemFile.h> // for max path decl
#include <AzCore/std/parallel/thread.h>
#include <AzCore/std/parallel/semaphore.h>
#include <AzCore/std/functional.h> // for function<> in the find files callback.
#include <AzFramework/IO/LocalFileIO.h>
#include <AzFramework/Archive/ArchiveFileIO.h>
#include <AzFramework/Archive/Archive.h>
#include <AzFramework/Archive/INestedArchive.h>
#include <ILevelSystem.h>
namespace CryPakUnitTests
{
#if defined(AZ_PLATFORM_WINDOWS)
// Note: none of the below is really a unit test, its all basic feature tests
// for critical functionality
class Integ_CryPakUnitTests
: public ::testing::Test
{
protected:
bool IsPackValid(const char* path)
{
AZ::IO::IArchive* pak = gEnv->pCryPak;
if (!pak)
{
return false;
}
if (!pak->OpenPack(path, AZ::IO::IArchive::FLAGS_PATH_REAL))
{
return false;
}
pak->ClosePack(path);
return true;
}
};
TEST_F(Integ_CryPakUnitTests, TestCryPakModTime)
{
AZ::IO::FileIOBase* fileIo = AZ::IO::FileIOBase::GetInstance();
ASSERT_NE(nullptr, fileIo);
AZ::IO::IArchive* pak = gEnv->pCryPak;
// repeat the following test multiple times, since timing (seconds) can affect it and it involves time!
for (int iteration = 0; iteration < 10; ++iteration)
{
AZStd::this_thread::sleep_for(AZStd::chrono::milliseconds{ 100 });
// helper paths and strings
AZStd::string gameFolder = fileIo->GetAlias("@usercache@");
AZStd::string testFile = "unittest.bin";
AZStd::string testFilePath = gameFolder + "\\" + testFile;
AZStd::string testPak = "unittest.pak";
AZStd::string testPakPath = gameFolder + "\\" + testPak;
AZStd::string zipCmd = "-zip=" + testPakPath;
// delete test files in case they already exist
fileIo->Remove(testFilePath.c_str());
pak->ClosePack(testPakPath);
fileIo->Remove(testPakPath.c_str());
// create a test file
char data[] = "unittest";
FILE* f = nullptr;
azfopen(&f, testFilePath.c_str(), "wb");
EXPECT_TRUE(f != nullptr); // file successfully opened for writing
EXPECT_TRUE(fwrite(data, sizeof(char), sizeof(data), f) == sizeof(data)); // file written to successfully
EXPECT_TRUE(fclose(f) == 0); // file closed successfully
AZ::IO::HandleType fDisk = pak->FOpen(testFilePath.c_str(), "rb");
EXPECT_TRUE(fDisk > 0); // opened file on disk successfully
uint64_t modTimeDisk = pak->GetModificationTime(fDisk); // high res mod time extracted from file on disk
EXPECT_TRUE(pak->FClose(fDisk) == 0); // file closed successfully
// create a low res copy of disk file's mod time
uint64_t absDiff, maxDiff = 20000000ul;
uint16_t dosDate, dosTime;
FILETIME ft;
LARGE_INTEGER lt;
ft.dwHighDateTime = modTimeDisk >> 32;
ft.dwLowDateTime = modTimeDisk & 0xFFFFFFFF;
EXPECT_TRUE(FileTimeToDosDateTime(&ft, &dosDate, &dosTime) != FALSE); // converted to DOSTIME successfully
ft.dwHighDateTime = 0;
ft.dwLowDateTime = 0;
EXPECT_TRUE(DosDateTimeToFileTime(dosDate, dosTime, &ft) != FALSE); // converted to FILETIME successfully
lt.HighPart = ft.dwHighDateTime;
lt.LowPart = ft.dwLowDateTime;
uint64_t modTimeDiskLowRes = lt.QuadPart;
absDiff = modTimeDiskLowRes >= modTimeDisk ? modTimeDiskLowRes - modTimeDisk : modTimeDisk - modTimeDiskLowRes;
EXPECT_LE(absDiff, maxDiff); // FILETIME (high res) and DOSTIME (low res) should be at most 2 seconds apart
gEnv->pResourceCompilerHelper->CallResourceCompiler(testFilePath.c_str(), zipCmd.c_str());
EXPECT_EQ(AZ::IO::ResultCode::Success, fileIo->Remove(testFilePath.c_str())); // test file on disk deleted successfully
EXPECT_TRUE(pak->OpenPack(testPakPath)); // opened pak successfully
AZ::IO::HandleType fPak = pak->FOpen(testFilePath.c_str(), "rb");
EXPECT_GT(fPak, 0); // file (in pak) opened correctly
uint64_t modTimePak = pak->GetModificationTime(fPak); // low res mod time extracted from file in pak
EXPECT_EQ(0, pak->FClose(fPak)); // file closed successfully
EXPECT_TRUE(pak->ClosePack(testPakPath)); // closed pak successfully
EXPECT_EQ(AZ::IO::ResultCode::Success, fileIo->Remove(testPakPath.c_str())); // test pak file deleted successfully
absDiff = modTimePak >= modTimeDisk ? modTimePak - modTimeDisk : modTimeDisk - modTimePak;
// compare mod times. They are allowed to be up to 2 seconds apart but no more
EXPECT_LE(absDiff, maxDiff); // FILETIME (disk) and DOSTIME (pak) should be at most 2 seconds apart
// note: Do not directly compare the disk time and pack time, the resolution drops the last digit off in some cases in pak
// it only has a 2 second resolution. you may compare to make sure that the pak time is WITHIN 2 seconds (as above) but not equal.
// we depend on the fact that crypak is rounding up, instead of down
EXPECT_GE(modTimePak, modTimeDisk);
}
}
#endif
}
-6
View File
@@ -783,12 +783,6 @@ void CUNIXConsole::KeyEnter()
if (pushCommand)
{
CSystem* pSystem = static_cast<CSystem*>(gEnv->pSystem);
#if defined(CVARS_WHITELIST)
ICVarsWhitelist* pCVarsWhitelist = pSystem->GetCVarsWhiteList();
bool execute = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(m_InputLine, false) : true;
if (execute)
#endif // defined(CVARS_WHITELIST)
{
m_CommandQueue.push_back(m_InputLine);
}
-200
View File
@@ -140,147 +140,6 @@ void Command_SetWaitFrames(IConsoleCmdArgs* pCmd)
}
}
/*
CNotificationNetworkConsole
*/
#include <INotificationNetwork.h>
class CNotificationNetworkConsole
: public INotificationNetworkListener
{
private:
static const uint32 LENGTH_MAX = 256;
static CNotificationNetworkConsole* s_pInstance;
public:
static bool Initialize()
{
if (s_pInstance)
{
return true;
}
INotificationNetwork* pNotificationNetwork = gEnv->pSystem->GetINotificationNetwork();
if (!pNotificationNetwork)
{
return false;
}
s_pInstance = new CNotificationNetworkConsole();
pNotificationNetwork->ListenerBind("Command", s_pInstance);
return true;
}
static void Shutdown()
{
if (!s_pInstance)
{
return;
}
delete s_pInstance;
s_pInstance = NULL;
}
static void Update()
{
if (s_pInstance)
{
s_pInstance->ProcessCommand();
}
}
private:
CNotificationNetworkConsole()
{
m_pConsole = NULL;
m_commandBuffer[0][0] = '\0';
m_commandBuffer[1][0] = '\0';
m_commandBufferIndex = 0;
m_commandCriticalSection = ::CryCreateCriticalSection();
}
~CNotificationNetworkConsole()
{
if (m_commandCriticalSection)
{
::CryDeleteCriticalSection(m_commandCriticalSection);
}
}
private:
void ProcessCommand()
{
if (!ValidateConsole())
{
return;
}
char* command = NULL;
::CryEnterCriticalSection(m_commandCriticalSection);
if (*m_commandBuffer[m_commandBufferIndex])
{
command = m_commandBuffer[m_commandBufferIndex];
}
++m_commandBufferIndex &= 1;
::CryLeaveCriticalSection(m_commandCriticalSection);
if (command)
{
m_pConsole->ExecuteString(command);
*command = '\0';
}
}
bool ValidateConsole()
{
if (m_pConsole)
{
return true;
}
if (!gEnv->pConsole)
{
return false;
}
m_pConsole = gEnv->pConsole;
return true;
}
// INotificationNetworkListener
public:
void OnNotificationNetworkReceive(const void* pBuffer, size_t length)
{
if (!ValidateConsole())
{
return;
}
if (length > LENGTH_MAX)
{
length = LENGTH_MAX;
}
::CryEnterCriticalSection(m_commandCriticalSection);
::memcpy(m_commandBuffer[m_commandBufferIndex], pBuffer, length);
m_commandBuffer[m_commandBufferIndex][LENGTH_MAX - 1] = '\0';
::CryLeaveCriticalSection(m_commandCriticalSection);
}
private:
IConsole* m_pConsole;
char m_commandBuffer[2][LENGTH_MAX];
size_t m_commandBufferIndex;
void* m_commandCriticalSection;
};
CNotificationNetworkConsole* CNotificationNetworkConsole::s_pInstance = NULL;
void ConsoleShow(IConsoleCmdArgs*)
{
gEnv->pConsole->ShowConsole(true);
@@ -359,8 +218,6 @@ CXConsole::CXConsole()
m_waitSeconds = 0.0f;
m_blockCounter = 0;
CNotificationNetworkConsole::Initialize();
AzFramework::ConsoleRequestBus::Handler::BusConnect();
AzFramework::CommandRegistrationBus::Handler::BusConnect();
@@ -379,8 +236,6 @@ CXConsole::~CXConsole()
gEnv->pSystem->GetIRemoteConsole()->UnregisterListener(this);
}
CNotificationNetworkConsole::Shutdown();
if (!m_mapVariables.empty())
{
while (!m_mapVariables.empty())
@@ -1205,8 +1060,6 @@ void CXConsole::Update()
}
}
}
CNotificationNetworkConsole::Update();
}
//enable this for now, we need it for profiling etc
@@ -1749,11 +1602,6 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
int devOnlyMask = VF_DEV_ONLY;
int dediOnlyMask = VF_DEDI_ONLY;
int excludeMask = cheatMask | constMask | readOnlyMask | devOnlyMask | dediOnlyMask;
#if defined(CVARS_WHITELIST)
CSystem* pSystem = static_cast<CSystem*>(gEnv->pSystem);
ICVarsWhitelist* pCVarsWhitelist = pSystem->GetCVarsWhiteList();
bool excludeWhitelist = true;
#endif // defined(CVARS_WHITELIST)
if (numArgs > 1)
{
@@ -1786,13 +1634,6 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
excludeMask &= ~dediOnlyMask;
}
#if defined(CVARS_WHITELIST)
if (azstricmp(arg, "whitelist") == 0)
{
excludeWhitelist = false;
}
#endif // defined(CVARS_WHITELIST)
--numArgs;
}
}
@@ -1810,11 +1651,6 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
int devOnlyFlags = (command.m_nFlags & devOnlyMask);
int dediOnlyFlags = (command.m_nFlags & dediOnlyMask);
bool shouldLog = ((cheatFlags | devOnlyFlags | dediOnlyFlags) == 0) || (((cheatFlags | devOnlyFlags | dediOnlyFlags) & ~excludeMask) != 0);
#if defined(CVARS_WHITELIST)
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(command.m_sName, true) : true;
shouldLog &= (!whitelisted || (whitelisted & !excludeWhitelist));
#endif // defined(CVARS_WHITELIST)
if (shouldLog)
{
CryLogAlways("[CVARS]: [COMMAND] %s%s%s%s%s",
@@ -1822,11 +1658,7 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
(cheatFlags != 0) ? " [VF_CHEAT]" : "",
(devOnlyFlags != 0) ? " [VF_DEV_ONLY]" : "",
(dediOnlyFlags != 0) ? " [VF_DEDI_ONLY]" : "",
#if defined(CVARS_WHITELIST)
(whitelisted == true) ? " [WHITELIST]" : ""
#else
""
#endif // defined(CVARS_WHITELIST)
);
++commandCount;
}
@@ -1843,11 +1675,6 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
int devOnlyFlags = (flags & devOnlyMask);
int dediOnlyFlags = (flags & dediOnlyMask);
bool shouldLog = ((cheatFlags | constFlags | readOnlyFlags | devOnlyFlags | dediOnlyFlags) == 0) || (((cheatFlags | constFlags | readOnlyFlags | devOnlyFlags | dediOnlyFlags) & ~excludeMask) != 0);
#if defined(CVARS_WHITELIST)
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(pVariable->GetName(), true) : true;
shouldLog &= (!whitelisted || (whitelisted & !excludeWhitelist));
#endif // defined(CVARS_WHITELIST)
if (shouldLog)
{
CryLogAlways("[CVARS]: [VARIABLE] %s%s%s%s%s%s%s",
@@ -1857,11 +1684,7 @@ void CXConsole::AuditCVars(IConsoleCmdArgs* pArg)
(readOnlyFlags != 0) ? " [VF_READONLY]" : "",
(devOnlyFlags != 0) ? " [VF_DEV_ONLY]" : "",
(dediOnlyFlags != 0) ? " [VF_DEDI_ONLY]" : "",
#if defined(CVARS_WHITELIST)
(whitelisted == true) ? " [WHITELIST]" : ""
#else
""
#endif // defined(CVARS_WHITELIST)
);
++cvarCount;
}
@@ -2520,11 +2343,6 @@ const char* CXConsole::ProcessCompletion(const char* szInputBuffer)
}
}
//try to search in command list
#if defined(CVARS_WHITELIST)
CSystem* pSystem = static_cast<CSystem*>(gEnv->pSystem);
ICVarsWhitelist* pCVarsWhitelist = pSystem->GetCVarsWhiteList();
#endif // defined(CVARS_WHITELIST)
bool bArgumentAutoComplete = false;
std::vector<string> matches;
@@ -2565,10 +2383,6 @@ const char* CXConsole::ProcessCompletion(const char* szInputBuffer)
string cmd = string(sVar) + " " + pArgumentAutoComplete->GetValue(i);
if (_strnicmp(m_sPrevTab.c_str(), cmd.c_str(), m_sPrevTab.length()) == 0)
{
#if defined(CVARS_WHITELIST)
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(cmd, true) : true;
if (whitelisted)
#endif // defined(CVARS_WHITELIST)
{
bArgumentAutoComplete = true;
matches.push_back(cmd);
@@ -2590,10 +2404,6 @@ const char* CXConsole::ProcessCompletion(const char* szInputBuffer)
{
if (_strnicmp(m_sPrevTab.c_str(), itrCmds->first.c_str(), m_sPrevTab.length()) == 0)
{
#if defined(CVARS_WHITELIST)
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(itrCmds->first, true) : true;
if (whitelisted)
#endif // defined(CVARS_WHITELIST)
{
matches.push_back((char* const)itrCmds->first.c_str());
}
@@ -2613,10 +2423,6 @@ const char* CXConsole::ProcessCompletion(const char* szInputBuffer)
{//if(itrVars->first.compare(0,m_sPrevTab.length(),m_sPrevTab)==0)
if (_strnicmp(m_sPrevTab.c_str(), itrVars->first, m_sPrevTab.length()) == 0)
{
#if defined(CVARS_WHITELIST)
bool whitelisted = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(itrVars->first, true) : true;
if (whitelisted)
#endif // defined(CVARS_WHITELIST)
{
matches.push_back((char* const)itrVars->first);
}
@@ -2990,12 +2796,6 @@ void CXConsole::ExecuteInputBuffer()
AddCommandToHistory(sTemp.c_str());
#if defined(CVARS_WHITELIST)
CSystem* pSystem = static_cast<CSystem*>(gEnv->pSystem);
ICVarsWhitelist* pCVarsWhitelist = pSystem->GetCVarsWhiteList();
bool execute = (pCVarsWhitelist) ? pCVarsWhitelist->IsWhiteListed(sTemp, false) : true;
if (execute)
#endif // defined(CVARS_WHITELIST)
{
ExecuteStringInternal(sTemp.c_str(), true); // from console
}
-2
View File
@@ -1809,8 +1809,6 @@ XmlNodeRef XmlParserImp::ParseFile(const char* filename, XmlString& errorString,
ParseEnd();
}
SYNCHRONOUS_LOADING_TICK();
delete [] pFileContents;
return root;
@@ -19,14 +19,11 @@ set(FILES
ConsoleBatchFile.cpp
ConsoleHelpGen.cpp
CryAsyncMemcpy.cpp
DebugCallStack.cpp
GeneralMemoryHeap.cpp
HandlerBase.cpp
IDebugCallStack.cpp
AsyncPakManager.cpp
Log.cpp
SystemRender.cpp
NotificationNetwork.cpp
PhysRenderer.cpp
ResourceManager.cpp
ServerHandler.cpp
@@ -36,7 +33,6 @@ set(FILES
SystemCFG.cpp
SystemEventDispatcher.cpp
SystemInit.cpp
SystemScheduler.cpp
SystemWin32.cpp
Timer.cpp
UnixConsole.cpp
@@ -52,7 +48,6 @@ set(FILES
ServerHandler.h
ServerThrottle.h
SyncLock.h
SystemScheduler.h
UnixConsole.h
SystemInit.h
XML/ReadWriteXMLSink.h
@@ -63,12 +58,8 @@ set(FILES
ConsoleBatchFile.h
ConsoleHelpGen.h
CryWaterMark.h
DebugCallStack.h
GeneralMemoryHeap.h
IDebugCallStack.h
IThreadConfigManager.h
Log.h
NotificationNetwork.h
resource.h
SimpleStringPool.h
CrySystem_precompiled.h
@@ -107,24 +98,12 @@ set(FILES
XML/WriteXMLSource.cpp
ZipFile.h
ZipFileFormat_info.h
ProfileLogSystem.cpp
Sampler.cpp
ProfileLogSystem.h
Sampler.h
LocalizedStringManager.cpp
LocalizedStringManager.h
CryThreadUtil_win32_thread.h
ThreadInfo.cpp
ThreadInfo.h
ThreadTask.h
ThreadTask.cpp
ThreadConfigManager.h
ThreadConfigManager.cpp
SystemThreading.cpp
ZLibCompressor.cpp
ZLibCompressor.h
SoftCode/SoftCodeMgr.cpp
SoftCode/SoftCodeMgr.h
Huffman.cpp
Huffman.h
RemoteConsole/RemoteConsole.cpp
@@ -18,7 +18,5 @@ set(FILES
Tests/Test_Localization.cpp
Tests/test_Main.cpp
Tests/test_MaterialUtils.cpp
UnitTests/CryMathTests.cpp
UnitTests/CryPakUnitTests.cpp
DllMain.cpp
)