This commit is contained in:
Jessica Schumaker 2019-02-11 13:06:58 -05:00
Родитель 2798a04934
Коммит 7b0b92fd63
10 изменённых файлов: 73 добавлений и 40 удалений

Просмотреть файл

@ -58,6 +58,9 @@ namespace GVFS.Common
public abstract Dictionary<string, string> GetPhysicalDiskInfo(string path, bool sizeStatsOnly);
public abstract bool IsConsoleOutputRedirectedToFile();
public abstract bool TryKillProcessTree(int processId, out int exitCode, out string error);
public abstract bool TryGetGVFSEnlistmentRoot(string directory, out string enlistmentRoot, out string errorMessage);
public abstract bool IsGitStatusCacheSupported();

Просмотреть файл

@ -126,34 +126,33 @@ namespace GVFS.Common.Git
return true;
}
public bool WaitForRunningGitProcess()
/// <summary>
/// Tries to kill the run git process. Make sure you only use this on git processes that can safely be killed!
/// </summary>
/// <param name="processName">Name of the running process</param>
/// <param name="exitCode">Exit code of the kill. -1 means there was no running process.</param>
/// <param name="error">Error message of the kill</param>
/// <returns></returns>
public bool TryKillRunningProcess(out string processName, out int exitCode, out string error)
{
this.stopping = true;
processName = null;
exitCode = -1;
error = null;
try
lock (this.processLock)
{
lock (this.processLock)
Process process = this.executingProcess;
if (process != null)
{
Process process = this.executingProcess;
processName = process.ProcessName;
if (process != null)
{
process.WaitForExit();
}
return true;
return GVFSPlatform.Instance.TryKillProcessTree(process.Id, out exitCode, out error);
}
}
catch (Win32Exception)
{
// Thrown when process is already terminating
}
catch (InvalidOperationException)
{
// Process already terminated
}
return false;
return true;
}
}
public virtual void RevokeCredential(string repoUrl)

Просмотреть файл

@ -74,12 +74,10 @@ namespace GVFS.Upgrader
return true;
}
public virtual bool NoBlockingProcessCheck(out string consoleError)
public virtual bool IsInstallationBlockedByRunningProcess(out string consoleError)
{
consoleError = null;
this.tracer.RelatedInfo("Checking for running git processes.");
// While checking for blocking processes like GVFS.Mount immediately after un-mounting,
// then sometimes GVFS.Mount shows up as running. But if the check is done after waiting
// for some time, then eventually GVFS.Mount goes away. The retry loop below is to help
@ -87,7 +85,7 @@ namespace GVFS.Upgrader
// actually quits.
this.tracer.RelatedInfo("Checking if GVFS or dependent processes are running.");
int retryCount = 10;
List<string> processList = null;
HashSet<string> processList = null;
while (retryCount > 0)
{
if (!this.IsBlockingProcessRunning(out processList))
@ -105,7 +103,7 @@ namespace GVFS.Upgrader
Environment.NewLine,
"Blocking processes are running.",
$"Run {this.CommandToRerun} again after quitting these processes - " + string.Join(", ", processList.ToArray()));
this.tracer.RelatedError($"{nameof(this.TryUnmountAllGVFSRepos)}: {consoleError}");
this.tracer.RelatedError($"{nameof(this.IsInstallationBlockedByRunningProcess)}: {consoleError}");
return false;
}
@ -134,11 +132,11 @@ namespace GVFS.Upgrader
return GVFSEnlistment.IsUnattended(this.tracer);
}
protected virtual bool IsBlockingProcessRunning(out List<string> processes)
protected virtual bool IsBlockingProcessRunning(out HashSet<string> processes)
{
int currentProcessId = Process.GetCurrentProcess().Id;
Process[] allProcesses = Process.GetProcesses();
List<string> matchingNames = new List<string>();
HashSet<string> matchingNames = new HashSet<string>();
foreach (Process process in allProcesses)
{

Просмотреть файл

@ -79,18 +79,28 @@ namespace GVFS.Common.Maintenance
if (process != null)
{
if (process.WaitForRunningGitProcess())
if (process.TryKillRunningProcess(out string processName, out int exitCode, out string error))
{
this.Context.Tracer.RelatedEvent(
EventLevel.Informational,
this.Area + ": waited for background Git process during " + nameof(this.Stop),
string.Format(
"{0}: killed background process {1} during {2}",
this.Area,
processName,
nameof(this.Stop)),
metadata: null);
}
else
{
this.Context.Tracer.RelatedEvent(
EventLevel.Informational,
this.Area + ": failed to wait for background Git process during " + nameof(this.Stop),
string.Format(
"{0}: failed to kill background process {1} during {2}. ExitCode:{3} Error:{4}",
this.Area,
processName,
nameof(this.Stop),
exitCode,
error),
metadata: null);
}
}

Просмотреть файл

@ -159,5 +159,13 @@ namespace GVFS.Platform.Mac
{
return new MacFileBasedLock(fileSystem, tracer, lockPath);
}
public override bool TryKillProcessTree(int processId, out int exitCode, out string error)
{
ProcessResult result = ProcessHelper.Run("pkill", $"-P {processId}");
error = result.Errors;
exitCode = result.ExitCode;
return result.ExitCode == 0;
}
}
}

