diff --git a/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.cpp b/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.cpp new file mode 100644 index 000000000..2e79dccb2 --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.cpp @@ -0,0 +1,80 @@ +// Coordinator +//------------------------------------------------------------------------------ + +// Includes +//------------------------------------------------------------------------------ +#include "Coordinator.h" + +// FBuild +#include "Tools/FBuild/FBuildCore/FBuild.h" +#include "Tools/FBuild/FBuildCore/FBuildVersion.h" +#include "Tools/FBuild/FBuildCore/WorkerPool/WorkerConnectionPool.h" + +// Core +#include "Core/Profile/Profile.h" +#include "Core/Tracing/Tracing.h" + +// CONSTRUCTOR +//------------------------------------------------------------------------------ +Coordinator::Coordinator( const AString & args ) + : m_BaseArgs( args ) + , m_ConnectionPool( nullptr ) +{ + m_ConnectionPool = FNEW( WorkerConnectionPool ); +} + +// DESTRUCTOR +//------------------------------------------------------------------------------ +Coordinator::~Coordinator() +{ + FDELETE m_ConnectionPool; +} + +// Start +//------------------------------------------------------------------------------ +int32_t Coordinator::Start() +{ + // spawn work thread + m_WorkThread = Thread::CreateThread( &WorkThreadWrapper, + "CoordinatorThread", + ( 256 * KILOBYTE ), + this ); + ASSERT( m_WorkThread != INVALID_THREAD_HANDLE ); + + // Join work thread and get exit code + return Thread::WaitForThread( m_WorkThread ); +} + +// WorkThreadWrapper +//------------------------------------------------------------------------------ +/*static*/ uint32_t Coordinator::WorkThreadWrapper( void * userData ) +{ + Coordinator * coordinator = static_cast( userData ); + return coordinator->WorkThread(); +} + +// Start +//------------------------------------------------------------------------------ +uint32_t Coordinator::WorkThread() +{ + OUTPUT( "FBuildCoordinator - " FBUILD_VERSION_STRING "\n" ); + + // start listening + OUTPUT( "Listening on port %u\n", (uint32_t)Protocol::COORDINATOR_PORT ); + if ( m_ConnectionPool->Listen( Protocol::COORDINATOR_PORT ) == false ) + { + OUTPUT( "Failed to listen on port %u. Check port is not in use.\n", (uint32_t)Protocol::COORDINATOR_PORT ); + return (uint32_t)-3; + } + + for(;;) + { + PROFILE_SYNCHRONIZE + + Thread::Sleep( 500 ); + } + + //return 0; +} + +//------------------------------------------------------------------------------ diff --git a/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.h b/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.h new file mode 100644 index 000000000..57f8a8b0b --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/Coordinator/Coordinator.h @@ -0,0 +1,36 @@ +// Coordinator +//------------------------------------------------------------------------------ +#pragma once + +// Includes +//------------------------------------------------------------------------------ + +// Core +#include "Core/Process/Thread.h" +#include "Core/Strings/AString.h" + +// Forward Declarations +//------------------------------------------------------------------------------ +class WorkerConnectionPool; + +// Coordinator +//------------------------------------------------------------------------------ +class Coordinator +{ +public: + + explicit Coordinator( const AString & args ); + ~Coordinator(); + + int32_t Start(); + +private: + static uint32_t WorkThreadWrapper( void * userData ); + uint32_t WorkThread(); + + AString m_BaseArgs; + WorkerConnectionPool * m_ConnectionPool; + Thread::ThreadHandle m_WorkThread; +}; + +//------------------------------------------------------------------------------ diff --git a/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinator.bff b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinator.bff new file mode 100644 index 000000000..b00492422 --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinator.bff @@ -0,0 +1,105 @@ +// FBuildCoordinator +//------------------------------------------------------------------------------ +{ + .ProjectName = 'FBuildCoordinator' + .ProjectPath = 'Tools\FBuild\FBuildCoordinator' + + // Executable + //-------------------------------------------------------------------------- + .ProjectConfigs = {} + ForEach( .BuildConfig in .BuildConfigs ) + { + Using( .BuildConfig ) + .OutputBase + '/$Platform$-$BuildConfigName$' + + // Unity + //-------------------------------------------------------------------------- + Unity( '$ProjectName$-Unity-$Platform$-$BuildConfigName$' ) + { + .UnityInputPath = '$ProjectPath$/' + .UnityOutputPath = '$OutputBase$/$ProjectPath$/' + .UnityOutputPattern = '$ProjectName$_Unity*.cpp' + } + + // Library + //-------------------------------------------------------------------------- + ObjectList( '$ProjectName$-Lib-$Platform$-$BuildConfigName$' ) + { + // Input (Unity) + .CompilerInputUnity = '$ProjectName$-Unity-$Platform$-$BuildConfigName$' + + // Output + .CompilerOutputPath = '$OutputBase$/$ProjectPath$/' + } + + // Executable + //-------------------------------------------------------------------------- + Executable( '$ProjectName$-Exe-$Platform$-$BuildConfigName$' ) + { + .Libraries = { + 'FBuildCoordinator-Lib-$Platform$-$BuildConfigName$', + 'FBuildCore-Lib-$Platform$-$BuildConfigName$', + 'Core-Lib-$Platform$-$BuildConfigName$', + 'LZ4-Lib-$Platform$-$BuildConfigName$' + } + #if __LINUX__ + .LinkerOutput = '$OutputBase$/$ProjectPath$/fbuildcoordinator$ExeExtension$' // NOTE: lower case + #else + .LinkerOutput = '$OutputBase$/$ProjectPath$/FBuildCoordinator$ExeExtension$' + #endif + #if __WINDOWS__ + .LinkerOptions + ' /SUBSYSTEM:CONSOLE' + + ' Advapi32.lib' + + ' Iphlpapi.lib' + + ' kernel32.lib' + + ' Ws2_32.lib' + + ' User32.lib' + + ' Shell32.lib' + + .CRTLibs_Static + #endif + #if __LINUX__ + .LinkerOptions + ' -pthread -ldl -lrt' + + .LinkerStampExe = '/bin/bash' + .ExtractDebugInfo = 'objcopy --only-keep-debug $LinkerOutput$ $LinkerOutput$.debug' + .StripDebugInfo = 'objcopy --strip-debug $LinkerOutput$' + .AddDebugLink = 'objcopy --add-gnu-debuglink $LinkerOutput$.debug $LinkerOutput$' + .LinkerStampExeArgs = '-c "$ExtractDebugInfo$ && $StripDebugInfo$ && $AddDebugLink$"' + #endif + } + Alias( '$ProjectName$-$Platform$-$BuildConfigName$' ) { .Targets = '$ProjectName$-Exe-$Platform$-$BuildConfigName$' } + ^'Targets_$Platform$_$BuildConfigName$' + { '$ProjectName$-$Platform$-$BuildConfigName$' } + + #if __WINDOWS__ + .ProjectConfig = [ Using( .'Project_$Platform$_$BuildConfigName$' ) .Target = '$ProjectName$-$Platform$-$BuildConfigName$' ] + ^ProjectConfigs + .ProjectConfig + #endif + #if __OSX__ + .ProjectConfig = [ .Config = '$BuildConfigName$' .Target = '$ProjectName$-x64OSX-$BuildConfigName$' ] + ^ProjectConfigs + .ProjectConfig + #endif + } + + // Aliases + //-------------------------------------------------------------------------- + CreateCommonAliases( .ProjectName ) + + // Visual Studio Project Generation + //-------------------------------------------------------------------------- + #if __WINDOWS__ + CreateVCXProject_Exe( .ProjectName, .ProjectPath, .ProjectConfigs ) + #endif + + // XCode Project Generation + //-------------------------------------------------------------------------- + #if __OSX__ + XCodeProject( '$ProjectName$-xcodeproj' ) + { + .ProjectOutput = '../tmp/XCode/Projects/3_Apps/$ProjectName$.xcodeproj/project.pbxproj' + .ProjectInputPaths = '$ProjectPath$/' + .ProjectBasePath = '$ProjectPath$/' + + .XCodeBuildWorkingDir = '../../../../Code/' + } + #endif +} diff --git a/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.cpp b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.cpp new file mode 100644 index 000000000..5736b3a0a --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.cpp @@ -0,0 +1,39 @@ +// FBuildCoordinatorOptions +//------------------------------------------------------------------------------ + +// Includes +//------------------------------------------------------------------------------ +#include "FBuildCoordinatorOptions.h" +#include "Tools/FBuild/FBuildCore/FBuildVersion.h" + +// Core +#include "Core/Containers/Array.h" +#include "Core/Strings/AStackString.h" +#include "Core/Tracing/Tracing.h" + +// FBuildCoordinatorOptions (CONSTRUCTOR) +//------------------------------------------------------------------------------ +FBuildCoordinatorOptions::FBuildCoordinatorOptions() +{ +} + +// ProcessCommandLine +//------------------------------------------------------------------------------ +bool FBuildCoordinatorOptions::ProcessCommandLine( const AString & commandLine ) +{ + // Tokenize + Array< AString > tokens; + commandLine.Tokenize( tokens ); + + return true; +} + +// ShowUsageError +//------------------------------------------------------------------------------ +void FBuildCoordinatorOptions::ShowUsageError() +{ + OUTPUT( "FBuildCoordinator - " FBUILD_VERSION_STRING " - " + "Copyright 2012-2019 Franta Fulin - http://www.fastbuild.org\n" ); +} + +//------------------------------------------------------------------------------ diff --git a/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.h b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.h new file mode 100644 index 000000000..2e800649a --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/FBuildCoordinatorOptions.h @@ -0,0 +1,25 @@ +// FBuildCoordinatorOptions +//------------------------------------------------------------------------------ +#pragma once + +// Includes +//------------------------------------------------------------------------------ + +// Forward Declaration +//------------------------------------------------------------------------------ +class AString; + +// FBuildCoordinatorOptions +//------------------------------------------------------------------------------ +class FBuildCoordinatorOptions +{ +public: + FBuildCoordinatorOptions(); + + bool ProcessCommandLine( const AString & commandLine ); + +private: + void ShowUsageError(); +}; + +//------------------------------------------------------------------------------ diff --git a/Code/Tools/FBuild/FBuildCoordinator/Main.cpp b/Code/Tools/FBuild/FBuildCoordinator/Main.cpp new file mode 100644 index 000000000..ece6d32b6 --- /dev/null +++ b/Code/Tools/FBuild/FBuildCoordinator/Main.cpp @@ -0,0 +1,80 @@ +// Main +//------------------------------------------------------------------------------ + +// Includes +//------------------------------------------------------------------------------ +#include "FBuildCoordinatorOptions.h" +#include "Coordinator/Coordinator.h" +#include "Tools/FBuild/FBuildCore/FBuild.h" +#include "Tools/FBuild/FBuildCore/FLog.h" + +#include "Core/Profile/Profile.h" +#include "Core/Process/SystemMutex.h" +#include "Core/Tracing/Tracing.h" + +// Global Data +//------------------------------------------------------------------------------ +// only allow 1 worker per system +SystemMutex g_OneProcessMutex( "Global\\FBuildCoordinator" ); + +// Return Codes +//------------------------------------------------------------------------------ +enum ReturnCodes +{ + FBUILD_OK = 0, + FBUILD_BAD_ARGS = -1, + FBUILD_ALREADY_RUNNING = -2 +}; + +// Headers +//------------------------------------------------------------------------------ +int Main( const AString & args ); + +// main +//------------------------------------------------------------------------------ +int main(int argc, char * argv[]) +{ + AStackString<> args; + for ( int i=1; i 0 ) + { + args += ' '; + } + args += argv[ i ]; + } + + // This wrapper is purely for profiling scope + const int result = Main( args ); + PROFILE_SYNCHRONIZE // make sure no tags are active and do one final sync + return result; +} + +// Main +//------------------------------------------------------------------------------ +int Main( const AString & args ) +{ + // handle cmd line args + FBuildCoordinatorOptions options; + if ( options.ProcessCommandLine( args ) == false ) + { + return FBUILD_BAD_ARGS; + } + + // only allow 1 worker per system + const Timer t; + while ( g_OneProcessMutex.TryLock() == false ) + { + // retry for upto 2 seconds, to allow some time for old worker to close + if ( t.GetElapsed() > 5.0f ) + { + OUTPUT( "An FBuildCoordinator is already running!\n" ); + return FBUILD_ALREADY_RUNNING; + } + Thread::Sleep(100); + } + + Coordinator coordinator( args ); + + return coordinator.Start(); +}