Esempio n. 1
0
            public void ConnectToServerFails()
            {
                // Create and grab the mutex for the server. This should make
                // the client believe that a server is active and it will try
                // to connect. When it fails it should fall back to in-proc
                // compilation.
                bool holdsMutex;

                using (var serverMutex = new Mutex(initiallyOwned: true,
                                                   name: DesktopBuildClient.GetServerMutexName(_pipeName),
                                                   createdNew: out holdsMutex))
                {
                    Assert.True(holdsMutex);
                    var ranLocal = false;
                    // Note: Connecting to a server can take up to a second to time out
                    var client = CreateClient(
                        compileFunc: delegate
                    {
                        ranLocal = true;
                        return(0);
                    });
                    var exitCode = client.RunCompilation(new[] { "/shared" }, _buildPaths).ExitCode;
                    Assert.Equal(0, exitCode);
                    Assert.True(ranLocal);
                }
            }
Esempio n. 2
0
        protected override int RunServerCore(string pipeName, IClientConnectionHost connectionHost, IDiagnosticListener listener, TimeSpan?keepAlive, CancellationToken cancellationToken)
        {
            // Grab the server mutex to prevent multiple servers from starting with the same
            // pipename and consuming excess resources. If someone else holds the mutex
            // exit immediately with a non-zero exit code
            var  mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
            bool holdsMutex;

            using (var serverMutex = new Mutex(initiallyOwned: true,
                                               name: mutexName,
                                               createdNew: out holdsMutex))
            {
                if (!holdsMutex)
                {
                    return(CommonCompiler.Failed);
                }

                try
                {
                    return(base.RunServerCore(pipeName, connectionHost, listener, keepAlive, cancellationToken));
                }
                finally
                {
                    serverMutex.ReleaseMutex();
                }
            }
        }
Esempio n. 3
0
        private static int MainCore(string[] args)
        {
#if NET46
            return(DesktopBuildClient.Run(args, RequestLanguage.CSharpCompile, Csc.Run, new DesktopAnalyzerAssemblyLoader()));
#else
            return(CoreClrBuildClient.Run(args, RequestLanguage.CSharpCompile, Csc.Run, new CoreClrAnalyzerAssemblyLoader()));
#endif
        }
        public static int MainInternal(string[] args)
        {
#if DESKTOP
            return(DesktopBuildClient.Run(args, Array.Empty <string>(), RequestLanguage.CSharpCompile, new CompileFunc(Csc.Run), new DesktopAnalyzerAssemblyLoader()));
#else
            return(CoreClrBuildClient.Run(args, RequestLanguage.CSharpCompile, new CompileFunc(Csc.Run)));
#endif
        }
Esempio n. 5
0
            public void GetBasePipeNameSlashes()
            {
                var path = string.Format(@"q:{0}the{0}path", Path.DirectorySeparatorChar);
                var name = DesktopBuildClient.GetBasePipeName(path);

                Assert.Equal(name, DesktopBuildClient.GetBasePipeName(path));
                Assert.Equal(name, DesktopBuildClient.GetBasePipeName(path + Path.DirectorySeparatorChar));
                Assert.Equal(name, DesktopBuildClient.GetBasePipeName(path + Path.DirectorySeparatorChar + Path.DirectorySeparatorChar));
            }
Esempio n. 6
0
        private static int MainCore(string[] args)
        {
#if NET472
            var loader = new DesktopAnalyzerAssemblyLoader();
#else
            var loader = new CoreClrAnalyzerAssemblyLoader();
#endif
            return(DesktopBuildClient.Run(args, RequestLanguage.StarkCompile, Skc.Run, loader));
        }
Esempio n. 7
0
        private static int MainCore(string[] args)
        {
#if BOOTSTRAP
            ExitingTraceListener.Install();
#endif

#if NET472
            var loader = new DesktopAnalyzerAssemblyLoader();
#else
            var loader = new CoreClrAnalyzerAssemblyLoader();
#endif
            return(DesktopBuildClient.Run(args, RequestLanguage.VisualBasicCompile, Vbc.Run, loader));
        }
Esempio n. 8
0
 public static Task <BuildResponse> RunServerCompilation(
     RequestLanguage language,
     List <string> arguments,
     BuildPaths buildPaths,
     string keepAlive,
     string libEnvVariable,
     CancellationToken cancellationToken)
 => DesktopBuildClient.RunServerCompilation(
     language,
     arguments,
     buildPaths,
     keepAlive,
     libEnvVariable,
     cancellationToken);
