Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
PortableThreadPool.cs
Go to the documentation of this file.
7
8namespace System.Threading;
9
10internal sealed class PortableThreadPool
11{
12 [StructLayout(LayoutKind.Explicit, Size = 384)]
13 private struct CacheLineSeparated
14 {
15 [FieldOffset(64)]
17
18 [FieldOffset(128)]
19 public int lastDequeueTime;
20
21 [FieldOffset(192)]
23
24 [FieldOffset(196)]
26
27 [FieldOffset(200)]
29
30 [FieldOffset(256)]
31 public volatile int numRequestedWorkers;
32
33 [FieldOffset(260)]
35 }
36
37 private enum PendingBlockingAdjustment : byte
38 {
39 None,
42 }
43
44 private static class BlockingConfig
45 {
46 public static readonly bool IsCooperativeBlockingEnabled;
47
48 public static readonly short ThreadsToAddWithoutDelay;
49
50 public static readonly short ThreadsPerDelayStep;
51
52 public static readonly uint DelayStepMs;
53
54 public static readonly uint MaxDelayMs;
55
57 {
58 IsCooperativeBlockingEnabled = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.Blocking.CooperativeBlocking", defaultValue: true);
59 int int32Config = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.Blocking.ThreadsToAddWithoutDelay_ProcCountFactor", 1, allowNegative: false);
60 int int32Config2 = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.Blocking.ThreadsPerDelayStep_ProcCountFactor", 1, allowNegative: false);
61 DelayStepMs = (uint)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.Blocking.DelayStepMs", 25, allowNegative: false);
62 MaxDelayMs = (uint)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.Blocking.MaxDelayMs", 250, allowNegative: false);
63 int processorCount = Environment.ProcessorCount;
64 ThreadsToAddWithoutDelay = (short)(processorCount * int32Config);
65 if (ThreadsToAddWithoutDelay > short.MaxValue || ThreadsToAddWithoutDelay / processorCount != int32Config)
66 {
67 ThreadsToAddWithoutDelay = short.MaxValue;
68 }
69 int32Config2 = Math.Max(1, int32Config2);
70 short num = (short)(32767 - ThreadsToAddWithoutDelay);
71 ThreadsPerDelayStep = (short)(processorCount * int32Config2);
72 if (ThreadsPerDelayStep > num || ThreadsPerDelayStep / processorCount != int32Config2)
73 {
75 }
76 MaxDelayMs = Math.Max(1u, Math.Min(MaxDelayMs, 500u));
78 }
79 }
80
81 private static class GateThread
82 {
83 private struct DelayHelper
84 {
86
88
90
92
94
96
97 public void SetGateActivitiesTime(int currentTimeMs)
98 {
99 _previousGateActivitiesTimeMs = currentTimeMs;
100 }
101
102 public void SetBlockingAdjustmentTimeAndDelay(int currentTimeMs, uint delayMs)
103 {
106 }
107
112
113 public uint GetNextDelay(int currentTimeMs)
114 {
115 uint num = (uint)(currentTimeMs - _previousGateActivitiesTimeMs);
116 uint num2 = ((num >= 500) ? 1u : (500 - num));
118 {
121 return num2;
122 }
123 uint num3 = (uint)(currentTimeMs - _previousBlockingAdjustmentDelayStartTimeMs);
124 uint num4 = ((num3 >= _previousBlockingAdjustmentDelayMs) ? 1u : (_previousBlockingAdjustmentDelayMs - num3));
125 uint num5 = Math.Min(num2, num4);
128 return num5;
129 }
130
131 public bool ShouldPerformGateActivities(int currentTimeMs, bool wasSignaledToWake)
132 {
133 bool flag = (!wasSignaledToWake && _runGateActivitiesAfterNextDelay) || (uint)(currentTimeMs - _previousGateActivitiesTimeMs) >= 500u;
134 if (flag)
135 {
136 SetGateActivitiesTime(currentTimeMs);
137 }
138 return flag;
139 }
140
141 public bool HasBlockingAdjustmentDelayElapsed(int currentTimeMs, bool wasSignaledToWake)
142 {
143 if (!wasSignaledToWake && _adjustForBlockingAfterNextDelay)
144 {
145 return true;
146 }
147 uint num = (uint)(currentTimeMs - _previousBlockingAdjustmentDelayStartTimeMs);
149 }
150 }
151
152 private static readonly AutoResetEvent RunGateThreadEvent = new AutoResetEvent(initialState: true);
153
154 private static readonly AutoResetEvent DelayEvent = new AutoResetEvent(initialState: false);
155
156 private static void GateThreadStart()
157 {
158 bool booleanConfig = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.DisableStarvationDetection", defaultValue: false);
159 bool booleanConfig2 = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.DebugBreakOnWorkerStarvation", defaultValue: false);
160 CpuUtilizationReader cpuUtilizationReader = default(CpuUtilizationReader);
161 _ = cpuUtilizationReader.CurrentUtilization;
162 PortableThreadPool threadPoolInstance = ThreadPoolInstance;
163 LowLevelLock threadAdjustmentLock = threadPoolInstance._threadAdjustmentLock;
164 DelayHelper delayHelper = default(DelayHelper);
166 {
167 threadPoolInstance.OnGen2GCCallback();
168 Gen2GcCallback.Register(threadPoolInstance.OnGen2GCCallback);
169 }
170 while (true)
171 {
172 RunGateThreadEvent.WaitOne();
173 int tickCount = Environment.TickCount;
174 delayHelper.SetGateActivitiesTime(tickCount);
175 while (true)
176 {
177 bool wasSignaledToWake = DelayEvent.WaitOne((int)delayHelper.GetNextDelay(tickCount));
178 tickCount = Environment.TickCount;
179 PendingBlockingAdjustment pendingBlockingAdjustment = threadPoolInstance._pendingBlockingAdjustment;
180 if (pendingBlockingAdjustment == PendingBlockingAdjustment.None)
181 {
182 delayHelper.ClearBlockingAdjustmentDelay();
183 }
184 else
185 {
186 bool flag = false;
187 if (delayHelper.HasBlockingAdjustmentDelay)
188 {
189 flag = delayHelper.HasBlockingAdjustmentDelayElapsed(tickCount, wasSignaledToWake);
190 if (pendingBlockingAdjustment == PendingBlockingAdjustment.WithDelayIfNecessary && !flag)
191 {
192 goto IL_00ee;
193 }
194 }
195 uint num = threadPoolInstance.PerformBlockingAdjustment(flag);
196 if (num == 0)
197 {
198 delayHelper.ClearBlockingAdjustmentDelay();
199 }
200 else
201 {
202 delayHelper.SetBlockingAdjustmentTimeAndDelay(tickCount, num);
203 }
204 }
205 goto IL_00ee;
206 IL_00ee:
207 if (!delayHelper.ShouldPerformGateActivities(tickCount, wasSignaledToWake))
208 {
209 continue;
210 }
212 {
213 NativeRuntimeEventSource.Log.ThreadPoolWorkingThreadCount((uint)threadPoolInstance.GetAndResetHighWatermarkCountOfThreadsProcessingUserCallbacks(), 0);
214 }
215 bool flag2 = ThreadPool.PerformRuntimeSpecificGateActivities(threadPoolInstance._cpuUtilization = cpuUtilizationReader.CurrentUtilization);
216 if (!booleanConfig && threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && threadPoolInstance._separated.numRequestedWorkers > 0 && SufficientDelaySinceLastDequeue(threadPoolInstance))
217 {
218 bool flag3 = false;
219 threadAdjustmentLock.Acquire();
220 try
221 {
222 ThreadCounts threadCounts = threadPoolInstance._separated.counts;
223 while (threadCounts.NumProcessingWork < threadPoolInstance._maxThreads && threadCounts.NumProcessingWork >= threadCounts.NumThreadsGoal)
224 {
225 if (booleanConfig2)
226 {
227 Debugger.Break();
228 }
229 ThreadCounts newCounts = threadCounts;
230 short newThreadCount = (newCounts.NumThreadsGoal = (short)(threadCounts.NumProcessingWork + 1));
231 ThreadCounts threadCounts2 = threadPoolInstance._separated.counts.InterlockedCompareExchange(newCounts, threadCounts);
232 if (threadCounts2 == threadCounts)
233 {
234 HillClimbing.ThreadPoolHillClimber.ForceChange(newThreadCount, HillClimbing.StateOrTransition.Starvation);
235 flag3 = true;
236 break;
237 }
238 threadCounts = threadCounts2;
239 }
240 }
241 finally
242 {
243 threadAdjustmentLock.Release();
244 }
245 if (flag3)
246 {
247 WorkerThread.MaybeAddWorkingWorker(threadPoolInstance);
248 }
249 }
250 if (!flag2 && threadPoolInstance._separated.numRequestedWorkers <= 0 && threadPoolInstance._pendingBlockingAdjustment == PendingBlockingAdjustment.None && Interlocked.Decrement(ref threadPoolInstance._separated.gateThreadRunningState) <= GetRunningStateForNumRuns(0))
251 {
252 break;
253 }
254 }
255 }
256 }
257
258 public static void Wake(PortableThreadPool threadPoolInstance)
259 {
260 DelayEvent.Set();
261 EnsureRunning(threadPoolInstance);
262 }
263
264 private static bool SufficientDelaySinceLastDequeue(PortableThreadPool threadPoolInstance)
265 {
266 uint num = (uint)(Environment.TickCount - threadPoolInstance._separated.lastDequeueTime);
267 uint num2 = ((threadPoolInstance._cpuUtilization >= 80) ? ((uint)(threadPoolInstance._separated.counts.NumThreadsGoal * 1000)) : 500u);
268 return num > num2;
269 }
270
271 internal static void EnsureRunning(PortableThreadPool threadPoolInstance)
272 {
274 {
275 EnsureRunningSlow(threadPoolInstance);
276 }
277 }
278
279 [MethodImpl(MethodImplOptions.NoInlining)]
280 internal static void EnsureRunningSlow(PortableThreadPool threadPoolInstance)
281 {
283 if (num == GetRunningStateForNumRuns(0))
284 {
285 RunGateThreadEvent.Set();
286 }
287 else if ((num & 4) == 0)
288 {
289 CreateGateThread(threadPoolInstance);
290 }
291 }
292
293 private static int GetRunningStateForNumRuns(int numRuns)
294 {
295 return 4 | numRuns;
296 }
297
298 [MethodImpl(MethodImplOptions.NoInlining)]
299 private static void CreateGateThread(PortableThreadPool threadPoolInstance)
300 {
301 bool flag = false;
302 try
303 {
304 Thread thread = new Thread(GateThreadStart, 262144)
305 {
306 IsThreadPoolThread = true,
307 IsBackground = true,
308 Name = ".NET ThreadPool Gate"
309 };
310 thread.UnsafeStart();
311 flag = true;
312 }
313 finally
314 {
315 if (!flag)
316 {
317 Interlocked.Exchange(ref threadPoolInstance._separated.gateThreadRunningState, 0);
318 }
319 }
320 }
321 }
322
323 private sealed class HillClimbing
324 {
337
338 private struct LogEntry
339 {
340 public int tickCount;
341
343
345
347
348 public float lastHistoryMean;
349 }
350
351 private struct Complex
352 {
353 public double Imaginary { get; }
354
355 public double Real { get; }
356
357 public Complex(double real, double imaginary)
358 {
359 Real = real;
360 Imaginary = imaginary;
361 }
362
363 public static Complex operator *(double scalar, Complex complex)
364 {
365 return new Complex(scalar * complex.Real, scalar * complex.Imaginary);
366 }
367
368 public static Complex operator /(Complex complex, double scalar)
369 {
370 return new Complex(complex.Real / scalar, complex.Imaginary / scalar);
371 }
372
373 public static Complex operator -(Complex lhs, Complex rhs)
374 {
375 return new Complex(lhs.Real - rhs.Real, lhs.Imaginary - rhs.Imaginary);
376 }
377
378 public static Complex operator /(Complex lhs, Complex rhs)
379 {
380 double num = rhs.Real * rhs.Real + rhs.Imaginary * rhs.Imaginary;
381 return new Complex((lhs.Real * rhs.Real + lhs.Imaginary * rhs.Imaginary) / num, ((0.0 - lhs.Real) * rhs.Imaginary + lhs.Imaginary * rhs.Real) / num);
382 }
383
384 public double Abs()
385 {
386 return Math.Sqrt(Real * Real + Imaginary * Imaginary);
387 }
388 }
389
390 public static readonly bool IsDisabled = AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.HillClimbing.Disable", defaultValue: false);
391
392 public static readonly HillClimbing ThreadPoolHillClimber = new HillClimbing();
393
394 private readonly int _wavePeriod;
395
396 private readonly int _samplesToMeasure;
397
398 private readonly double _targetThroughputRatio;
399
400 private readonly double _targetSignalToNoiseRatio;
401
402 private readonly double _maxChangePerSecond;
403
404 private readonly double _maxChangePerSample;
405
406 private readonly int _maxThreadWaveMagnitude;
407
408 private readonly int _sampleIntervalMsLow;
409
410 private readonly double _threadMagnitudeMultiplier;
411
412 private readonly int _sampleIntervalMsHigh;
413
414 private readonly double _throughputErrorSmoothingFactor;
415
416 private readonly double _gainExponent;
417
418 private readonly double _maxSampleError;
419
421
422 private long _totalSamples;
423
424 private int _lastThreadCount;
425
427
429
431
433
435
436 private readonly double[] _samples;
437
438 private readonly double[] _threadCounts;
439
440 private int _currentSampleMs;
441
442 private readonly Random _randomIntervalGenerator = new Random();
443
444 private readonly LogEntry[] _log = new LogEntry[200];
445
446 private int _logStart;
447
448 private int _logSize;
449
451 {
452 _wavePeriod = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.WavePeriod", 4, allowNegative: false);
453 _maxThreadWaveMagnitude = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.MaxWaveMagnitude", 20, allowNegative: false);
454 _threadMagnitudeMultiplier = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.WaveMagnitudeMultiplier", 100, allowNegative: false) / 100.0;
455 _samplesToMeasure = _wavePeriod * AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.WaveHistorySize", 8, allowNegative: false);
456 _targetThroughputRatio = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.Bias", 15, allowNegative: false) / 100.0;
457 _targetSignalToNoiseRatio = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.TargetSignalToNoiseRatio", 300, allowNegative: false) / 100.0;
458 _maxChangePerSecond = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.MaxChangePerSecond", 4, allowNegative: false);
459 _maxChangePerSample = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.MaxChangePerSample", 20, allowNegative: false);
460 int int32Config = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.SampleIntervalLow", 10, allowNegative: false);
461 int int32Config2 = AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.SampleIntervalHigh", 200, allowNegative: false);
462 if (int32Config <= int32Config2)
463 {
464 _sampleIntervalMsLow = int32Config;
465 _sampleIntervalMsHigh = int32Config2;
466 }
467 else
468 {
471 }
472 _throughputErrorSmoothingFactor = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.ErrorSmoothingFactor", 1, allowNegative: false) / 100.0;
473 _gainExponent = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.GainExponent", 200, allowNegative: false) / 100.0;
474 _maxSampleError = (double)AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.HillClimbing.MaxSampleErrorPercent", 15, allowNegative: false) / 100.0;
475 _samples = new double[_samplesToMeasure];
476 _threadCounts = new double[_samplesToMeasure];
478 }
479
480 public (int newThreadCount, int newSampleMs) Update(int currentThreadCount, double sampleDurationSeconds, int numCompletions)
481 {
482 if (currentThreadCount != _lastThreadCount)
483 {
484 ForceChange(currentThreadCount, StateOrTransition.Initializing);
485 }
486 _secondsElapsedSinceLastChange += sampleDurationSeconds;
487 _completionsSinceLastChange += numCompletions;
488 sampleDurationSeconds += _accumulatedSampleDurationSeconds;
489 numCompletions += _accumulatedCompletionCount;
490 if (_totalSamples > 0 && ((double)currentThreadCount - 1.0) / (double)numCompletions >= _maxSampleError)
491 {
492 _accumulatedSampleDurationSeconds = sampleDurationSeconds;
493 _accumulatedCompletionCount = numCompletions;
494 return (newThreadCount: currentThreadCount, newSampleMs: 10);
495 }
498 double num = (double)numCompletions / sampleDurationSeconds;
499 if (NativeRuntimeEventSource.Log.IsEnabled())
500 {
501 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentSample(num, 0);
502 }
503 int num2 = (int)(_totalSamples % _samplesToMeasure);
504 _samples[num2] = num;
505 _threadCounts[num2] = currentThreadCount;
507 Complex complex = default(Complex);
508 Complex complex2 = default(Complex);
509 double num3 = 0.0;
510 Complex complex3 = default(Complex);
511 double num4 = 0.0;
514 if (num5 > _wavePeriod)
515 {
516 double num6 = 0.0;
517 double num7 = 0.0;
518 for (int i = 0; i < num5; i++)
519 {
520 num6 += _samples[(_totalSamples - num5 + i) % _samplesToMeasure];
521 num7 += _threadCounts[(_totalSamples - num5 + i) % _samplesToMeasure];
522 }
523 double num8 = num6 / (double)num5;
524 double num9 = num7 / (double)num5;
525 if (num8 > 0.0 && num9 > 0.0)
526 {
527 double period = (double)num5 / ((double)num5 / (double)_wavePeriod + 1.0);
528 double num10 = (double)num5 / ((double)num5 / (double)_wavePeriod - 1.0);
529 complex2 = GetWaveComponent(_samples, num5, _wavePeriod) / num8;
530 num3 = (GetWaveComponent(_samples, num5, period) / num8).Abs();
531 if (num10 <= (double)num5)
532 {
533 num3 = Math.Max(num3, (GetWaveComponent(_samples, num5, num10) / num8).Abs());
534 }
535 complex = GetWaveComponent(_threadCounts, num5, _wavePeriod) / num9;
536 if (_averageThroughputNoise == 0.0)
537 {
539 }
540 else
541 {
543 }
544 if (complex.Abs() > 0.0)
545 {
546 complex3 = (complex2 - _targetThroughputRatio * complex) / complex;
547 state = StateOrTransition.ClimbingMove;
548 }
549 else
550 {
551 complex3 = new Complex(0.0, 0.0);
552 state = StateOrTransition.Stabilizing;
553 }
554 double num11 = Math.Max(_averageThroughputNoise, num3);
555 num4 = ((!(num11 > 0.0)) ? 1.0 : (complex.Abs() / num11 / _targetSignalToNoiseRatio));
556 }
557 }
558 double num12 = Math.Min(1.0, Math.Max(-1.0, complex3.Real));
559 num12 *= Math.Min(1.0, Math.Max(0.0, num4));
560 double num13 = _maxChangePerSecond * sampleDurationSeconds;
561 num12 = Math.Pow(Math.Abs(num12), _gainExponent) * (double)((num12 >= 0.0) ? 1 : (-1)) * num13;
562 num12 = Math.Min(num12, _maxChangePerSample);
563 PortableThreadPool threadPoolInstance = ThreadPoolInstance;
564 if (num12 > 0.0 && threadPoolInstance._cpuUtilization > 95)
565 {
566 num12 = 0.0;
567 }
568 _currentControlSetting += num12;
570 val = Math.Min(val, _maxThreadWaveMagnitude);
571 val = Math.Max(val, 1);
572 int maxThreads = threadPoolInstance._maxThreads;
573 int minThreadsGoal = threadPoolInstance.MinThreadsGoal;
576 int val2 = (int)(_currentControlSetting + (double)(val * (_totalSamples / (_wavePeriod / 2) % 2)));
577 val2 = Math.Min(maxThreads, val2);
578 val2 = Math.Max(minThreadsGoal, val2);
579 if (NativeRuntimeEventSource.Log.IsEnabled())
580 {
581 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentStats(sampleDurationSeconds, num, complex.Real, complex2.Real, num3, _averageThroughputNoise, complex3.Real, num4, _currentControlSetting, (ushort)val, 0);
582 }
583 if (val2 != currentThreadCount)
584 {
588 }
589 int item = ((!(complex3.Real < 0.0) || val2 != minThreadsGoal) ? _currentSampleMs : ((int)(0.5 + (double)_currentSampleMs * (10.0 * Math.Min(0.0 - complex3.Real, 1.0)))));
590 return (newThreadCount: val2, newSampleMs: item);
591 }
592
603
604 private void LogTransition(int newThreadCount, double throughput, StateOrTransition stateOrTransition)
605 {
606 int num = (_logStart + _logSize) % 200;
607 if (_logSize == 200)
608 {
609 _logStart = (_logStart + 1) % 200;
610 _logSize--;
611 }
612 ref LogEntry reference = ref _log[num];
613 reference.tickCount = Environment.TickCount;
614 reference.stateOrTransition = stateOrTransition;
615 reference.newControlSetting = newThreadCount;
616 reference.lastHistoryCount = (int)(Math.Min(_totalSamples, _samplesToMeasure) / _wavePeriod) * _wavePeriod;
617 reference.lastHistoryMean = (float)throughput;
618 _logSize++;
619 if (NativeRuntimeEventSource.Log.IsEnabled())
620 {
621 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadAdjustmentAdjustment(throughput, (uint)newThreadCount, (NativeRuntimeEventSource.ThreadAdjustmentReasonMap)stateOrTransition, 0);
622 }
623 }
624
633
634 private Complex GetWaveComponent(double[] samples, int numSamples, double period)
635 {
636 double num = Math.PI * 2.0 / period;
637 double num2 = Math.Cos(num);
638 double num3 = 2.0 * num2;
639 double num4 = 0.0;
640 double num5 = 0.0;
641 double num6 = 0.0;
642 for (int i = 0; i < numSamples; i++)
643 {
644 num4 = num3 * num5 - num6 + samples[(_totalSamples - numSamples + i) % _samplesToMeasure];
645 num6 = num5;
646 num5 = num4;
647 }
648 return new Complex(num5 - num6 * num2, num6 * Math.Sin(num)) / numSamples;
649 }
650 }
651
652 private struct ThreadCounts
653 {
654 private ulong _data;
655
656 public short NumProcessingWork
657 {
658 get
659 {
660 return GetInt16Value(0);
661 }
662 set
663 {
665 }
666 }
667
669 {
670 get
671 {
672 return GetInt16Value(16);
673 }
674 set
675 {
676 SetInt16Value(value, 16);
677 }
678 }
679
680 public short NumThreadsGoal
681 {
682 get
683 {
684 return GetInt16Value(32);
685 }
686 set
687 {
688 SetInt16Value(value, 32);
689 }
690 }
691
692 private ThreadCounts(ulong data)
693 {
694 _data = data;
695 }
696
697 private short GetInt16Value(byte shift)
698 {
699 return (short)(_data >> (int)shift);
700 }
701
702 private void SetInt16Value(short value, byte shift)
703 {
704 _data = (_data & (ulong)(~(65535L << (int)shift))) | ((ulong)(ushort)value << (int)shift);
705 }
706
708 {
709 _data -= (ushort)value;
710 }
711
713 {
714 ThreadCounts threadCounts = new ThreadCounts(Interlocked.Decrement(ref _data));
715 }
716
718 {
719 _data -= (ulong)(ushort)value << 16;
720 }
721
723 {
724 ThreadCounts threadCounts = this;
725 ThreadCounts threadCounts2;
726 while (true)
727 {
728 threadCounts2 = threadCounts;
729 threadCounts2.NumThreadsGoal = value;
730 ThreadCounts threadCounts3 = InterlockedCompareExchange(threadCounts2, threadCounts);
731 if (threadCounts3 == threadCounts)
732 {
733 break;
734 }
735 threadCounts = threadCounts3;
736 }
737 return threadCounts2;
738 }
739
741 {
742 return new ThreadCounts(Volatile.Read(ref _data));
743 }
744
746 {
747 return new ThreadCounts(Interlocked.CompareExchange(ref _data, newCounts._data, oldCounts._data));
748 }
749
750 public static bool operator ==(ThreadCounts lhs, ThreadCounts rhs)
751 {
752 return lhs._data == rhs._data;
753 }
754
755 public override bool Equals([NotNullWhen(true)] object obj)
756 {
757 if (obj is ThreadCounts threadCounts)
758 {
759 return _data == threadCounts._data;
760 }
761 return false;
762 }
763
764 public override int GetHashCode()
765 {
766 return (int)_data + (int)(_data >> 32);
767 }
768 }
769
770 private sealed class WaitThreadNode
771 {
772 public WaitThread Thread { get; }
773
774 public WaitThreadNode Next { get; set; }
775
777 {
778 Thread = thread;
779 }
780 }
781
782 internal sealed class WaitThread
783 {
785
786 private readonly SafeWaitHandle[] _waitHandles = new SafeWaitHandle[64];
787
788 private int _numUserWaits;
789
791
793
794 private readonly AutoResetEvent _changeHandlesEvent = new AutoResetEvent(initialState: false);
795
796 internal bool AnyUserWaits => _numUserWaits != 0;
797
798 public WaitThread()
799 {
801 Thread thread = new Thread(WaitThreadStart, 262144)
802 {
803 IsThreadPoolThread = true,
804 IsBackground = true,
805 Name = ".NET ThreadPool Wait"
806 };
807 thread.UnsafeStart();
808 }
809
810 private void WaitThreadStart()
811 {
812 while (true)
813 {
814 int num = ProcessRemovals();
815 int tickCount = Environment.TickCount;
816 int num2 = -1;
817 if (num == 0)
818 {
819 num2 = 20000;
820 }
821 else
822 {
823 for (int i = 0; i < num; i++)
824 {
825 RegisteredWaitHandle registeredWaitHandle = _registeredWaits[i];
826 if (!registeredWaitHandle.IsInfiniteTimeout)
827 {
828 int num3 = Math.Max(0, registeredWaitHandle.TimeoutTimeMs - tickCount);
829 num2 = ((num2 != -1) ? Math.Min(num3, num2) : num3);
830 if (num2 == 0)
831 {
832 break;
833 }
834 }
835 }
836 }
837 int num4 = WaitHandle.WaitAny(new ReadOnlySpan<SafeWaitHandle>(_waitHandles, 0, num + 1), num2);
838 if (num4 >= 128 && num4 < 129 + num)
839 {
840 num4 += -128;
841 }
842 switch (num4)
843 {
844 case 0:
845 break;
846 default:
847 {
848 RegisteredWaitHandle registeredHandle = _registeredWaits[num4 - 1];
849 QueueWaitCompletion(registeredHandle, timedOut: false);
850 break;
851 }
852 case 258:
853 {
854 if (num == 0 && ThreadPoolInstance.TryRemoveWaitThread(this))
855 {
856 return;
857 }
858 tickCount = Environment.TickCount;
859 for (int j = 0; j < num; j++)
860 {
861 RegisteredWaitHandle registeredWaitHandle2 = _registeredWaits[j];
862 if (!registeredWaitHandle2.IsInfiniteTimeout && tickCount - registeredWaitHandle2.TimeoutTimeMs >= 0)
863 {
864 QueueWaitCompletion(registeredWaitHandle2, timedOut: true);
865 }
866 }
867 break;
868 }
869 }
870 }
871 }
872
873 private int ProcessRemovals()
874 {
875 PortableThreadPool threadPoolInstance = ThreadPoolInstance;
876 threadPoolInstance._waitThreadLock.Acquire();
877 try
878 {
879 if (_numPendingRemoves == 0 || _numUserWaits == 0)
880 {
881 return _numUserWaits;
882 }
883 int numUserWaits = _numUserWaits;
884 int numPendingRemoves = _numPendingRemoves;
885 for (int i = 0; i < _numPendingRemoves; i++)
886 {
887 RegisteredWaitHandle registeredWaitHandle = _pendingRemoves[i];
888 int numUserWaits2 = _numUserWaits;
889 int j;
890 for (j = 0; j < numUserWaits2 && registeredWaitHandle != _registeredWaits[j]; j++)
891 {
892 }
893 registeredWaitHandle.OnRemoveWait();
894 if (j + 1 < numUserWaits2)
895 {
896 int num = j;
897 int num2 = numUserWaits2;
898 Array.Copy(_registeredWaits, num + 1, _registeredWaits, num, num2 - (num + 1));
899 _registeredWaits[num2 - 1] = null;
900 num++;
901 num2++;
902 Array.Copy(_waitHandles, num + 1, _waitHandles, num, num2 - (num + 1));
903 _waitHandles[num2 - 1] = null;
904 }
905 else
906 {
907 _registeredWaits[j] = null;
908 _waitHandles[j + 1] = null;
909 }
910 _numUserWaits = numUserWaits2 - 1;
911 _pendingRemoves[i] = null;
912 registeredWaitHandle.Handle.DangerousRelease();
913 }
915 return _numUserWaits;
916 }
917 finally
918 {
919 threadPoolInstance._waitThreadLock.Release();
920 }
921 }
922
923 private void QueueWaitCompletion(RegisteredWaitHandle registeredHandle, bool timedOut)
924 {
925 registeredHandle.RequestCallback();
926 if (registeredHandle.Repeating)
927 {
928 registeredHandle.RestartTimeout();
929 }
930 else
931 {
932 UnregisterWait(registeredHandle, blocking: false);
933 }
935 }
936
938 {
939 if (_numUserWaits == 63)
940 {
941 return false;
942 }
943 bool success = false;
944 handle.Handle.DangerousAddRef(ref success);
946 _waitHandles[_numUserWaits + 1] = handle.Handle;
948 handle.WaitThread = this;
950 return true;
951 }
952
954 {
955 UnregisterWait(handle, blocking: true);
956 }
957
958 private void UnregisterWait(RegisteredWaitHandle handle, bool blocking)
959 {
960 bool flag = false;
961 PortableThreadPool threadPoolInstance = ThreadPoolInstance;
962 threadPoolInstance._waitThreadLock.Acquire();
963 try
964 {
966 {
968 {
971 }
972 flag = true;
973 }
974 }
975 finally
976 {
977 threadPoolInstance._waitThreadLock.Release();
978 }
979 if (blocking)
980 {
981 if (handle.IsBlocking)
982 {
983 handle.WaitForCallbacks();
984 }
985 else if (flag)
986 {
987 handle.WaitForRemoval();
988 }
989 }
990 }
991 }
992
993 private static class WorkerThread
994 {
995 private static readonly LowLevelLifoSemaphore s_semaphore = new LowLevelLifoSemaphore(0, 32767, AppContextConfigHelper.GetInt32Config("System.Threading.ThreadPool.UnfairSemaphoreSpinLimit", 70, allowNegative: false), delegate
996 {
997 if (NativeRuntimeEventSource.Log.IsEnabled())
998 {
999 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadWait((uint)ThreadPoolInstance._separated.counts.VolatileRead().NumExistingThreads, 0u, 0);
1000 }
1001 });
1002
1004
1005 private static void WorkerThreadStart()
1006 {
1007 Thread.CurrentThread.SetThreadPoolWorkerThreadName();
1008 PortableThreadPool threadPoolInstance = ThreadPoolInstance;
1009 if (NativeRuntimeEventSource.Log.IsEnabled())
1010 {
1011 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadStart((uint)threadPoolInstance._separated.counts.VolatileRead().NumExistingThreads, 0u, 0);
1012 }
1013 LowLevelLock threadAdjustmentLock = threadPoolInstance._threadAdjustmentLock;
1014 LowLevelLifoSemaphore lowLevelLifoSemaphore = s_semaphore;
1015 while (true)
1016 {
1017 bool spinWait = true;
1018 while (lowLevelLifoSemaphore.Wait(20000, spinWait))
1019 {
1020 bool flag = false;
1021 while (TakeActiveRequest(threadPoolInstance))
1022 {
1023 threadPoolInstance._separated.lastDequeueTime = Environment.TickCount;
1025 {
1026 flag = true;
1027 break;
1028 }
1029 if (threadPoolInstance._separated.numRequestedWorkers <= 0)
1030 {
1031 break;
1032 }
1035 {
1036 Thread.SpinWait(1);
1037 }
1038 }
1039 spinWait = !flag;
1040 if (!flag)
1041 {
1042 RemoveWorkingWorker(threadPoolInstance);
1043 }
1044 }
1045 threadAdjustmentLock.Acquire();
1046 try
1047 {
1048 ThreadCounts threadCounts = threadPoolInstance._separated.counts;
1049 while (true)
1050 {
1051 short numExistingThreads = threadCounts.NumExistingThreads;
1052 if (numExistingThreads <= threadCounts.NumProcessingWork)
1053 {
1054 break;
1055 }
1056 ThreadCounts newCounts = threadCounts;
1057 newCounts.SubtractNumExistingThreads(1);
1058 short num = (short)(numExistingThreads - 1);
1059 short newThreadCount = (newCounts.NumThreadsGoal = Math.Max(threadPoolInstance.MinThreadsGoal, Math.Min(num, threadCounts.NumThreadsGoal)));
1060 ThreadCounts threadCounts2 = threadPoolInstance._separated.counts.InterlockedCompareExchange(newCounts, threadCounts);
1061 if (threadCounts2 == threadCounts)
1062 {
1063 HillClimbing.ThreadPoolHillClimber.ForceChange(newThreadCount, HillClimbing.StateOrTransition.ThreadTimedOut);
1064 if (NativeRuntimeEventSource.Log.IsEnabled())
1065 {
1066 NativeRuntimeEventSource.Log.ThreadPoolWorkerThreadStop((uint)num, 0u, 0);
1067 }
1068 return;
1069 }
1070 threadCounts = threadCounts2;
1071 }
1072 }
1073 finally
1074 {
1075 threadAdjustmentLock.Release();
1076 }
1077 }
1078 }
1079
1080 private static void RemoveWorkingWorker(PortableThreadPool threadPoolInstance)
1081 {
1083 if (threadPoolInstance._separated.numRequestedWorkers > 0)
1084 {
1085 MaybeAddWorkingWorker(threadPoolInstance);
1086 }
1087 }
1088
1089 internal static void MaybeAddWorkingWorker(PortableThreadPool threadPoolInstance)
1090 {
1091 ThreadCounts threadCounts = threadPoolInstance._separated.counts;
1092 short numProcessingWork;
1093 short num;
1094 short numExistingThreads;
1095 short num2;
1096 while (true)
1097 {
1098 numProcessingWork = threadCounts.NumProcessingWork;
1099 if (numProcessingWork >= threadCounts.NumThreadsGoal)
1100 {
1101 return;
1102 }
1103 num = (short)(numProcessingWork + 1);
1104 numExistingThreads = threadCounts.NumExistingThreads;
1105 num2 = Math.Max(numExistingThreads, num);
1106 ThreadCounts newCounts = threadCounts;
1107 newCounts.NumProcessingWork = num;
1108 newCounts.NumExistingThreads = num2;
1109 ThreadCounts threadCounts2 = threadPoolInstance._separated.counts.InterlockedCompareExchange(newCounts, threadCounts);
1110 if (threadCounts2 == threadCounts)
1111 {
1112 break;
1113 }
1114 threadCounts = threadCounts2;
1115 }
1116 int num3 = num2 - numExistingThreads;
1117 int num4 = num - numProcessingWork;
1118 if (num4 > 0)
1119 {
1120 s_semaphore.Release(num4);
1121 }
1122 while (num3 > 0)
1123 {
1125 {
1126 num3--;
1127 continue;
1128 }
1129 threadCounts = threadPoolInstance._separated.counts;
1130 while (true)
1131 {
1132 ThreadCounts newCounts2 = threadCounts;
1133 newCounts2.SubtractNumProcessingWork((short)num3);
1134 newCounts2.SubtractNumExistingThreads((short)num3);
1135 ThreadCounts threadCounts3 = threadPoolInstance._separated.counts.InterlockedCompareExchange(newCounts2, threadCounts);
1136 if (!(threadCounts3 == threadCounts))
1137 {
1138 threadCounts = threadCounts3;
1139 continue;
1140 }
1141 break;
1142 }
1143 break;
1144 }
1145 }
1146
1147 internal static bool ShouldStopProcessingWorkNow(PortableThreadPool threadPoolInstance)
1148 {
1149 ThreadCounts threadCounts = threadPoolInstance._separated.counts;
1150 while (true)
1151 {
1152 if (threadCounts.NumProcessingWork <= threadCounts.NumThreadsGoal)
1153 {
1154 return false;
1155 }
1156 ThreadCounts newCounts = threadCounts;
1157 newCounts.SubtractNumProcessingWork(1);
1158 ThreadCounts threadCounts2 = threadPoolInstance._separated.counts.InterlockedCompareExchange(newCounts, threadCounts);
1159 if (threadCounts2 == threadCounts)
1160 {
1161 break;
1162 }
1163 threadCounts = threadCounts2;
1164 }
1165 return true;
1166 }
1167
1168 private static bool TakeActiveRequest(PortableThreadPool threadPoolInstance)
1169 {
1170 int num = threadPoolInstance._separated.numRequestedWorkers;
1171 while (num > 0)
1172 {
1173 int num2 = Interlocked.CompareExchange(ref threadPoolInstance._separated.numRequestedWorkers, num - 1, num);
1174 if (num2 == num)
1175 {
1176 return true;
1177 }
1178 num = num2;
1179 }
1180 return false;
1181 }
1182
1183 private static bool TryCreateWorkerThread()
1184 {
1185 try
1186 {
1187 Thread thread = new Thread(s_workerThreadStart);
1188 thread.IsThreadPoolThread = true;
1189 thread.IsBackground = true;
1190 thread.UnsafeStart();
1191 }
1192 catch (ThreadStartException)
1193 {
1194 return false;
1195 }
1196 catch (OutOfMemoryException)
1197 {
1198 return false;
1199 }
1200 return true;
1201 }
1202 }
1203
1205 {
1206 private uint _data;
1207
1208 public short Current => GetInt16Value(0);
1209
1210 public short HighWatermark => GetInt16Value(16);
1211
1213 {
1214 _data = data;
1215 }
1216
1217 private short GetInt16Value(byte shift)
1218 {
1219 return (short)(_data >> (int)shift);
1220 }
1221
1222 private void SetInt16Value(short value, byte shift)
1223 {
1224 _data = (_data & (uint)(~(65535 << (int)shift))) | (uint)((ushort)value << (int)shift);
1225 }
1226
1227 public void IncrementCurrent()
1228 {
1229 if (Current < HighWatermark)
1230 {
1231 _data++;
1232 }
1233 else
1234 {
1235 _data += 65537u;
1236 }
1237 }
1238
1239 public void DecrementCurrent()
1240 {
1241 _data--;
1242 }
1243
1245 {
1247 }
1248
1253
1255 {
1256 return lhs._data == rhs._data;
1257 }
1258
1259 public override bool Equals([NotNullWhen(true)] object obj)
1260 {
1261 if (obj is CountsOfThreadsProcessingUserCallbacks countsOfThreadsProcessingUserCallbacks)
1262 {
1263 return _data == countsOfThreadsProcessingUserCallbacks._data;
1264 }
1265 return false;
1266 }
1267
1268 public override int GetHashCode()
1269 {
1270 return (int)_data;
1271 }
1272 }
1273
1275 {
1276 public long _idleTime;
1277
1278 public long _kernelTime;
1279
1280 public long _userTime;
1281
1283 {
1284 get
1285 {
1286 if (!Interop.Kernel32.GetSystemTimes(out var idle, out var kernel, out var user))
1287 {
1288 return 0;
1289 }
1290 long num = user - _userTime + (kernel - _kernelTime);
1291 long num2 = num - (idle - _idleTime);
1292 _kernelTime = kernel;
1293 _userTime = user;
1294 _idleTime = idle;
1295 if (num > 0 && num2 > 0)
1296 {
1297 long val = num2 * 100 / num;
1298 val = Math.Min(val, 100L);
1299 return (int)val;
1300 }
1301 return 0;
1302 }
1303 }
1304 }
1305
1306 private static readonly short ForcedMinWorkerThreads = AppContextConfigHelper.GetInt16Config("System.Threading.ThreadPool.MinThreads", 0, allowNegative: false);
1307
1308 private static readonly short ForcedMaxWorkerThreads = AppContextConfigHelper.GetInt16Config("System.Threading.ThreadPool.MaxThreads", 0, allowNegative: false);
1309
1310 [ThreadStatic]
1311 private static object t_completionCountObject;
1312
1314
1315 private int _cpuUtilization;
1316
1317 private short _minThreads;
1318
1319 private short _maxThreads;
1320
1322
1324
1326
1327 private short _numBlockedThreads;
1328
1330
1332
1333 private long _memoryUsageBytes;
1334
1335 private long _memoryLimitBytes;
1336
1338
1340
1342
1344
1346
1348
1350
1352
1354 {
1355 get
1356 {
1357 if (_numBlockedThreads > 0)
1358 {
1359 return (short)Math.Min((ushort)(_minThreads + _numBlockedThreads), (ushort)_maxThreads);
1360 }
1361 return _minThreads;
1362 }
1363 }
1364
1366 {
1368 if (_minThreads > short.MaxValue)
1369 {
1370 _minThreads = short.MaxValue;
1371 }
1372 _maxThreads = ((ForcedMaxWorkerThreads > 0) ? ForcedMaxWorkerThreads : short.MaxValue);
1373 if (_maxThreads > short.MaxValue)
1374 {
1375 _maxThreads = short.MaxValue;
1376 }
1377 else if (_maxThreads < _minThreads)
1378 {
1380 }
1381 _separated.counts.NumThreadsGoal = _minThreads;
1382 }
1383
1384 public bool SetMinThreads(int workerThreads, int ioCompletionThreads)
1385 {
1386 if (workerThreads < 0 || ioCompletionThreads < 0)
1387 {
1388 return false;
1389 }
1390 bool flag = false;
1391 bool flag2 = false;
1393 try
1394 {
1395 if (workerThreads > _maxThreads || !ThreadPool.CanSetMinIOCompletionThreads(ioCompletionThreads))
1396 {
1397 return false;
1398 }
1399 ThreadPool.SetMinIOCompletionThreads(ioCompletionThreads);
1400 if (ForcedMinWorkerThreads != 0)
1401 {
1402 return true;
1403 }
1404 short num = (_minThreads = (short)Math.Max(1, Math.Min(workerThreads, 32767)));
1405 if (_numBlockedThreads > 0)
1406 {
1408 {
1410 flag2 = true;
1411 }
1412 }
1413 else if (_separated.counts.NumThreadsGoal < num)
1414 {
1417 {
1418 flag = true;
1419 }
1420 }
1421 }
1422 finally
1423 {
1425 }
1426 if (flag)
1427 {
1429 }
1430 else if (flag2)
1431 {
1432 GateThread.Wake(this);
1433 }
1434 return true;
1435 }
1436
1437 public int GetMinThreads()
1438 {
1439 return Volatile.Read(ref _minThreads);
1440 }
1441
1442 public bool SetMaxThreads(int workerThreads, int ioCompletionThreads)
1443 {
1444 if (workerThreads <= 0 || ioCompletionThreads <= 0)
1445 {
1446 return false;
1447 }
1449 try
1450 {
1451 if (workerThreads < _minThreads || !ThreadPool.CanSetMaxIOCompletionThreads(ioCompletionThreads))
1452 {
1453 return false;
1454 }
1455 ThreadPool.SetMaxIOCompletionThreads(ioCompletionThreads);
1456 if (ForcedMaxWorkerThreads != 0)
1457 {
1458 return true;
1459 }
1460 short num = (_maxThreads = (short)Math.Min(workerThreads, 32767));
1462 {
1464 }
1465 return true;
1466 }
1467 finally
1468 {
1470 }
1471 }
1472
1473 public int GetMaxThreads()
1474 {
1475 return Volatile.Read(ref _maxThreads);
1476 }
1477
1479 {
1480 ThreadCounts threadCounts = _separated.counts.VolatileRead();
1481 int num = _maxThreads - threadCounts.NumProcessingWork;
1482 if (num < 0)
1483 {
1484 return 0;
1485 }
1486 return num;
1487 }
1488
1493
1494 [MethodImpl(MethodImplOptions.NoInlining)]
1499
1500 private void NotifyWorkItemProgress(object threadLocalCompletionCountObject, int currentTimeMs)
1501 {
1502 ThreadInt64PersistentCounter.Increment(threadLocalCompletionCountObject);
1503 _separated.lastDequeueTime = currentTimeMs;
1504 if (ShouldAdjustMaxWorkersActive(currentTimeMs))
1505 {
1507 }
1508 }
1509
1514
1515 internal bool NotifyWorkItemComplete(object threadLocalCompletionCountObject, int currentTimeMs)
1516 {
1517 NotifyWorkItemProgress(threadLocalCompletionCountObject, currentTimeMs);
1519 }
1520
1522 {
1523 LowLevelLock threadAdjustmentLock = _threadAdjustmentLock;
1524 if (!threadAdjustmentLock.TryAcquire())
1525 {
1526 return;
1527 }
1528 bool flag = false;
1529 try
1530 {
1533 {
1534 return;
1535 }
1536 long currentSampleStartTime = _currentSampleStartTime;
1537 long timestamp = Stopwatch.GetTimestamp();
1538 long frequency = Stopwatch.Frequency;
1539 double num = (double)(timestamp - currentSampleStartTime) / (double)frequency;
1540 if (num * 1000.0 >= (double)(_threadAdjustmentIntervalMs / 2))
1541 {
1542 int tickCount = Environment.TickCount;
1543 int num2 = (int)_completionCounter.Count;
1544 int numCompletions = num2 - _separated.priorCompletionCount;
1545 short numThreadsGoal = counts.NumThreadsGoal;
1546 int num3;
1547 (num3, _threadAdjustmentIntervalMs) = HillClimbing.ThreadPoolHillClimber.Update(numThreadsGoal, num, numCompletions);
1548 if (numThreadsGoal != (short)num3)
1549 {
1551 if (num3 > numThreadsGoal)
1552 {
1553 flag = true;
1554 }
1555 }
1556 _separated.priorCompletionCount = num2;
1557 _separated.nextCompletedWorkRequestsTime = tickCount + _threadAdjustmentIntervalMs;
1559 _currentSampleStartTime = timestamp;
1560 }
1561 }
1562 finally
1563 {
1564 threadAdjustmentLock.Release();
1565 }
1566 if (flag)
1567 {
1569 }
1570 }
1571
1572 private bool ShouldAdjustMaxWorkersActive(int currentTimeMs)
1573 {
1575 {
1576 return false;
1577 }
1579 uint num2 = (uint)(_separated.nextCompletedWorkRequestsTime - num);
1580 uint num3 = (uint)(currentTimeMs - num);
1581 if (num3 < num2)
1582 {
1583 return false;
1584 }
1586 if (counts.NumProcessingWork > counts.NumThreadsGoal)
1587 {
1588 return false;
1589 }
1591 }
1592
1599
1600 private bool OnGen2GCCallback()
1601 {
1602 GCMemoryInfo gCMemoryInfo = GC.GetGCMemoryInfo();
1605 return true;
1606 }
1607
1609 {
1611 {
1612 return false;
1613 }
1614 bool flag = false;
1616 try
1617 {
1620 {
1622 {
1623 flag = true;
1624 }
1626 }
1627 }
1628 finally
1629 {
1631 }
1632 if (flag)
1633 {
1634 GateThread.Wake(this);
1635 }
1636 return true;
1637 }
1638
1640 {
1641 bool flag = false;
1643 try
1644 {
1647 {
1648 flag = true;
1650 }
1651 }
1652 finally
1653 {
1655 }
1656 if (flag)
1657 {
1658 GateThread.Wake(this);
1659 }
1660 }
1661
1662 private uint PerformBlockingAdjustment(bool previousDelayElapsed)
1663 {
1665 uint result;
1666 bool addWorker;
1667 try
1668 {
1669 result = PerformBlockingAdjustment(previousDelayElapsed, out addWorker);
1670 }
1671 finally
1672 {
1674 }
1675 if (addWorker)
1676 {
1678 }
1679 return result;
1680 }
1681
1682 private uint PerformBlockingAdjustment(bool previousDelayElapsed, out bool addWorker)
1683 {
1685 addWorker = false;
1686 short targetThreadsGoalForBlockingAdjustment = TargetThreadsGoalForBlockingAdjustment;
1688 short num = counts.NumThreadsGoal;
1689 if (num == targetThreadsGoalForBlockingAdjustment)
1690 {
1691 return 0u;
1692 }
1693 if (num > targetThreadsGoalForBlockingAdjustment)
1694 {
1696 {
1697 return 0u;
1698 }
1699 short num2 = Math.Min((short)(num - targetThreadsGoalForBlockingAdjustment), _numThreadsAddedDueToBlocking);
1701 num -= num2;
1703 HillClimbing.ThreadPoolHillClimber.ForceChange(num, HillClimbing.StateOrTransition.CooperativeBlocking);
1704 return 0u;
1705 }
1706 short num3 = (short)Math.Min((ushort)(_minThreads + BlockingConfig.ThreadsToAddWithoutDelay), (ushort)_maxThreads);
1707 short val = Math.Max(num3, Math.Min(counts.NumExistingThreads, _maxThreads));
1708 short num4 = Math.Min(targetThreadsGoalForBlockingAdjustment, val);
1709 short num5;
1710 if (num < num4)
1711 {
1712 num5 = num4;
1713 }
1714 else
1715 {
1716 if (!previousDelayElapsed)
1717 {
1718 goto IL_019f;
1719 }
1720 num5 = (short)(num + 1);
1721 }
1722 if (num5 > counts.NumExistingThreads)
1723 {
1724 long memoryLimitBytes = _memoryLimitBytes;
1725 if (memoryLimitBytes > 0)
1726 {
1727 long num6 = _memoryUsageBytes + (long)counts.NumExistingThreads * 65536L;
1728 long num7 = memoryLimitBytes * 8 / 10;
1729 if (num6 >= num7)
1730 {
1731 return 0u;
1732 }
1733 long val2 = counts.NumExistingThreads + (num7 - num6) / 65536;
1734 num5 = (short)Math.Min(num5, val2);
1735 if (num5 <= num)
1736 {
1737 return 0u;
1738 }
1739 }
1740 }
1741 _numThreadsAddedDueToBlocking += (short)(num5 - num);
1743 HillClimbing.ThreadPoolHillClimber.ForceChange(num5, HillClimbing.StateOrTransition.CooperativeBlocking);
1744 if (counts.NumProcessingWork >= num && _separated.numRequestedWorkers > 0)
1745 {
1746 addWorker = true;
1747 }
1748 num = num5;
1749 if (num >= targetThreadsGoalForBlockingAdjustment)
1750 {
1751 return 0u;
1752 }
1753 goto IL_019f;
1754 IL_019f:
1756 int num8 = 1 + (num - num3) / BlockingConfig.ThreadsPerDelayStep;
1758 }
1759
1760 internal static void EnsureGateThreadRunning()
1761 {
1763 }
1764
1766 {
1767 if (NativeRuntimeEventSource.Log.IsEnabled())
1768 {
1769 NativeRuntimeEventSource.Log.ThreadPoolIOEnqueue(handle);
1770 }
1772 try
1773 {
1774 WaitThreadNode waitThreadNode = _waitThreadsHead;
1775 if (waitThreadNode == null)
1776 {
1777 waitThreadNode = (_waitThreadsHead = new WaitThreadNode(new WaitThread()));
1778 }
1779 WaitThreadNode waitThreadNode2;
1780 do
1781 {
1782 if (waitThreadNode.Thread.RegisterWaitHandle(handle))
1783 {
1784 return;
1785 }
1786 waitThreadNode2 = waitThreadNode;
1787 waitThreadNode = waitThreadNode.Next;
1788 }
1789 while (waitThreadNode != null);
1790 waitThreadNode2.Next = new WaitThreadNode(new WaitThread());
1791 waitThreadNode2.Next.Thread.RegisterWaitHandle(handle);
1792 }
1793 finally
1794 {
1796 }
1797 }
1798
1799 internal static void CompleteWait(RegisteredWaitHandle handle, bool timedOut)
1800 {
1801 if (NativeRuntimeEventSource.Log.IsEnabled())
1802 {
1803 NativeRuntimeEventSource.Log.ThreadPoolIODequeue(handle);
1804 }
1805 handle.PerformCallback(timedOut);
1806 }
1807
1808 private bool TryRemoveWaitThread(WaitThread thread)
1809 {
1811 try
1812 {
1813 if (thread.AnyUserWaits)
1814 {
1815 return false;
1816 }
1817 RemoveWaitThread(thread);
1818 }
1819 finally
1820 {
1822 }
1823 return true;
1824 }
1825
1826 private void RemoveWaitThread(WaitThread thread)
1827 {
1828 WaitThreadNode waitThreadNode = _waitThreadsHead;
1829 if (waitThreadNode.Thread == thread)
1830 {
1831 _waitThreadsHead = waitThreadNode.Next;
1832 return;
1833 }
1834 WaitThreadNode waitThreadNode2;
1835 do
1836 {
1837 waitThreadNode2 = waitThreadNode;
1838 waitThreadNode = waitThreadNode.Next;
1839 }
1840 while (waitThreadNode != null && waitThreadNode.Thread != thread);
1841 if (waitThreadNode != null)
1842 {
1843 waitThreadNode2.Next = waitThreadNode.Next;
1844 }
1845 }
1846
1847 public void ReportThreadStatus(bool isProcessingUserCallback)
1848 {
1850 while (true)
1851 {
1852 CountsOfThreadsProcessingUserCallbacks newCounts = countsOfThreadsProcessingUserCallbacks;
1853 if (isProcessingUserCallback)
1854 {
1855 newCounts.IncrementCurrent();
1856 }
1857 else
1858 {
1859 newCounts.DecrementCurrent();
1860 }
1861 CountsOfThreadsProcessingUserCallbacks countsOfThreadsProcessingUserCallbacks2 = _countsOfThreadsProcessingUserCallbacks.InterlockedCompareExchange(newCounts, countsOfThreadsProcessingUserCallbacks);
1862 if (!(countsOfThreadsProcessingUserCallbacks2 == countsOfThreadsProcessingUserCallbacks))
1863 {
1864 countsOfThreadsProcessingUserCallbacks = countsOfThreadsProcessingUserCallbacks2;
1865 continue;
1866 }
1867 break;
1868 }
1869 }
1870
1872 {
1874 CountsOfThreadsProcessingUserCallbacks countsOfThreadsProcessingUserCallbacks2;
1875 while (true)
1876 {
1877 CountsOfThreadsProcessingUserCallbacks newCounts = countsOfThreadsProcessingUserCallbacks;
1878 newCounts.ResetHighWatermark();
1879 countsOfThreadsProcessingUserCallbacks2 = _countsOfThreadsProcessingUserCallbacks.InterlockedCompareExchange(newCounts, countsOfThreadsProcessingUserCallbacks);
1880 if (countsOfThreadsProcessingUserCallbacks2 == countsOfThreadsProcessingUserCallbacks || countsOfThreadsProcessingUserCallbacks2.HighWatermark == countsOfThreadsProcessingUserCallbacks2.Current)
1881 {
1882 break;
1883 }
1884 countsOfThreadsProcessingUserCallbacks = countsOfThreadsProcessingUserCallbacks2;
1885 }
1886 return countsOfThreadsProcessingUserCallbacks2.HighWatermark;
1887 }
1888}
static bool GetSystemTimes(out long idle, out long kernel, out long user)
static short GetInt16Config(string configName, short defaultValue, bool allowNegative=true)
static bool GetBooleanConfig(string configName, bool defaultValue)
static int GetInt32Config(string configName, int defaultValue, bool allowNegative=true)
int IList. IndexOf(object value)
Definition Array.cs:1228
static unsafe void Copy(Array sourceArray, Array destinationArray, int length)
Definition Array.cs:624
static readonly long Frequency
Definition Stopwatch.cs:13
static int ProcessorCount
static bool IsSingleProcessor
static int TickCount
static GCMemoryInfo GetGCMemoryInfo()
Definition GC.cs:37
Definition GC.cs:8
static void Register(Func< bool > callback)
static double Cos(double d)
static byte Min(byte val1, byte val2)
Definition Math.cs:912
static double Sqrt(double d)
static double Pow(double x, double y)
static double Abs(double value)
static double Sin(double a)
static byte Max(byte val1, byte val2)
Definition Math.cs:738
virtual int Next()
Definition Random.cs:651
static int CompareExchange(ref int location1, int value, int comparand)
static int Exchange(ref int location1, int value)
static int Decrement(ref int location)
static int Increment(ref int location)
bool Wait(int timeoutMs, bool spinWait)
static void Wake(PortableThreadPool threadPoolInstance)
static void EnsureRunning(PortableThreadPool threadPoolInstance)
static readonly AutoResetEvent RunGateThreadEvent
static void EnsureRunningSlow(PortableThreadPool threadPoolInstance)
static bool SufficientDelaySinceLastDequeue(PortableThreadPool threadPoolInstance)
static void CreateGateThread(PortableThreadPool threadPoolInstance)
Complex GetWaveComponent(double[] samples, int numSamples, double period)
void ChangeThreadCount(int newThreadCount, StateOrTransition state)
void LogTransition(int newThreadCount, double throughput, StateOrTransition stateOrTransition)
void ForceChange(int newThreadCount, StateOrTransition state)
void UnregisterWait(RegisteredWaitHandle handle)
bool RegisterWaitHandle(RegisteredWaitHandle handle)
readonly RegisteredWaitHandle[] _registeredWaits
readonly RegisteredWaitHandle[] _pendingRemoves
void UnregisterWait(RegisteredWaitHandle handle, bool blocking)
void QueueWaitCompletion(RegisteredWaitHandle registeredHandle, bool timedOut)
static void RemoveWorkingWorker(PortableThreadPool threadPoolInstance)
static readonly LowLevelLifoSemaphore s_semaphore
static bool ShouldStopProcessingWorkNow(PortableThreadPool threadPoolInstance)
static void MaybeAddWorkingWorker(PortableThreadPool threadPoolInstance)
static bool TakeActiveRequest(PortableThreadPool threadPoolInstance)
bool TryRemoveWaitThread(WaitThread thread)
PendingBlockingAdjustment _pendingBlockingAdjustment
CountsOfThreadsProcessingUserCallbacks _countsOfThreadsProcessingUserCallbacks
readonly ThreadInt64PersistentCounter _completionCounter
bool SetMinThreads(int workerThreads, int ioCompletionThreads)
static void CompleteWait(RegisteredWaitHandle handle, bool timedOut)
bool ShouldAdjustMaxWorkersActive(int currentTimeMs)
bool SetMaxThreads(int workerThreads, int ioCompletionThreads)
uint PerformBlockingAdjustment(bool previousDelayElapsed)
bool NotifyWorkItemComplete(object threadLocalCompletionCountObject, int currentTimeMs)
void ReportThreadStatus(bool isProcessingUserCallback)
void NotifyWorkItemProgress(object threadLocalCompletionCountObject, int currentTimeMs)
static readonly PortableThreadPool ThreadPoolInstance
uint PerformBlockingAdjustment(bool previousDelayElapsed, out bool addWorker)
void RegisterWaitHandle(RegisteredWaitHandle handle)
static void Increment(object threadLocalCountObject)
static void SetMinIOCompletionThreads(int ioCompletionThreads)
static bool EnableWorkerTracking
Definition ThreadPool.cs:60
static bool PerformRuntimeSpecificGateActivities(int cpuUtilization)
static void SetMaxIOCompletionThreads(int ioCompletionThreads)
static void UnsafeQueueWaitCompletion(CompleteWaitThreadPoolWorkItem completeWaitWorkItem)
static bool CanSetMinIOCompletionThreads(int ioCompletionThreads)
static bool CanSetMaxIOCompletionThreads(int ioCompletionThreads)
static Thread CurrentThread
Definition Thread.cs:312
static void SpinWait(int iterations)
Definition Thread.cs:404
static void UninterruptibleSleep0()
void UnsafeStart(object? parameter)
Definition Thread.cs:580
static bool Read(ref bool location)
Definition Volatile.cs:67
static void Write(ref bool location, bool value)
Definition Volatile.cs:74
static int WaitAny(WaitHandle[] waitHandles, int millisecondsTimeout)
SafeWaitHandle SafeWaitHandle
Definition WaitHandle.cs:54
delegate void ThreadStart()
long HighMemoryLoadThresholdBytes
CountsOfThreadsProcessingUserCallbacks InterlockedCompareExchange(CountsOfThreadsProcessingUserCallbacks newCounts, CountsOfThreadsProcessingUserCallbacks oldCounts)
static bool operator==(CountsOfThreadsProcessingUserCallbacks lhs, CountsOfThreadsProcessingUserCallbacks rhs)
bool ShouldPerformGateActivities(int currentTimeMs, bool wasSignaledToWake)
bool HasBlockingAdjustmentDelayElapsed(int currentTimeMs, bool wasSignaledToWake)
void SetBlockingAdjustmentTimeAndDelay(int currentTimeMs, uint delayMs)
static Complex operator*(double scalar, Complex complex)
static Complex operator-(Complex lhs, Complex rhs)
static Complex operator/(Complex complex, double scalar)
static bool operator==(ThreadCounts lhs, ThreadCounts rhs)
override bool Equals([NotNullWhen(true)] object obj)
ThreadCounts InterlockedCompareExchange(ThreadCounts newCounts, ThreadCounts oldCounts)