diff --git a/.editorconfig b/.editorconfig
index c90eff1..6d18247 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -1,16 +1,27 @@
# EditorConfig is awesome: http://EditorConfig.org
-#
-# https://visualstudiogallery.msdn.microsoft.com/c8bccfe2-650c-4b42-bc5c-845e21f96328
-# Or install via Extensions inside Visual Studio.
# top-most EditorConfig file
root = true
-# Unix-style newlines with a newline ending every file
[*]
+charset = utf-8
end_of_line = lf
-insert_final_newline = true
-charset = utf-8-bom
+indent_brace_style = K&R
+indent_size = 4
indent_style = space
+insert_final_newline = true
+max_line_length = 120
tab_width = 4
trim_trailing_whitespace = true
+curly_bracket_next_line = true
+
+[*.{js,ts}]
+quote_type = double
+
+[*.json]
+indent_size = 2
+tab_width = 2
+indent_style = space
+
+[*.yaml]
+indent_style = space
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1ff0c42..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
diff --git a/.gitignore b/.gitignore
index 3c4efe2..f5dfa15 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,261 +1,15 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
+launchSettings.json
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-bld/
-[Bb]in/
-[Oo]bj/
-[Ll]og/
-
-# Visual Studio 2015 cache/options directory
-.vs/
-# Uncomment if you have tasks that create the project's static files in wwwroot
-#wwwroot/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# DNX
-project.lock.json
-project.fragment.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opendb
-*.opensdf
-*.sdf
-*.cachefile
-*.VC.db
-*.VC.VC.opendb
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-*.sap
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding add-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-nCrunchTemp_*
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
-# but database connection strings (with potential passwords) will be unencrypted
-#*.pubxml
-*.publishproj
-
-# Microsoft Azure Web App publish settings. Comment the next line if you want to
-# checkin your Azure Web App publish settings, but sensitive information contained
-# in these scripts will be unencrypted
-PublishScripts/
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
-*.nuget.props
-*.nuget.targets
-
-# Microsoft Azure Build Output
-csx/
-*.build.csdef
-
-# Microsoft Azure Emulator
-ecf/
-rcf/
-
-# Windows Store app package directories and files
-AppPackages/
-BundleArtifacts/
-Package.StoreAssociation.xml
-_pkginfo.txt
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-~$*
*~
-*.dbmdl
-*.dbproj.schemaview
-*.jfm
-*.pfx
-*.publishsettings
-node_modules/
-orleans.codegen.cs
+*.user
-# Since there are multiple workflows, uncomment next line to ignore bower_components
-# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
-#bower_components/
+NaNoGenMo.*
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# GhostDoc plugin setting file
-*.GhostDoc.xml
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-# Visual Studio LightSwitch build output
-**/*.HTMLClient/GeneratedArtifacts
-**/*.DesktopClient/GeneratedArtifacts
-**/*.DesktopClient/ModelManifest.xml
-**/*.Server/GeneratedArtifacts
-**/*.Server/ModelManifest.xml
-_Pvt_Extensions
-
-# Paket dependency manager
-.paket/paket.exe
-paket-files/
-
-# FAKE - F# Make
-.fake/
-
-# JetBrains Rider
+obj/
+[Bb]in/
+.vs/
+.vscode/
.idea/
-*.sln.iml
+_ReSharper.Caches/
-# CodeRush
-.cr/
-
-# Python Tools for Visual Studio (PTVS)
-__pycache__/
-*.pyc
\ No newline at end of file
+.author-intrusion
diff --git a/MfGames.Locking.sln b/MfGames.Locking.sln
index 264106d..1bc0268 100644
--- a/MfGames.Locking.sln
+++ b/MfGames.Locking.sln
@@ -1,25 +1,57 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
-VisualStudioVersion = 15.0.27130.2024
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Locking", "MfGames.Locking\MfGames.Locking.csproj", "{51E00BEF-AAF1-4D45-BF82-5DCD7D5EA7FC}"
+VisualStudioVersion = 15.0.26124.0
+MinimumVisualStudioVersion = 15.0.26124.0
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{EE3B4148-AC01-4E30-93AB-AA6EC2201555}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MfGames.Locking", "src\MfGames.Locking\MfGames.Locking.csproj", "{016D2590-46B8-4776-A7F9-1B0586920932}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MfGames.Locking.Tests", "src\MfGames.Locking.Tests\MfGames.Locking.Tests.csproj", "{50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {51E00BEF-AAF1-4D45-BF82-5DCD7D5EA7FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {51E00BEF-AAF1-4D45-BF82-5DCD7D5EA7FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {51E00BEF-AAF1-4D45-BF82-5DCD7D5EA7FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {51E00BEF-AAF1-4D45-BF82-5DCD7D5EA7FC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|x64.Build.0 = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Debug|x86.Build.0 = Debug|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|Any CPU.Build.0 = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|x64.ActiveCfg = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|x64.Build.0 = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|x86.ActiveCfg = Release|Any CPU
+ {016D2590-46B8-4776-A7F9-1B0586920932}.Release|x86.Build.0 = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|x64.Build.0 = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Debug|x86.Build.0 = Debug|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|x64.ActiveCfg = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|x64.Build.0 = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|x86.ActiveCfg = Release|Any CPU
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {016D2590-46B8-4776-A7F9-1B0586920932} = {EE3B4148-AC01-4E30-93AB-AA6EC2201555}
+ {50475AFD-8D3A-4AB2-9B16-A2FC3D6AE05C} = {EE3B4148-AC01-4E30-93AB-AA6EC2201555}
+ EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
- SolutionGuid = {FED5BE58-8CEB-48E6-82E0-0B80035F4AEA}
+ SolutionGuid = {78D75C86-DAB1-43D2-AD2D-B0D57EDF2ED3}
EndGlobalSection
EndGlobal
diff --git a/MfGames.Locking.sln.DotSettings b/MfGames.Locking.sln.DotSettings
index c62cd45..59dfc40 100644
--- a/MfGames.Locking.sln.DotSettings
+++ b/MfGames.Locking.sln.DotSettings
@@ -37,11 +37,12 @@
DoHide
DoHide
HINT
- <?xml version="1.0" encoding="utf-16"?><Profile name="Full WEI Cleanup"><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_BOTH</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName>Namespaces</RegionName></CSOptimizeUsings><CSUseAutoProperty>True</CSUseAutoProperty><CSArrangeQualifiers>True</CSArrangeQualifiers><CSEnforceVarKeywordUsageSettings>True</CSEnforceVarKeywordUsageSettings><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="False" AddMissingParentheses="True" ArrangeBraces="False" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" /><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSUpdateFileHeader>True</CSUpdateFileHeader><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><HtmlReformatCode>True</HtmlReformatCode></Profile>
+ <?xml version="1.0" encoding="utf-16"?><Profile name="Project"><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSMakeFieldReadonly>True</CSMakeFieldReadonly><CSUseVar><BehavourStyle>CAN_CHANGE_BOTH</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSShortenReferences>True</CSShortenReferences><CSReformatCode>True</CSReformatCode><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSOptimizeUsings><OptimizeUsings>True</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName>Namespaces</RegionName></CSOptimizeUsings><CSUseAutoProperty>True</CSUseAutoProperty><CSArrangeQualifiers>True</CSArrangeQualifiers><CSEnforceVarKeywordUsageSettings>True</CSEnforceVarKeywordUsageSettings><CSCodeStyleAttributes ArrangeTypeAccessModifier="True" ArrangeTypeMemberAccessModifier="True" SortModifiers="True" RemoveRedundantParentheses="False" AddMissingParentheses="True" ArrangeBraces="False" ArrangeAttributes="True" ArrangeArgumentsStyle="True" ArrangeCodeBodyStyle="True" ArrangeVarStyle="True" /><CSMakeAutoPropertyGetOnly>True</CSMakeAutoPropertyGetOnly><FormatAttributeQuoteDescriptor>True</FormatAttributeQuoteDescriptor><CSFixBuiltinTypeReferences>True</CSFixBuiltinTypeReferences><CSUpdateFileHeader>True</CSUpdateFileHeader><JsReformatCode>True</JsReformatCode><JsFormatDocComments>True</JsFormatDocComments><CSharpFormatDocComments>True</CSharpFormatDocComments><CSReorderTypeMembers>True</CSReorderTypeMembers><JsInsertSemicolon>True</JsInsertSemicolon><HtmlReformatCode>True</HtmlReformatCode></Profile>
<?xml version="1.0" encoding="utf-16"?><Profile name="Remove Redundant Qualifiers"><CSArrangeThisQualifier>True</CSArrangeThisQualifier><CSRemoveCodeRedundancies>True</CSRemoveCodeRedundancies><CSUseAutoProperty>False</CSUseAutoProperty><CSMakeFieldReadonly>False</CSMakeFieldReadonly><CSUseVar><BehavourStyle>DISABLED</BehavourStyle><LocalVariableStyle>IMPLICIT_WHEN_INITIALIZER_HAS_TYPE</LocalVariableStyle><ForeachVariableStyle>ALWAYS_EXPLICIT</ForeachVariableStyle></CSUseVar><CSUpdateFileHeader>False</CSUpdateFileHeader><VBOptimizeImports>False</VBOptimizeImports><VBShortenReferences>False</VBShortenReferences><CSOptimizeUsings><OptimizeUsings>False</OptimizeUsings><EmbraceInRegion>False</EmbraceInRegion><RegionName /></CSOptimizeUsings><CSShortenReferences>True</CSShortenReferences><VBReformatCode>False</VBReformatCode><CSReformatCode>False</CSReformatCode><CSReorderTypeMembers>False</CSReorderTypeMembers></Profile>
Full Cleanup
- Full WEI Cleanup
+ Project
OPTIMAL_FILL
+ LF
True
False
True
@@ -67,7 +68,7 @@
1
1
- 1
+
NEXT_LINE
SEPARATE
ALWAYS_ADD
@@ -522,13 +523,13 @@ II.2.12 <HandlesEvent />
CustomLayout
True
False
+ True
UseExplicitType
UseVarWhenEvident
UseVarWhenEvident
+ True
<copyright file="$FILENAME$" company="Moonfire Games">
-Copyright (c) Moonfire Games.
-This code is licensed under the MIT license.
-See LICENSE.md in the source or https://opensource.org/licenses/MIT
+Copyright (c) Moonfire Games. MIT License.
</copyright>
False
@@ -640,6 +641,7 @@ See LICENSE.md in the source or https://opensource.org/licenses/MIT
<Policy Inspect="True" Prefix="" Suffix="" Style="aaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
<Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" />
+ C:\Users\rc04727\AppData\Local\JetBrains\Transient\ReSharperPlatformVs15\v11_ede7cb44\SolutionCaches
LIVE_MONITOR
LIVE_MONITOR
DO_NOTHING
@@ -671,6 +673,8 @@ See LICENSE.md in the source or https://opensource.org/licenses/MIT
True
Always
False
+ <data><IncludeFilters /><ExcludeFilters><Filter ModuleMask="MfGames.Locking.Tests" ModuleVersionMask="*" ClassMask="*" FunctionMask="*" IsEnabled="True" /></ExcludeFilters></data>
+ ForWarningsOrErrors
tag
10
( )
@@ -1300,4 +1304,4 @@ using(DataAccessAdapter dataAccessAdapter = new DataAccessAdapter(ConnectionStri
0
True
2.0
- InCSharpStatement
\ No newline at end of file
+ InCSharpStatement
diff --git a/MfGames.Locking/MfGames.Locking.csproj b/MfGames.Locking/MfGames.Locking.csproj
deleted file mode 100644
index c3a4a82..0000000
--- a/MfGames.Locking/MfGames.Locking.csproj
+++ /dev/null
@@ -1,39 +0,0 @@
-
-
-
- net452;net461;netstandard1.6;netstandard2.0;netcoreapp2.0
- MfGames.Locking
- 5.0.0
- Dylan R. E. Moonfire
- Various locking patterns for multi-threaded code.
- false
- Copyright (c) Moonfire Games. MIT license.
- lock; locking
- https://opensource.org/licenses/MIT
-
-
-
- bin\Debug\netcoreapp2.0\MfGames.Locking.xml
- Off
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- all
- compile; build; native; contentfiles; analyzers
-
-
-
-
diff --git a/MfGames.Locking/stylecop.json b/MfGames.Locking/stylecop.json
deleted file mode 100644
index 68e837c..0000000
--- a/MfGames.Locking/stylecop.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "$schema":
- "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
- "settings": {
- "documentationRules": {
- "companyName": "Moonfire Games",
- "copyrightText":
- "Copyright (c) {companyName}.\nThis code is licensed under the MIT license.\nSee LICENSE.md in the source or https://opensource.org/licenses/MIT"
- }
- }
-}
diff --git a/src/MfGames.Locking.Tests/LockTests.cs b/src/MfGames.Locking.Tests/LockTests.cs
new file mode 100644
index 0000000..75b883c
--- /dev/null
+++ b/src/MfGames.Locking.Tests/LockTests.cs
@@ -0,0 +1,209 @@
+//
+// Copyright (c) Moonfire Games. MIT License.
+//
+
+namespace MfGames.Locking.Tests
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Threading;
+ using System.Threading.Tasks;
+ using Xunit;
+ using Xunit.Abstractions;
+
+ public class LockTests
+ {
+ public static readonly TimeSpan ProcessTime = TimeSpan.FromMilliseconds(50);
+
+ private readonly List events;
+
+ private readonly ReaderWriterLockSlim locker;
+
+ private readonly ITestOutputHelper output;
+
+ private readonly DateTime start;
+
+ public LockTests(ITestOutputHelper output)
+ {
+ this.output = output;
+ this.start = DateTime.UtcNow;
+ this.locker = new ReaderWriterLockSlim();
+ this.events = new List();
+ }
+
+ private TimeSpan Elapsed => DateTime.UtcNow - this.start;
+
+ [Fact]
+ public void BasicDataGatheringWorks()
+ {
+ this.Report(ProcessTime, 1);
+ this.Verify();
+ }
+
+ [Fact]
+ public void ReadBlocksWrite()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 0, ProcessTime * 3, 1)),
+ Task.Run(() => this.ReportInWriteLock(ProcessTime * 1, ProcessTime * 1, 2)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void ReadsDoNotBlockReads()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInReadLock(ProcessTime, ProcessTime * 5, 3)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime, 1)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime * 2, 2)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void ThreadedDataGatheringWorks()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInReadLock(ProcessTime, ProcessTime, 1)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void UpgradableBlocksUpgradable()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInUpgradableLock(ProcessTime, ProcessTime * 5, 1)),
+ Task.Run(() => this.ReportInUpgradableLock(ProcessTime * 3, ProcessTime, 2)),
+ Task.Run(() => this.ReportInUpgradableLock(ProcessTime * 2, ProcessTime * 2, 3)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void UpgradableDoesNotBlockReads()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInUpgradableLock(ProcessTime, ProcessTime * 5, 3)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime, 1)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime * 2, 2)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void WriteBlockRead()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInWriteLock(ProcessTime, ProcessTime * 3, 1)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime, 2)));
+
+ this.Verify();
+ }
+
+ [Fact]
+ public void WriteBlockReads()
+ {
+ Task.WaitAll(
+ Task.Run(() => this.ReportInWriteLock(ProcessTime, ProcessTime * 5, 1)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime, 2)),
+ Task.Run(() => this.ReportInReadLock(ProcessTime * 2, ProcessTime * 2, 3)));
+
+ this.Verify();
+ }
+
+ private void AddEvent(int sequence)
+ {
+ // This is a monitor lock on the slim, just to give us a second lock.
+ lock (this.locker)
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => adding sequence");
+ this.events.Add(sequence);
+ }
+ }
+
+ ///
+ /// Waits a short period of time and then injects the sequence into the event list.
+ ///
+ private void Report(
+ TimeSpan processTime,
+ int sequence)
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => starting process");
+ Thread.Sleep(processTime);
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => finished process");
+ this.AddEvent(sequence);
+ }
+
+ private void ReportInReadLock(
+ TimeSpan settleTime,
+ TimeSpan processTime,
+ int sequence)
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => entering read lock: " + sequence);
+
+ Thread.Sleep(settleTime);
+
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => locking read lock: " + sequence);
+
+ using (new ReadLock(this.locker))
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => starting read lock: " + sequence);
+
+ this.Report(processTime, sequence);
+ }
+ }
+
+ private void ReportInUpgradableLock(
+ TimeSpan settleTime,
+ TimeSpan processTime,
+ int sequence)
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => entering upgradable lock: " + sequence);
+
+ Thread.Sleep(settleTime);
+
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => locking upgradable lock: " + sequence);
+
+ using (new UpgradableLock(this.locker))
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => starting upgradable lock: " + sequence);
+
+ this.Report(processTime, sequence);
+ }
+ }
+
+ private void ReportInWriteLock(
+ TimeSpan settleTime,
+ TimeSpan processTime,
+ int sequence)
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => entering write lock: " + sequence);
+
+ Thread.Sleep(settleTime);
+
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => locking write lock: " + sequence);
+
+ using (new WriteLock(this.locker))
+ {
+ this.output.WriteLine(this.Elapsed + ": " + sequence + " => starting write lock: " + sequence);
+
+ this.Report(processTime, sequence);
+ }
+ }
+
+ ///
+ /// Verifies the sequence of events.
+ ///
+ private void Verify()
+ {
+ this.output.WriteLine("Final Sequence: " + string.Join(", ", this.events));
+
+ for (int i = 1; i <= this.events.Count; i++)
+ {
+ Assert.Equal(i, this.events[i - 1]);
+ }
+ }
+ }
+}
diff --git a/src/MfGames.Locking.Tests/MfGames.Locking.Tests.csproj b/src/MfGames.Locking.Tests/MfGames.Locking.Tests.csproj
new file mode 100644
index 0000000..4277460
--- /dev/null
+++ b/src/MfGames.Locking.Tests/MfGames.Locking.Tests.csproj
@@ -0,0 +1,20 @@
+
+
+
+ netcoreapp2.1
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/MfGames.Locking/MfGames.Locking.csproj b/src/MfGames.Locking/MfGames.Locking.csproj
new file mode 100644
index 0000000..7080019
--- /dev/null
+++ b/src/MfGames.Locking/MfGames.Locking.csproj
@@ -0,0 +1,37 @@
+
+
+
+ netcoreapp2.1
+ true
+ true
+ $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
+ Dylan Moonfire
+ Moonfire Games
+ https://gitlab.com/dmoonfire/mfgames-locking-cil
+ Git
+ locking
+ https://gitlab.com/dmoonfire/mfgames-locking-cil
+ https://gitlab.com/dmoonfire/mfgames-locking-cil/blob/master/LICENSE.txt
+ An IDisposable pattern for using ReaderWriterLockSlim.
+
+
+ ..\..\bin
+ ..\..\bin\$(AssemblyName).xml
+
+
+ ..\..\bin
+ ..\..\bin\$(AssemblyName).xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/MfGames.Locking/NestableReadLock.cs b/src/MfGames.Locking/NestableReadLock.cs
similarity index 91%
rename from MfGames.Locking/NestableReadLock.cs
rename to src/MfGames.Locking/NestableReadLock.cs
index 915c5f9..f353b45 100644
--- a/MfGames.Locking/NestableReadLock.cs
+++ b/src/MfGames.Locking/NestableReadLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/NestableUpgradableReadLock.cs b/src/MfGames.Locking/NestableUpgradableReadLock.cs
similarity index 91%
rename from MfGames.Locking/NestableUpgradableReadLock.cs
rename to src/MfGames.Locking/NestableUpgradableReadLock.cs
index d5e4041..c37287d 100644
--- a/MfGames.Locking/NestableUpgradableReadLock.cs
+++ b/src/MfGames.Locking/NestableUpgradableReadLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/NestableWriteLock.cs b/src/MfGames.Locking/NestableWriteLock.cs
similarity index 90%
rename from MfGames.Locking/NestableWriteLock.cs
rename to src/MfGames.Locking/NestableWriteLock.cs
index 632dc11..d1701de 100644
--- a/MfGames.Locking/NestableWriteLock.cs
+++ b/src/MfGames.Locking/NestableWriteLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/ReadLock.cs b/src/MfGames.Locking/ReadLock.cs
similarity index 85%
rename from MfGames.Locking/ReadLock.cs
rename to src/MfGames.Locking/ReadLock.cs
index 9475b6e..995f4ac 100644
--- a/MfGames.Locking/ReadLock.cs
+++ b/src/MfGames.Locking/ReadLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/TryGetCreate.cs b/src/MfGames.Locking/TryGetCreate.cs
similarity index 96%
rename from MfGames.Locking/TryGetCreate.cs
rename to src/MfGames.Locking/TryGetCreate.cs
index ca0e187..8152b65 100644
--- a/MfGames.Locking/TryGetCreate.cs
+++ b/src/MfGames.Locking/TryGetCreate.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/TryGetHandler.cs b/src/MfGames.Locking/TryGetHandler.cs
similarity index 82%
rename from MfGames.Locking/TryGetHandler.cs
rename to src/MfGames.Locking/TryGetHandler.cs
index d3f26a9..e6339c5 100644
--- a/MfGames.Locking/TryGetHandler.cs
+++ b/src/MfGames.Locking/TryGetHandler.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/UpgradableLock.cs b/src/MfGames.Locking/UpgradableLock.cs
similarity index 87%
rename from MfGames.Locking/UpgradableLock.cs
rename to src/MfGames.Locking/UpgradableLock.cs
index e50dc30..1906ae3 100644
--- a/MfGames.Locking/UpgradableLock.cs
+++ b/src/MfGames.Locking/UpgradableLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/MfGames.Locking/WriteLock.cs b/src/MfGames.Locking/WriteLock.cs
similarity index 87%
rename from MfGames.Locking/WriteLock.cs
rename to src/MfGames.Locking/WriteLock.cs
index fd7d892..ff99346 100644
--- a/MfGames.Locking/WriteLock.cs
+++ b/src/MfGames.Locking/WriteLock.cs
@@ -1,7 +1,5 @@
//
-// Copyright (c) Moonfire Games.
-// This code is licensed under the MIT license.
-// See LICENSE.md in the source or https://opensource.org/licenses/MIT
+// Copyright (c) Moonfire Games. MIT License.
//
namespace MfGames.Locking
diff --git a/src/stylecop.json b/src/stylecop.json
new file mode 100644
index 0000000..94dc57b
--- /dev/null
+++ b/src/stylecop.json
@@ -0,0 +1,10 @@
+{
+ "$schema":
+ "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
+ "settings": {
+ "documentationRules": {
+ "companyName": "Moonfire Games",
+ "copyrightText": "Copyright (c) Moonfire Games. MIT License."
+ }
+ }
+}