未验证 提交 b3bba197 编写于 作者: J Jared Parsons 提交者: GitHub

Merge pull request #25650 from jaredpar/fix-server

Account for Mutex ctor throwing
......@@ -15,6 +15,7 @@
using Roslyn.Test.Utilities;
using System.Threading;
using System.IO.Pipes;
using System.Security.AccessControl;
namespace Microsoft.CodeAnalysis.CompilerServer.UnitTests
{
......@@ -145,6 +146,32 @@ public void ConnectToServerFails()
}
}
#if NET461
[Fact]
public void TestMutexConstructorException()
{
using (var outer = new Mutex(initiallyOwned: true, name: BuildServerConnection.GetClientMutexName(_pipeName), out bool createdNew))
{
Assert.True(createdNew);
var mutexSecurity = outer.GetAccessControl();
var user = Environment.UserDomainName + "\\" + Environment.UserName;
mutexSecurity.AddAccessRule(new MutexAccessRule(user, MutexRights.FullControl, AccessControlType.Deny));
outer.SetAccessControl(mutexSecurity);
var ranLocal = false;
var client = CreateClient(
compileFunc: delegate
{
ranLocal = true;
return 0;
});
var exitCode = client.RunCompilation(new[] { "/shared" }, _buildPaths).ExitCode;
Assert.Equal(0, exitCode);
Assert.True(ranLocal);
}
}
#endif
[Fact]
public async Task ConnectToPipe()
{
......
......@@ -118,47 +118,62 @@ internal sealed class BuildServerConnection
var clientDir = buildPaths.ClientDirectory;
var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess;
var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
var clientMutexName = GetClientMutexName(pipeName);
Task<NamedPipeClientStream> pipeTask = null;
using (var clientMutex = new Mutex(initiallyOwned: true,
name: clientMutexName,
createdNew: out var holdsMutex))
Mutex clientMutex = null;
var holdsMutex = false;
try
{
try
{
if (!holdsMutex)
var clientMutexName = GetClientMutexName(pipeName);
clientMutex = new Mutex(initiallyOwned: true, name: 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
{
try
{
holdsMutex = clientMutex.WaitOne(timeoutNewProcess);
holdsMutex = clientMutex.WaitOne(timeoutNewProcess);
if (!holdsMutex)
{
return new RejectedBuildResponse();
}
}
catch (AbandonedMutexException)
if (!holdsMutex)
{
holdsMutex = true;
return new RejectedBuildResponse();
}
}
// Check for an already running server
var serverMutexName = GetServerMutexName(pipeName);
bool wasServerRunning = WasServerMutexOpen(serverMutexName);
var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;
if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
catch (AbandonedMutexException)
{
pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
holdsMutex = true;
}
}
finally
// Check for an already running server
var serverMutexName = GetServerMutexName(pipeName);
bool wasServerRunning = WasServerMutexOpen(serverMutexName);
var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;
if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
{
pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
}
}
finally
{
if (clientMutex != null)
{
if (holdsMutex)
{
clientMutex.ReleaseMutex();
}
clientMutex.Dispose();
}
}
......@@ -555,12 +570,21 @@ internal static string GetBasePipeName(string compilerExeDirectory)
internal static bool WasServerMutexOpen(string mutexName)
{
Mutex mutex;
var open = Mutex.TryOpenExisting(mutexName, out mutex);
if (open)
try
{
mutex.Dispose();
return true;
Mutex mutex;
var open = Mutex.TryOpenExisting(mutexName, out mutex);
if (open)
{
mutex.Dispose();
return true;
}
}
catch
{
// In the case an exception occured trying to open the Mutex then
// the assumption is that it's not open.
return false;
}
return false;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册