Esempio n. 9
0
        internal static ServerData CreateServer(
            string pipeName  = null,
            TimeSpan?timeout = null,
            ICompilerServerHost compilerServerHost     = null,
            IClientConnectionHost clientConnectionHost = null)
        {
            pipeName           = pipeName ?? Guid.NewGuid().ToString();
            compilerServerHost = compilerServerHost ?? new DesktopCompilerServerHost(DefaultClientDirectory, DefaultSdkDirectory);

            var serverStatsSource  = new TaskCompletionSource <ServerStats>();
            var serverListenSource = new TaskCompletionSource <bool>();
            var cts       = new CancellationTokenSource();
            var mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
            var thread    = new Thread(_ =>
            {
                var listener        = new TestableDiagnosticListener();
                listener.Listening += (sender, e) => { serverListenSource.TrySetResult(true); };
                try
                {
                    clientConnectionHost = clientConnectionHost ?? new NamedPipeClientConnectionHost(compilerServerHost, pipeName);

                    DesktopBuildServerController.RunServer(
                        pipeName,
                        clientConnectionHost,
                        listener,
                        timeout ?? TimeSpan.FromMilliseconds(-1),
                        cts.Token);
                }
                finally
                {
                    var serverStats = new ServerStats(connections: listener.ConnectionCount, completedConnections: listener.CompletedCount);
                    serverStatsSource.SetResult(serverStats);
                }
            });

            thread.Start();

            // The contract of this function is that it will return once the server has started.  Spin here until
            // we can verify the server has started or simply failed to start.
            while (DesktopBuildClient.WasServerMutexOpen(mutexName) != true && thread.IsAlive)
            {
                Thread.Yield();
            }

            return(new ServerData(cts, pipeName, serverStatsSource.Task, serverListenSource.Task));
        }
Esempio n. 10
0
        public void MutexAcquiredWhenRunningServer()
        {
            var pipeName  = Guid.NewGuid().ToString("N");
            var mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
            var host      = new Mock <IClientConnectionHost>(MockBehavior.Strict);

            host
            .Setup(x => x.CreateListenTask(It.IsAny <CancellationToken>()))
            .Returns(() =>
            {
                // Use a thread instead of Task to guarantee this code runs on a different
                // thread and we can validate the mutex state.
                var source = new TaskCompletionSource <bool>();
                var thread = new Thread(_ =>
                {
                    Mutex mutex = null;
                    try
                    {
                        Assert.True(Mutex.TryOpenExisting(mutexName, out mutex));
                        Assert.False(mutex.WaitOne(millisecondsTimeout: 0));
                        source.SetResult(true);
                    }
                    catch (Exception ex)
                    {
                        source.SetException(ex);
                        throw;
                    }
                    finally
                    {
                        mutex?.Dispose();
                    }
                });

                // Synchronously wait here.  Don't returned a Task value because we need to
                // ensure the above check completes before the server hits a timeout and
                // releases the mutex.
                thread.Start();
                source.Task.Wait();

                return(new TaskCompletionSource <IClientConnection>().Task);
            });

            var result = DesktopBuildServerController.RunServer(pipeName, host.Object, keepAlive: TimeSpan.FromSeconds(1));

            Assert.Equal(CommonCompiler.Succeeded, result);
        }
Esempio n. 11
0
            public async Task ServerShutdownsDuringProcessing()
            {
                using (var readyMre = new ManualResetEvent(initialState: false))
                    using (var doneMre = new ManualResetEvent(initialState: false))
                    {
                        var  pipeName  = Guid.NewGuid().ToString();
                        var  mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
                        bool created   = false;
                        bool connected = false;

                        var thread = new Thread(() =>
                        {
                            using (var stream = new NamedPipeServerStream(pipeName))
                            {
                                var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out created);
                                readyMre.Set();

                                stream.WaitForConnection();
                                connected = true;

                                // Client is waiting for a response.  Close the mutex now.  Then close the connection
                                // so the client gets an error.
                                mutex.ReleaseMutex();
                                mutex.Dispose();
                                stream.Close();

                                doneMre.WaitOne();
                            }
                        });

                        // Block until the mutex and named pipe is setup.
                        thread.Start();
                        readyMre.WaitOne();

                        var exitCode = await RunShutdownAsync(pipeName, waitForProcess : false);

                        // Let the fake server exit.
                        doneMre.Set();
                        thread.Join();

                        Assert.Equal(CommonCompiler.Succeeded, exitCode);
                        Assert.True(connected);
                        Assert.True(created);
                    }
            }
