/// <summary> /// Cleans up any context or state that may have been built up for a given task. /// </summary> /// <param name="task">The task to clean up.</param> /// <remarks> /// For many factories, this method is a no-op. But some factories may have built up /// an AppDomain as part of an individual task instance, and this is their opportunity /// to shutdown the AppDomain. /// </remarks> public void CleanupTask(ITask task) { ErrorUtilities.VerifyThrowArgumentNull(task, "task"); AppDomain appDomain; if (_tasksAndAppDomains.TryGetValue(task, out appDomain)) { _tasksAndAppDomains.Remove(task); if (appDomain != null) { // Unload the AppDomain asynchronously to avoid a deadlock that can happen because // AppDomain.Unload blocks for the process's one Finalizer thread to finalize all // objects. Some objects are RCWs for STA COM objects and as such would need the // VS main thread to be processing messages in order to finalize. But if the main thread // is blocked in a non-pumping wait waiting for this build request to complete, we would // deadlock. By unloading asynchronously, the AppDomain unload can block till the main // thread is available, even if it isn't available until after this MSBuild Task has // finished executing. Task.Run(() => AppDomain.Unload(appDomain)); } } TaskHostTask taskAsTaskHostTask = task as TaskHostTask; if (taskAsTaskHostTask != null) { taskAsTaskHostTask.Cleanup(); } else { // It's really not necessary to do it for TaskHostTasks TaskLoader.RemoveAssemblyResolver(); } }
/// <summary> /// Create an instance of the wrapped ITask for a batch run of the task. /// </summary> internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary <string, string> taskIdentityParameters, #if FEATURE_APPDOMAIN AppDomainSetup appDomainSetup, #endif bool isOutOfProc) { bool useTaskFactory = false; IDictionary <string, string> mergedParameters = null; _taskLoggingContext = taskLoggingContext; // Optimization for the common (vanilla AssemblyTaskFactory) case -- only calculate // the task factory parameters if we have any to calculate; otherwise even if we // still launch the task factory, it will be with parameters corresponding to the // current process. if ((_factoryIdentityParameters != null && _factoryIdentityParameters.Count > 0) || (taskIdentityParameters != null && taskIdentityParameters.Count > 0)) { VerifyThrowIdentityParametersValid(taskIdentityParameters, taskLocation, _taskName, "MSBuildRuntime", "MSBuildArchitecture"); mergedParameters = MergeTaskFactoryParameterSets(_factoryIdentityParameters, taskIdentityParameters); useTaskFactory = !NativeMethodsShared.IsMono && (_taskHostFactoryExplicitlyRequested || !TaskHostParametersMatchCurrentProcess(mergedParameters)); } else { // if we don't have any task host parameters specified on either the using task or the // task invocation, then we will run in-proc UNLESS "TaskHostFactory" is explicitly specified // as the task factory. useTaskFactory = _taskHostFactoryExplicitlyRequested; } if (useTaskFactory) { ErrorUtilities.VerifyThrowInternalNull(buildComponentHost, "buildComponentHost"); mergedParameters = mergedParameters ?? new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase); string runtime = null; string architecture = null; if (!mergedParameters.TryGetValue(XMakeAttributes.runtime, out runtime)) { mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.MSBuildRuntimeValues.clr4; } if (!mergedParameters.TryGetValue(XMakeAttributes.architecture, out architecture)) { mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture(); } TaskHostTask task = new TaskHostTask(taskLocation, taskLoggingContext, buildComponentHost, mergedParameters, _loadedType #if FEATURE_APPDOMAIN , appDomainSetup #endif ); return(task); } else { #if FEATURE_APPDOMAIN AppDomain taskAppDomain = null; #endif ITask taskInstance = TaskLoader.CreateTask(_loadedType, _taskName, taskLocation.File, taskLocation.Line, taskLocation.Column, new TaskLoader.LogError(ErrorLoggingDelegate) #if FEATURE_APPDOMAIN , appDomainSetup #endif , isOutOfProc #if FEATURE_APPDOMAIN , out taskAppDomain #endif ); #if FEATURE_APPDOMAIN if (taskAppDomain != null) { _tasksAndAppDomains[taskInstance] = taskAppDomain; } #endif return(taskInstance); } }
/// <summary> /// Create an instance of the wrapped ITask for a batch run of the task. /// </summary> internal ITask CreateTaskInstance(ElementLocation taskLocation, TaskLoggingContext taskLoggingContext, IBuildComponentHost buildComponentHost, IDictionary<string, string> taskIdentityParameters, AppDomainSetup appDomainSetup, bool isOutOfProc) { bool useTaskFactory = false; IDictionary<string, string> mergedParameters = null; _taskLoggingContext = taskLoggingContext; // Optimization for the common (vanilla AssemblyTaskFactory) case -- only calculate // the task factory parameters if we have any to calculate; otherwise even if we // still launch the task factory, it will be with parameters corresponding to the // current process. if ((_factoryIdentityParameters != null && _factoryIdentityParameters.Count > 0) || (taskIdentityParameters != null && taskIdentityParameters.Count > 0)) { VerifyThrowIdentityParametersValid(taskIdentityParameters, taskLocation, _taskName, "MSBuildRuntime", "MSBuildArchitecture"); mergedParameters = MergeTaskFactoryParameterSets(_factoryIdentityParameters, taskIdentityParameters); useTaskFactory = _taskHostFactoryExplicitlyRequested || !TaskHostParametersMatchCurrentProcess(mergedParameters); } else { // if we don't have any task host parameters specified on either the using task or the // task invocation, then we will run in-proc UNLESS "TaskHostFactory" is explicitly specified // as the task factory. useTaskFactory = _taskHostFactoryExplicitlyRequested; } if (useTaskFactory) { ErrorUtilities.VerifyThrowInternalNull(buildComponentHost, "buildComponentHost"); mergedParameters = mergedParameters ?? new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); string runtime = null; string architecture = null; if (!mergedParameters.TryGetValue(XMakeAttributes.runtime, out runtime)) { mergedParameters[XMakeAttributes.runtime] = XMakeAttributes.MSBuildRuntimeValues.clr4; } if (!mergedParameters.TryGetValue(XMakeAttributes.architecture, out architecture)) { mergedParameters[XMakeAttributes.architecture] = XMakeAttributes.GetCurrentMSBuildArchitecture(); } TaskHostTask task = new TaskHostTask(taskLocation, taskLoggingContext, buildComponentHost, mergedParameters, _loadedType, appDomainSetup); return task; } else { AppDomain taskAppDomain = null; ITask taskInstance = TaskLoader.CreateTask(_loadedType, _taskName, taskLocation.File, taskLocation.Line, taskLocation.Column, new TaskLoader.LogError(ErrorLoggingDelegate), appDomainSetup, isOutOfProc, out taskAppDomain); if (taskAppDomain != null) { _tasksAndAppDomains[taskInstance] = taskAppDomain; } return taskInstance; } }