From bbd58339cd6001b58e6e05805a08b02c7ae3511b Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 17 Jun 2012 17:57:19 +0200 Subject: [PATCH] BuildWorker: swap communication and build threads. This is an attempt to fix http://community.sharpdevelop.net/forums/t/15654.aspx - BuildWorker40 hangs on windows 7 x64bit when invoking the markup compiler. According the the report in the forums, the problem disappears when MSBuild is invoked on the main thread, and communication is suspended while the build is in progress (breaking cancellation). This patch also moves the communication onto a background thread, fixing build cancellation. This might solve the problem if the hang was somehow related to the thread MSBuild was running on. However, if the AppDomain unload fails due to the thread stuck reading from the named pipe, the build worker might continue hanging with this patch. --- .../Program.cs | 55 +++++++++++++++---- 1 file changed, 43 insertions(+), 12 deletions(-) diff --git a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs index 6d0fa74182..ac386a42a0 100644 --- a/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs +++ b/src/Main/ICSharpCode.SharpDevelop.BuildWorker/Program.cs @@ -18,9 +18,10 @@ namespace ICSharpCode.SharpDevelop.BuildWorker { sealed class Program { - static HostProcess host; + HostProcess host; BuildJob currentJob; bool requestCancellation; + bool requestProcessShutdown; [STAThread] internal static void Main(string[] args) @@ -29,8 +30,12 @@ namespace ICSharpCode.SharpDevelop.BuildWorker if (args.Length == 3 && args[0] == "worker") { try { - host = new HostProcess(args[1], args[2]); - host.Run(new Program().DataReceived); + Program program = new Program(); + program.host = new HostProcess(args[1], args[2]); + Thread communicationThread = new Thread(program.RunCommunicationThread); + communicationThread.Name = "Communication"; + communicationThread.Start(); + program.RunBuildThread(); } catch (Exception ex) { ShowMessageBox(ex.ToString()); } @@ -42,10 +47,25 @@ namespace ICSharpCode.SharpDevelop.BuildWorker } } + void RunCommunicationThread() + { + try { + host.Run(DataReceived); + } catch (Exception ex) { + ShowMessageBox(ex.ToString()); + } finally { + lock (this) { + requestProcessShutdown = true; + Monitor.PulseAll(this); + } + } + } + readonly MSBuildWrapper buildWrapper = new MSBuildWrapper(); void DataReceived(string command, BinaryReader reader) { + // called on communication thread switch (command) { case "StartBuild": StartBuild(BuildJob.ReadFrom(reader)); @@ -86,28 +106,26 @@ namespace ICSharpCode.SharpDevelop.BuildWorker [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] public void StartBuild(BuildJob job) { + // called on communication thread if (job == null) throw new ArgumentNullException("job"); + Program.Log("Got job:"); + Program.Log(job.ToString()); lock (this) { if (currentJob != null) throw new InvalidOperationException("Already running a job"); currentJob = job; requestCancellation = false; + Monitor.PulseAll(this); } #if WORKERDEBUG Console.Title = "BuildWorker - " + Path.GetFileName(job.ProjectFileName); #endif - Program.Log("Got job:"); - Program.Log(job.ToString()); - Program.Log("Start build thread"); - Thread thread = new Thread(RunThread); - thread.Name = "Build thread"; - thread.SetApartmentState(ApartmentState.STA); - thread.Start(); } public void CancelBuild() { + // called on communication thread Program.Log("CancelBuild()"); lock (this) { if (!requestCancellation) { @@ -117,8 +135,21 @@ namespace ICSharpCode.SharpDevelop.BuildWorker } } - [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] - void RunThread() + void RunBuildThread() + { + while (true) { + // Wait for next job, or for shutdown + lock (this) { + while (currentJob == null && !requestProcessShutdown) + Monitor.Wait(this); + if (requestProcessShutdown) + break; + } + PerformBuild(); + } + } + + void PerformBuild() { Program.Log("In build thread"); bool success = false;