├── .gitignore
├── LICENSE
├── README.md
├── RELEASE_NOTES.md
├── build-system
├── README.md
├── azure-pipeline.template.yaml
├── nightly-builds.yaml
├── windows-pr-validation.yaml
└── windows-release.yaml
├── build.cmd
├── build.fsx
├── build.ps1
├── build.sh
└── src
├── .nuget
├── NuGet.Config
├── NuGet.exe
└── NuGet.targets
├── Helios.DedicatedThreadPool.sln
├── common.props
├── core
└── Helios.DedicatedThreadPool
│ ├── Helios.Concurrency.DedicatedThreadPool.cs
│ ├── Helios.DedicatedThreadPool.csproj
│ └── _Visibility.cs
└── tests
├── Helios.DedicatedThreadPool.Tests.Performance
├── DedicatedThreadPoolBenchmark.cs
├── Helios.DedicatedThreadPool.Tests.Performance.csproj
└── Program.cs
└── Helios.DedicatedThreadPool.Tests
├── AtomicCounter.cs
├── DedicatedThreadPoolTaskSchedulerTests.cs
├── DedicatedThreadPoolTests.cs
└── Helios.DedicatedThreadPool.Tests.csproj
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 | .fake/
25 | TestResults/
26 | PerfResults/
27 | *.lock.json
28 |
29 | # Visual Studo 2015 cache/options directory
30 | .vs/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | *_i.c
46 | *_p.c
47 | *_i.h
48 | *.ilk
49 | *.meta
50 | *.obj
51 | *.pch
52 | *.pdb
53 | *.pgc
54 | *.pgd
55 | *.rsp
56 | *.sbr
57 | *.tlb
58 | *.tli
59 | *.tlh
60 | *.tmp
61 | *.tmp_proj
62 | *.log
63 | *.vspscc
64 | *.vssscc
65 | .builds
66 | *.pidb
67 | *.svclog
68 | *.scc
69 |
70 | # Chutzpah Test files
71 | _Chutzpah*
72 |
73 | # Visual C++ cache files
74 | ipch/
75 | *.aps
76 | *.ncb
77 | *.opensdf
78 | *.sdf
79 | *.cachefile
80 |
81 | # Visual Studio profiler
82 | *.psess
83 | *.vsp
84 | *.vspx
85 |
86 | # TFS 2012 Local Workspace
87 | $tf/
88 |
89 | # Guidance Automation Toolkit
90 | *.gpState
91 |
92 | # ReSharper is a .NET coding add-in
93 | _ReSharper*/
94 | *.[Rr]e[Ss]harper
95 | *.DotSettings.user
96 |
97 | # JustCode is a .NET coding addin-in
98 | .JustCode
99 |
100 | # TeamCity is a build add-in
101 | _TeamCity*
102 |
103 | # DotCover is a Code Coverage Tool
104 | *.dotCover
105 |
106 | # NCrunch
107 | _NCrunch_*
108 | .*crunch*.local.xml
109 |
110 | # MightyMoose
111 | *.mm.*
112 | AutoTest.Net/
113 |
114 | # Web workbench (sass)
115 | .sass-cache/
116 |
117 | # Installshield output folder
118 | [Ee]xpress/
119 |
120 | # DocProject is a documentation generator add-in
121 | DocProject/buildhelp/
122 | DocProject/Help/*.HxT
123 | DocProject/Help/*.HxC
124 | DocProject/Help/*.hhc
125 | DocProject/Help/*.hhk
126 | DocProject/Help/*.hhp
127 | DocProject/Help/Html2
128 | DocProject/Help/html
129 |
130 | # Click-Once directory
131 | publish/
132 |
133 | # Publish Web Output
134 | *.[Pp]ublish.xml
135 | *.azurePubxml
136 | # TODO: Comment the next line if you want to checkin your web deploy settings
137 | # but database connection strings (with potential passwords) will be unencrypted
138 | *.pubxml
139 | *.publishproj
140 |
141 | # NuGet Packages
142 | *.nupkg
143 | # The packages folder can be ignored because of Package Restore
144 | **/packages/*
145 | # except build/, which is used as an MSBuild target.
146 | !**/packages/build/
147 | # Uncomment if necessary however generally it will be regenerated when needed
148 | #!**/packages/repositories.config
149 |
150 | # Windows Azure Build Output
151 | csx/
152 | *.build.csdef
153 |
154 | # Windows Store app package directory
155 | AppPackages/
156 |
157 | # Others
158 | *.[Cc]ache
159 | ClientBin/
160 | [Ss]tyle[Cc]op.*
161 | ~$*
162 | *~
163 | *.dbmdl
164 | *.dbproj.schemaview
165 | *.pfx
166 | *.publishsettings
167 | node_modules/
168 | bower_components/
169 |
170 | # RIA/Silverlight projects
171 | Generated_Code/
172 |
173 | # Backup & report files from converting an old project file
174 | # to a newer Visual Studio version. Backup files are not needed,
175 | # because we have git ;-)
176 | _UpgradeReport_Files/
177 | Backup*/
178 | UpgradeLog*.XML
179 | UpgradeLog*.htm
180 |
181 | # SQL Server files
182 | *.mdf
183 | *.ldf
184 |
185 | # Business Intelligence projects
186 | *.rdl.data
187 | *.bim.layout
188 | *.bim_*.settings
189 |
190 | # Microsoft Fakes
191 | FakesAssemblies/
192 |
193 | # Node.js Tools for Visual Studio
194 | .ntvs_analysis.dat
195 |
196 | # Visual Studio 6 build log
197 | *.plg
198 |
199 | # Visual Studio 6 workspace options file
200 | *.opt
201 |
202 | tools/
203 | build/
204 | .nuget/
205 | .dotnet/
206 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
203 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DedicatedThreadPool
2 | An instanced, dedicated thread pool for eliminating "noisy neighbor" problems on the CLR `ThreadPool`.
3 |
4 | ## Installation
5 |
6 | You can install `DedicatedThreadPool` via NuGet!
7 |
8 | ```
9 | PS> Install-package Helios.DedicatedThreadPool
10 | ```
11 |
12 | This package doesn't install any binaries, just the following C# file: `Helios.Concurrency.DedicatedThreadPool.cs` - which contains the `DedicatedThreadPool`, `DedicatedThreadPoolTaskScheduler`, and `DedicatedThreadPoolSettings` classes.
13 |
14 | ## API
15 |
16 | You can create a `Helios.Concurrency.DedicatedThreadPool` instance via the following API:
17 |
18 | ```csharp
19 | using (var threadPool = new Helios.Concurrency.DedicatedThreadPool(
20 | new DedicatedThreadPoolSettings(numThreads)))
21 | {
22 | threadPool.QueueUserWorkItem(() => { ... }));
23 | }
24 | ```
25 |
26 | This creates a `DedicatedThreadPool` object which allocates a fixed number of threads, each with their own independent task queue.
27 |
28 | This `DedicatedThreadPool` can also be used in combination with a `DedicatedThreadPoolTaskScheduler` for TPL support, like this:
29 |
30 | ```csharp
31 | //use 3 threads
32 | var Pool = new DedicatedThreadPool(new DedicatedThreadPoolSettings(3));
33 | var Scheduler = new DedicatedThreadPoolTaskScheduler(Pool);
34 | var Factory = new TaskFactory(Scheduler);
35 |
36 | var task = Factory.StartNew(() =>
37 | {
38 | //work that'll run on the dedicated thread pool...
39 | });
40 |
41 | task.Wait();
42 | ```
43 |
44 | > NOTE: `DedicatedThreadPool` is marked as `internal` by default, so it can be used opaquely across many dependent projects.
45 |
46 | ## Benchmark
47 |
48 | Latest benchmark on our build server (2 core Windows Azure A2 medium)
49 |
50 | ### Helios.DedicatedThreadPool v0.3
51 |
52 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
53 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
54 | [Counter] BenchmarkCalls | operations | 9,998,100.36 | 8,661,529.31 | 7,093,003.46 | 944,954.17 |
55 |
56 | ### System.Threading.ThreadPool
57 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
58 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
59 | [Counter] BenchmarkCalls | operations | 2,651,289.19 | 2,510,678.63 | 2,098,882.55 | 179,585.24 |
60 |
61 | ## License
62 |
63 | See [LICENSE](LICENSE) for details.
64 |
65 | Copyright (C) 2015-2016 Roger Alsing, Aaron Stannard, Jeff Cyr
--------------------------------------------------------------------------------
/RELEASE_NOTES.md:
--------------------------------------------------------------------------------
1 | #### 0.3.0 April 05 2016
2 | Major upgrade to the performance and stability of `DedicatedThreadPool`.
3 |
4 | Previous (v0.2) numbers:
5 |
6 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
7 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
8 | [Counter] BenchmarkCalls | operations | 2,381,933.51 | 2,335,262.42 | 2,123,061.11 | 75,849.97 |
9 |
10 | Current (v0.3) numbers:
11 |
12 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
13 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
14 | [Counter] BenchmarkCalls | operations | 9,998,100.36 | 8,661,529.31 | 7,093,003.46 | 944,954.17 |
15 |
16 |
17 | #### 0.2.0 Mar 26 2015
18 | Added deadlock detection to the `DedicatedThreadPool` and other bug / performance fixes.
19 |
20 | Deadlock detection is somewhat simplistic and it can't tell the difference between extremely long running tasks and a deadlock, so by default it's disabled.
21 |
22 | However, if you want to enable it you can turn it on via the the `DedicatedThreadPoolSettings` class:
23 |
24 | ```csharp
25 | /*
26 | * Any task running longer than 5 seconds will be assumed deadlocked
27 | * and aborted.
28 | */
29 | using (var threadPool = new Helios.Concurrency.DedicatedThreadPool(
30 | new DedicatedThreadPoolSettings(numThreads, TimeSpan.FromSeconds(5))))
31 | {
32 | threadPool.QueueUserWorkItem(() => { ... }));
33 | }
34 | ```
35 |
36 | #### 0.1.0 Mar 17 2015
37 | Initial build of `DedicatedThreadPool`. Works via the following API:
38 |
39 | ```csharp
40 | using (var threadPool = new Helios.Concurrency.DedicatedThreadPool(
41 | new DedicatedThreadPoolSettings(numThreads)))
42 | {
43 | threadPool.QueueUserWorkItem(() => { ... }));
44 | }
45 | ```
46 |
47 | Creates a `DedicatedThreadPool` object which allocates a fixed number of threads, each with their own independent task queue.
48 |
49 | This `DedicatedThreadPool` can also be used in combination with a `DedicatedThreadPoolTaskScheduler` for TPL support, like this:
50 |
51 | ```csharp
52 | //use 3 threads
53 | var Pool = new DedicatedThreadPool(new DedicatedThreadPoolSettings(3));
54 | var Scheduler = new DedicatedThreadPoolTaskScheduler(Pool);
55 | var Factory = new TaskFactory(Scheduler);
56 |
57 | var task = Factory.StartNew(() =>
58 | {
59 | //work that'll run on the dedicated thread pool...
60 | });
61 |
62 | task.Wait();
63 | ```
--------------------------------------------------------------------------------
/build-system/README.md:
--------------------------------------------------------------------------------
1 | # Azure Pipelines Build Files
2 | These `.yaml` files are used by Windows Azure DevOps Pipelines to help execute the following types of builds:
3 |
4 | - Pull request validation on Linux (Mono / .NET Core)
5 | - Pull request validation on Windows (.NET Framework / .NET Core)
6 | - NuGet releases with automatic release notes posted to a Github Release repository.
7 |
8 | **NOTE**: you will need to change some of the pipeline variables inside the `windows-release.yaml` for your specific project and you will also want to create variable groups with your signing and NuGet push information.
--------------------------------------------------------------------------------
/build-system/azure-pipeline.template.yaml:
--------------------------------------------------------------------------------
1 | parameters:
2 | name: ''
3 | vmImage: ''
4 | scriptFileName: ''
5 | scriptArgs: 'all'
6 | timeoutInMinutes: 120
7 |
8 | jobs:
9 | - job: ${{ parameters.name }}
10 | timeoutInMinutes: ${{ parameters.timeoutInMinutes }}
11 | pool:
12 | vmImage: ${{ parameters.vmImage }}
13 | steps:
14 | - checkout: self # self represents the repo where the initial Pipelines YAML file was found
15 | clean: false # whether to fetch clean each time
16 | submodules: recursive # set to 'true' for a single level of submodules or 'recursive' to get submodules of submodules
17 | persistCredentials: true
18 | # Linux or macOS
19 | - task: Bash@3
20 | displayName: Linux / OSX Build
21 | inputs:
22 | filePath: ${{ parameters.scriptFileName }}
23 | arguments: ${{ parameters.scriptArgs }}
24 | continueOnError: true
25 | condition: in( variables['Agent.OS'], 'Linux', 'Darwin' )
26 | # Windows
27 | - task: BatchScript@1
28 | displayName: Windows Build
29 | inputs:
30 | filename: ${{ parameters.scriptFileName }}
31 | arguments: ${{ parameters.scriptArgs }}
32 | continueOnError: true
33 | condition: eq( variables['Agent.OS'], 'Windows_NT' )
34 | - task: PublishTestResults@2
35 | inputs:
36 | testRunner: VSTest
37 | testResultsFiles: '**/*.trx' #TestResults folder usually
38 | testRunTitle: ${{ parameters.name }}
39 | mergeTestResults: true
40 | - script: 'echo 1>&2'
41 | failOnStderr: true
42 | displayName: 'If above is partially succeeded, then fail'
43 | condition: eq(variables['Agent.JobStatus'], 'SucceededWithIssues')
--------------------------------------------------------------------------------
/build-system/nightly-builds.yaml:
--------------------------------------------------------------------------------
1 | # Release task for PbLib projects
2 | # See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference
3 |
4 | pool:
5 | vmImage: vs2017-win2016
6 | demands: Cmd
7 |
8 | trigger: none
9 | pr: none
10 |
11 | schedules:
12 | - cron: "0 0 * * *"
13 | displayName: Daily midnight build
14 | branches:
15 | include:
16 | - dev
17 |
18 | variables:
19 | - group: nugetKeys #create this group with SECRET variables `nugetKey`
20 |
21 | steps:
22 | - task: UseDotNet@2
23 | displayName: 'Use .NET Core SDK 3.1.105'
24 | inputs:
25 | packageType: sdk
26 | version: 3.1.105
27 | - task: BatchScript@1
28 | displayName: 'FAKE Build'
29 | inputs:
30 | filename: build.cmd
31 | arguments: 'Nuget nugetprerelease=dev nugetpublishurl=$(nightlyUrl) nugetkey=$(nightlyKey)'
--------------------------------------------------------------------------------
/build-system/windows-pr-validation.yaml:
--------------------------------------------------------------------------------
1 | # Pull request validation for Windows against the `dev` and `master` branches
2 | # See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference
3 | trigger:
4 | branches:
5 | include:
6 | - dev
7 | - master
8 |
9 | pr:
10 | autoCancel: true # indicates whether additional pushes to a PR should cancel in-progress runs for the same PR. Defaults to true
11 | branches:
12 | include: [ dev, master ] # branch names which will trigger a build
13 |
14 | name: $(Year:yyyy).$(Month).$(DayOfMonth)$(Rev:.r)
15 |
16 | jobs:
17 | - template: azure-pipeline.template.yaml
18 | parameters:
19 | name: Windows
20 | vmImage: 'vs2017-win2016'
21 | scriptFileName: build.cmd
22 | scriptArgs: all
23 |
24 | - template: azure-pipeline.template.yaml
25 | parameters:
26 | name: Ubuntu
27 | vmImage: 'ubuntu-16.04'
28 | scriptFileName: ./build.sh
29 | scriptArgs: all
--------------------------------------------------------------------------------
/build-system/windows-release.yaml:
--------------------------------------------------------------------------------
1 | # Release task for PbLib projects
2 | # See https://docs.microsoft.com/en-us/azure/devops/pipelines/yaml-schema for reference
3 |
4 | pool:
5 | vmImage: vs2017-win2016
6 | demands: Cmd
7 |
8 | trigger:
9 | branches:
10 | include:
11 | - refs/tags/*
12 | pr: none
13 |
14 | variables:
15 | - group: signingSecrets #create this group with SECRET variables `signingUsername` and `signingPassword`
16 | - group: nugetKeys #create this group with SECRET variables `nugetKey`
17 | - name: githubConnectionName
18 | value: AkkaDotNet_Releases
19 | - name: projectName
20 | value: Akka.Streams.Kafka
21 | - name: githubRepositoryName
22 | value: akkadotnet/Akka.Streams.Kafka
23 |
24 | steps:
25 | - task: BatchScript@1
26 | displayName: 'FAKE Build'
27 | inputs:
28 | filename: build.cmd
29 | arguments: 'nuget nugetpublishurl=https://www.nuget.org/api/v2/package nugetkey=$(nugetKey)'
30 |
31 | - task: GitHubRelease@0
32 | displayName: 'GitHub release (create)'
33 | inputs:
34 | gitHubConnection: $(githubConnectionName)
35 | repositoryName: $(githubRepositoryName)
36 | title: '$(projectName) v$(Build.SourceBranchName)'
37 | releaseNotesFile: 'RELEASE_NOTES.md'
38 | assets: |
39 | bin\nuget\*.nupkg
40 |
--------------------------------------------------------------------------------
/build.cmd:
--------------------------------------------------------------------------------
1 | PowerShell.exe -file "build.ps1" %*
--------------------------------------------------------------------------------
/build.fsx:
--------------------------------------------------------------------------------
1 | #I @"tools/FAKE/tools"
2 | #r "FakeLib.dll"
3 |
4 | open System
5 | open System.IO
6 | open System.Text
7 |
8 | open Fake
9 | open Fake.DotNetCli
10 | open Fake.DocFxHelper
11 |
12 | // Information about the project for Nuget and Assembly info files
13 | let product = "Akka.Streams.Kafka"
14 | let configuration = "Release"
15 |
16 | // Metadata used when signing packages and DLLs
17 | let signingName = "Akka.Streams.Kafka"
18 | let signingDescription = "Apache Kafka adapter for Akka.NET Streams"
19 | let signingUrl = "https://github.com/akkadotnet/Akka.Streams.Kafka"
20 |
21 | // Read release notes and version
22 | let codeDirectory = __SOURCE_DIRECTORY__ @@ "src"
23 | let solutionFile = FindFirstMatchingFile "*.sln" codeDirectory // dynamically look up the solution
24 | let buildNumber = environVarOrDefault "BUILD_NUMBER" "0"
25 | let hasTeamCity = (not (buildNumber = "0")) // check if we have the TeamCity environment variable for build # set
26 | let preReleaseVersionSuffix = "beta" + (if (not (buildNumber = "0")) then (buildNumber) else DateTime.UtcNow.Ticks.ToString())
27 |
28 | let releaseNotes =
29 | File.ReadLines (__SOURCE_DIRECTORY__ @@ "RELEASE_NOTES.md")
30 | |> ReleaseNotesHelper.parseReleaseNotes
31 |
32 | let versionFromReleaseNotes =
33 | match releaseNotes.SemVer.PreRelease with
34 | | Some r -> r.Origin
35 | | None -> ""
36 |
37 | let versionSuffix =
38 | match (getBuildParam "nugetprerelease") with
39 | | "dev" -> preReleaseVersionSuffix
40 | | "" -> versionFromReleaseNotes
41 | | str -> str
42 |
43 | // Directories
44 | let toolsDir = __SOURCE_DIRECTORY__ @@ "tools"
45 | let output = __SOURCE_DIRECTORY__ @@ "bin"
46 | let outputTests = __SOURCE_DIRECTORY__ @@ "TestResults"
47 | let outputPerfTests = __SOURCE_DIRECTORY__ @@ "PerfResults"
48 | let outputNuGet = output @@ "nuget"
49 |
50 | // Copied from original NugetCreate target
51 | let nugetDir = output @@ "nuget"
52 | let workingDir = output @@ "build"
53 | let nugetExe = FullName @"./tools/nuget.exe"
54 |
55 | Target "Clean" (fun _ ->
56 | ActivateFinalTarget "KillCreatedProcesses"
57 |
58 | CleanDir output
59 | CleanDir outputTests
60 | CleanDir outputPerfTests
61 | CleanDir outputNuGet
62 | CleanDir "docs/_site"
63 | )
64 |
65 | Target "AssemblyInfo" (fun _ ->
66 | XmlPokeInnerText "./src/common.props" "//Project/PropertyGroup/VersionPrefix" releaseNotes.AssemblyVersion
67 | XmlPokeInnerText "./src/common.props" "//Project/PropertyGroup/PackageReleaseNotes" (releaseNotes.Notes |> String.concat "\n")
68 | )
69 |
70 | Target "RestorePackages" (fun _ ->
71 | DotNetCli.Restore
72 | (fun p ->
73 | { p with
74 | Project = solutionFile
75 | NoCache = false })
76 | )
77 |
78 | Target "Build" (fun _ ->
79 | DotNetCli.Build
80 | (fun p ->
81 | { p with
82 | Project = solutionFile
83 | Configuration = configuration }) // "Rebuild"
84 | )
85 |
86 |
87 | //--------------------------------------------------------------------------------
88 | // Tests targets
89 | //--------------------------------------------------------------------------------
90 | module internal ResultHandling =
91 | let (|OK|Failure|) = function
92 | | 0 -> OK
93 | | x -> Failure x
94 |
95 | let buildErrorMessage = function
96 | | OK -> None
97 | | Failure errorCode ->
98 | Some (sprintf "xUnit2 reported an error (Error Code %d)" errorCode)
99 |
100 | let failBuildWithMessage = function
101 | | DontFailBuild -> traceError
102 | | _ -> (fun m -> raise(FailedTestsException m))
103 |
104 | let failBuildIfXUnitReportedError errorLevel =
105 | buildErrorMessage
106 | >> Option.iter (failBuildWithMessage errorLevel)
107 |
108 | Target "RunTests" (fun _ ->
109 | let projects =
110 | match (isWindows) with
111 | | true -> !! "./src/**/*.Tests.csproj"
112 | -- "./src/**/*.Integration.Tests.csproj" // Zipkin containers can't run on Windows VMs
113 | | _ -> !! "./src/**/*.Tests.csproj" // if you need to filter specs for Linux vs. Windows, do it here
114 |
115 | let runSingleProject project =
116 | let arguments =
117 | match (hasTeamCity) with
118 | | true -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none -teamcity" (outputTests))
119 | | false -> (sprintf "test -c Release --no-build --logger:trx --logger:\"console;verbosity=normal\" --results-directory %s -- -parallel none" (outputTests))
120 |
121 | let result = ExecProcess(fun info ->
122 | info.FileName <- "dotnet"
123 | info.WorkingDirectory <- (Directory.GetParent project).FullName
124 | info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0)
125 |
126 | ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.Error result
127 |
128 | projects |> Seq.iter (log)
129 | projects |> Seq.iter (runSingleProject)
130 | )
131 |
132 | Target "NBench" <| fun _ ->
133 | let projects =
134 | match (isWindows) with
135 | | true -> !! "./src/**/*.Tests.Performance.csproj"
136 | | _ -> !! "./src/**/*.Tests.Performance.csproj" // if you need to filter specs for Linux vs. Windows, do it here
137 |
138 |
139 | let runSingleProject project =
140 | let arguments =
141 | match (hasTeamCity) with
142 | | true -> (sprintf "nbench --nobuild --teamcity --concurrent true --trace true --output %s" (outputPerfTests))
143 | | false -> (sprintf "nbench --nobuild --concurrent true --trace true --output %s" (outputPerfTests))
144 |
145 | let result = ExecProcess(fun info ->
146 | info.FileName <- "dotnet"
147 | info.WorkingDirectory <- (Directory.GetParent project).FullName
148 | info.Arguments <- arguments) (TimeSpan.FromMinutes 30.0)
149 |
150 | ResultHandling.failBuildIfXUnitReportedError TestRunnerErrorLevel.DontFailBuild result
151 |
152 | projects |> Seq.iter runSingleProject
153 |
154 |
155 | //--------------------------------------------------------------------------------
156 | // Code signing targets
157 | //--------------------------------------------------------------------------------
158 | Target "SignPackages" (fun _ ->
159 | let canSign = hasBuildParam "SignClientSecret" && hasBuildParam "SignClientUser"
160 | if(canSign) then
161 | log "Signing information is available."
162 |
163 | let assemblies = !! (outputNuGet @@ "*.nupkg")
164 |
165 | let signPath =
166 | let globalTool = tryFindFileOnPath "SignClient.exe"
167 | match globalTool with
168 | | Some t -> t
169 | | None -> if isWindows then findToolInSubPath "SignClient.exe" "tools/signclient"
170 | elif isMacOS then findToolInSubPath "SignClient" "tools/signclient"
171 | else findToolInSubPath "SignClient" "tools/signclient"
172 |
173 | let signAssembly assembly =
174 | let args = StringBuilder()
175 | |> append "sign"
176 | |> append "--config"
177 | |> append (__SOURCE_DIRECTORY__ @@ "appsettings.json")
178 | |> append "-i"
179 | |> append assembly
180 | |> append "-r"
181 | |> append (getBuildParam "SignClientUser")
182 | |> append "-s"
183 | |> append (getBuildParam "SignClientSecret")
184 | |> append "-n"
185 | |> append signingName
186 | |> append "-d"
187 | |> append signingDescription
188 | |> append "-u"
189 | |> append signingUrl
190 | |> toText
191 |
192 | let result = ExecProcess(fun info ->
193 | info.FileName <- signPath
194 | info.WorkingDirectory <- __SOURCE_DIRECTORY__
195 | info.Arguments <- args) (System.TimeSpan.FromMinutes 5.0) (* Reasonably long-running task. *)
196 | if result <> 0 then failwithf "SignClient failed.%s" args
197 |
198 | assemblies |> Seq.iter (signAssembly)
199 | else
200 | log "SignClientSecret not available. Skipping signing"
201 | )
202 |
203 | //--------------------------------------------------------------------------------
204 | // Nuget targets
205 | //--------------------------------------------------------------------------------
206 |
207 | let overrideVersionSuffix (project:string) =
208 | match project with
209 | | _ -> versionSuffix // add additional matches to publish different versions for different projects in solution
210 | Target "CreateNuget" (fun _ ->
211 | let projects = !! "src/**/*.csproj"
212 | -- "src/**/*Tests.csproj" // Don't publish unit tests
213 | -- "src/**/*Tests*.csproj"
214 |
215 | let runSingleProject project =
216 | DotNetCli.Pack
217 | (fun p ->
218 | { p with
219 | Project = project
220 | Configuration = configuration
221 | AdditionalArgs = ["--include-symbols --no-build"]
222 | VersionSuffix = overrideVersionSuffix project
223 | OutputPath = outputNuGet })
224 |
225 | projects |> Seq.iter (runSingleProject)
226 | )
227 |
228 | Target "PublishNuget" (fun _ ->
229 | let projects = !! "./bin/nuget/*.nupkg" -- "./bin/nuget/*.symbols.nupkg"
230 | let apiKey = getBuildParamOrDefault "nugetkey" ""
231 | let source = getBuildParamOrDefault "nugetpublishurl" ""
232 | let symbolSource = getBuildParamOrDefault "symbolspublishurl" ""
233 | let shouldPublishSymbolsPackages = not (symbolSource = "")
234 |
235 | if (not (source = "") && not (apiKey = "") && shouldPublishSymbolsPackages) then
236 | let runSingleProject project =
237 | DotNetCli.RunCommand
238 | (fun p ->
239 | { p with
240 | TimeOut = TimeSpan.FromMinutes 10. })
241 | (sprintf "nuget push %s --api-key %s --source %s --symbol-source %s" project apiKey source symbolSource)
242 |
243 | projects |> Seq.iter (runSingleProject)
244 | else if (not (source = "") && not (apiKey = "") && not shouldPublishSymbolsPackages) then
245 | let runSingleProject project =
246 | DotNetCli.RunCommand
247 | (fun p ->
248 | { p with
249 | TimeOut = TimeSpan.FromMinutes 10. })
250 | (sprintf "nuget push %s --api-key %s --source %s" project apiKey source)
251 |
252 | projects |> Seq.iter (runSingleProject)
253 | )
254 |
255 | //--------------------------------------------------------------------------------
256 | // Documentation
257 | //--------------------------------------------------------------------------------
258 | Target "DocFx" (fun _ ->
259 | DotNetCli.Restore (fun p -> { p with Project = solutionFile })
260 | DotNetCli.Build (fun p -> { p with Project = solutionFile; Configuration = configuration })
261 |
262 | let docsPath = "./docs"
263 |
264 | DocFx (fun p ->
265 | { p with
266 | Timeout = TimeSpan.FromMinutes 30.0;
267 | WorkingDirectory = docsPath;
268 | DocFxJson = docsPath @@ "docfx.json" })
269 | )
270 |
271 | //--------------------------------------------------------------------------------
272 | // Cleanup
273 | //--------------------------------------------------------------------------------
274 |
275 | FinalTarget "KillCreatedProcesses" (fun _ ->
276 | log "Shutting down dotnet build-server"
277 | let result = ExecProcess(fun info ->
278 | info.FileName <- "dotnet"
279 | info.WorkingDirectory <- __SOURCE_DIRECTORY__
280 | info.Arguments <- "build-server shutdown") (System.TimeSpan.FromMinutes 2.0)
281 | if result <> 0 then failwithf "dotnet build-server shutdown failed"
282 | )
283 |
284 | //--------------------------------------------------------------------------------
285 | // Help
286 | //--------------------------------------------------------------------------------
287 |
288 | Target "Help" <| fun _ ->
289 | List.iter printfn [
290 | "usage:"
291 | "./build.ps1 [target]"
292 | ""
293 | " Targets for building:"
294 | " * Build Builds"
295 | " * Nuget Create and optionally publish nugets packages"
296 | " * SignPackages Signs all NuGet packages, provided that the following arguments are passed into the script: SignClientSecret={secret} and SignClientUser={username}"
297 | " * RunTests Runs tests"
298 | " * All Builds, run tests, creates and optionally publish nuget packages"
299 | " * DocFx Creates a DocFx-based website for this solution"
300 | ""
301 | " Other Targets"
302 | " * Help Display this help"
303 | ""]
304 |
305 | //--------------------------------------------------------------------------------
306 | // Target dependencies
307 | //--------------------------------------------------------------------------------
308 |
309 | Target "BuildRelease" DoNothing
310 | Target "All" DoNothing
311 | Target "Nuget" DoNothing
312 |
313 | // build dependencies
314 | "Clean" ==> "RestorePackages" ==> "AssemblyInfo" ==> "Build" ==> "BuildRelease"
315 |
316 | // tests dependencies
317 | "Clean" ==> "RestorePackages" ==> "Build" ==> "RunTests"
318 |
319 | // nuget dependencies
320 | "Clean" ==> "RestorePackages" ==> "Build" ==> "CreateNuget"
321 | "CreateNuget" ==> "SignPackages" ==> "PublishNuget" ==> "Nuget"
322 |
323 | // docs
324 | "Clean" ==> "RestorePackages" ==> "BuildRelease" ==> "Docfx"
325 |
326 | // all
327 | "BuildRelease" ==> "All"
328 | "RunTests" ==> "All"
329 | "NBench" ==> "All"
330 | "Nuget" ==> "All"
331 |
332 | RunTargetOrDefault "Help"
333 |
--------------------------------------------------------------------------------
/build.ps1:
--------------------------------------------------------------------------------
1 | <#
2 | .SYNOPSIS
3 | This is a Powershell script to bootstrap a Fake build.
4 | .DESCRIPTION
5 | This Powershell script will download NuGet if missing, restore NuGet tools (including Fake)
6 | and execute your Fake build script with the parameters you provide.
7 | .PARAMETER Target
8 | The build script target to run.
9 | .PARAMETER Configuration
10 | The build configuration to use.
11 | .PARAMETER Verbosity
12 | Specifies the amount of information to be displayed.
13 | .PARAMETER WhatIf
14 | Performs a dry run of the build script.
15 | No tasks will be executed.
16 | .PARAMETER ScriptArgs
17 | Remaining arguments are added here.
18 | #>
19 |
20 | [CmdletBinding()]
21 | Param(
22 | [string]$Target = "Default",
23 | [ValidateSet("Release", "Debug")]
24 | [string]$Configuration = "Release",
25 | [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")]
26 | [string]$Verbosity = "Verbose",
27 | [switch]$WhatIf,
28 | [Parameter(Position=0,Mandatory=$false,ValueFromRemainingArguments=$true)]
29 | [string[]]$ScriptArgs
30 | )
31 |
32 | $FakeVersion = "4.61.2"
33 | $DotNetChannel = "LTS";
34 | $DotNetVersion = "3.1.100";
35 | $DotNetInstallerUri = "https://dot.net/v1/dotnet-install.ps1";
36 | $NugetVersion = "4.1.0";
37 | $NugetUrl = "https://dist.nuget.org/win-x86-commandline/v$NugetVersion/nuget.exe"
38 | $ProtobufVersion = "3.4.0"
39 | $DocfxVersion = "2.49.0"
40 |
41 | # Make sure tools folder exists
42 | $PSScriptRoot = Split-Path $MyInvocation.MyCommand.Path -Parent
43 | $ToolPath = Join-Path $PSScriptRoot "tools"
44 | if (!(Test-Path $ToolPath)) {
45 | Write-Verbose "Creating tools directory..."
46 | New-Item -Path $ToolPath -Type directory | out-null
47 | }
48 |
49 | ###########################################################################
50 | # INSTALL .NET CORE CLI
51 | ###########################################################################
52 |
53 | Function Remove-PathVariable([string]$VariableToRemove)
54 | {
55 | $path = [Environment]::GetEnvironmentVariable("PATH", "User")
56 | if ($path -ne $null)
57 | {
58 | $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
59 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "User")
60 | }
61 |
62 | $path = [Environment]::GetEnvironmentVariable("PATH", "Process")
63 | if ($path -ne $null)
64 | {
65 | $newItems = $path.Split(';', [StringSplitOptions]::RemoveEmptyEntries) | Where-Object { "$($_)" -inotlike $VariableToRemove }
66 | [Environment]::SetEnvironmentVariable("PATH", [System.String]::Join(';', $newItems), "Process")
67 | }
68 | }
69 |
70 | # Get .NET Core CLI path if installed.
71 | $FoundDotNetCliVersion = $null;
72 | if (Get-Command dotnet -ErrorAction SilentlyContinue) {
73 | $FoundDotNetCliVersion = dotnet --version;
74 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
75 | $env:DOTNET_CLI_TELEMETRY_OPTOUT=1
76 | }
77 |
78 | if($FoundDotNetCliVersion -ne $DotNetVersion) {
79 | $InstallPath = Join-Path $PSScriptRoot ".dotnet"
80 | if (!(Test-Path $InstallPath)) {
81 | mkdir -Force $InstallPath | Out-Null;
82 | }
83 | (New-Object System.Net.WebClient).DownloadFile($DotNetInstallerUri, "$InstallPath\dotnet-install.ps1");
84 | & $InstallPath\dotnet-install.ps1 -Channel $DotNetChannel -Version $DotNetVersion -InstallDir $InstallPath -Architecture x64;
85 |
86 | Remove-PathVariable "$InstallPath"
87 | $env:PATH = "$InstallPath;$env:PATH"
88 | $env:DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
89 | $env:DOTNET_CLI_TELEMETRY_OPTOUT=1
90 | $env:DOTNET_ROOT=$InstallPath
91 | }
92 |
93 | ###########################################################################
94 | # INSTALL NUGET
95 | ###########################################################################
96 |
97 | # Make sure nuget.exe exists.
98 | $NugetPath = Join-Path $ToolPath "nuget.exe"
99 | if (!(Test-Path $NugetPath)) {
100 | Write-Host "Downloading NuGet.exe..."
101 | (New-Object System.Net.WebClient).DownloadFile($NugetUrl, $NugetPath);
102 | }
103 |
104 | ###########################################################################
105 | # INSTALL FAKE
106 | ###########################################################################
107 | # Make sure Fake has been installed.
108 |
109 | $FakeExePath = Join-Path $ToolPath "FAKE/tools/FAKE.exe"
110 | if (!(Test-Path $FakeExePath)) {
111 | Write-Host "Installing Fake..."
112 | Invoke-Expression "&`"$NugetPath`" install Fake -ExcludeVersion -Version $FakeVersion -OutputDirectory `"$ToolPath`"" | Out-Null;
113 | if ($LASTEXITCODE -ne 0) {
114 | Throw "An error occured while restoring Fake from NuGet."
115 | }
116 | }
117 |
118 | ###########################################################################
119 | # Docfx
120 | ###########################################################################
121 |
122 | # Make sure Docfx has been installed.
123 | $DocfxExePath = Join-Path $ToolPath "docfx.console/tools/docfx.exe"
124 | if (!(Test-Path $DocfxExePath)) {
125 | Write-Host "Installing Docfx..."
126 | Invoke-Expression "&`"$NugetPath`" install docfx.console -ExcludeVersion -Version $DocfxVersion -OutputDirectory `"$ToolPath`"" | Out-Null;
127 | if ($LASTEXITCODE -ne 0) {
128 | Throw "An error occured while restoring docfx.console from NuGet."
129 | }
130 | }
131 |
132 | ###########################################################################
133 | # SignTool
134 | ###########################################################################
135 |
136 | # Make sure the SignClient has been installed
137 | if (Get-Command signclient -ErrorAction SilentlyContinue) {
138 | Write-Host "Found SignClient. Skipping install."
139 | }
140 | else{
141 | $SignClientFolder = Join-Path $ToolPath "signclient"
142 | Write-Host "SignClient not found. Installing to ... $SignClientFolder"
143 | dotnet tool install SignClient --version 1.0.82 --tool-path "$SignClientFolder"
144 | }
145 |
146 | ###########################################################################
147 | # RUN BUILD SCRIPT
148 | ###########################################################################
149 |
150 | # Build the argument list.
151 | $Arguments = @{
152 | target=$Target;
153 | configuration=$Configuration;
154 | verbosity=$Verbosity;
155 | dryrun=$WhatIf;
156 | }.GetEnumerator() | %{"--{0}=`"{1}`"" -f $_.key, $_.value };
157 |
158 | # Start Fake
159 | Write-Host "Running build script..."
160 | Invoke-Expression "$FakeExePath `"build.fsx`" $ScriptArgs $Arguments"
161 |
162 | exit $LASTEXITCODE
163 | # SIG # Begin signature block
164 | # MIIgTwYJKoZIhvcNAQcCoIIgQDCCIDwCAQExDzANBglghkgBZQMEAgEFADB5Bgor
165 | # BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG
166 | # KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCDy+m5x/ontiIGy
167 | # a2+Kn4J7jbsGsFWkLaQLK39iFQNsb6CCDiIwggO3MIICn6ADAgECAhAM5+DlF9hG
168 | # /o/lYPwb8DA5MA0GCSqGSIb3DQEBBQUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK
169 | # EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV
170 | # BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0wNjExMTAwMDAwMDBa
171 | # Fw0zMTExMTAwMDAwMDBaMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy
172 | # dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lD
173 | # ZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
174 | # AQoCggEBAK0OFc7kQ4BcsYfzt2D5cRKlrtwmlIiq9M71IDkoWGAM+IDaqRWVMmE8
175 | # tbEohIqK3J8KDIMXeo+QrIrneVNcMYQq9g+YMjZ2zN7dPKii72r7IfJSYd+fINcf
176 | # 4rHZ/hhk0hJbX/lYGDW8R82hNvlrf9SwOD7BG8OMM9nYLxj+KA+zp4PWw25EwGE1
177 | # lhb+WZyLdm3X8aJLDSv/C3LanmDQjpA1xnhVhyChz+VtCshJfDGYM2wi6YfQMlqi
178 | # uhOCEe05F52ZOnKh5vqk2dUXMXWuhX0irj8BRob2KHnIsdrkVxfEfhwOsLSSplaz
179 | # vbKX7aqn8LfFqD+VFtD/oZbrCF8Yd08CAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGG
180 | # MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEXroq/0ksuCMS1Ri6enIZ3zbcgP
181 | # MB8GA1UdIwQYMBaAFEXroq/0ksuCMS1Ri6enIZ3zbcgPMA0GCSqGSIb3DQEBBQUA
182 | # A4IBAQCiDrzf4u3w43JzemSUv/dyZtgy5EJ1Yq6H6/LV2d5Ws5/MzhQouQ2XYFwS
183 | # TFjk0z2DSUVYlzVpGqhH6lbGeasS2GeBhN9/CTyU5rgmLCC9PbMoifdf/yLil4Qf
184 | # 6WXvh+DfwWdJs13rsgkq6ybteL59PyvztyY1bV+JAbZJW58BBZurPSXBzLZ/wvFv
185 | # hsb6ZGjrgS2U60K3+owe3WLxvlBnt2y98/Efaww2BxZ/N3ypW2168RJGYIPXJwS+
186 | # S86XvsNnKmgR34DnDDNmvxMNFG7zfx9jEB76jRslbWyPpbdhAbHSoyahEHGdreLD
187 | # +cOZUbcrBwjOLuZQsqf6CkUvovDyMIIFLzCCBBegAwIBAgIQDGOJqewvySRbpPsq
188 | # IflH5DANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGln
189 | # aUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhE
190 | # aWdpQ2VydCBTSEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBMB4XDTE3MDEw
191 | # NjAwMDAwMFoXDTIwMDExNTEyMDAwMFowbDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
192 | # CkNhbGlmb3JuaWExFDASBgNVBAcTC0xvcyBBbmdlbGVzMRgwFgYDVQQKEw9QZXRh
193 | # YnJpZGdlLCBMTEMxGDAWBgNVBAMTD1BldGFicmlkZ2UsIExMQzCCASIwDQYJKoZI
194 | # hvcNAQEBBQADggEPADCCAQoCggEBAJriBjrKlrcxMnq3l2fLb5lQjuc6+J5r8cm6
195 | # J1IlK+BLcf0WnLxOJRBRhHXzdNkiCUJsLw2qE8Adfq0XpfxgQjTSk9Mbn4w7U7wk
196 | # 9/GMsripQZ8qIiQw479XuhQkKqa7A4W4gPSNpanDP93VXQ1rq2QJbYVSG3QG2xhT
197 | # YJQrtYICZUTAX5545iktupiwJcKalr3QK7qrqNlX+D9Io83gapXTTxJcnLQQ49+P
198 | # zg4k84dBsx3ZKRwlQfyay42+vPZzoBqAl3GB5PFhjN1nGYJDOny3OeEbl2Jtlhf/
199 | # 7AG5/iEpD/H1pmMTMbfNXWYcydqsUJpx+ZP41dEoZtHFdpjAMTsCAwEAAaOCAcUw
200 | # ggHBMB8GA1UdIwQYMBaAFFrEuXsqCqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBS+
201 | # T6RUtpfdoqSY120tEgyk++hNkjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYI
202 | # KwYBBQUHAwMwdwYDVR0fBHAwbjA1oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQu
203 | # Y29tL3NoYTItYXNzdXJlZC1jcy1nMS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRp
204 | # Z2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtY3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJ
205 | # YIZIAYb9bAMBMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNv
206 | # bS9DUFMwCAYGZ4EMAQQBMIGEBggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0
207 | # dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2Vy
208 | # dHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5n
209 | # Q0EuY3J0MAwGA1UdEwEB/wQCMAAwDQYJKoZIhvcNAQELBQADggEBAHq4G8r7TMcb
210 | # o2NNnWedUctYyfwoqTCxbssff5aU9b0FwkmuP56VlqAlNVojMze7LhvIvIf0WabY
211 | # 3NxBnUlCble3MXYMa9btcn1HbLpdKBHoDJ9DbhNeWeBh9DuYtxTnXJoi6mOPgull
212 | # syuMzN7A5V8RFtmJQpMwjJ8+8Pw1KBmE2b/Nr1DvbOAGYQ8pnL+wgaCAOU+7ZlyL
213 | # 7ffmloyIE0mh63ReveR8t8IwOy3tF4Zyp9u+rcEMct0Wo42b1hiXlLKMs0YupoaC
214 | # /H7tTfvnGBs9jZRaAJ1BcLrF4xRMSfTxtPlFRxunZ1ZzVKoiyctXLmET3MOuTyXn
215 | # aI2JwwH+zUYwggUwMIIEGKADAgECAhAECRgbX9W7ZnVTQ7VvlVAIMA0GCSqGSIb3
216 | # DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAX
217 | # BgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0IEFzc3Vy
218 | # ZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBaFw0yODEwMjIxMjAwMDBaMHIx
219 | # CzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3
220 | # dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJ
221 | # RCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
222 | # AQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/lqJ3bMtdx6nadBS63j/qSQ8Cl
223 | # +YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fTeyOU5JEjlpB3gvmhhCNmElQz
224 | # UHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqHCN8M9eJNYBi+qsSyrnAxZjNx
225 | # PqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+bMt+dDk2DZDv5LVOpKnqagqr
226 | # hPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLoLFH3c7y9hbFig3NBggfkOItq
227 | # cyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIByTASBgNVHRMBAf8ECDAGAQH/
228 | # AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAKBggrBgEFBQcDAzB5BggrBgEF
229 | # BQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBD
230 | # BggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0
231 | # QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHoweDA6oDigNoY0aHR0cDovL2Ny
232 | # bDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDA6oDig
233 | # NoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9v
234 | # dENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwAAgQwKjAoBggrBgEFBQcCARYc
235 | # aHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAKBghghkgBhv1sAzAdBgNVHQ4E
236 | # FgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0jBBgwFoAUReuir/SSy4IxLVGL
237 | # p6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7sDVoks/Mi0RXILHwlKXaoHV0c
238 | # LToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGSdQ9RtG6ljlriXiSBThCk7j9x
239 | # jmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6r7VRwo0kriTGxycqoSkoGjpx
240 | # KAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo+MUSaJ/PQMtARKUT8OZkDCUI
241 | # QjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qzsIzV6Q3d9gEgzpkxYz0IGhiz
242 | # gZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHqaGxEMrJmoecYpJpkUe8xghGD
243 | # MIIRfwIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5j
244 | # MRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBT
245 | # SEEyIEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhAMY4mp7C/JJFuk+yoh+Ufk
246 | # MA0GCWCGSAFlAwQCAQUAoIIBATAZBgkqhkiG9w0BCQMxDAYKKwYBBAGCNwIBBDAc
247 | # BgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAvBgkqhkiG9w0BCQQxIgQgJuHi
248 | # vbFHMNp3nUjNSOgj/F89M0Ct8VgVgwOelqhnzlAwgZQGCisGAQQBgjcCAQwxgYUw
249 | # gYKgSIBGAFAAZQB0AGEAYgByAGkAZABnAGUAIABTAHQAYQBuAGQAYQByAGQAIABC
250 | # AHUAaQBsAGQAIABUAGUAbQBwAGwAYQB0AGUAc6E2gDRodHRwczovL2dpdGh1Yi5j
251 | # b20vcGV0YWJyaWRnZS9wZXRhYnJpZGdlLWRvdG5ldC1uZXcgMA0GCSqGSIb3DQEB
252 | # AQUABIIBAIJgaaYF7d0eCozYo6KiZYYKU3Qptr33/FYVlEKc6kgh+9D/ZAQ1lqsF
253 | # k9mZVCB4IbJs92KSNuHhkZpeZjV30YiWJ6Ixd+tF5sAcKfNTSjH3QfqJAdXUG8gL
254 | # mUbk0H64wz/lTsWLz5l6SrSSnHvABVjn/PqLMRqbrwRvhFFt9yoRlmDzG7/UAPWB
255 | # +ftkGkPOUUUEIbF/RCdPiXIb82W4cXuBk8Kqkou6X4Dbv07GzKkeCun5DbgD4mL3
256 | # 2h91fyUsUkh5USpZVcScsLSsIqFavZ3GPExWhkGvo8EQ756+ZT+EdyleQd70eI6V
257 | # +jrFfrNWxRlmVcfE+ZBH8bLJinzYGNChgg7IMIIOxAYKKwYBBAGCNwMDATGCDrQw
258 | # gg6wBgkqhkiG9w0BBwKggg6hMIIOnQIBAzEPMA0GCWCGSAFlAwQCAQUAMHcGCyqG
259 | # SIb3DQEJEAEEoGgEZjBkAgEBBglghkgBhv1sBwEwMTANBglghkgBZQMEAgEFAAQg
260 | # yVw1M/glzmvyYENKoVDAlG2PPFDPhYSmm6N4s9jIPD0CEGcCUCnVFW/SW5WYFvGQ
261 | # UdEYDzIwMTkwMzE1MTYwMDU3WqCCC7swggaCMIIFaqADAgECAhAJwPxGyARCE7VZ
262 | # i68oT05BMA0GCSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxE
263 | # aWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMT
264 | # KERpZ2lDZXJ0IFNIQTIgQXNzdXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwHhcNMTcw
265 | # MTA0MDAwMDAwWhcNMjgwMTE4MDAwMDAwWjBMMQswCQYDVQQGEwJVUzERMA8GA1UE
266 | # ChMIRGlnaUNlcnQxKjAoBgNVBAMTIURpZ2lDZXJ0IFNIQTIgVGltZXN0YW1wIFJl
267 | # c3BvbmRlcjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ6VmGo0O3Mb
268 | # qH78x74paYnHaCZGXz2NYnOHgaOhnPC3WyQ3WpLU9FnXdonk3NUn8NVmvArutCsx
269 | # Z6xYxUqRWStFHgkB1mSzWe6NZk37I17MEA0LimfvUq6gCJDCUvf1qLVumyx7nee1
270 | # Pvt4zTJQGL9AtUyMu1f0oE8RRWxCQrnlr9bf9Kd8CmiWD9JfKVfO+x0y//QRoRMi
271 | # +xLL79dT0uuXy6KsGx2dWCFRgsLC3uorPywihNBD7Ds7P0fE9lbcRTeYtGt0tVmv
272 | # eFdpyA8JAnjd2FPBmdtgxJ3qrq/gfoZKXKlYYahedIoBKGhyTqeGnbUCUodwZkjT
273 | # ju+BJMzc2GUCAwEAAaOCAzgwggM0MA4GA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8E
274 | # AjAAMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMIMIIBvwYDVR0gBIIBtjCCAbIwggGh
275 | # BglghkgBhv1sBwEwggGSMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2Vy
276 | # dC5jb20vQ1BTMIIBZAYIKwYBBQUHAgIwggFWHoIBUgBBAG4AeQAgAHUAcwBlACAA
277 | # bwBmACAAdABoAGkAcwAgAEMAZQByAHQAaQBmAGkAYwBhAHQAZQAgAGMAbwBuAHMA
278 | # dABpAHQAdQB0AGUAcwAgAGEAYwBjAGUAcAB0AGEAbgBjAGUAIABvAGYAIAB0AGgA
279 | # ZQAgAEQAaQBnAGkAQwBlAHIAdAAgAEMAUAAvAEMAUABTACAAYQBuAGQAIAB0AGgA
280 | # ZQAgAFIAZQBsAHkAaQBuAGcAIABQAGEAcgB0AHkAIABBAGcAcgBlAGUAbQBlAG4A
281 | # dAAgAHcAaABpAGMAaAAgAGwAaQBtAGkAdAAgAGwAaQBhAGIAaQBsAGkAdAB5ACAA
282 | # YQBuAGQAIABhAHIAZQAgAGkAbgBjAG8AcgBwAG8AcgBhAHQAZQBkACAAaABlAHIA
283 | # ZQBpAG4AIABiAHkAIAByAGUAZgBlAHIAZQBuAGMAZQAuMAsGCWCGSAGG/WwDFTAf
284 | # BgNVHSMEGDAWgBT0tuEgHf4prtLkYaWyoiWyyBc1bjAdBgNVHQ4EFgQU4acySu4B
285 | # ISh9VNXyB5JutAcPPYcwcQYDVR0fBGowaDAyoDCgLoYsaHR0cDovL2NybDMuZGln
286 | # aWNlcnQuY29tL3NoYTItYXNzdXJlZC10cy5jcmwwMqAwoC6GLGh0dHA6Ly9jcmw0
287 | # LmRpZ2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMuY3JsMIGFBggrBgEFBQcBAQR5
288 | # MHcwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBPBggrBgEF
289 | # BQcwAoZDaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0U0hBMkFz
290 | # c3VyZWRJRFRpbWVzdGFtcGluZ0NBLmNydDANBgkqhkiG9w0BAQsFAAOCAQEAHvBB
291 | # gjKu7fG0NRPcUMLVl64iIp0ODq8z00z9fL9vARGnlGUiXMYiociJUmuajHNc2V4/
292 | # Mt4WYEyLNv0xmQq9wYS3jR3viSYTBVbzR81HW62EsjivaiO1ReMeiDJGgNK3ppki
293 | # /cF4z/WL2AyMBQnuROaA1W1wzJ9THifdKkje2pNlrW5lo5mnwkAOc8xYT49FKOW8
294 | # nIjmKM5gXS0lXYtzLqUNW1Hamk7/UAWJKNryeLvSWHiNRKesOgCReGmJZATTXZbf
295 | # Kr/5pUwsk//mit2CrPHSs6KGmsFViVZqRz/61jOVQzWJBXhaOmnaIrgEQ9NvaDU2
296 | # ehQ+RemYZIYPEwwmSjCCBTEwggQZoAMCAQICEAqhJdbWMht+QeQF2jaXwhUwDQYJ
297 | # KoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IElu
298 | # YzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTEkMCIGA1UEAxMbRGlnaUNlcnQg
299 | # QXNzdXJlZCBJRCBSb290IENBMB4XDTE2MDEwNzEyMDAwMFoXDTMxMDEwNzEyMDAw
300 | # MFowcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UE
301 | # CxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1
302 | # cmVkIElEIFRpbWVzdGFtcGluZyBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
303 | # AQoCggEBAL3QMu5LzY9/3am6gpnFOVQoV7YjSsQOB0UzURB90Pl9TWh+57ag9I2z
304 | # iOSXv2MhkJi/E7xX08PhfgjWahQAOPcuHjvuzKb2Mln+X2U/4Jvr40ZHBhpVfgsn
305 | # fsCi9aDg3iI/Dv9+lfvzo7oiPhisEeTwmQNtO4V8CdPuXciaC1TjqAlxa+DPIhAP
306 | # dc9xck4Krd9AOly3UeGheRTGTSQjMF287DxgaqwvB8z98OpH2YhQXv1mblZhJymJ
307 | # hFHmgudGUP2UKiyn5HU+upgPhH+fMRTWrdXyZMt7HgXQhBlyF/EXBu89zdZN7wZC
308 | # /aJTKk+FHcQdPK/P2qwQ9d2srOlW/5MCAwEAAaOCAc4wggHKMB0GA1UdDgQWBBT0
309 | # tuEgHf4prtLkYaWyoiWyyBc1bjAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYunpyGd
310 | # 823IDzASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUE
311 | # DDAKBggrBgEFBQcDCDB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6
312 | # Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMu
313 | # ZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0f
314 | # BHoweDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNz
315 | # dXJlZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29t
316 | # L0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBQBgNVHSAESTBHMDgGCmCGSAGG
317 | # /WwAAgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ
318 | # UzALBglghkgBhv1sBwEwDQYJKoZIhvcNAQELBQADggEBAHGVEulRh1Zpze/d2nyq
319 | # Y3qzeM8GN0CE70uEv8rPAwL9xafDDiBCLK938ysfDCFaKrcFNB1qrpn4J6Jmvwmq
320 | # YN92pDqTD/iy0dh8GWLoXoIlHsS6HHssIeLWWywUNUMEaLLbdQLgcseY1jxk5R9I
321 | # EBhfiThhTWJGJIdjjJFSLK8pieV4H9YLFKWA1xJHcLN11ZOFk362kmf7U2GJqPVr
322 | # lsD0WGkNfMgBsbkodbeZY4UijGHKeZR+WfyMD+NvtQEmtmyl7odRIeRYYJu6DC0r
323 | # baLEfrvEJStHAgh8Sa4TtuF8QkIoxhhWz0E0tmZdtnR79VYzIi8iNrJLokqV2PWm
324 | # jlIxggJNMIICSQIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNl
325 | # cnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdp
326 | # Q2VydCBTSEEyIEFzc3VyZWQgSUQgVGltZXN0YW1waW5nIENBAhAJwPxGyARCE7VZ
327 | # i68oT05BMA0GCWCGSAFlAwQCAQUAoIGYMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0B
328 | # CRABBDAcBgkqhkiG9w0BCQUxDxcNMTkwMzE1MTYwMDU3WjArBgsqhkiG9w0BCRAC
329 | # DDEcMBowGDAWBBRAAZFHXJiJHeuhBK9HCRtettTLyzAvBgkqhkiG9w0BCQQxIgQg
330 | # jLu5eXUI0j43Sq/ZJ76+UJmWF/2Amb+YAcVtGZhRJKowDQYJKoZIhvcNAQEBBQAE
331 | # ggEAQBQNwdmatbURcWuntIUvk18FZGGLRA3bT0kNXN0pwwwopQlr4G6WbL8C8oSw
332 | # 0KUbWa3VonUYHemc6ZYgSOaa07X9dMoEWdgf9Jy7LDFZQCYBkI7034x0ujyTAZ6U
333 | # KtqQupuRPdLAsCb67KB6DR6lIuP1hj1yolPb9uyqEsH1JJqusTiirZvO1UvNVtHU
334 | # ljscye8j2SiO8UNLhYHL1me43S4NmqgLkaDvIE8lVx8GtyFyGRdFZYTzAufXTR9H
335 | # HK8lsD0ekQiOpaAIw/MfhEgTej1Z3L686Z0xwBVyH988UA9lVbXdDZWS3odGd2CT
336 | # /JdEUFIMzW5J8N+QntZ/Fjua/A==
337 | # SIG # End signature block
338 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 | ##########################################################################
3 | # This is the Fake bootstrapper script for Linux and OS X.
4 | ##########################################################################
5 |
6 | # Define directories.
7 | SCRIPT_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )
8 | TOOLS_DIR=$SCRIPT_DIR/tools
9 | SIGNCLIENT_DIR=$TOOLS_DIR/signclient
10 | NUGET_EXE=$TOOLS_DIR/nuget.exe
11 | NUGET_URL=https://dist.nuget.org/win-x86-commandline/v4.0.0/nuget.exe
12 | FAKE_VERSION=4.61.2
13 | FAKE_EXE=$TOOLS_DIR/FAKE/tools/FAKE.exe
14 | DOTNET_VERSION=3.1.100
15 | DOTNET_INSTALLER_URL=https://dot.net/v1/dotnet-install.sh
16 | DOTNET_CHANNEL=LTS;
17 | DOCFX_VERSION=2.49.0
18 | DOCFX_EXE=$TOOLS_DIR/docfx.console/tools/docfx.exe
19 |
20 | # Define default arguments.
21 | TARGET="Default"
22 | CONFIGURATION="Release"
23 | VERBOSITY="verbose"
24 | DRYRUN=
25 | SCRIPT_ARGUMENTS=()
26 |
27 | # Parse arguments.
28 | for i in "$@"; do
29 | case $1 in
30 | -t|--target) TARGET="$2"; shift ;;
31 | -c|--configuration) CONFIGURATION="$2"; shift ;;
32 | -v|--verbosity) VERBOSITY="$2"; shift ;;
33 | -d|--dryrun) DRYRUN="-dryrun" ;;
34 | --) shift; SCRIPT_ARGUMENTS+=("$@"); break ;;
35 | *) SCRIPT_ARGUMENTS+=("$1") ;;
36 | esac
37 | shift
38 | done
39 |
40 | # Make sure the tools folder exist.
41 | if [ ! -d "$TOOLS_DIR" ]; then
42 | mkdir "$TOOLS_DIR"
43 | fi
44 |
45 | ###########################################################################
46 | # INSTALL .NET CORE CLI
47 | ###########################################################################
48 |
49 | echo "Installing .NET CLI..."
50 | if [ ! -d "$SCRIPT_DIR/.dotnet" ]; then
51 | mkdir "$SCRIPT_DIR/.dotnet"
52 | fi
53 | curl -Lsfo "$SCRIPT_DIR/.dotnet/dotnet-install.sh" $DOTNET_INSTALLER_URL
54 | bash "$SCRIPT_DIR/.dotnet/dotnet-install.sh" --version $DOTNET_VERSION --channel $DOTNET_CHANNEL --install-dir .dotnet --no-path
55 | export PATH="$SCRIPT_DIR/.dotnet":$PATH
56 | export DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
57 | export DOTNET_CLI_TELEMETRY_OPTOUT=1
58 | chmod -R 0755 ".dotnet"
59 | "$SCRIPT_DIR/.dotnet/dotnet" --info
60 |
61 |
62 | ###########################################################################
63 | # INSTALL NUGET
64 | ###########################################################################
65 |
66 | # Download NuGet if it does not exist.
67 | if [ ! -f "$NUGET_EXE" ]; then
68 | echo "Downloading NuGet..."
69 | curl -Lsfo "$NUGET_EXE" $NUGET_URL
70 | if [ $? -ne 0 ]; then
71 | echo "An error occured while downloading nuget.exe."
72 | exit 1
73 | fi
74 | fi
75 |
76 | ###########################################################################
77 | # INSTALL FAKE
78 | ###########################################################################
79 |
80 | if [ ! -f "$FAKE_EXE" ]; then
81 | mono "$NUGET_EXE" install Fake -ExcludeVersion -Version $FAKE_VERSION -OutputDirectory "$TOOLS_DIR"
82 | if [ $? -ne 0 ]; then
83 | echo "An error occured while installing Cake."
84 | exit 1
85 | fi
86 | fi
87 |
88 | # Make sure that Fake has been installed.
89 | if [ ! -f "$FAKE_EXE" ]; then
90 | echo "Could not find Fake.exe at '$FAKE_EXE'."
91 | exit 1
92 | fi
93 |
94 | ###########################################################################
95 | # INSTALL DOCFX
96 | ###########################################################################
97 | if [ ! -f "$DOCFX_EXE" ]; then
98 | mono "$NUGET_EXE" install docfx.console -ExcludeVersion -Version $DOCFX_VERSION -OutputDirectory "$TOOLS_DIR"
99 | if [ $? -ne 0 ]; then
100 | echo "An error occured while installing DocFx."
101 | exit 1
102 | fi
103 | fi
104 |
105 | # Make sure that DocFx has been installed.
106 | if [ ! -f "$DOCFX_EXE" ]; then
107 | echo "Could not find docfx.exe at '$DOCFX_EXE'."
108 | exit 1
109 | fi
110 |
111 | ###########################################################################
112 | # INSTALL SignTool
113 | ###########################################################################
114 | if [ ! -f "$SIGNTOOL_EXE" ]; then
115 | "$SCRIPT_DIR/.dotnet/dotnet" tool install SignClient --version 1.0.82 --tool-path "$SIGNCLIENT_DIR"
116 | if [ $? -ne 0 ]; then
117 | echo "SignClient already installed."
118 | fi
119 | fi
120 |
121 |
122 | ###########################################################################
123 | # WORKAROUND FOR MONO
124 | ###########################################################################
125 | export FrameworkPathOverride=/usr/lib/mono/4.5/
126 |
127 | ###########################################################################
128 | # RUN BUILD SCRIPT
129 | ###########################################################################
130 |
131 | # Start Fake
132 | exec mono "$FAKE_EXE" build.fsx "${SCRIPT_ARGUMENTS[@]}" --verbosity=$VERBOSITY --configuration=$CONFIGURATION --target=$TARGET $DRYRUN
133 |
--------------------------------------------------------------------------------
/src/.nuget/NuGet.Config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/src/.nuget/NuGet.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/helios-io/DedicatedThreadPool/b7be5f3342314417d2becd23864115cbedb16e5c/src/.nuget/NuGet.exe
--------------------------------------------------------------------------------
/src/.nuget/NuGet.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(MSBuildProjectDirectory)\..\
5 |
6 |
7 | false
8 |
9 |
10 | false
11 |
12 |
13 | true
14 |
15 |
16 | false
17 |
18 |
19 |
20 |
21 |
22 |
26 |
27 |
28 |
29 |
30 | $([System.IO.Path]::Combine($(SolutionDir), ".nuget"))
31 |
32 |
33 |
34 |
35 | $(SolutionDir).nuget
36 |
37 |
38 |
39 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName.Replace(' ', '_')).config
40 | $(MSBuildProjectDirectory)\packages.$(MSBuildProjectName).config
41 |
42 |
43 |
44 | $(MSBuildProjectDirectory)\packages.config
45 | $(PackagesProjectConfig)
46 |
47 |
48 |
49 |
50 | $(NuGetToolsPath)\NuGet.exe
51 | @(PackageSource)
52 |
53 | "$(NuGetExePath)"
54 | mono --runtime=v4.0.30319 "$(NuGetExePath)"
55 |
56 | $(TargetDir.Trim('\\'))
57 |
58 | -RequireConsent
59 | -NonInteractive
60 |
61 | "$(SolutionDir) "
62 | "$(SolutionDir)"
63 |
64 |
65 | $(NuGetCommand) install "$(PackagesConfig)" -source "$(PackageSources)" $(NonInteractiveSwitch) $(RequireConsentSwitch) -solutionDir $(PaddedSolutionDir)
66 | $(NuGetCommand) pack "$(ProjectPath)" -Properties "Configuration=$(Configuration);Platform=$(Platform)" $(NonInteractiveSwitch) -OutputDirectory "$(PackageOutputDir)" -symbols
67 |
68 |
69 |
70 | RestorePackages;
71 | $(BuildDependsOn);
72 |
73 |
74 |
75 |
76 | $(BuildDependsOn);
77 | BuildPackage;
78 |
79 |
80 |
81 |
82 |
83 |
84 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
99 |
100 |
103 |
104 |
105 |
106 |
108 |
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
141 |
142 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/src/Helios.DedicatedThreadPool.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.24720.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helios.DedicatedThreadPool", "core\Helios.DedicatedThreadPool\Helios.DedicatedThreadPool.csproj", "{6C8F359E-E479-44D5-8FA0-02BFD38C3860}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helios.DedicatedThreadPool.Tests", "tests\Helios.DedicatedThreadPool.Tests\Helios.DedicatedThreadPool.Tests.csproj", "{BD7B3C66-14D8-4F01-AECE-F7F3F440A899}"
9 | EndProject
10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{741F51D5-FB48-4AE3-837E-3C32FAC6584E}"
11 | EndProject
12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "core", "core", "{E86B275F-E912-47C5-8F5E-BA62D5959EBD}"
13 | EndProject
14 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{527902B6-8DD0-41E9-AB01-EE6A809F5447}"
15 | ProjectSection(SolutionItems) = preProject
16 | ..\build.fsx = ..\build.fsx
17 | EndProjectSection
18 | EndProject
19 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{39EF5BC0-8ADB-47AE-9A53-6AB9D40D601D}"
20 | ProjectSection(SolutionItems) = preProject
21 | .nuget\NuGet.Config = .nuget\NuGet.Config
22 | .nuget\NuGet.exe = .nuget\NuGet.exe
23 | .nuget\NuGet.targets = .nuget\NuGet.targets
24 | EndProjectSection
25 | EndProject
26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Helios.DedicatedThreadPool.Tests.Performance", "tests\Helios.DedicatedThreadPool.Tests.Performance\Helios.DedicatedThreadPool.Tests.Performance.csproj", "{428DF580-1734-4AB6-B80E-F5ABABCE61D6}"
27 | EndProject
28 | Global
29 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
30 | Debug|Any CPU = Debug|Any CPU
31 | Release|Any CPU = Release|Any CPU
32 | EndGlobalSection
33 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
34 | {6C8F359E-E479-44D5-8FA0-02BFD38C3860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
35 | {6C8F359E-E479-44D5-8FA0-02BFD38C3860}.Debug|Any CPU.Build.0 = Debug|Any CPU
36 | {6C8F359E-E479-44D5-8FA0-02BFD38C3860}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {6C8F359E-E479-44D5-8FA0-02BFD38C3860}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {BD7B3C66-14D8-4F01-AECE-F7F3F440A899}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
39 | {BD7B3C66-14D8-4F01-AECE-F7F3F440A899}.Debug|Any CPU.Build.0 = Debug|Any CPU
40 | {BD7B3C66-14D8-4F01-AECE-F7F3F440A899}.Release|Any CPU.ActiveCfg = Release|Any CPU
41 | {BD7B3C66-14D8-4F01-AECE-F7F3F440A899}.Release|Any CPU.Build.0 = Release|Any CPU
42 | {428DF580-1734-4AB6-B80E-F5ABABCE61D6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
43 | {428DF580-1734-4AB6-B80E-F5ABABCE61D6}.Debug|Any CPU.Build.0 = Debug|Any CPU
44 | {428DF580-1734-4AB6-B80E-F5ABABCE61D6}.Release|Any CPU.ActiveCfg = Release|Any CPU
45 | {428DF580-1734-4AB6-B80E-F5ABABCE61D6}.Release|Any CPU.Build.0 = Release|Any CPU
46 | EndGlobalSection
47 | GlobalSection(SolutionProperties) = preSolution
48 | HideSolutionNode = FALSE
49 | EndGlobalSection
50 | GlobalSection(NestedProjects) = preSolution
51 | {6C8F359E-E479-44D5-8FA0-02BFD38C3860} = {E86B275F-E912-47C5-8F5E-BA62D5959EBD}
52 | {BD7B3C66-14D8-4F01-AECE-F7F3F440A899} = {741F51D5-FB48-4AE3-837E-3C32FAC6584E}
53 | {428DF580-1734-4AB6-B80E-F5ABABCE61D6} = {741F51D5-FB48-4AE3-837E-3C32FAC6584E}
54 | EndGlobalSection
55 | EndGlobal
56 |
--------------------------------------------------------------------------------
/src/common.props:
--------------------------------------------------------------------------------
1 |
2 |
3 | Helios.DedicatedThreadPool
4 | Copyright © 2015-2016 Roger Alsing, Aaron Stannard, Jeff Cyr
5 | 0.3.0
6 | https://github.com/helios-io/DedicatedThreadPool
7 | Apache
8 | Major upgrade to the performance and stability of `DedicatedThreadPool`.
9 | Previous (v0.2) numbers:
10 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
11 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
12 | [Counter] BenchmarkCalls | operations | 2,381,933.51 | 2,335,262.42 | 2,123,061.11 | 75,849.97 |
13 | Current (v0.3) numbers:
14 | Metric | Units / s | Max / s | Average / s | Min / s | StdDev / s |
15 | ---------------- |---------------- |---------------- |---------------- |---------------- |---------------- |
16 | [Counter] BenchmarkCalls | operations | 9,998,100.36 | 8,661,529.31 | 7,093,003.46 | 944,954.17 |
17 | git
18 | https://github.com/helios-io/DedicatedThreadPool
19 |
20 |
--------------------------------------------------------------------------------
/src/core/Helios.DedicatedThreadPool/Helios.Concurrency.DedicatedThreadPool.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2015-2016 Roger Alsing, Aaron Stannard, Jeff Cyr
3 | * Helios.DedicatedThreadPool - https://github.com/helios-io/DedicatedThreadPool
4 | */
5 | using System;
6 | using System.Collections.Concurrent;
7 | using System.Collections.Generic;
8 | using System.Diagnostics;
9 | using System.Linq;
10 | using System.Runtime.InteropServices;
11 | using System.Threading;
12 | using System.Threading.Tasks;
13 |
14 | namespace Helios.Concurrency
15 | {
16 | ///
17 | /// The type of threads to use - either foreground or background threads.
18 | ///
19 | internal enum ThreadType
20 | {
21 | Foreground,
22 | Background
23 | }
24 |
25 | ///
26 | /// Provides settings for a dedicated thread pool
27 | ///
28 | internal class DedicatedThreadPoolSettings
29 | {
30 | ///
31 | /// Background threads are the default thread type
32 | ///
33 | public const ThreadType DefaultThreadType = ThreadType.Background;
34 |
35 | public DedicatedThreadPoolSettings(int numThreads, string name = null, TimeSpan? deadlockTimeout = null, Action exceptionHandler = null)
36 | : this(numThreads, DefaultThreadType, name, deadlockTimeout, exceptionHandler)
37 | { }
38 |
39 | public DedicatedThreadPoolSettings(int numThreads, ThreadType threadType, string name = null, TimeSpan? deadlockTimeout = null, Action exceptionHandler = null)
40 | {
41 | Name = name ?? ("DedicatedThreadPool-" + Guid.NewGuid());
42 | ThreadType = threadType;
43 | NumThreads = numThreads;
44 | DeadlockTimeout = deadlockTimeout;
45 | ExceptionHandler = exceptionHandler ?? (ex => { });
46 |
47 | if (deadlockTimeout.HasValue && deadlockTimeout.Value.TotalMilliseconds <= 0)
48 | throw new ArgumentOutOfRangeException("deadlockTimeout", string.Format("deadlockTimeout must be null or at least 1ms. Was {0}.", deadlockTimeout));
49 | if (numThreads <= 0)
50 | throw new ArgumentOutOfRangeException("numThreads", string.Format("numThreads must be at least 1. Was {0}", numThreads));
51 | }
52 |
53 | ///
54 | /// The total number of threads to run in this thread pool.
55 | ///
56 | public int NumThreads { get; private set; }
57 |
58 | ///
59 | /// The type of threads to run in this thread pool.
60 | ///
61 | public ThreadType ThreadType { get; private set; }
62 |
63 | ///
64 | /// Interval to check for thread deadlocks.
65 | ///
66 | /// If a thread takes longer than it will be aborted
67 | /// and replaced.
68 | ///
69 | public TimeSpan? DeadlockTimeout { get; private set; }
70 |
71 | ///
72 | /// TBD
73 | ///
74 | public string Name { get; private set; }
75 |
76 | ///
77 | /// TBD
78 | ///
79 | public Action ExceptionHandler { get; private set; }
80 | }
81 |
82 | ///
83 | /// TaskScheduler for working with a instance
84 | ///
85 | internal class DedicatedThreadPoolTaskScheduler : TaskScheduler
86 | {
87 | // Indicates whether the current thread is processing work items.
88 | [ThreadStatic]
89 | private static bool _currentThreadIsRunningTasks;
90 |
91 | ///
92 | /// Number of tasks currently running
93 | ///
94 | private volatile int _parallelWorkers = 0;
95 |
96 | private readonly LinkedList _tasks = new LinkedList();
97 |
98 | private readonly DedicatedThreadPool _pool;
99 |
100 | ///
101 | /// TBD
102 | ///
103 | /// TBD
104 | public DedicatedThreadPoolTaskScheduler(DedicatedThreadPool pool)
105 | {
106 | _pool = pool;
107 | }
108 |
109 | ///
110 | /// TBD
111 | ///
112 | /// TBD
113 | protected override void QueueTask(Task task)
114 | {
115 | lock (_tasks)
116 | {
117 | _tasks.AddLast(task);
118 | }
119 |
120 | EnsureWorkerRequested();
121 | }
122 |
123 | ///
124 | /// TBD
125 | ///
126 | /// TBD
127 | /// TBD
128 | protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued)
129 | {
130 | //current thread isn't running any tasks, can't execute inline
131 | if (!_currentThreadIsRunningTasks) return false;
132 |
133 | //remove the task from the queue if it was previously added
134 | if (taskWasPreviouslyQueued)
135 | if (TryDequeue(task))
136 | return TryExecuteTask(task);
137 | else
138 | return false;
139 | return TryExecuteTask(task);
140 | }
141 |
142 | ///
143 | /// TBD
144 | ///
145 | /// TBD
146 | /// TBD
147 | protected override bool TryDequeue(Task task)
148 | {
149 | lock (_tasks) return _tasks.Remove(task);
150 | }
151 |
152 | ///
153 | /// Level of concurrency is directly equal to the number of threads
154 | /// in the .
155 | ///
156 | public override int MaximumConcurrencyLevel
157 | {
158 | get { return _pool.Settings.NumThreads; }
159 | }
160 |
161 | ///
162 | /// TBD
163 | ///
164 | ///
165 | /// This exception is thrown if can't ensure a thread-safe return of the list of tasks.
166 | ///
167 | /// TBD
168 | protected override IEnumerable GetScheduledTasks()
169 | {
170 | var lockTaken = false;
171 | try
172 | {
173 | Monitor.TryEnter(_tasks, ref lockTaken);
174 |
175 | //should this be immutable?
176 | if (lockTaken) return _tasks;
177 | else throw new NotSupportedException();
178 | }
179 | finally
180 | {
181 | if (lockTaken) Monitor.Exit(_tasks);
182 | }
183 | }
184 |
185 | private void EnsureWorkerRequested()
186 | {
187 | var count = _parallelWorkers;
188 | while (count < _pool.Settings.NumThreads)
189 | {
190 | var prev = Interlocked.CompareExchange(ref _parallelWorkers, count + 1, count);
191 | if (prev == count)
192 | {
193 | RequestWorker();
194 | break;
195 | }
196 | count = prev;
197 | }
198 | }
199 |
200 | private void ReleaseWorker()
201 | {
202 | var count = _parallelWorkers;
203 | while (count > 0)
204 | {
205 | var prev = Interlocked.CompareExchange(ref _parallelWorkers, count - 1, count);
206 | if (prev == count)
207 | {
208 | break;
209 | }
210 | count = prev;
211 | }
212 | }
213 |
214 | private void RequestWorker()
215 | {
216 | _pool.QueueUserWorkItem(() =>
217 | {
218 | // this thread is now available for inlining
219 | _currentThreadIsRunningTasks = true;
220 | try
221 | {
222 | // Process all available items in the queue.
223 | while (true)
224 | {
225 | Task item;
226 | lock (_tasks)
227 | {
228 | // done processing
229 | if (_tasks.Count == 0)
230 | {
231 | ReleaseWorker();
232 | break;
233 | }
234 |
235 | // Get the next item from the queue
236 | item = _tasks.First.Value;
237 | _tasks.RemoveFirst();
238 | }
239 |
240 | // Execute the task we pulled out of the queue
241 | TryExecuteTask(item);
242 | }
243 | }
244 | // We're done processing items on the current thread
245 | finally { _currentThreadIsRunningTasks = false; }
246 | });
247 | }
248 | }
249 |
250 |
251 |
252 | ///
253 | /// An instanced, dedicated thread pool.
254 | ///
255 | internal sealed class DedicatedThreadPool : IDisposable
256 | {
257 | ///
258 | /// TBD
259 | ///
260 | /// TBD
261 | public DedicatedThreadPool(DedicatedThreadPoolSettings settings)
262 | {
263 | _workQueue = new ThreadPoolWorkQueue();
264 | Settings = settings;
265 | _workers = Enumerable.Range(1, settings.NumThreads).Select(workerId => new PoolWorker(this, workerId)).ToArray();
266 |
267 | // Note:
268 | // The DedicatedThreadPoolSupervisor was removed because aborting thread could lead to unexpected behavior
269 | // If a new implementation is done, it should spawn a new thread when a worker is not making progress and
270 | // try to keep {settings.NumThreads} active threads.
271 | }
272 |
273 | ///
274 | /// TBD
275 | ///
276 | public DedicatedThreadPoolSettings Settings { get; private set; }
277 |
278 | private readonly ThreadPoolWorkQueue _workQueue;
279 | private readonly PoolWorker[] _workers;
280 |
281 | ///
282 | /// TBD
283 | ///
284 | ///
285 | /// This exception is thrown if the given item is undefined.
286 | ///
287 | /// TBD
288 | public bool QueueUserWorkItem(Action work)
289 | {
290 | if (work == null)
291 | throw new ArgumentNullException(nameof(work), "Work item cannot be null.");
292 |
293 | return _workQueue.TryAdd(work);
294 | }
295 |
296 | ///
297 | /// TBD
298 | ///
299 | public void Dispose()
300 | {
301 | _workQueue.CompleteAdding();
302 | }
303 |
304 | ///
305 | /// TBD
306 | ///
307 | public void WaitForThreadsExit()
308 | {
309 | WaitForThreadsExit(Timeout.InfiniteTimeSpan);
310 | }
311 |
312 | ///
313 | /// TBD
314 | ///
315 | /// TBD
316 | public void WaitForThreadsExit(TimeSpan timeout)
317 | {
318 | Task.WaitAll(_workers.Select(worker => worker.ThreadExit).ToArray(), timeout);
319 | }
320 |
321 | #region Pool worker implementation
322 |
323 | private class PoolWorker
324 | {
325 | private readonly DedicatedThreadPool _pool;
326 |
327 | private readonly TaskCompletionSource