Files
ArchiSteamFarm/packages/Microsoft.Bcl.Build.1.0.21/build/Microsoft.Bcl.Build.targets
JustArchi a8045ac50b Fix async/await with ConcurrentHashSet
Now this is a nice bug that was found accidentally by ArchiBoT...
ReaderWriterLockSlim() is very decent solution, but it's thread-based, and we're using our ConcurrentHashSet in mixed async/sync context. This means that if we use something like:
foreach (var item in concHashSet) {
    await AnythingAsync().ConfigureAwait(false);
}
It's totally possible that we'll request read lock as thread 1, and release the read lock as thread 2, which will lead to RWLock exception => System.Threading.SynchronizationLockException: The read lock is being released without being held.
Fortunately it looks like we didn't have any scenario like this in ASF, as this was possible only when we async/await while enumerating over ConcurrentHashSet, so that specific bug didn't affect ASF codebase (yet). Still, I must fix this as current implementation is not thread-safe, so our HashSet is in fact not concurrent in the first place.
I analyzed possible solutions and there are basically 3: either using ConcurrentDictionary and wrapping around it, replacing lock with SemaphoreSlim, or using third-party AsyncReaderWriterLock from StephenCleary. SemaphoreSlim entirely kills the concept of multiple readers one writer, and could affect performance negatively, moreover - it doesn't support upgreadable lock scenario we have with ReplaceIfNeededWith(). Concurrent dictionary would be nice if I didn't have that awful memory hit from storing mandatory pointless value, plus I don't really like concept of wrapping around conc dictionary if I can simply use it right away and drop my conc hashset entirely. AsyncReaderWriterLock seem to be really well written, and works on Mono + should be compatible with .NET core in the future, so we should go for it as it's the best bet both performance-wise and memory-wise.
This brings another package dependency and changes a bit backend of ConcurrentHashSet
2017-02-07 20:14:51 +01:00

250 lines
15 KiB
XML