Просмотреть файл

@ -332,6 +332,14 @@ namespace GVFS.Platform.Windows
return WindowsPlatform.TryGetGVFSEnlistmentRootImplementation(directory, out enlistmentRoot, out errorMessage);
}
public override bool TryKillProcessTree(int processId, out int exitCode, out string error)
{
ProcessResult result = ProcessHelper.Run("taskkill", $"/pid {processId} /f /t");
error = result.Errors;
exitCode = result.ExitCode;
return result.ExitCode == 0;
}
private static object GetValueFromRegistry(RegistryHive registryHive, string key, string valueName, RegistryView view)
{
RegistryKey localKey = RegistryKey.OpenBaseKey(registryHive, view);

Просмотреть файл

@ -72,9 +72,9 @@ namespace GVFS.UnitTests.Windows.Mock.Upgrader
return this.FakedResultOfCheck(FailOnCheckType.UnattendedMode);
}
protected override bool IsBlockingProcessRunning(out List<string> processes)
protected override bool IsBlockingProcessRunning(out HashSet<string> processes)
{
processes = new List<string>();
processes = new HashSet<string>();
bool isRunning = this.FakedResultOfCheck(FailOnCheckType.BlockingProcessesRunning);
if (isRunning)

Просмотреть файл

@ -12,7 +12,11 @@ namespace GVFS.UnitTests.Git
public void TryKillRunningProcess_NeverRan()
{
GitProcess process = new GitProcess(new MockGVFSEnlistment());
process.WaitForRunningGitProcess().ShouldBeTrue();
process.TryKillRunningProcess(out string processName, out int exitCode, out string error).ShouldBeTrue();
processName.ShouldBeNull();
exitCode.ShouldEqual(-1);
error.ShouldBeNull();
}
[TestCase]

Просмотреть файл

@ -122,5 +122,12 @@ namespace GVFS.UnitTests.Mock.Common
{
return new MockFileBasedLock(fileSystem, tracer, lockPath);
}
public override bool TryKillProcessTree(int processId, out int exitCode, out string error)
{
error = null;
exitCode = 0;
return true;
}
}
}

Просмотреть файл

@ -222,18 +222,14 @@ namespace GVFS.Upgrader
if (!this.LaunchInsideSpinner(
() =>
{
// if (!this.preRunChecker.TryUnmountAllGVFSRepos(out error))
if (!this.preRunChecker.NoBlockingProcessCheck(out error))
if (!this.preRunChecker.IsInstallationBlockedByRunningProcess(out error))
{
return false;
}
this.mount = true;
return true;
},
"Checking for running git processes."))
"Checking for blocking processes."))
{
newVersion = null;
consoleError = error;