2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "LaunchPrivatePCH.h"
# include "ExceptionHandling.h"
2014-10-07 05:41:02 -04:00
# include "LinuxPlatformCrashContext.h"
2014-03-14 14:13:41 -04:00
# if WITH_EDITOR
2014-05-29 17:09:19 -04:00
# include "Editor/MainFrame/Private/Frame/MainFrameActions.h"
2014-03-14 14:13:41 -04:00
# endif
# include <locale.h>
# include <sys/resource.h>
static FString GSavedCommandLine ;
extern int32 GuardedMain ( const TCHAR * CmdLine ) ;
extern void LaunchStaticShutdownAfterError ( ) ;
// FIXME: handle expose it someplace else?
2015-01-26 13:38:36 -05:00
extern int32 DLLIMPORT ReportCrash ( const FLinuxCrashContext & Context ) ;
extern void DLLIMPORT GenerateCrashInfoAndLaunchReporter ( const FLinuxCrashContext & Context ) ;
2014-03-14 14:13:41 -04:00
/**
* Game - specific crash reporter
*/
2014-10-01 14:45:04 -04:00
void EngineCrashHandler ( const FGenericCrashContext & GenericContext )
2014-03-14 14:13:41 -04:00
{
const FLinuxCrashContext & Context = static_cast < const FLinuxCrashContext & > ( GenericContext ) ;
printf ( " EngineCrashHandler: Signal=%d \n " , Context . Signal ) ;
ReportCrash ( Context ) ;
if ( GLog )
{
GLog - > Flush ( ) ;
}
if ( GWarn )
{
GWarn - > Flush ( ) ;
}
if ( GError )
{
GError - > Flush ( ) ;
GError - > HandleError ( ) ;
}
//LaunchStaticShutdownAfterError(); // this tends to crash itself, so while it should be here, it needs to be commented
return GenerateCrashInfoAndLaunchReporter ( Context ) ;
}
/**
* Increases ( soft ) limit on a specific resource
*
* @ param DesiredLimit - max number of open files desired .
*/
static bool IncreaseLimit ( int Resource , rlim_t DesiredLimit )
{
rlimit Limit ;
if ( getrlimit ( Resource , & Limit ) ! = 0 )
{
fprintf ( stderr , " getrlimit() failed with error %d (%s) \n " , errno , strerror ( errno ) ) ;
return false ;
}
if ( Limit . rlim_cur = = RLIM_INFINITY | | Limit . rlim_cur > = DesiredLimit )
{
# if !UE_BUILD_SHIPPING
printf ( " - Existing per-process limit (soft=%lu, hard=%lu) is enough for us (need only %lu) \n " , Limit . rlim_cur , Limit . rlim_max , DesiredLimit ) ;
# endif // !UE_BUILD_SHIPPING
return true ;
}
Limit . rlim_cur = DesiredLimit ;
if ( setrlimit ( Resource , & Limit ) ! = 0 )
{
fprintf ( stderr , " setrlimit() failed with error %d (%s) \n " , errno , strerror ( errno ) ) ;
if ( errno = = EINVAL )
{
if ( DesiredLimit = = RLIM_INFINITY )
{
fprintf ( stderr , " - Max per-process value allowed is %lu (we wanted infinity). \n " , Limit . rlim_max ) ;
}
else
{
fprintf ( stderr , " - Max per-process value allowed is %lu (we wanted %lu). \n " , Limit . rlim_max , DesiredLimit ) ;
}
}
return false ;
}
return true ;
}
/**
2014-04-30 10:13:06 -04:00
* Expects GSavedCommandLine to be set up . Increases limit on
* - number of open files to be no less than desired ( if specified on command line , otherwise left alone )
* - size of core file , so core gets dumped and we can debug crashed builds ( unless overriden with - nocore )
2014-03-14 14:13:41 -04:00
*
*/
2014-04-30 10:13:06 -04:00
static bool IncreasePerProcessLimits ( )
2014-03-14 14:13:41 -04:00
{
2014-04-30 10:13:06 -04:00
// honor the parameter if given, but don't change limits if not
int32 FileHandlesToReserve = - 1 ;
if ( FParse : : Value ( * GSavedCommandLine , TEXT ( " numopenfiles= " ) , FileHandlesToReserve ) & & FileHandlesToReserve > 0 )
2014-03-14 14:13:41 -04:00
{
2014-04-30 10:13:06 -04:00
# if !UE_BUILD_SHIPPING
printf ( " Increasing per-process limit of open file handles to %d \n " , FileHandlesToReserve ) ;
# endif // !UE_BUILD_SHIPPING
if ( ! IncreaseLimit ( RLIMIT_NOFILE , FileHandlesToReserve ) )
{
2014-05-08 13:01:46 -04:00
fprintf ( stderr , " Could not adjust number of file handles, consider changing \" nofile \" in /etc/security/limits.conf and relogin. \n error(%d): %s \n " , errno , strerror ( errno ) ) ;
2014-04-30 10:13:06 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
}
# if !UE_BUILD_SHIPPING
2014-04-30 10:13:06 -04:00
if ( ! FParse : : Param ( * GSavedCommandLine , TEXT ( " nocore " ) ) )
2014-03-14 14:13:41 -04:00
{
2014-04-30 10:13:06 -04:00
printf ( " Increasing per-process limit of core file size to infinity. \n " ) ;
if ( ! IncreaseLimit ( RLIMIT_CORE , RLIM_INFINITY ) )
{
2014-05-08 13:01:46 -04:00
fprintf ( stderr , " Could not adjust core file size, consider changing \" core \" in /etc/security/limits.conf and relogin. \n error(%d): %s \n " , errno , strerror ( errno ) ) ;
2014-04-30 10:18:07 -04:00
fprintf ( stderr , " Alternatively, pass -nocore if you are unable or unwilling to do that. \n " ) ;
2014-04-30 10:13:06 -04:00
return false ;
}
2014-03-14 14:13:41 -04:00
}
2014-04-30 10:13:06 -04:00
# endif // !UE_BUILD_SHIPPING
2014-03-14 14:13:41 -04:00
return true ;
}
int main ( int argc , char * argv [ ] )
{
FPlatformMisc : : SetGracefulTerminationHandler ( ) ;
2014-08-11 14:57:34 -04:00
# if UE_BUILD_SHIPPING
2014-03-14 14:13:41 -04:00
// only printed in shipping
printf ( " %s %d %d %d %d \n " , StringCast < ANSICHAR > ( * GEngineVersion . ToString ( ) ) . Get ( ) , GEngineMinNetVersion , GEngineNegotiationVersion , GPackageFileUE4Version , GPackageFileLicenseeUE4Version ) ;
# endif // UE_BUILD_SHIPPING
int ErrorLevel = 0 ;
setlocale ( LC_CTYPE , " " ) ;
for ( int32 Option = 1 ; Option < argc ; Option + + )
{
GSavedCommandLine + = TEXT ( " " ) ;
2014-08-11 14:57:34 -04:00
// we need to quote stuff that has spaces in it because something somewhere is removing quotation marks before they arrive here
FString Temp = UTF8_TO_TCHAR ( argv [ Option ] ) ;
if ( Temp . Contains ( TEXT ( " " ) ) )
{
if ( Temp . StartsWith ( TEXT ( " - " ) ) )
{
Temp = Temp . Replace ( TEXT ( " = " ) , TEXT ( " = \" " ) ) ;
}
else
{
Temp = TEXT ( " \" " ) + Temp ;
}
Temp + = TEXT ( " \" " ) ;
}
GSavedCommandLine + = Temp ; // note: technically it depends on locale
2014-03-14 14:13:41 -04:00
}
# if !UE_BUILD_SHIPPING
GAlwaysReportCrash = true ; // set by default and reverse the behavior
if ( FParse : : Param ( * GSavedCommandLine , TEXT ( " nocrashreports " ) ) | | FParse : : Param ( * GSavedCommandLine , TEXT ( " no-crashreports " ) ) )
{
GAlwaysReportCrash = false ;
}
# endif
2014-04-30 10:13:06 -04:00
if ( ! IncreasePerProcessLimits ( ) )
2014-03-14 14:13:41 -04:00
{
fprintf ( stderr , " Could not set desired per-process limits, consider changing system limits. \n " ) ;
ErrorLevel = 1 ;
}
else
{
# if UE_BUILD_DEBUG
if ( true & & ! GAlwaysReportCrash )
# else
if ( FPlatformMisc : : IsDebuggerPresent ( ) & & ! GAlwaysReportCrash )
# endif
{
// Don't use exception handling when a debugger is attached to exactly trap the crash. This does NOT check
// whether we are the first instance or not!
ErrorLevel = GuardedMain ( * GSavedCommandLine ) ;
}
else
{
FPlatformMisc : : SetCrashHandler ( EngineCrashHandler ) ;
GIsGuarded = 1 ;
// Run the guarded code.
ErrorLevel = GuardedMain ( * GSavedCommandLine ) ;
GIsGuarded = 0 ;
}
}
2014-05-20 07:48:06 -04:00
if ( ErrorLevel )
{
printf ( " Exiting abnormally (error code: %d) \n " , ErrorLevel ) ;
}
2014-03-14 14:13:41 -04:00
return ErrorLevel ;
}