<!--
***********************************************************************************************
Microsoft.Bcl.targets
WARNING: DO NOT MODIFY this file unless you are knowledgeable about MSBuild and have
created a backup copy. Incorrect changes to this file will make it
impossible to load or build your projects from the command-line or the IDE.
Copyright (C) Microsoft Corporation. All rights reserved.
***********************************************************************************************
-->
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<BclBuildImported>true</BclBuildImported>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFrameworkIdentifier)' != 'Silverlight' and '$(OutputType)' != 'AppContainerExe'">
<!--
Workaround MSBuild issue that prevents System.Runtime 2.5 and System.Threading.Tasks 2.5 from
satisfying indirect dependencies on System.Runtime 1.5 and System.Threading.Tasks 1.5 respectively.
-->
<AutoUnifyAssemblyReferences>false</AutoUnifyAssemblyReferences>
<!-- MSBuild by default doesn't pass the Web.Config ResolveAssemblyReference, in which case, set it so that it sees binding redirects -->
<AppConfig Condition="'$(AppConfig)' == '' And '$(WebProjectOutputDir)' != '' And Exists('$(ProjectConfigFileName)')">$(ProjectConfigFileName)</AppConfig>
</PropertyGroup>
<!-- Workaround issue that incorrectly unifies references not in the current profile to the version in the superset of all profiles. -->
<Target Name="_BclBuildSetFullFrameworkFolderToProfile" AfterTargets="GetReferenceAssemblyPaths" Condition="'$(TargetFrameworkIdentifier)' == '.NETPortable'">
<PropertyGroup>
<_FullFrameworkReferenceAssemblyPaths>$(TargetFrameworkDirectory)</_FullFrameworkReferenceAssemblyPaths>
</PropertyGroup>
</Target>
<!--
*******************************************************************************************************************
*******************************************************************************************************************
EnsureBindingRedirects Section
*******************************************************************************************************************
*******************************************************************************************************************
-->
<PropertyGroup>
<__IntermediateAppConfig>$(IntermediateOutputPath)$(MSBuildProjectFile).App.config</__IntermediateAppConfig>
<SkipEnsureBindingRedirects Condition="'$(TargetFrameworkIdentifier)' == 'Silverlight' or '$(OutputType)' == 'AppContainerExe'">true</SkipEnsureBindingRedirects>
<!-- Default logic is to use existing Bcl.Build code for any binding redirects which are not now supported by the
framework functionality which is controlled by existing MSBUILD properties, that were added in Dev12
Supported Dev12 scenarios are:
Project Output Type exe, winexe
<AutoGenerateBindingRedirects> in project file set to true
All others outside of this should continue to use existing mechanism in BCL.Build to ensure behavioural compatbility
for output types. -->
<SkipEnsureBindingRedirects Condition="'$(SkipEnsureBindingRedirects)' == ''">false</SkipEnsureBindingRedirects>
<SkipEnsureBindingRedirects Condition="'$(AutoGenerateBindingRedirects)' =='true' and '$(GenerateBindingRedirectsOutputType)' == 'true'">true</SkipEnsureBindingRedirects>
</PropertyGroup>
<!-- we haven't already been told to skip binding redirects, the project supports bindingredirect generation, and hasn't yet opted-in, force the opt in and disable our own bindingRedirect generation. -->
<PropertyGroup Condition="'$(SkipEnsureBindingRedirects)' != 'true' and ('$(AutoGenerateBindingRedirects)' =='' and '$(GenerateBindingRedirectsOutputType)' == 'true')">
<SkipEnsureBindingRedirects>true</SkipEnsureBindingRedirects>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
</PropertyGroup>
<UsingTask TaskName="EnsureBindingRedirects" AssemblyFile="$(MSBuildThisFileDirectory)Microsoft.Bcl.Build.Tasks.dll" />
<!--
===================================================================================================================
BclBuildDetermineReferencesToRedirect
Determine which references are opted in for binding redirects
===================================================================================================================
-->
<Target Name="BclBuildDetermineReferencesToRedirect" BeforeTargets="BclBuildEnsureBindingRedirects" Condition="'$(SkipEnsureBindingRedirects)' != 'true'">
<!-- Convention is a file next to the reference with name "ensureRedirect.xml" -->
<ItemGroup>
<_EnsureBindingRedirectReference Include="@(Reference)"
Condition="'%(Reference.HintPath)' != '' and Exists('$([System.IO.Path]::GetDirectoryName(&quot;%(Reference.HintPath)&quot;))\\ensureRedirect.xml')" />
</ItemGroup>
</Target>
<!--
===================================================================================================================
BclBuildEnsureBindingRedirects
Generate a new app.config with merged binding redirects if we have binding redirects to ensure and it's out of date
===================================================================================================================
-->
<Target Name="BclBuildEnsureBindingRedirects"
DependsOnTargets="BclBuildDetermineReferencesToRedirect"
BeforeTargets="ResolveAssemblyReferences"
Condition="'@(_EnsureBindingRedirectReference)' != '' and '$(SkipEnsureBindingRedirects)' != 'true'"
Inputs="$(MSBuildAllProjects);$(AppConfig);@(_EnsureBindingRedirectReference->'%(HintPath)')"
Outputs="$(__IntermediateAppConfig)">
<EnsureBindingRedirects References="@(_EnsureBindingRedirectReference->'%(HintPath)')"
SourceAppConfigPath="$(AppConfig)"
DestinationAppConfigPath="$(__IntermediateAppConfig)">
<Output TaskParameter="DestinationAppConfigPath" ItemName="FileWrites"/>
</EnsureBindingRedirects>
</Target>
<!--
===================================================================================================================
BclBuildUpdateAppConfigWithTargetPath
Update project properties to point to the generated app.config
===================================================================================================================
-->
<Target Name="BclBuildUpdateAppConfigWithTargetPath"
DependsOnTargets="BclBuildDetermineReferencesToRedirect;BclBuildEnsureBindingRedirects"
BeforeTargets="ResolveAssemblyReferences"
Condition="'@(_EnsureBindingRedirectReference)' != '' and '$(SkipEnsureBindingRedirects)' != 'true'">
<PropertyGroup>
<AppConfig>$(__IntermediateAppConfig)</AppConfig>
</PropertyGroup>
<ItemGroup>
<AppConfigWithTargetPath Remove="@(AppConfigWithTargetPath)" />
<AppConfigWithTargetPath Include="$(AppConfig)">
<TargetPath>$(TargetFileName).config</TargetPath>
</AppConfigWithTargetPath>
</ItemGroup>
</Target>
<!--
*******************************************************************************************************************
*******************************************************************************************************************
ValidatePackageReferences Section
This group of targets enables validation of nuget package references when building inside VisualStudio.
*******************************************************************************************************************
*******************************************************************************************************************
-->
<!--
===================================================================================================================
BclBuildAddProjectReferenceProperties
Adds properties to be set when resolving project references. The properties ensure that the references get built
in the context of the referencer (by changing the set of properties used to build the project) and pass down the
context needed to validate the referencing project.
===================================================================================================================
-->
<Target Name="BclBuildAddProjectReferenceProperties"
BeforeTargets="AssignProjectConfiguration"
Condition="'$(BuildingInsideVisualStudio)' == 'true'">
<PropertyGroup>
<_BclBuildProjectReferenceProperties>BclBuildReferencingProject=$(MSBuildProjectFullPath);BclBuildReferencingProjectConfig=$(MSBuildProjectDirectory)\packages.config</_BclBuildProjectReferenceProperties>
<_BclBuildProjectReferenceProperties Condition="'$(SkipValidatePackageReferences)' != ''">$(_BclBuildProjectReferenceProperties);SkipValidatePackageReferences=$(SkipValidatePackageReferences)</_BclBuildProjectReferenceProperties>
</PropertyGroup>
<ItemGroup>
<ProjectReference>
<AdditionalProperties>$(_BclBuildProjectReferenceProperties);%(ProjectReference.AdditionalProperties)</AdditionalProperties>
</ProjectReference>
</ItemGroup>
</Target>
<!--
===================================================================================================================
BclBuildSetRunningFullBuild
Determines when a full build is running as opposed to a single target.
===================================================================================================================
-->
<Target Name="BclBuildSetRunningFullBuild"
BeforeTargets="BuildOnlySettings">
<PropertyGroup>
<BclBuildRunningFullBuild>true</BclBuildRunningFullBuild>
</PropertyGroup>
</Target>
<!--
===================================================================================================================
GetTargetPath/BclBuildGetTargetPath
MSBuild will only build a target once for a given set of properties.
We need that single build of GetTargetPath to run during project reference resolution, so that we can detect a
referencing project that doesn't have Bcl.Build.
To accomplish this we replace GetTargetPath with BclBuildGetTargetPath when running a full build.
===================================================================================================================
-->
<Target
Name="GetTargetPath"
Condition="'$(BclBuildRunningFullBuild)' != 'true'"
DependsOnTargets="$(GetTargetPathDependsOn)"
Returns="$(TargetPath)"/>
<Target
Name="BclBuildGetTargetPath"
Condition="'$(BclBuildRunningFullBuild)' == 'true'"
AfterTargets="GetTargetPath"
Returns="$(TargetPath)">
<PropertyGroup>
<!-- Reset BclBuildRunningFullBuild, it will be set again when doing a full build. -->
<BclBuildRunningFullBuild>false</BclBuildRunningFullBuild>
</PropertyGroup>
</Target>
<!--
===================================================================================================================
BclBuildValidateNugetPackageReferences
This target validates that any Nuget packages installed in the current project are also installed in projects
referencing the current project.
This is necessary because Nuget packages contain more than just simple references. Installing the package ensures
1. The right set of references for the target framework are added
2. Config file transforms are applied
3. Project installation scripts are run
For all packages listed as installed for the current project in packages config, if the package ID matches one
specified in @(ValidatePackages), ensure that the same package is installed in the referencing project.
This target can be disabled for a project reference by setting SkipValidatePackageReferences=true for the reference:
<ProjectReference Include="..\pcl\pcl.csproj">
<Project>{664a9e98-fac7-4567-a046-0dde95fddb48}</Project>
<Name>pcl</Name>
<Properties>SkipValidatePackageReferences=true</Properties>
</ProjectReference>
This target can be disabled for all references to a project by adding the following:
<PropertyGroup>
<SkipValidatePackageReferences>true</SkipValidatePackageReferences>
</PropertyGroup>
===================================================================================================================
-->
<UsingTask TaskName="ValidatePackageReferences" AssemblyFile="$(MSBuildThisFileDirectory)Microsoft.Bcl.Build.Tasks.dll" />
<Target Name="BclBuildValidateNugetPackageReferences"
Condition="'$(BclBuildRunningFullBuild)' != 'true' AND '$(SkipValidatePackageReferences)' != 'true' AND '$(BuildingInsideVisualStudio)' == 'true'"
BeforeTargets="GetTargetPath">
<ItemGroup>
<ValidatePackages Include="Microsoft.Bcl"/>
<ValidatePackages Include="Microsoft.Bcl.Async"/>
<ValidatePackages Include="Microsoft.Bcl.Compression"/>
<ValidatePackages Include="Microsoft.Net.Http"/>
</ItemGroup>
<ValidatePackageReferences Packages="@(ValidatePackages)"
ReferencingProject="$(BclBuildReferencingProject)"
ReferencingProjectPackagesConfig="$(BclBuildReferencingProjectConfig)"
ReferencedProject="$(MSBuildProjectFullPath)"
ReferencedProjectPackagesConfig="$(MSBuildProjectDirectory)\packages.config"
TreatWarningsAsErrors="$(TreatWarningsAsErrors)" />
</Target>
</Project>