Core: fix several initialization bugs

- Don't free console if the process is being closed from the console, this will cause the process to freeze within the FreeConsole() call
- Properly check for CPU features in order, and moved all checks to a single function utilizing the CPUInformation struct.
- Made SDK_Init() and SDK_Shutdown() more resilient against mistakes with new checks and error messages (added since they are exported now).
This commit is contained in:
Kawe Mazidjatari 2024-04-04 18:49:00 +02:00
parent b4ad19275f
commit bf5dd318a7
7 changed files with 91 additions and 54 deletions

View File

@ -3,6 +3,7 @@
#include "core/init.h"
#include "core/logdef.h"
#include "core/logger.h"
#include "tier0/cpu.h"
#include "tier0/basetypes.h"
#include "tier0/crashhandler.h"
#include "tier0/commandline.h"
@ -24,6 +25,11 @@
#endif
bool g_bSdkInitialized = false;
bool g_bSdkInitCallInitiated = false;
bool g_bSdkShutdownCallInitiated = false;
bool g_bSdkShutdownInitiatedFromConsoleHandler = false;
HMODULE s_hModuleHandle = NULL;
//#############################################################################
@ -77,7 +83,21 @@ void Tier0_Init()
void SDK_Init()
{
CheckCPU(); // Check CPU as early as possible; error out if CPU isn't supported.
assert(!g_bSdkInitialized);
CheckSystemCPU(); // Check CPU as early as possible; error out if CPU isn't supported.
if (g_bSdkInitCallInitiated)
{
spdlog::error("Recursive initialization!\n");
return;
}
// Set after checking cpu and initializing MathLib since we check CPU
// features there. Else we crash on the recursive initialization error as
// SpdLog uses SSE features.
g_bSdkInitCallInitiated = true;
MathLib_Init(); // Initialize Mathlib.
PEB64* pEnv = CModule::GetProcessEnvironmentBlock();
@ -129,13 +149,25 @@ void SDK_Shutdown()
{
assert(g_bSdkInitialized);
if (!g_bSdkInitialized)
// Also check CPU in shutdown, since this function is exported, if they
// call this with an unsupported CPU we should let them know rather than
// crashing the process.
CheckSystemCPU();
if (g_bSdkShutdownCallInitiated)
{
spdlog::error("Recursive shutdown!\n");
return;
}
g_bSdkInitialized = false;
g_bSdkShutdownCallInitiated = true;
if (!g_bSdkInitialized)
{
spdlog::error("Not initialized!\n");
return;
}
Msg(eDLL_T::NONE, "GameSDK shutdown initiated\n");
curl_global_cleanup();
@ -151,7 +183,13 @@ void SDK_Shutdown()
Winsock_Shutdown();
SpdLog_Shutdown();
Console_Shutdown();
// If the shutdown was initiated from the console window itself, don't
// shutdown the console as it would otherwise deadlock in FreeConsole!
if (!g_bSdkShutdownInitiatedFromConsoleHandler)
Console_Shutdown();
g_bSdkInitialized = false;
}
//#############################################################################

View File

@ -418,33 +418,6 @@ void QuerySystemInfo()
}
}
void CheckCPU() // Respawn's engine and our SDK utilize POPCNT, SSE3 and SSSE3 (Supplemental SSE 3 Instructions).
{
CpuIdResult_t cpuResult;
__cpuid(reinterpret_cast<int*>(&cpuResult), 1);
char szBuf[1024];
if ((cpuResult.ecx & (1 << 0)) == 0)
{
V_snprintf(szBuf, sizeof(szBuf), "CPU does not have %s!\n", "SSE 3");
MessageBoxA(NULL, szBuf, "Unsupported CPU", MB_ICONERROR | MB_OK);
ExitProcess(0xFFFFFFFF);
}
if ((cpuResult.ecx & (1 << 9)) == 0)
{
V_snprintf(szBuf, sizeof(szBuf), "CPU does not have %s!\n", "SSSE 3 (Supplemental SSE 3 Instructions)");
MessageBoxA(NULL, szBuf, "Unsupported CPU", MB_ICONERROR | MB_OK);
ExitProcess(0xFFFFFFFF);
}
if ((cpuResult.ecx & (1 << 23)) == 0)
{
V_snprintf(szBuf, sizeof(szBuf), "CPU does not have %s!\n", "POPCNT");
MessageBoxA(NULL, szBuf, "Unsupported CPU", MB_ICONERROR | MB_OK);
ExitProcess(0xFFFFFFFF);
}
}
#if defined (DEDICATED)
#define SIGDB_FILE "cfg/server/startup.bin"
#elif defined (CLIENT_DLL)

View File

@ -11,10 +11,10 @@ void Winsock_Shutdown();
void DirtySDK_Startup();
void DirtySDK_Shutdown();
void QuerySystemInfo();
void CheckCPU();
void DetourInit();
void DetourAddress();
void DetourRegister();
extern bool g_bSdkInitialized;
extern bool g_bSdkShutdownInitiatedFromConsoleHandler;

