// RuntimeForStatic base library | C+- (SysRoutine) | Author: Sergei Y.Kitáev
#include "Precompiled.h"
#include "SharedIncludes.h"
namespace RuntimeForStatic {
//==================================================================================================

UINT __stdcall $FatalError::TerminationRoutine(PVOID pStartData)
{
   $$VERIFY_POINTER_ARG_( pStartData );
   auto tsp = $RT::GetThreadSettingsPattern();
   $ThreadSettings tset = {};
   if ( tsp ) tset = *tsp;
   tset.ReplaceEmptyLocaleValues();
   ::SetThreadLocale( tset.LocaleId );
   $Interlocked::Write($, &_TerminationThreadId_, ::GetCurrentThreadId() );
   ::MemoryBarrier();
   const TerminationParams &tp = *(PTerminationParams)pStartData;
   PCWSTR message = tp.Message;
   $$VERIFY_POINTER( message );
   HelpersRT::TraceInformation($$, IsInTerminationThread() ?
      $TEXT( L"Fatal error thread is in action.",
             L"Задействован программный поток фатальной ошибки." ) :
      $TEXT( L"Termination routine was started in fatal error source thread.",
             L"Терминирующая процедура была запущена из программного потока-источника "
             L"фатальной ошибки." ));
   auto emergencyHandler = GetEmergencyHandler();
   if ( emergencyHandler )
   {
      HelpersRT::TraceOperation($$, $TEXT(
         L"Calling fatal error emergency handler",
         L"Вызов чрезвычайного обработчика фатальной ошибки" ));
      try
      {
         emergencyHandler( message );
      }
      catch (const std::exception& e)
      {
         TraceExceptionMessage( $TEXT(
            L"Exception in fatal error emergency handler",
            L"Исключение в чрезвычайном обработчике фатальной ошибки" ),
            e );
      }
   }
   ReportError( ReportOutputs::UI, tp );
   auto emergencyFinalHandler = GetEmergencyFinalHandler();
   if ( emergencyFinalHandler )
   {
      HelpersRT::TraceOperation($$, $TEXT(
         L"Calling fatal error emergency final handler",
         L"Вызов чрезвычайного финального обработчика фатальной ошибки" ));
      try
      {
         emergencyFinalHandler( message );
      }
      catch (const std::exception& e)
      {
         TraceExceptionMessage( $TEXT(
            L"Exception in fatal error emergency final handler",
            L"Исключение в чрезвычайном финальном обработчике фатальной ошибки" ),
            e );
      }
   }
   Terminate();
   $DEAD_CODE_BRANCH();
   return (UINT)-1;
}

//--------------------------------------------------------------------------------------------------

void $FatalError::Terminate() $not_returns
{
   PWSTR pSysErrorText = nullptr;
   DWORD dwSysError = 0;
   if ( !::TerminateProcess( ::GetCurrentProcess(), $RT::GetBreakdownExitCode() ) )
      pSysErrorText = HelpersRT::GetSystemMessage($, dwSysError );
   PCWSTR baseErrorText = $TEXT(
      L"Can not terminate execution process of the program.",
      L"Не удаётся прервать процесс исполнения программы." );
   PWSTR pErrorText = nullptr;
   if ( pSysErrorText )
      pErrorText = HelpersRT::FormatAlloc($, L"%s\r\n%s", baseErrorText, pSysErrorText );
   $Memory::Free( pSysErrorText );
   if ( !pErrorText && dwSysError )
      pErrorText = HelpersRT::FormatAlloc($, $TEXT(
         L"%s\r\nSystem error code: %d (0x%.8X).",
         L"%s\r\nКод системной ошибки: %d (0x%.8X)." ),
         baseErrorText, dwSysError, dwSysError );
   TerminationParams tp = { $_( (PCWSTR)pErrorText, baseErrorText ) }; // Message
   ReportError( tp, true );
   $Memory::Free( pErrorText );
   $Thread::Hang();
   $DEAD_CODE_BRANCH();
}

//==================================================================================================
} // RuntimeForStatic
