| File: Internal\Infrastructure\ResourceCounter.cs | Web Access |
| Project: src\aspnetcore\src\Servers\Kestrel\Core\src\Microsoft.AspNetCore.Server.Kestrel.Core.csproj (Microsoft.AspNetCore.Server.Kestrel.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; namespace Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Infrastructure; internal abstract class ResourceCounter { public abstract bool TryLockOne(); public abstract void ReleaseOne(); public static ResourceCounter Unlimited { get; } = new UnlimitedCounter(); public static ResourceCounter Quota(long amount) => new FiniteCounter(amount); private sealed class UnlimitedCounter : ResourceCounter { public override bool TryLockOne() => true; public override void ReleaseOne() { } } internal sealed class FiniteCounter : ResourceCounter { private readonly long _max; private long _count; public FiniteCounter(long max) { if (max < 0) { throw new ArgumentOutOfRangeException(CoreStrings.NonNegativeNumberRequired); } _max = max; } public override bool TryLockOne() { var count = _count; // Exit if count == MaxValue as incrementing would overflow. while (count < _max && count != long.MaxValue) { var prev = Interlocked.CompareExchange(ref _count, count + 1, count); if (prev == count) { return true; } // Another thread changed the count before us. Try again with the new counter value. count = prev; } return false; } public override void ReleaseOne() { Interlocked.Decrement(ref _count); Debug.Assert(_count >= 0, "Resource count is negative. More resources were released than were locked."); } // for testing internal long Count { get => _count; set => _count = value; } } }