Esempio n. 12
0
            public async Task NoServerConnection()
            {
                using (var readyMre = new ManualResetEvent(initialState: false))
                    using (var doneMre = new ManualResetEvent(initialState: false))
                    {
                        var  pipeName  = Guid.NewGuid().ToString();
                        var  mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
                        bool created   = false;
                        bool connected = false;

                        var thread = new Thread(() =>
                        {
                            using (var mutex = new Mutex(initiallyOwned: true, name: mutexName, createdNew: out created))
                                using (var stream = new NamedPipeServerStream(pipeName))
                                {
                                    readyMre.Set();

                                    // Get a client connection and then immediately close it.  Don't give any response.
                                    stream.WaitForConnection();
                                    connected = true;
                                    stream.Close();

                                    doneMre.WaitOne();
                                    mutex.ReleaseMutex();
                                }
                        });

                        // Block until the mutex and named pipe is setup.
                        thread.Start();
                        readyMre.WaitOne();

                        var exitCode = await RunShutdownAsync(pipeName, waitForProcess : false);

                        // Let the fake server exit.
                        doneMre.Set();
                        thread.Join();

                        Assert.Equal(CommonCompiler.Failed, exitCode);
                        Assert.True(connected);
                        Assert.True(created);
                    }
            }
Esempio n. 13
0
        /// <summary>
        /// Create a compiler server that fails all connections.
        /// </summary>
        internal static ServerData CreateServerFailsConnection(string pipeName = null)
        {
            pipeName = pipeName ?? Guid.NewGuid().ToString();

            var taskSource = new TaskCompletionSource <ServerStats>();
            var cts        = new CancellationTokenSource();

            using (var mre = new ManualResetEvent(initialState: false))
            {
                var thread = new Thread(_ =>
                {
                    var mutexName = DesktopBuildClient.GetServerMutexName(pipeName);
                    bool holdsMutex;
                    using (var serverMutex = new Mutex(initiallyOwned: true,
                                                       name: mutexName,
                                                       createdNew: out holdsMutex))
                    {
                        mre.Set();
                        if (!holdsMutex)
                        {
                            throw new InvalidOperationException("Mutex should be unique");
                        }

                        var connections = CreateServerFailsConnectionCore(pipeName, cts.Token).Result;
                        taskSource.SetResult(new ServerStats(connections: connections, completedConnections: 0));
                    }
                });

                thread.Start();

                // Can't exit until the mutex is acquired.  Otherwise the client can end up in a race
                // condition trying to start the server.
                mre.WaitOne();
            }

            return(new ServerData(cts, pipeName, taskSource.Task, Task.FromException(new Exception())));
        }
Esempio n. 14
0
        public void MutexStopsServerStarting()
        {
            var pipeName  = Guid.NewGuid().ToString("N");
            var mutexName = DesktopBuildClient.GetServerMutexName(pipeName);

            bool holdsMutex;

            using (var mutex = new Mutex(initiallyOwned: true,
                                         name: mutexName,
                                         createdNew: out holdsMutex))
            {
                Assert.True(holdsMutex);
                try
                {
                    var host   = new Mock <IClientConnectionHost>(MockBehavior.Strict);
                    var result = DesktopBuildServerController.RunServer(pipeName, host.Object, keepAlive: null);
                    Assert.Equal(CommonCompiler.Failed, result);
                }
                finally
                {
                    mutex.ReleaseMutex();
                }
            }
        }
Esempio n. 15
0
        /// <summary>
        /// Shutting down the server is an inherently racy operation.  The server can be started or stopped by
        /// external parties at any time.
        ///
        /// This function will return success if at any time in the function the server is determined to no longer
        /// be running.
        /// </summary>
        internal static async Task <int> RunShutdownAsync(string pipeName, bool waitForProcess = true, TimeSpan?timeout = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (string.IsNullOrEmpty(pipeName))
            {
                var clientDirectory = AppDomain.CurrentDomain.BaseDirectory;
                pipeName = DesktopBuildClient.GetPipeNameFromFileInfo(clientDirectory);
            }

            var mutexName = BuildProtocolConstants.GetServerMutexName(pipeName);

            if (!DesktopBuildClient.WasServerMutexOpen(mutexName))
            {
                // The server holds the mutex whenever it is running, if it's not open then the
                // server simply isn't running.
                return(CommonCompiler.Succeeded);
            }

            try
            {
                using (var client = new NamedPipeClientStream(pipeName))
                {
                    var realTimeout = timeout != null
                        ? (int)timeout.Value.TotalMilliseconds
                        : Timeout.Infinite;
                    client.Connect(realTimeout);

                    var request = BuildRequest.CreateShutdown();
                    await request.WriteAsync(client, cancellationToken).ConfigureAwait(false);

                    var response = await BuildResponse.ReadAsync(client, cancellationToken).ConfigureAwait(false);

                    var shutdownResponse = (ShutdownBuildResponse)response;

                    if (waitForProcess)
                    {
                        try
                        {
                            var process = Process.GetProcessById(shutdownResponse.ServerProcessId);
                            process.WaitForExit();
                        }
                        catch (Exception)
                        {
                            // There is an inherent race here with the server process.  If it has already shutdown
                            // by the time we try to access it then the operation has succeed.
                        }
                    }
                }

                return(CommonCompiler.Succeeded);
            }
            catch (Exception)
            {
                if (!DesktopBuildClient.WasServerMutexOpen(mutexName))
                {
                    // If the server was in the process of shutting down when we connected then it's reasonable
                    // for an exception to happen.  If the mutex has shutdown at this point then the server
                    // is shut down.
                    return(CommonCompiler.Succeeded);
                }

                return(CommonCompiler.Failed);
            }
        }
