From ec10d083d135c15778f14f30158008886534e2c5 Mon Sep 17 00:00:00 2001 From: ian davis Date: Thu, 4 Jul 2019 21:54:37 +1000 Subject: [PATCH 1/2] Fixed git deadlock bug in GitServiceExecutor. Fault due to stdIn and stdOut buffers filling, handling now asynchronous. --- .../Git/GitService/GitServiceExecutor.cs | 44 +++++++++++++++---- 1 file changed, 36 insertions(+), 8 deletions(-) diff --git a/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs b/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs index 746a2acf7..ecdfe1571 100644 --- a/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs +++ b/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs @@ -7,6 +7,8 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Threading; +using System.Threading.Tasks; namespace Bonobo.Git.Server.Git.GitService { @@ -93,15 +95,41 @@ public void ExecuteServiceByName( using (var process = Process.Start(info)) { - inStream.CopyTo(process.StandardInput.BaseStream); - if (options.endStreamWithClose) { - process.StandardInput.Close(); - } else { - process.StandardInput.Write('\0'); - } + //Do asynchronous copy i.e. spin up a separate task so we can simultaneously read/write & + //avoid deadlock due to filled buffers within git process + Task stdInTask = inStream.CopyToAsync(process.StandardInput.BaseStream); + + //Don't bother waiting on completion of stdOutTask while process is running. + //task will be sitting idle waiting for new bytes on stdOut of git + Task stdOutTask = process.StandardOutput.BaseStream.CopyToAsync(outStream); + + //wait for process death and ensure all data is sent and received + bool completionJobDone = false; + while (true) + { + //check if all output has been sent to git exe via stdin + if ((stdInTask.IsCompleted) && (completionJobDone==false)) + { + //all output has been sent to git process, send final signal. + if (options.endStreamWithClose) + { + process.StandardInput.Close(); + } + else + { + process.StandardInput.Write('\0'); + } + completionJobDone = true; + } - process.StandardOutput.BaseStream.CopyTo(outStream); - process.WaitForExit(); + //check if git has terminated + if (process.HasExited) + break; + + //lets not hog all the CPU, sleep for a little while (20ms) + Thread.Sleep(20); + } + stdOutTask.Wait(); } } From dbabdd42d34c2a3ea8e9d94dccf4c4f4681a6e11 Mon Sep 17 00:00:00 2001 From: ian davis Date: Thu, 4 Jul 2019 23:28:15 +1000 Subject: [PATCH 2/2] removed trailing white-space. --- Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs b/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs index ecdfe1571..d10a2b595 100644 --- a/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs +++ b/Bonobo.Git.Server/Git/GitService/GitServiceExecutor.cs @@ -95,7 +95,7 @@ public void ExecuteServiceByName( using (var process = Process.Start(info)) { - //Do asynchronous copy i.e. spin up a separate task so we can simultaneously read/write & + //Do asynchronous copy i.e. spin up a separate task so we can simultaneously read/write & //avoid deadlock due to filled buffers within git process Task stdInTask = inStream.CopyToAsync(process.StandardInput.BaseStream); @@ -107,7 +107,7 @@ public void ExecuteServiceByName( bool completionJobDone = false; while (true) { - //check if all output has been sent to git exe via stdin + //check if all output has been sent to git exe via stdin if ((stdInTask.IsCompleted) && (completionJobDone==false)) { //all output has been sent to git process, send final signal.