Esempio n. 1
0
 internal static bool WasServerMutexOpen(string mutexName)
 {
     try
     {
         if (PlatformInformation.IsRunningOnMono)
         {
             IServerMutex mutex      = null;
             bool         createdNew = false;
             try
             {
                 mutex = new ServerFileMutexPair(mutexName, false, out createdNew);
                 return(!createdNew);
             }
             finally
             {
                 mutex?.Dispose();
             }
         }
         else
         {
             return(ServerNamedMutex.WasOpen(mutexName));
         }
     }
     catch
     {
         // In the case an exception occured trying to open the Mutex then
         // the assumption is that it's not open.
         return(false);
     }
 }
Esempio n. 2
0
            // This code uses a Mutex.WaitOne / ReleaseMutex pairing. Both of these calls must occur on the same thread
            // or an exception will be thrown. This code lives in a separate non-async function to help ensure this
            // invariant doesn't get invalidated in the future by an `await` being inserted.
            static Task <NamedPipeClientStream> tryConnectToServer(
                string pipeName,
                BuildPathsAlt buildPaths,
                int?timeoutOverride,
                CreateServerFunc createServerFunc,
                CancellationToken cancellationToken)
            {
                var originalThreadId                  = Thread.CurrentThread.ManagedThreadId;
                var clientDir                         = buildPaths.ClientDirectory;
                var timeoutNewProcess                 = timeoutOverride ?? TimeOutMsNewProcess;
                var timeoutExistingProcess            = timeoutOverride ?? TimeOutMsExistingProcess;
                Task <NamedPipeClientStream> pipeTask = null;
                IServerMutex clientMutex              = null;

                try
                {
                    var holdsMutex = false;
                    try
                    {
                        var clientMutexName = GetClientMutexName(pipeName);
                        clientMutex = OpenOrCreateMutex(clientMutexName, out holdsMutex);
                    }
                    catch
                    {
                        // The Mutex constructor can throw in certain cases. One specific example is docker containers
                        // where the /tmp directory is restricted. In those cases there is no reliable way to execute
                        // the server and we need to fall back to the command line.
                        //
                        // Example: https://github.com/dotnet/roslyn/issues/24124
                        return(null);
                    }

                    if (!holdsMutex)
                    {
                        try
                        {
                            holdsMutex = clientMutex.TryLock(timeoutNewProcess);

                            if (!holdsMutex)
                            {
                                return(null);
                            }
                        }
                        catch (AbandonedMutexException)
                        {
                            holdsMutex = true;
                        }
                    }

                    // Check for an already running server
                    var  serverMutexName  = GetServerMutexName(pipeName);
                    bool wasServerRunning = WasServerMutexOpen(serverMutexName);
                    var  timeout          = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;

                    if (wasServerRunning || createServerFunc(clientDir, pipeName))
                    {
                        pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                    }

                    return(pipeTask);
                }
                finally
                {
                    try
                    {
                        clientMutex?.Dispose();
                    }
                    catch (ApplicationException e)
                    {
                        var releaseThreadId = Thread.CurrentThread.ManagedThreadId;
                        var message         = $"ReleaseMutex failed. WaitOne Id: {originalThreadId} Release Id: {releaseThreadId}";
                        throw new Exception(message, e);
                    }
                }
            }
Esempio n. 3
0
        internal static async Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(new RejectedBuildResponse());
            }

            if (buildPaths.TempDirectory == null)
            {
                return(new RejectedBuildResponse());
            }

            // early check for the build hash. If we can't find it something is wrong; no point even trying to go to the server
            if (string.IsNullOrWhiteSpace(BuildProtocolConstants.GetCommitHash()))
            {
                return(new IncorrectHashBuildResponse());
            }

            var clientDir                         = buildPaths.ClientDirectory;
            var timeoutNewProcess                 = timeoutOverride ?? TimeOutMsNewProcess;
            var timeoutExistingProcess            = timeoutOverride ?? TimeOutMsExistingProcess;
            Task <NamedPipeClientStream> pipeTask = null;
            IServerMutex clientMutex              = null;

            try
            {
                var holdsMutex = false;
                try
                {
                    var clientMutexName = GetClientMutexName(pipeName);
                    clientMutex = OpenOrCreateMutex(clientMutexName, out holdsMutex);
                }
                catch
                {
                    // The Mutex constructor can throw in certain cases. One specific example is docker containers
                    // where the /tmp directory is restricted. In those cases there is no reliable way to execute
                    // the server and we need to fall back to the command line.
                    //
                    // Example: https://github.com/dotnet/roslyn/issues/24124
                    return(new RejectedBuildResponse());
                }

                if (!holdsMutex)
                {
                    try
                    {
                        holdsMutex = clientMutex.TryLock(timeoutNewProcess);

                        if (!holdsMutex)
                        {
                            return(new RejectedBuildResponse());
                        }
                    }
                    catch (AbandonedMutexException)
                    {
                        holdsMutex = true;
                    }
                }

                // Check for an already running server
                var  serverMutexName  = GetServerMutexName(pipeName);
                bool wasServerRunning = WasServerMutexOpen(serverMutexName);
                var  timeout          = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;

                if (wasServerRunning || createServerFunc(clientDir, pipeName))
                {
                    pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                }
            }
            finally
            {
                clientMutex?.Dispose();
            }

            if (pipeTask != null)
            {
                var pipe = await pipeTask.ConfigureAwait(false);

                if (pipe != null)
                {
                    var request = BuildRequest.Create(language,
                                                      buildPaths.WorkingDirectory,
                                                      buildPaths.TempDirectory,
                                                      BuildProtocolConstants.GetCommitHash(),
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

                    return(await TryCompile(pipe, request, cancellationToken).ConfigureAwait(false));
                }
            }

            return(new RejectedBuildResponse());
        }