/// <summary> /// Constructor /// </summary> /// <param name="result">Result of the task's execution.</param> /// <param name="buildProcessEnvironment">The build process environment as it was at the end of the task's execution.</param> public TaskHostTaskComplete(OutOfProcTaskHostTaskResult result, IDictionary <string, string> buildProcessEnvironment) { ErrorUtilities.VerifyThrowInternalNull(result, "result"); _taskResult = result.Result; _taskException = result.TaskException; _taskExceptionMessage = result.ExceptionMessage; _taskExceptionMessageArgs = result.ExceptionMessageArgs; if (result.FinalParameterValues != null) { _taskOutputParameters = new Dictionary <string, TaskParameter>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair <string, object> parameter in result.FinalParameterValues) { _taskOutputParameters[parameter.Key] = new TaskParameter(parameter.Value); } } if (buildProcessEnvironment != null) { _buildProcessEnvironment = buildProcessEnvironment as Dictionary <string, string>; if (_buildProcessEnvironment == null) { _buildProcessEnvironment = new Dictionary <string, string>(buildProcessEnvironment); } } }
/// <summary> /// Execute a task on the STA thread. /// </summary> /// <comment> /// STA thread launching code lifted from XMakeBuildEngine\BackEnd\Components\RequestBuilder\TaskBuilder.cs, ExecuteTaskInSTAThread method. /// Any bug fixes made to this code, please ensure that you also fix that code. /// </comment> private OutOfProcTaskHostTaskResult InstantiateAndExecuteTaskInSTAThread ( IBuildEngine oopTaskHostNode, LoadedType taskType, string taskName, string taskLocation, string taskFile, int taskLine, int taskColumn, #if FEATURE_APPDOMAIN AppDomainSetup appDomainSetup, #endif IDictionary <string, TaskParameter> taskParams ) { ManualResetEvent taskRunnerFinished = new ManualResetEvent(false); OutOfProcTaskHostTaskResult taskResult = null; Exception exceptionFromExecution = null; try { ThreadStart taskRunnerDelegate = delegate() { try { taskResult = InstantiateAndExecuteTask ( oopTaskHostNode, taskType, taskName, taskLocation, taskFile, taskLine, taskColumn, #if FEATURE_APPDOMAIN appDomainSetup, #endif taskParams ); } catch (Exception e) { if (ExceptionHandling.IsCriticalException(e)) { throw; } exceptionFromExecution = e; } finally { taskRunnerFinished.Set(); } }; Thread staThread = new Thread(taskRunnerDelegate); staThread.SetApartmentState(ApartmentState.STA); staThread.Name = "MSBuild STA task runner thread"; staThread.CurrentCulture = Thread.CurrentThread.CurrentCulture; staThread.CurrentUICulture = Thread.CurrentThread.CurrentUICulture; staThread.Start(); // TODO: Why not just Join on the thread??? taskRunnerFinished.WaitOne(); } finally { #if CLR2COMPATIBILITY taskRunnerFinished.Close(); #else taskRunnerFinished.Dispose(); #endif taskRunnerFinished = null; } if (exceptionFromExecution != null) { // Unfortunately this will reset the callstack throw exceptionFromExecution; } return(taskResult); }
/// <summary> /// Task runner method /// </summary> private void RunTask(object state) { _isTaskExecuting = true; OutOfProcTaskHostTaskResult taskResult = null; TaskHostConfiguration taskConfiguration = state as TaskHostConfiguration; IDictionary <string, TaskParameter> taskParams = taskConfiguration.TaskParameters; // We only really know the values of these variables for sure once we see what we received from our parent // environment -- otherwise if this was a completely new build, we could lose out on expected environment // variables. _debugCommunications = taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBUILDDEBUGCOMM", "1", StringComparison.OrdinalIgnoreCase); _updateEnvironment = !taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBuildTaskHostDoNotUpdateEnvironment", "1", StringComparison.OrdinalIgnoreCase); _updateEnvironmentAndLog = taskConfiguration.BuildProcessEnvironment.ContainsValueAndIsEqual("MSBuildTaskHostUpdateEnvironmentAndLog", "1", StringComparison.OrdinalIgnoreCase); try { // Change to the startup directory NativeMethodsShared.SetCurrentDirectory(taskConfiguration.StartupDirectory); if (_updateEnvironment) { InitializeMismatchedEnvironmentTable(taskConfiguration.BuildProcessEnvironment); } // Now set the new environment SetTaskHostEnvironment(taskConfiguration.BuildProcessEnvironment); // Set culture Thread.CurrentThread.CurrentCulture = taskConfiguration.Culture; Thread.CurrentThread.CurrentUICulture = taskConfiguration.UICulture; string taskName = taskConfiguration.TaskName; string taskLocation = taskConfiguration.TaskLocation; // We will not create an appdomain now because of a bug // As a fix, we will create the class directly without wrapping it in a domain _taskWrapper = new OutOfProcTaskAppDomainWrapper(); taskResult = _taskWrapper.ExecuteTask ( this as IBuildEngine, taskName, taskLocation, taskConfiguration.ProjectFileOfTask, taskConfiguration.LineNumberOfTask, taskConfiguration.ColumnNumberOfTask, taskConfiguration.AppDomainSetup, taskParams ); } catch (Exception e) { if (e is ThreadAbortException) { // This thread was aborted as part of Cancellation, we will return a failure task result taskResult = new OutOfProcTaskHostTaskResult(TaskCompleteType.Failure); } else if (ExceptionHandling.IsCriticalException(e)) { throw; } else { taskResult = new OutOfProcTaskHostTaskResult(TaskCompleteType.CrashedDuringExecution, e); } } finally { try { _isTaskExecuting = false; IDictionary <string, string> currentEnvironment = CommunicationsUtilities.GetEnvironmentVariables(); currentEnvironment = UpdateEnvironmentForMainNode(currentEnvironment); if (taskResult == null) { taskResult = new OutOfProcTaskHostTaskResult(TaskCompleteType.Failure); } lock (_taskCompleteLock) { _taskCompletePacket = new TaskHostTaskComplete ( taskResult, currentEnvironment ); } foreach (TaskParameter param in taskParams.Values) { // Tell remoting to forget connections to the parameter RemotingServices.Disconnect(param); } // Restore the original clean environment CommunicationsUtilities.SetEnvironment(_savedEnvironment); } catch (Exception e) { lock (_taskCompleteLock) { // Create a minimal taskCompletePacket to carry the exception so that the TaskHostTask does not hang while waiting _taskCompletePacket = new TaskHostTaskComplete(new OutOfProcTaskHostTaskResult(TaskCompleteType.CrashedAfterExecution, e), null); } } finally { // Call CleanupTask to unload any domains and other necessary cleanup in the taskWrapper _taskWrapper.CleanupTask(); // The task has now fully completed executing _taskCompleteEvent.Set(); } } }