2020-12-15 09:27:44 -04:00
// Copyright 2011-2020 Molecular Matters GmbH, all rights reserved.
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
//#include PCH_INCLUDE
// END EPIC MOD
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
# include "LC_LiveProcess.h"
# include "LC_HeartBeat.h"
# include "LC_CodeCave.h"
2019-07-16 08:43:32 -04:00
# include "LC_Event.h"
# include "LC_PrimitiveNames.h"
# include "LC_VisualStudioAutomation.h"
2020-12-15 09:27:44 -04:00
# include "LC_Process.h"
// BEGIN EPIC MOD
2019-07-16 08:44:38 -04:00
# include "LC_Logging.h"
2020-12-15 09:27:44 -04:00
// END EPIC MOD
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
2021-01-18 13:02:32 -04:00
# if LC_64_BIT
2021-01-19 12:58:35 -04:00
// EPIC BEGIN MOD
namespace liveProcess // Duplicate definitions
// EPIC END MOD
2021-01-18 13:02:32 -04:00
{
static const void * GetLowerBoundIn4GBRange ( const void * moduleBase )
{
// nothing can be loaded at address 0x0, 64 KB seems like a realistic minimum
const uint64_t LOWEST_ADDRESS = 64u * 1024u ;
const uint64_t base = pointer : : AsInteger < uint64_t > ( moduleBase ) ;
// make sure we don't underflow
if ( base > = 0x80000000ull + LOWEST_ADDRESS )
{
return pointer : : FromInteger < const void * > ( base - 0x80000000ull ) ;
}
// operation would underflow
return pointer : : FromInteger < const void * > ( LOWEST_ADDRESS ) ;
}
static const void * GetUpperBoundIn4GBRange ( const void * moduleBase )
{
2022-08-08 11:29:32 -04:00
const uint64_t HighestPossibleAddress = 0x00007FFFFFFF0000ull ;
const uint64_t HighestPossibleAddressThreshold = HighestPossibleAddress - 2ull * 1024ull * 1024ull * 1024ull ;
2021-01-18 13:02:32 -04:00
const uint64_t base = pointer : : AsInteger < uint64_t > ( moduleBase ) ;
// make sure we don't overflow
2022-08-08 11:29:32 -04:00
if ( base < = HighestPossibleAddressThreshold )
2021-01-18 13:02:32 -04:00
{
2022-08-08 11:29:32 -04:00
return pointer : : FromInteger < const void * > ( base + 2ull * 1024ull * 1024ull * 1024ull ) ;
2021-01-18 13:02:32 -04:00
}
// operation would overflow
2022-08-08 11:29:32 -04:00
return pointer : : FromInteger < const void * > ( HighestPossibleAddress ) ;
2021-01-18 13:02:32 -04:00
}
}
# endif
2020-12-15 09:27:44 -04:00
LiveProcess : : LiveProcess ( Process : : Handle processHandle , Process : : Id processId , Thread : : Id commandThreadId , const void * jumpToSelf , const DuplexPipe * pipe ,
2019-07-16 08:43:32 -04:00
const wchar_t * imagePath , const wchar_t * commandLine , const wchar_t * workingDirectory , const void * environment , size_t environmentSize )
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
: m_processHandle ( processHandle )
, m_processId ( processId )
, m_commandThreadId ( commandThreadId )
2019-05-24 11:51:54 -04:00
, m_jumpToSelf ( jumpToSelf )
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
, m_pipe ( pipe )
2019-07-16 08:43:32 -04:00
, m_imagePath ( imagePath )
, m_commandLine ( commandLine )
, m_workingDirectory ( workingDirectory )
, m_environment ( environment , environmentSize )
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
, m_imagesTriedToLoad ( )
, m_heartBeatDelta ( 0ull )
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:45:13 -04:00
# if WITH_VISUALSTUDIO_DTE
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
, m_vsDebugger ( nullptr )
, m_vsDebuggerThreads ( )
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:44:38 -04:00
# endif
2020-12-15 09:27:44 -04:00
// END EPIC MOD
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
, m_codeCave ( nullptr )
2019-07-16 08:43:32 -04:00
, m_restartState ( RestartState : : DEFAULT )
2021-01-18 13:02:32 -04:00
, m_virtualMemoryRange ( processHandle )
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
{
m_imagesTriedToLoad . reserve ( 256u ) ;
}
void LiveProcess : : ReadHeartBeatDelta ( const wchar_t * const processGroupName )
{
HeartBeat heartBeat ( processGroupName , m_processId ) ;
m_heartBeatDelta = heartBeat . ReadBeatDelta ( ) ;
}
bool LiveProcess : : MadeProgress ( void ) const
{
if ( m_heartBeatDelta > = 100ull * 10000ull )
{
// the client process hasn't stored a new heart beat in more than 100ms.
// as long as it is running, it stores a new heart beat every 10ms, so we conclude that it
// didn't make progress, e.g. because it is being held in the debugger.
return false ;
}
return true ;
}
2019-07-16 08:43:32 -04:00
void LiveProcess : : HandleDebuggingPreCompile ( void )
{
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:45:13 -04:00
# if WITH_VISUALSTUDIO_DTE
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
if ( ! MadeProgress ( ) )
{
// this process did not make progress.
// try to find a debugger that's currently debugging our process.
m_vsDebugger = visualStudio : : FindDebuggerForProcess ( m_processId ) ;
if ( m_vsDebugger )
{
// found a debugger.
// enumerate all threads, freeze every thread but the command thread, and let the debugger resume.
// this "halts" the process but lets the command thread act on commands sent by us.
m_vsDebuggerThreads = visualStudio : : EnumerateThreads ( m_vsDebugger ) ;
if ( m_vsDebuggerThreads . size ( ) > 0u )
{
2020-12-15 09:27:44 -04:00
if ( visualStudio : : FreezeThreads ( m_vsDebugger , m_vsDebuggerThreads ) )
{
if ( visualStudio : : ThawThread ( m_vsDebugger , m_vsDebuggerThreads , m_commandThreadId ) )
{
if ( visualStudio : : Resume ( m_vsDebugger ) )
{
LC_SUCCESS_USER ( " Automating debugger attached to process (PID: %d) " , m_processId ) ;
2019-07-16 08:43:32 -04:00
2020-12-15 09:27:44 -04:00
return ;
}
else
{
LC_LOG_USER ( " Failed to resume debugger (PID: %d) " , m_processId ) ;
}
}
else
{
// BEGIN EPIC MOD
LC_LOG_USER ( " Failed to thaw Live coding command thread in debugger (PID: %d) " , m_processId ) ;
// END EPIC MOD
}
}
else
{
LC_LOG_USER ( " Failed to freeze threads in debugger (PID: %d) " , m_processId ) ;
}
2019-07-16 08:43:32 -04:00
}
2020-12-15 09:27:44 -04:00
else
{
LC_LOG_USER ( " Failed to enumerate threads in debugger (PID: %d) " , m_processId ) ;
}
}
else
{
LC_LOG_USER ( " Failed to find debugger attached to process (PID: %d) " , m_processId ) ;
2019-07-16 08:43:32 -04:00
}
// no debugger could be found or an error occurred.
// continue by installing a code cave.
2020-12-15 09:27:44 -04:00
m_vsDebugger = nullptr ;
2019-07-16 08:43:32 -04:00
LC_LOG_USER ( " Failed to automate debugger attached to process (PID: %d), using fallback mechanism " , m_processId ) ;
LC_SUCCESS_USER ( " Waiting for client process (PID: %d), hit 'Continue' (F5 in Visual Studio) if being held in the debugger " , m_processId ) ;
}
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:44:38 -04:00
# endif
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
// this process either made progress and is not held in the debugger, or we failed automating the debugger.
// "halt" this process by installing a code cave.
InstallCodeCave ( ) ;
}
void LiveProcess : : HandleDebuggingPostCompile ( void )
{
if ( m_codeCave )
{
// we installed a code cave previously, remove it
UninstallCodeCave ( ) ;
}
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:45:13 -04:00
# if WITH_VISUALSTUDIO_DTE
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
else if ( m_vsDebugger )
{
// we automated the debugger previously. break into the debugger again and resume all threads.
// when debugging a C# project that calls into C++ code, the VS debugger sometimes creates new MTA threads in between our PreCompile and PostCompile calls.
// try getting a new list of threads and thaw them all as well.
2020-12-15 09:27:44 -04:00
if ( visualStudio : : Break ( m_vsDebugger ) )
{
types : : vector < EnvDTE : : ThreadPtr > newDebuggerThreads = visualStudio : : EnumerateThreads ( m_vsDebugger ) ;
if ( newDebuggerThreads . size ( ) > 0u )
{
visualStudio : : ThawThreads ( m_vsDebugger , newDebuggerThreads ) ;
}
visualStudio : : ThawThreads ( m_vsDebugger , m_vsDebuggerThreads ) ;
}
2019-07-16 08:43:32 -04:00
}
m_vsDebugger = nullptr ;
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2019-07-16 08:44:38 -04:00
# endif
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
}
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
void LiveProcess : : InstallCodeCave ( void )
{
2019-05-24 11:51:54 -04:00
m_codeCave = new CodeCave ( m_processHandle , m_processId , m_commandThreadId , m_jumpToSelf ) ;
Integrating live coding feature (aka Live++) into UE4.
Allows fast iteration of C++ changes without restarting the application. To use, select the "Live Coding (Experimental)" mode from the drop down menu next to the editor's compile button, or type "LiveCoding" into the console for a monolithic build. Press Ctrl+Alt+F11 to find changes and compile.
Changes vs standalone Live++ version:
* UBT is used to execute builds. This allows standard UE4 adaptive unity mode, allows us to reuse object files when we do regular builds, supports using any build executor allowed by UBT (XGE, SNDBS, etc..).
* Adding new source files is supported.
* Custom visualizer for FNames is supported via a weakly linked symbol in a static library (Engine/Extras/NatvisHelpers).
* Settings are exposed in the editor's project settings dialog.
* Standalone application has been rewritten as a Slate app ("LiveCodingConsole"). There is an additional option to start the program as hidden, where it will not be visible until Ctrl+Alt+F11 is hit. Similarly, closing the window will hide it instead of closing the application.
* Does not require a standalone licensed version of Live++.
Known issues:
* Does not currently support class layout changes / object reinstancing
#rb none
[FYI] Marc.Audy, Stefan.Boberg, Nick.Penwarden
#jira
#ROBOMERGE-SOURCE: CL 5304722 in //UE4/Release-4.22/...
#ROBOMERGE-BOT: RELEASE (Release-4.22 -> Main)
[CL 5309051 by ben marsh in Main branch]
2019-03-05 18:49:25 -05:00
m_codeCave - > Install ( ) ;
}
void LiveProcess : : UninstallCodeCave ( void )
{
m_codeCave - > Uninstall ( ) ;
delete m_codeCave ;
m_codeCave = nullptr ;
}
void LiveProcess : : AddLoadedImage ( const executable : : Header & imageHeader )
{
m_imagesTriedToLoad . insert ( imageHeader ) ;
}
void LiveProcess : : RemoveLoadedImage ( const executable : : Header & imageHeader )
{
m_imagesTriedToLoad . erase ( imageHeader ) ;
}
bool LiveProcess : : TriedToLoadImage ( const executable : : Header & imageHeader ) const
{
return ( m_imagesTriedToLoad . find ( imageHeader ) ! = m_imagesTriedToLoad . end ( ) ) ;
}
2019-03-18 18:07:05 -04:00
2019-07-16 08:43:32 -04:00
bool LiveProcess : : PrepareForRestart ( void )
{
// signal to the target process that a restart for this process was requested
Event requestRestart ( primitiveNames : : RequestRestart ( m_processId ) . c_str ( ) , Event : : Type : : AUTO_RESET ) ;
requestRestart . Signal ( ) ;
// the client code in the target is now inside the lpp::lppWantsRestart() code block.
// wait until it calls lpp::lppRestart() after finishing custom client code.
// give the client 10 seconds to finish up.
Event restartPrepared ( primitiveNames : : PreparedRestart ( m_processId ) . c_str ( ) , Event : : Type : : AUTO_RESET ) ;
const bool success = restartPrepared . WaitTimeout ( 10u * 1000u ) ;
if ( success )
{
m_restartState = RestartState : : SUCCESSFUL_PREPARE ;
return true ;
}
else
{
LC_ERROR_USER ( " Client did not respond to restart request within 10 seconds, aborting restart (PID: %d) " , m_processId ) ;
m_restartState = RestartState : : FAILED_PREPARE ;
return false ;
}
}
2020-01-29 14:48:18 -05:00
void LiveProcess : : WaitForExitBeforeRestart ( void )
2019-07-16 08:43:32 -04:00
{
if ( m_restartState = = RestartState : : SUCCESSFUL_PREPARE )
{
// in case PrepareForRestart was successful, the client is now waiting for the signal to restart.
2020-01-29 14:48:18 -05:00
// tell the client to exit now.
2019-07-16 08:43:32 -04:00
Event executeRestart ( primitiveNames : : Restart ( m_processId ) . c_str ( ) , Event : : Type : : AUTO_RESET ) ;
executeRestart . Signal ( ) ;
// wait until the client terminates
2020-12-15 09:27:44 -04:00
Process : : Wait ( m_processHandle ) ;
2019-07-16 08:43:32 -04:00
2020-01-29 14:48:18 -05:00
m_restartState = RestartState : : SUCCESSFUL_EXIT ;
}
}
2020-12-15 09:27:44 -04:00
// BEGIN EPIC MOD
2020-01-29 14:48:18 -05:00
void LiveProcess : : Restart ( void * restartJob )
2020-12-15 09:27:44 -04:00
// END EPIC MOD
2020-01-29 14:48:18 -05:00
{
if ( m_restartState = = RestartState : : SUCCESSFUL_EXIT )
{
2019-07-16 08:43:32 -04:00
// restart the target application
2019-08-04 15:02:43 -04:00
// BEGIN EPIC MOD - Force LiveCoding to start up for child processes
std : : wstring commandLine ( m_commandLine ) ;
const std : : wstring argument ( L " -LiveCoding " ) ;
if ( commandLine . length ( ) > = argument . length ( ) & & commandLine . compare ( commandLine . length ( ) - argument . length ( ) , argument . length ( ) , argument ) ! = 0 )
{
commandLine + = argument ;
}
// END EPIC MOD
2019-08-04 14:34:45 -04:00
// BEGIN EPIC MOD - Prevent orphaned console instances if processes fail to restart. Job object will be duplicated into child process.
2020-12-15 09:27:44 -04:00
Process : : Context * context = Process : : Spawn ( m_imagePath . c_str ( ) , m_workingDirectory . c_str ( ) , commandLine . c_str ( ) , m_environment . GetData ( ) , Process : : SpawnFlags : : SUSPENDED ) ;
2019-08-04 14:34:45 -04:00
void * TargetHandle ;
2020-12-15 09:27:44 -04:00
DuplicateHandle ( GetCurrentProcess ( ) , restartJob , + Process : : GetHandle ( context ) , & TargetHandle , 0 , Windows : : TRUE , DUPLICATE_SAME_ACCESS ) ;
Process : : ResumeMainThread ( context ) ;
2019-08-04 14:34:45 -04:00
// END EPIC MOD
2019-07-16 08:43:32 -04:00
2020-01-29 14:48:18 -05:00
m_restartState = RestartState : : SUCCESSFUL_RESTART ;
2019-07-16 08:43:32 -04:00
}
}
bool LiveProcess : : WasSuccessfulRestart ( void ) const
{
2020-01-29 14:48:18 -05:00
return ( m_restartState = = RestartState : : SUCCESSFUL_RESTART ) ;
2019-07-16 08:43:32 -04:00
}
2021-01-18 13:02:32 -04:00
void LiveProcess : : ReserveVirtualMemoryPages ( void * moduleBase )
{
# if LC_64_BIT
2021-01-19 12:58:35 -04:00
// BEGIN EPIC MOD
const void * lowerBound = liveProcess : : GetLowerBoundIn4GBRange ( moduleBase ) ;
const void * upperBound = liveProcess : : GetUpperBoundIn4GBRange ( moduleBase ) ;
// END EPIC MOD
2021-01-18 13:02:32 -04:00
m_virtualMemoryRange . ReservePages ( lowerBound , upperBound , 64u * 1024u ) ;
# else
LC_UNUSED ( moduleBase ) ;
# endif
}
void LiveProcess : : FreeVirtualMemoryPages ( void * moduleBase )
{
# if LC_64_BIT
2021-01-19 12:58:35 -04:00
// BEGIN EPIC MOD
const void * lowerBound = liveProcess : : GetLowerBoundIn4GBRange ( moduleBase ) ;
const void * upperBound = liveProcess : : GetUpperBoundIn4GBRange ( moduleBase ) ;
// END EPIC MOD
2021-01-18 13:02:32 -04:00
m_virtualMemoryRange . FreePages ( lowerBound , upperBound ) ;
# else
LC_UNUSED ( moduleBase ) ;
# endif
}
2019-03-18 18:07:05 -04:00
// BEGIN EPIC MOD - Allow lazy-loading modules
void LiveProcess : : AddLazyLoadedModule ( const std : : wstring moduleName , Windows : : HMODULE moduleBase )
{
LazyLoadedModule module ;
module . m_moduleBase = moduleBase ;
module . m_loaded = false ;
m_lazyLoadedModules . insert ( std : : make_pair ( moduleName , module ) ) ;
}
void LiveProcess : : SetLazyLoadedModuleAsLoaded ( const std : : wstring moduleName )
{
std : : unordered_map < std : : wstring , LazyLoadedModule > : : iterator it = m_lazyLoadedModules . find ( moduleName ) ;
if ( it ! = m_lazyLoadedModules . end ( ) )
{
it - > second . m_loaded = true ;
}
}
bool LiveProcess : : IsPendingLazyLoadedModule ( const std : : wstring & moduleName ) const
{
std : : unordered_map < std : : wstring , LazyLoadedModule > : : const_iterator iter = m_lazyLoadedModules . find ( moduleName ) ;
return iter ! = m_lazyLoadedModules . end ( ) & & ! iter - > second . m_loaded ;
}
Windows : : HMODULE LiveProcess : : GetLazyLoadedModuleBase ( const std : : wstring & moduleName ) const
{
std : : unordered_map < std : : wstring , LazyLoadedModule > : : const_iterator iter = m_lazyLoadedModules . find ( moduleName ) ;
if ( iter = = m_lazyLoadedModules . end ( ) )
{
return nullptr ;
}
else
{
return iter - > second . m_moduleBase ;
}
}
2019-07-16 08:43:32 -04:00
// END EPIC MOD