Esempio n. 16
0
        protected override string GetDefaultPipeName()
        {
            var clientDirectory = AppDomain.CurrentDomain.BaseDirectory;

            return(DesktopBuildClient.GetPipeNameForPath(clientDirectory));
        }
Esempio n. 17
0
        protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
        {
            if (ProvideCommandLineArgs)
            {
                CommandLineArgs = GetArguments(commandLineCommands, responseFileCommands)
                                  .Select(arg => new TaskItem(arg)).ToArray();
            }

            if (SkipCompilerExecution)
            {
                return(0);
            }

            if (!UseSharedCompilation ||
                !string.IsNullOrEmpty(ToolPath) ||
                !Utilities.IsCompilerServerSupported)
            {
                return(base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands));
            }

            using (_sharedCompileCts = new CancellationTokenSource())
            {
                try
                {
                    CompilerServerLogger.Log($"CommandLine = '{commandLineCommands}'");
                    CompilerServerLogger.Log($"BuildResponseFile = '{responseFileCommands}'");

                    // Try to get the location of the user-provided build client and server,
                    // which should be located next to the build task. If not, fall back to
                    // "pathToTool", which is the compiler in the MSBuild default bin directory.
                    var clientDir = TryGetClientDir() ?? Path.GetDirectoryName(pathToTool);
                    pathToTool = Path.Combine(clientDir, ToolExe);

                    // Note: we can't change the "tool path" printed to the console when we run
                    // the Csc/Vbc task since MSBuild logs it for us before we get here. Instead,
                    // we'll just print our own message that contains the real client location
                    Log.LogMessage(ErrorString.UsingSharedCompilation, clientDir);

                    var buildPaths = new BuildPaths(
                        clientDir: clientDir,
                        // MSBuild doesn't need the .NET SDK directory
                        sdkDir: null,
                        workingDir: CurrentDirectoryToUse());

                    var responseTask = DesktopBuildClient.RunServerCompilation(
                        Language,
                        GetArguments(commandLineCommands, responseFileCommands).ToList(),
                        buildPaths,
                        keepAlive: null,
                        libEnvVariable: LibDirectoryToUse(),
                        cancellationToken: _sharedCompileCts.Token);

                    responseTask.Wait(_sharedCompileCts.Token);

                    var response = responseTask.Result;
                    if (response != null)
                    {
                        ExitCode = HandleResponse(response, pathToTool, responseFileCommands, commandLineCommands);
                    }
                    else
                    {
                        Log.LogMessage(ErrorString.SharedCompilationFallback, pathToTool);

                        ExitCode = base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
                    }
                }
                catch (OperationCanceledException)
                {
                    ExitCode = 0;
                }
                catch (Exception e)
                {
                    Log.LogErrorWithCodeFromResources("Compiler_UnexpectedException");
                    LogErrorOutput(e.ToString());
                    ExitCode = -1;
                }
            }
            return(ExitCode);
        }
Esempio n. 18
0
 private static int MainCore(string[] args)
 => DesktopBuildClient.Run(args, RequestLanguage.VisualBasicCompile, Vbc.Run, new DesktopAnalyzerAssemblyLoader());
Esempio n. 19
0
        protected override bool?WasServerRunning(string pipeName)
        {
            string mutexName = DesktopBuildClient.GetServerMutexName(pipeName);

            return(DesktopBuildClient.WasServerMutexOpen(mutexName));
        }
Esempio n. 20
0
 public static int Main(string[] args, string[] extraArgs)
 => DesktopBuildClient.Run(args, extraArgs, RequestLanguage.VisualBasicCompile, Vbc.Run, new SimpleAnalyzerAssemblyLoader());
Esempio n. 21
0
 public static int Main(string[] args, string[] extraArgs)
 => DesktopBuildClient.Run(args, extraArgs, RequestLanguage.CSharpCompile, Csc.Run, new DesktopAnalyzerAssemblyLoader());