intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message) { if(OVRIsDebuggerPresent()) { OVR_DEBUG_BREAK; } else { #if defined(OVR_BUILD_DEBUG) // Print a stack trace of all threads. OVR::String s; OVR::String threadListOutput; static OVR::SymbolLookup symbolLookup; s = "Failure: "; s += message; if(symbolLookup.Initialize() && symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our internal handling and retrieve starting at the assertion location (our caller) only. { s += "\r\n\r\n"; s += threadListOutput; } OVR::Util::DisplayMessageBox(title, s.ToCStr()); #else OVR::Util::DisplayMessageBox(title, message); #endif } return 0; }
intptr_t DefaultAssertionHandler(intptr_t /*userParameter*/, const char* title, const char* message) { if(OVRIsDebuggerPresent()) { OVR_DEBUG_BREAK; } else { OVR_UNUSED(title); OVR_UNUSED(message); #if defined(OVR_BUILD_DEBUG) if(Allocator::GetInstance()) // The code below currently depends on having a valid Allocator. { // Print a stack trace of all threads. OVR::String s; OVR::String threadListOutput; static OVR::SymbolLookup symbolLookup; s = "Failure: "; s += message; if(symbolLookup.Initialize() && symbolLookup.ReportThreadCallstack(threadListOutput, 4)) // This '4' is there to skip our internal handling and retrieve starting at the assertion location (our caller) only. { // threadListOutput has newlines that are merely \n, whereas Windows MessageBox wants \r\n newlines. So we insert \r in front of all \n. for(size_t i = 0, iEnd = threadListOutput.GetSize(); i < iEnd; i++) { if(threadListOutput[i] == '\n') { threadListOutput.Insert("\r", i, 1); ++i; ++iEnd; } } s += "\r\n\r\n"; s += threadListOutput; } OVR::Util::DisplayMessageBox(title, s.ToCStr()); } else { OVR::Util::DisplayMessageBox(title, message); } #else OVR::Util::DisplayMessageBox(title, message); #endif } return 0; }
int WatchDogObserver::Run() { OVR_DEBUG_LOG(("[WatchDogObserver] Starting")); SetThreadName("WatchDog"); while (!TerminationEvent.Wait(WakeupInterval)) { Lock::Locker locker(&ListLock); const uint32_t t1 = GetFastMsTime(); const int count = DogList.GetSizeI(); for (int i = 0; i < count; ++i) { WatchDog* dog = DogList[i]; const int threshold = dog->ThreshholdMilliseconds; const uint32_t t0 = dog->WhenLastFedMilliseconds; // If threshold exceeded, assume there is thread deadlock of some sort. int delta = (int)(t1 - t0); if (delta > threshold) { // Expected behavior: // SingleProcessDebug, SingleProcessRelease, Debug: This is only ever done for internal testing, so we don't want it to trigger the deadlock termination. // Release: This is our release configuration where we want it to terminate itself. // Print a stack trace of all threads if there's no debugger present. const bool debuggerPresent = OVRIsDebuggerPresent(); LogError("{ERR-027} [WatchDogObserver] Deadlock detected: %s", dog->ThreadName.ToCStr()); if (!debuggerPresent) // We don't print threads if a debugger is present because otherwise every time the developer paused the app to debug, it would spit out a long thread trace upon resuming. { if (SymbolLookup::Initialize()) { // symbolLookup is static here to avoid putting 32 KB on the stack // and potentially overflowing the stack. This function is only ever // run by one thread so it should be safe. static SymbolLookup symbolLookup; String threadListOutput, moduleListOutput; symbolLookup.ReportThreadCallstacks(threadListOutput); symbolLookup.ReportModuleInformation(moduleListOutput); LogError("---DEADLOCK STATE---\n\n%s\n\n%s\n---END OF DEADLOCK STATE---", threadListOutput.ToCStr(), moduleListOutput.ToCStr()); } if (IsReporting) { ExceptionHandler::ReportDeadlock(DogList[i]->ThreadName, OrganizationName , ApplicationName); // Disable reporting after the first deadlock report. IsReporting = false; } } if (IsExitingOnDeadlock()) { OVR_ASSERT_M(false, "Watchdog detected a deadlock. Exiting the process."); // This won't have an effect unless asserts are enabled in release builds. OVR::ExitProcess(-1); } } } } OVR_DEBUG_LOG(("[WatchDogObserver] Good night")); return 0; }