View File

@ -4059,11 +4059,6 @@ void MathLib_Init(float gamma, float texGamma, float brightness, int overbright)
// FIXME: Hook SSE into VectorAligned + Vector4DAligned
#if !defined( _GAMECONSOLE )
CheckCPUforSSE2();
#endif //!360
s_bMathlibInitialized = true;
InitSinCosTable();

View File

@ -470,7 +470,9 @@ const CPUInformation& GetCPUInformation(void)
pi.m_bSSE41 = (cpuid1.ecx >> 19) & 1;
pi.m_bSSE42 = (cpuid1.ecx >> 20) & 1;
pi.m_b3DNow = Check3DNowTechnology();
pi.m_bPOPCNT= (cpuid1.ecx >> 23) & 1;
pi.m_bAVX = (cpuid1.ecx >> 28) & 1;
pi.m_bHRVSR = (cpuid1.ecx >> 31) & 1;
pi.m_szProcessorID = const_cast<char*>(GetProcessorVendorId());
pi.m_szProcessorBrand = const_cast<char*>(GetProcessorBrand());
pi.m_bHT = (pi.m_nPhysicalProcessors < pi.m_nLogicalProcessors); //HTSupported();
@ -573,16 +575,36 @@ const CPUInformation& GetCPUInformation(void)
return pi;
}
void CheckCPUforSSE2()
void CheckSystemCPU()
{
const CPUInformation& pi = GetCPUInformation();
if (!(pi.m_bSSE && pi.m_bSSE2))
{
Assert(0);
if (MessageBoxA(NULL, "SSE and SSE2 are required.", "Unsupported CPU", MB_ICONERROR | MB_OK))
{
TerminateProcess(GetCurrentProcess(), EXIT_FAILURE);
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
}
}
if (!pi.m_bSSE3)
{
if (MessageBoxA(NULL, "SSE3 is required.", "Unsupported CPU", MB_ICONERROR | MB_OK))
{
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
}
}
if (!pi.m_bSSSE3)
{
if (MessageBoxA(NULL, "SSSE3 (Supplemental SSE3 Instructions) is required.", "Unsupported CPU", MB_ICONERROR | MB_OK))
{
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
}
}
if (!pi.m_bPOPCNT)
{
if (MessageBoxA(NULL, "POPCNT is required.", "Unsupported CPU", MB_ICONERROR | MB_OK))
{
TerminateProcess(GetCurrentProcess(), 0xFFFFFFFF);
}
}
}

View File

@ -62,7 +62,9 @@ struct CPUInformation
m_bSSE4a : 1,
m_bSSE41 : 1,
m_bSSE42 : 1,
m_bAVX : 1; // Is AVX supported?
m_bPOPCNT: 1, // Pop count
m_bAVX : 1, // Advanced Vector Extensions
m_bHRVSR : 1; // Hypervisor
uint32 m_nModel;
uint32 m_nFeatures[3];
@ -94,12 +96,14 @@ struct CPUInformation
m_szProcessorID = nullptr;
m_szProcessorBrand = nullptr;
m_bSSE3 = false;
m_bSSSE3 = false;
m_bSSE4a = false;
m_bSSE41 = false;
m_bSSE42 = false;
m_bAVX = false;
m_bSSE3 = false;
m_bSSSE3 = false;
m_bSSE4a = false;
m_bSSE41 = false;
m_bSSE42 = false;
m_bPOPCNT = false;
m_bAVX = false;
m_bHRVSR = false;
m_nModel = 0;
m_nFeatures[0] = 0;
@ -126,6 +130,6 @@ const char* GetProcessorBrand(bool bRemovePadding);
const CPUInformation& GetCPUInformation(void);
void CheckCPUforSSE2();
void CheckSystemCPU();
#endif // CPU_H

View File

@ -1,4 +1,5 @@
#include "core/stdafx.h"
#include "core/init.h"
#include "windows/system.h"
#include "engine/host_state.h"
@ -61,14 +62,18 @@ ConsoleHandlerRoutine(
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
if (g_pHostState)
{
g_pHostState->m_iNextState = HostStates_t::HS_SHUTDOWN;
}
if (!g_bSdkShutdownInitiatedFromConsoleHandler)
g_bSdkShutdownInitiatedFromConsoleHandler = true;
// Give it time to shutdown properly, value is set to the max possible
if (g_pHostState) // This tells the engine to gracefully shutdown on the next frame.
g_pHostState->m_iNextState = HostStates_t::HS_SHUTDOWN;
// Give it time to shutdown properly, this loop waits for max time
// of SPI_GETWAITTOKILLSERVICETIMEOUT, which is 20000ms by default.
Sleep(20000);
while (g_bSdkInitialized)
Sleep(50);
return TRUE;
}