From b20a970b1d0027d96ef73ed8c5ae573a38761c06 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 18 Oct 2019 11:10:48 -0500 Subject: [PATCH] fix shared memory reboot loss --- src/core/kernel/exports/EmuKrnlHal.cpp | 20 ++++++ src/core/kernel/init/CxbxKrnl.cpp | 89 +++++++++++++------------- 2 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlHal.cpp b/src/core/kernel/exports/EmuKrnlHal.cpp index 0dfbc9e1f..3baddd252 100644 --- a/src/core/kernel/exports/EmuKrnlHal.cpp +++ b/src/core/kernel/exports/EmuKrnlHal.cpp @@ -577,6 +577,26 @@ XBSYSAPI EXPORTNUM(49) xboxkrnl::VOID DECLSPEC_NORETURN NTAPI xboxkrnl::HalRetur if (!CxbxExec(false, nullptr, false)) { CxbxKrnlCleanup("Could not launch %s", XbePath.c_str()); } + + // This is a requirement to have shared memory buffers remain alive and transfer to new emulation process. + unsigned int retryAttempt = 0; + unsigned int curProcID = 0; + unsigned int oldProcID = GetCurrentProcessId(); + while(true) { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + g_EmuShared->GetKrnlProcID(&curProcID); + // Break when new emulation process has take over. + if (curProcID != oldProcID) { + break; + } + retryAttempt++; + // Terminate after 5 seconds of failure. + if (retryAttempt >= (5 * (1000 / 100))) { + CxbxShowError("Could not reboot, new emulation process did not take over."); + break; + } + } + } } break; diff --git a/src/core/kernel/init/CxbxKrnl.cpp b/src/core/kernel/init/CxbxKrnl.cpp index 824cdd346..8cb74336b 100644 --- a/src/core/kernel/init/CxbxKrnl.cpp +++ b/src/core/kernel/init/CxbxKrnl.cpp @@ -752,11 +752,6 @@ void CxbxKrnlEmulate(uint32_t blocks_reserved[384]) /* Initialize Cxbx File Paths */ CxbxInitFilePaths(); - /* Must be called after CxbxInitFilePaths */ - if (!CxbxLockFilePath()) { - return; - } - // Skip '/load' switch // Get XBE Name : std::string xbePath; @@ -784,44 +779,8 @@ void CxbxKrnlEmulate(uint32_t blocks_reserved[384]) } int BootFlags; - FILE* krnlLog = nullptr; g_EmuShared->GetBootFlags(&BootFlags); - // debug console allocation (if configured) - if (DbgMode == DM_CONSOLE) - { - if (AllocConsole()) - { - HANDLE StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - // Maximise the console scroll buffer height : - CONSOLE_SCREEN_BUFFER_INFO coninfo; - GetConsoleScreenBufferInfo(StdHandle, &coninfo); - coninfo.dwSize.Y = SHRT_MAX - 1; // = 32767-1 = 32766 = maximum value that works - SetConsoleScreenBufferSize(StdHandle, coninfo.dwSize); - (void)freopen("CONOUT$", "wt", stdout); - (void)freopen("CONIN$", "rt", stdin); - SetConsoleTitle("Cxbx-Reloaded : Kernel Debug Console"); - SetConsoleTextAttribute(StdHandle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); - } - } - else - { - FreeConsole(); - if (DbgMode == DM_FILE) { - // Peform clean write to kernel log for first boot. Unless multi-xbe boot occur then perform append to existing log. - krnlLog = freopen(DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout); - // Append separator for better readability after reboot. - if (BootFlags != DebugMode::DM_NONE) { - std::cout << "\n------REBOOT------REBOOT------REBOOT------REBOOT------REBOOT------\n" << std::endl; - } - } - else { - char buffer[16]; - if (GetConsoleTitle(buffer, 16) != NULL) - (void)freopen("nul", "w", stdout); - } - } - g_CurrentProcessHandle = GetCurrentProcess(); // OpenProcess(PROCESS_ALL_ACCESS, FALSE, GetCurrentProcessId()); // Set up the logging variables for the kernel process during initialization. @@ -862,6 +821,10 @@ void CxbxKrnlEmulate(uint32_t blocks_reserved[384]) DWORD dwExitCode = EXIT_SUCCESS; g_EmuShared->GetKrnlProcID(&prevKrnlProcID); + // Save current kernel proccess id for next reboot if will occur in the future. + // And to tell previous kernel process we had take over. This allow reboot's shared memory buffer to survive. + g_EmuShared->SetKrnlProcID(GetCurrentProcessId()); + // Force wait until previous kernel process is closed. if (prevKrnlProcID != 0) { HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, FALSE, prevKrnlProcID); @@ -879,15 +842,53 @@ void CxbxKrnlEmulate(uint32_t blocks_reserved[384]) CxbxKrnlShutDown(); } + /* Must be called after CxbxInitFilePaths and previous kernel process shutdown. */ + if (!CxbxLockFilePath()) { + return; + } + + FILE* krnlLog = nullptr; + // debug console allocation (if configured) + if (DbgMode == DM_CONSOLE) + { + if (AllocConsole()) + { + HANDLE StdHandle = GetStdHandle(STD_OUTPUT_HANDLE); + // Maximise the console scroll buffer height : + CONSOLE_SCREEN_BUFFER_INFO coninfo; + GetConsoleScreenBufferInfo(StdHandle, &coninfo); + coninfo.dwSize.Y = SHRT_MAX - 1; // = 32767-1 = 32766 = maximum value that works + SetConsoleScreenBufferSize(StdHandle, coninfo.dwSize); + (void)freopen("CONOUT$", "wt", stdout); + (void)freopen("CONIN$", "rt", stdin); + SetConsoleTitle("Cxbx-Reloaded : Kernel Debug Console"); + SetConsoleTextAttribute(StdHandle, FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED); + } + } + else + { + FreeConsole(); + if (DbgMode == DM_FILE) { + // Peform clean write to kernel log for first boot. Unless multi-xbe boot occur then perform append to existing log. + krnlLog = freopen(DebugFileName.c_str(), ((BootFlags == DebugMode::DM_NONE) ? "wt" : "at"), stdout); + // Append separator for better readability after reboot. + if (BootFlags != DebugMode::DM_NONE) { + std::cout << "\n------REBOOT------REBOOT------REBOOT------REBOOT------REBOOT------\n" << std::endl; + } + } + else { + char buffer[16]; + if (GetConsoleTitle(buffer, 16) != NULL) + (void)freopen("nul", "w", stdout); + } + } + bool isLogEnabled; g_EmuShared->GetIsKrnlLogEnabled(&isLogEnabled); g_bPrintfOn = isLogEnabled; g_EmuShared->ResetKrnl(); - // Save current kernel proccess id for next reboot if will occur in the future. - g_EmuShared->SetKrnlProcID(GetCurrentProcessId()); - // Write a header to the log { EmuLogInit(LOG_LEVEL::INFO, "Cxbx-Reloaded Version %s", CxbxVersionStr);