Please disclose if your mod was created primarily using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Agrona v1.49.0
BepInEx/core/Agrona/netstandard2.0/Adaptive.Agrona.dll
Decompiled 5 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.MemoryMappedFiles; using System.Linq; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading; using Adaptive.Agrona.Collections; using Adaptive.Agrona.Concurrent; using Adaptive.Agrona.Concurrent.Status; using Adaptive.Agrona.Util; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Adaptive Financial Consulting Ltd.")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright Adaptive Financial Consulting Ltd.")] [assembly: AssemblyDescription("Agrona provides a library of data structures and utility methods that are a common need when building high-performance applications in .NET")] [assembly: AssemblyFileVersion("1.49.0.0")] [assembly: AssemblyInformationalVersion("1.49.0+9179232fd342a742df7b8c88046b0306e4a0fc2e")] [assembly: AssemblyProduct("Agrona libraries initially included in Aeron Client")] [assembly: AssemblyTitle("Adaptive.Agrona")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.49.0.0")] [module: UnverifiableCode] namespace Adaptive.Agrona { public class BitUtil { public const int SIZE_OF_BYTE = 1; public const int SIZE_OF_BOOLEAN = 1; public const int SIZE_OF_CHAR = 2; public const int SIZE_OF_SHORT = 2; public const int SIZE_OF_INT = 4; public const int SIZE_OF_FLOAT = 4; public const int SIZE_OF_LONG = 8; public const int SIZE_OF_DOUBLE = 8; public const int CACHE_LINE_LENGTH = 64; private static readonly byte[] HexDigitTable; private static readonly byte[] FromHexDigitTable; private const int LastDigitMask = 1; private static readonly Encoding Utf8Encoding; private static readonly ThreadLocal<Random> threadLocalRandom; static BitUtil() { HexDigitTable = new byte[16] { 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 97, 98, 99, 100, 101, 102 }; Utf8Encoding = Encoding.UTF8; threadLocalRandom = new ThreadLocal<Random>(() => new Random()); FromHexDigitTable = new byte[128]; FromHexDigitTable[48] = 0; FromHexDigitTable[49] = 1; FromHexDigitTable[50] = 2; FromHexDigitTable[51] = 3; FromHexDigitTable[52] = 4; FromHexDigitTable[53] = 5; FromHexDigitTable[54] = 6; FromHexDigitTable[55] = 7; FromHexDigitTable[56] = 8; FromHexDigitTable[57] = 9; FromHexDigitTable[97] = 10; FromHexDigitTable[65] = 10; FromHexDigitTable[98] = 11; FromHexDigitTable[66] = 11; FromHexDigitTable[99] = 12; FromHexDigitTable[67] = 12; FromHexDigitTable[100] = 13; FromHexDigitTable[68] = 13; FromHexDigitTable[101] = 14; FromHexDigitTable[69] = 14; FromHexDigitTable[102] = 15; FromHexDigitTable[70] = 15; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int FindNextPositivePowerOfTwo(int value) { return 1 << 32 - IntUtil.NumberOfLeadingZeros(value - 1); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Align(int value, int alignment) { return (value + (alignment - 1)) & -alignment; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long Align(long value, long alignment) { return (value + (alignment - 1)) & -alignment; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] FromHexByteArray(byte[] buffer) { byte[] array = new byte[buffer.Length >> 1]; for (int i = 0; i < buffer.Length; i += 2) { array[i >> 1] = (byte)((FromHexDigitTable[buffer[i]] << 4) | FromHexDigitTable[buffer[i + 1]]); } return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] ToHexByteArray(byte[] buffer) { return ToHexByteArray(buffer, 0, buffer.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] ToHexByteArray(byte[] buffer, int offset, int length) { byte[] array = new byte[length << 1]; for (int i = 0; i < length << 1; i += 2) { byte b = buffer[offset + (i >> 1)]; array[i] = HexDigitTable[(b >> 4) & 0xF]; array[i + 1] = HexDigitTable[b & 0xF]; } return array; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static byte[] FromHex(string value) { return FromHexByteArray(Utf8Encoding.GetBytes(value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHex(byte[] buffer, int offset, int length) { byte[] array = ToHexByteArray(buffer, offset, length); return Utf8Encoding.GetString(array, 0, array.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static string ToHex(byte[] buffer) { byte[] array = ToHexByteArray(buffer); return Utf8Encoding.GetString(array, 0, array.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsEven(int value) { return (value & 1) == 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsPowerOfTwo(int value) { if (value > 0) { return (value & (~value + 1)) == value; } return false; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Next(int current, int max) { int num = current + 1; if (num == max) { num = 0; } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int Previous(int current, int max) { if (current == 0) { return max - 1; } return current - 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool IsAligned(long address, int alignment) { if (!IsPowerOfTwo(alignment)) { ThrowHelper.ThrowArgumentException("Alignment must be a power of 2: alignment=" + alignment); } return (address & (alignment - 1)) == 0; } public static int GenerateRandomisedId() { return threadLocalRandom.Value.Next(); } } public class BufferUtil { public static readonly byte[] NullBytes = Encoding.UTF8.GetBytes("null"); public static void BoundsCheck(byte[] buffer, long index, int length) { int num = buffer.Length; long num2 = index + length; if (index < 0 || num2 > num) { ThrowHelper.ThrowIndexOutOfRangeException($"index={index:D}, length={length:D}, capacity={num:D}"); } } public static ByteBuffer AllocateDirectAligned(int capacity, int alignment) { return new ByteBuffer(capacity, alignment); } public static ByteBuffer AllocateDirect(int capacity) { return new ByteBuffer(capacity, 8); } public static ByteBuffer Allocate(int capacity) { return new ByteBuffer(capacity, 8); } } public class ByteBuffer : IDisposable { private GCHandle _bufferHandle; private bool _disposed; public IntPtr BufferPointer { get; } public int Capacity { get; } public ByteBuffer(int capacity, int byteAlignment) { Capacity = capacity; byte[] value = new byte[capacity + byteAlignment]; _bufferHandle = GCHandle.Alloc(value, GCHandleType.Pinned); long num = _bufferHandle.AddrOfPinnedObject().ToInt64(); num = (num + byteAlignment - 1) & ~(byteAlignment - 1); BufferPointer = new IntPtr(num); } ~ByteBuffer() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); } private void Dispose(bool disposing) { if (!_disposed) { _bufferHandle.Free(); _disposed = true; } } public unsafe byte Get(int index) { return ((byte*)BufferPointer.ToPointer())[index]; } } public enum ByteOrder { BigEndian, LittleEndian } public struct CacheLinePadding { private long p1; private long p2; private long p3; private long p4; private long p5; private long p6; private long p7; private long p8; private long p9; private long p10; private long p11; private long p12; private long p13; private long p14; private long p15; public override string ToString() { return string.Format("{0}: {1}, {2}: {3}, {4}: {5}, {6}: {7}, {8}: {9}, {10}: {11}, {12}: {13}, {14}: {15}, {16}: {17}, {18}: {19}, {20}: {21}, {22}: {23}, {24}: {25}, {26}: {27}, {28}: {29}", "p1", p1, "p2", p2, "p3", p3, "p4", p4, "p5", p5, "p6", p6, "p7", p7, "p8", p8, "p9", p9, "p10", p10, "p11", p11, "p12", p12, "p13", p13, "p14", p14, "p15", p15); } } public static class CloseHelper { public static void QuietDispose(IDisposable disposable) { try { disposable?.Dispose(); } catch { } } public static void QuietDispose(Action disposable) { try { disposable?.Invoke(); } catch { } } public static void Dispose(ErrorHandler errorHandler, IDisposable disposable) { try { disposable?.Dispose(); } catch (Exception exception) { errorHandler(exception); } } public static void Dispose(IErrorHandler errorHandler, IDisposable disposable) { try { disposable?.Dispose(); } catch (Exception exception) { errorHandler.OnError(exception); } } public static void Dispose(ErrorHandler errorHandler, Action disposable) { try { disposable?.Invoke(); } catch (Exception exception) { errorHandler(exception); } } public static void Dispose(IDisposable disposable) { disposable?.Dispose(); } public static void CloseAll(IEnumerable<IDisposable> disposables) { if (disposables == null || !disposables.Any()) { return; } Exception ex = null; foreach (IDisposable disposable in disposables) { if (disposable != null) { try { disposable.Dispose(); } catch (Exception ex2) { ex = ((ex != null) ? new Exception(null, ex2) : ex2); } } } if (ex == null) { return; } throw ex; } public static void CloseAll<T>(IErrorHandler errorHandler, ICollection<T> disposables) where T : IDisposable { if (disposables == null) { return; } NullReferenceException ex = null; List<Exception> list = null; foreach (T disposable in disposables) { if (disposable == null) { continue; } try { disposable.Dispose(); } catch (Exception ex2) { if (errorHandler == null) { if (ex == null) { ex = new NullReferenceException("errorHandler is null"); } if (list == null) { list = new List<Exception>(); } list.Add(ex2); } else { errorHandler.OnError(ex2); } } } if (ex == null) { return; } if (list.Count > 0) { List<Exception> list2 = new List<Exception>(1 + list.Count); list2.Add(ex); list2.AddRange(list); throw new AggregateException("One or more errors occurred while disposing.", list2); } throw ex; } } public interface DelegatingErrorHandler : IErrorHandler { void Next(IErrorHandler errorHandler); } public static class EndianessConverter { private static readonly ByteOrder NativeByteOrder = (BitConverter.IsLittleEndian ? ByteOrder.LittleEndian : ByteOrder.BigEndian); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short ApplyInt16(ByteOrder byteOrder, short value) { if (byteOrder == NativeByteOrder) { return value; } return (short)((long)(((ulong)value & 0xFFuL) << 8) | ((long)((ulong)value & 0xFF00uL) >> 8)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ushort ApplyUint16(ByteOrder byteOrder, ushort value) { if (byteOrder == NativeByteOrder) { return value; } return (ushort)((uint)((value & 0xFF) << 8) | ((uint)(value & 0xFF00) >> 8)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int ApplyInt32(ByteOrder byteOrder, int value) { if (byteOrder == NativeByteOrder) { return value; } return (int)((long)((((ulong)value & 0xFFuL) << 24) | (((ulong)value & 0xFF00uL) << 8)) | ((long)((ulong)value & 0xFF0000uL) >> 8) | ((value & 0xFF000000u) >> 24)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static uint ApplyUint32(ByteOrder byteOrder, uint value) { if (byteOrder == NativeByteOrder) { return value; } return ((value & 0xFF) << 24) | ((value & 0xFF00) << 8) | ((value & 0xFF0000) >> 8) | ((value & 0xFF000000u) >> 24); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static ulong ApplyUint64(ByteOrder byteOrder, ulong value) { if (byteOrder == NativeByteOrder) { return value; } return ((value & 0xFF) << 56) | ((value & 0xFF00) << 40) | ((value & 0xFF0000) << 24) | ((value & 0xFF000000u) << 8) | ((value & 0xFF00000000L) >> 8) | ((value & 0xFF0000000000L) >> 24) | ((value & 0xFF000000000000L) >> 40) | ((value & 0xFF00000000000000uL) >> 56); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long ApplyInt64(ByteOrder byteOrder, long value) { if (byteOrder == NativeByteOrder) { return value; } return IPAddress.HostToNetworkOrder(value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static double ApplyDouble(ByteOrder byteOrder, double value) { if (byteOrder == NativeByteOrder) { return value; } return BitConverter.Int64BitsToDouble(IPAddress.HostToNetworkOrder(BitConverter.DoubleToInt64Bits(value))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static float ApplyFloat(ByteOrder byteOrder, float value) { if (byteOrder == NativeByteOrder) { return value; } int value2 = *(int*)(&value); int num = ApplyInt32(byteOrder, value2); return *(float*)(&num); } } public delegate void ErrorHandler(Exception exception); public class ExpandableArrayBuffer : IMutableDirectBuffer, IDirectBuffer, IComparable<IDirectBuffer> { public static readonly int MAX_ARRAY_LENGTH = 2147483639; public const int INITIAL_CAPACITY = 128; private byte[] _byteArray; private GCHandle _pinnedGcHandle; private unsafe byte* _pBuffer; public unsafe IntPtr BufferPointer => new IntPtr(_pBuffer); public byte[] ByteArray => _byteArray; public ByteBuffer ByteBuffer => null; public int Capacity => _byteArray.Length; public bool IsExpandable => true; public ExpandableArrayBuffer() : this(128) { } public ExpandableArrayBuffer(int initialCapacity) { AllocateAndPinArray(initialCapacity); } private unsafe void AllocateAndPinArray(int capacity) { _byteArray = new byte[capacity]; _pinnedGcHandle = GCHandle.Alloc(_byteArray, GCHandleType.Pinned); _pBuffer = (byte*)_pinnedGcHandle.AddrOfPinnedObject().ToPointer(); } ~ExpandableArrayBuffer() { if (_pinnedGcHandle.IsAllocated) { _pinnedGcHandle.Free(); } } public void Wrap(byte[] buffer) { throw new NotSupportedException(); } public void Wrap(byte[] buffer, int offset, int length) { throw new NotSupportedException(); } public void Wrap(IDirectBuffer buffer) { throw new NotSupportedException(); } public void Wrap(IDirectBuffer buffer, int offset, int length) { throw new NotSupportedException(); } public void Wrap(IntPtr pointer, int length) { throw new NotSupportedException(); } public void Wrap(IntPtr pointer, int offset, int length) { throw new NotSupportedException(); } public int CompareTo(IDirectBuffer other) { throw new NotSupportedException(); } public void CheckLimit(int limit) { EnsureCapacity(limit, 1); } public unsafe long GetLong(int index, ByteOrder byteOrder) { BoundsCheck0(index, 8); long value = *(long*)(_pBuffer + index); return EndianessConverter.ApplyInt64(byteOrder, value); } public unsafe long GetLong(int index) { BoundsCheck0(index, 8); return *(long*)(_pBuffer + index); } public unsafe int GetInt(int index, ByteOrder byteOrder) { BoundsCheck0(index, 4); int value = *(int*)(_pBuffer + index); return EndianessConverter.ApplyInt32(byteOrder, value); } public unsafe int GetInt(int index) { BoundsCheck0(index, 4); return *(int*)(_pBuffer + index); } public unsafe double GetDouble(int index) { BoundsCheck0(index, 8); return *(double*)(_pBuffer + index); } public unsafe float GetFloat(int index) { BoundsCheck0(index, 4); return *(float*)(_pBuffer + index); } public unsafe short GetShort(int index, ByteOrder byteOrder) { BoundsCheck0(index, 2); short value = *(short*)(_pBuffer + index); return EndianessConverter.ApplyInt16(byteOrder, value); } public unsafe short GetShort(int index) { BoundsCheck0(index, 2); return *(short*)(_pBuffer + index); } public unsafe char GetChar(int index) { BoundsCheck0(index, 2); return *(char*)(_pBuffer + index); } public byte GetByte(int index) { return _byteArray[index]; } public void GetBytes(int index, byte[] dst) { Array.Copy(_byteArray, index, dst, 0, dst.Length); } public void GetBytes(int index, byte[] dst, int offset, int length) { Array.Copy(_byteArray, index, dst, offset, length); } public void GetBytes(int index, IMutableDirectBuffer dstBuffer, int dstIndex, int length) { dstBuffer.PutBytes(dstIndex, _byteArray, index, length); } public string GetStringUtf8(int index) { int @int = GetInt(index); return GetStringUtf8(index, @int); } public string GetStringAscii(int index) { int @int = GetInt(index); return GetStringAscii(index, @int); } public int GetStringAscii(int index, StringBuilder appendable) { int @int = GetInt(index); return GetStringAscii(index, @int, appendable); } public unsafe int GetStringAscii(int index, int length, StringBuilder appendable) { int i = index + 4; for (int num = index + 4 + length; i < num; i++) { char c = *(char*)(_pBuffer + index); appendable.Append((c > '\u007f') ? '?' : c); } return length; } public string GetStringUtf8(int index, int length) { byte[] array = new byte[length]; GetBytes(index + 4, array); return Encoding.UTF8.GetString(array); } public string GetStringAscii(int index, int length) { byte[] array = new byte[length]; GetBytes(index + 4, array); return Encoding.ASCII.GetString(array); } public string GetStringWithoutLengthUtf8(int index, int length) { byte[] array = new byte[length]; GetBytes(index, array); return Encoding.UTF8.GetString(array); } public string GetStringWithoutLengthAscii(int index, int length) { byte[] array = new byte[length]; GetBytes(index, array); return Encoding.ASCII.GetString(array); } public void BoundsCheck(int index, int length) { BoundsCheck0(index, length); } public unsafe void SetMemory(int index, int length, byte value) { EnsureCapacity(index, length); Unsafe.InitBlock(_pBuffer + index, value, (uint)length); } public unsafe void PutLong(int index, long value, ByteOrder byteOrder) { EnsureCapacity(index, 8); value = EndianessConverter.ApplyInt64(byteOrder, value); *(long*)(_pBuffer + index) = value; } public unsafe void PutLong(int index, long value) { EnsureCapacity(index, 8); BoundsCheck0(index, 8); *(long*)(_pBuffer + index) = value; } public unsafe void PutInt(int index, int value, ByteOrder byteOrder) { EnsureCapacity(index, 4); value = EndianessConverter.ApplyInt32(byteOrder, value); *(int*)(_pBuffer + index) = value; } public unsafe void PutInt(int index, int value) { EnsureCapacity(index, 4); *(int*)(_pBuffer + index) = value; } public unsafe void PutDouble(int index, double value) { EnsureCapacity(index, 8); *(double*)(_pBuffer + index) = value; } public unsafe void PutFloat(int index, float value) { EnsureCapacity(index, 4); *(float*)(_pBuffer + index) = value; } public unsafe void PutShort(int index, short value, ByteOrder byteOrder) { EnsureCapacity(index, 2); value = EndianessConverter.ApplyInt16(byteOrder, value); *(short*)(_pBuffer + index) = value; } public unsafe void PutShort(int index, short value) { EnsureCapacity(index, 2); *(short*)(_pBuffer + index) = value; } public unsafe void PutChar(int index, char value) { EnsureCapacity(index, 2); *(char*)(_pBuffer + index) = value; } public unsafe void PutByte(int index, byte value) { EnsureCapacity(index, 1); _pBuffer[index] = value; } public void PutBytes(int index, byte[] src) { PutBytes(index, src, 0, src.Length); } public void PutBytes(int index, byte[] src, int offset, int length) { EnsureCapacity(index, length); Array.Copy(src, offset, _byteArray, index, length); } public unsafe void PutBytes(int index, IDirectBuffer srcBuffer, int srcIndex, int length) { if (length != 0) { EnsureCapacity(index, length); srcBuffer.BoundsCheck(srcIndex, length); byte* destination = _pBuffer + index; byte* source = (byte*)srcBuffer.BufferPointer.ToPointer() + srcIndex; ByteUtil.MemoryCopy(destination, source, (uint)length); } } public int PutStringUtf8(int index, string value) { return PutStringUtf8(index, value, int.MaxValue); } public int PutStringAscii(int index, string value) { return PutStringAscii(index, value, int.MaxValue); } public int PutStringAscii(int index, string value, int maxEncodedSize) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.ASCII.GetBytes(value)); if (array.Length > maxEncodedSize) { ThrowHelper.ThrowArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } EnsureCapacity(index, 4 + array.Length); PutInt(index, array.Length); PutBytes(index + 4, array); return 4 + array.Length; } public unsafe int PutStringWithoutLengthAscii(int index, string value) { int num = value?.Length ?? 0; EnsureCapacity(index, num); for (int i = 0; i < num; i++) { char c = value[i]; if (c > '\u007f') { c = '?'; } *(char*)(_pBuffer + index + i) = c; } return num; } public unsafe int PutStringWithoutLengthAscii(int index, string value, int valueOffset, int length) { int num = ((value != null) ? Math.Min(value.Length - valueOffset, length) : 0); EnsureCapacity(index, num); for (int i = 0; i < num; i++) { char c = value[valueOffset + i]; if (c > '\u007f') { c = '?'; } *(char*)(_pBuffer + index + i) = c; } return num; } public int PutStringUtf8(int index, string value, int maxEncodedSize) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.UTF8.GetBytes(value)); if (array.Length > maxEncodedSize) { ThrowHelper.ThrowArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } EnsureCapacity(index, 4 + array.Length); PutInt(index, array.Length); PutBytes(index + 4, array); return 4 + array.Length; } public int PutStringWithoutLengthUtf8(int index, string value) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.UTF8.GetBytes(value)); EnsureCapacity(index, array.Length); PutBytes(index, array); return array.Length; } private void EnsureCapacity(int index, int length) { if (index < 0 || length < 0) { throw new IndexOutOfRangeException("negative value: index=" + index + " length=" + length); } long num = (long)index + (long)length; int num2 = _byteArray.Length; if (num > num2) { if (num > MAX_ARRAY_LENGTH) { string[] obj = new string[6] { "index=", index.ToString(), " length=", length.ToString(), " maxCapacity=", null }; int mAX_ARRAY_LENGTH = MAX_ARRAY_LENGTH; obj[5] = mAX_ARRAY_LENGTH.ToString(); throw new IndexOutOfRangeException(string.Concat(obj)); } int capacity = CalculateExpansion(num2, num); byte[] byteArray = _byteArray; _pinnedGcHandle.Free(); AllocateAndPinArray(capacity); Array.Copy(byteArray, _byteArray, byteArray.Length); } } private int CalculateExpansion(int currentLength, long requiredLength) { long num = Math.Max(currentLength, 128); while (num < requiredLength) { num += num >> 1; if (num > MAX_ARRAY_LENGTH) { num = MAX_ARRAY_LENGTH; } } return (int)num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BoundsCheck0(int index, int length) { int num = _byteArray.Length; long num2 = (long)index + (long)length; if (index < 0 || length < 0 || num2 > num) { ThrowHelper.ThrowIndexOutOfRangeException($"index={index:D}, length={length:D}, capacity={Capacity:D}"); } } } public interface IDirectBuffer : IComparable<IDirectBuffer> { IntPtr BufferPointer { get; } byte[] ByteArray { get; } ByteBuffer ByteBuffer { get; } int Capacity { get; } void Wrap(byte[] buffer); void Wrap(byte[] buffer, int offset, int length); void Wrap(IDirectBuffer buffer); void Wrap(IDirectBuffer buffer, int offset, int length); void Wrap(IntPtr pointer, int length); void Wrap(IntPtr pointer, int offset, int length); void CheckLimit(int limit); long GetLong(int index, ByteOrder byteOrder); long GetLong(int index); int GetInt(int index, ByteOrder byteOrder); int GetInt(int index); double GetDouble(int index); float GetFloat(int index); short GetShort(int index, ByteOrder byteOrder); short GetShort(int index); char GetChar(int index); byte GetByte(int index); void GetBytes(int index, byte[] dst); void GetBytes(int index, byte[] dst, int offset, int length); void GetBytes(int index, IMutableDirectBuffer dstBuffer, int dstIndex, int length); string GetStringUtf8(int index); string GetStringAscii(int index); int GetStringAscii(int index, StringBuilder appendable); int GetStringAscii(int index, int length, StringBuilder appendable); string GetStringUtf8(int index, int length); string GetStringAscii(int index, int length); string GetStringWithoutLengthUtf8(int index, int length); string GetStringWithoutLengthAscii(int index, int length); void BoundsCheck(int index, int length); } public interface IErrorHandler { void OnError(Exception exception); } public interface IManagedResource { void TimeOfLastStateChange(long time); long TimeOfLastStateChange(); void Delete(); } public interface IMutableDirectBuffer : IDirectBuffer, IComparable<IDirectBuffer> { bool IsExpandable { get; } void SetMemory(int index, int length, byte value); void PutLong(int index, long value, ByteOrder byteOrder); void PutLong(int index, long value); void PutInt(int index, int value, ByteOrder byteOrder); void PutInt(int index, int value); void PutDouble(int index, double value); void PutFloat(int index, float value); void PutShort(int index, short value, ByteOrder byteOrder); void PutShort(int index, short value); void PutChar(int index, char value); void PutByte(int index, byte value); void PutBytes(int index, byte[] src); void PutBytes(int index, byte[] src, int offset, int length); void PutBytes(int index, IDirectBuffer srcBuffer, int srcIndex, int length); int PutStringUtf8(int index, string value); int PutStringAscii(int index, string value); int PutStringWithoutLengthAscii(int index, string value); int PutStringWithoutLengthAscii(int index, string value, int valueOffset, int length); int PutStringUtf8(int index, string value, int maxEncodedSize); int PutStringWithoutLengthUtf8(int index, string value); } public enum MapMode { ReadOnly, ReadWrite } public class IoUtil { public static MappedByteBuffer MapExistingFile(string path, MapMode mapMode) { return new MappedByteBuffer(OpenMemoryMappedFile(path)); } public static MappedByteBuffer MapExistingFile(FileInfo path, long offset, long length) { return new MappedByteBuffer(OpenMemoryMappedFile(path.FullName), offset, length); } public static MappedByteBuffer MapNewFile(FileInfo cncFile, long length, bool fillWithZeros = true) { FileAccess access = FileAccess.ReadWrite; FileShare share = FileShare.ReadWrite | FileShare.Delete; MemoryMappedFileAccess access2 = MemoryMappedFileAccess.ReadWrite; MappedByteBuffer mappedByteBuffer = new MappedByteBuffer(MemoryMappedFile.CreateFromFile(new FileStream(cncFile.FullName, FileMode.CreateNew, access, share), null, length, access2, HandleInheritability.None, leaveOpen: false), 0L, length); if (fillWithZeros) { mappedByteBuffer.FillWithZeros(); } return mappedByteBuffer; } public static MappedByteBuffer MapNewOrExistingFile(FileInfo cncFile, long length) { FileAccess access = FileAccess.ReadWrite; FileShare share = FileShare.ReadWrite | FileShare.Delete; MemoryMappedFileAccess access2 = MemoryMappedFileAccess.ReadWrite; return new MappedByteBuffer(MemoryMappedFile.CreateFromFile(new FileStream(cncFile.FullName, FileMode.OpenOrCreate, access, share), null, length, access2, HandleInheritability.None, leaveOpen: false), 0L, length); } public static MemoryMappedFile OpenMemoryMappedFile(string path) { CheckFileExists(path); FileAccess access = FileAccess.ReadWrite; FileShare share = FileShare.ReadWrite | FileShare.Delete; return OpenMemoryMappedFile(new FileStream(path, FileMode.Open, access, share)); } private static MemoryMappedFile OpenMemoryMappedFile(FileStream f) { MemoryMappedFileAccess access = MemoryMappedFileAccess.ReadWrite; return MemoryMappedFile.CreateFromFile(f, null, 0L, access, HandleInheritability.None, leaveOpen: false); } public static MappedByteBuffer MapExistingFile(FileStream fileStream) { return new MappedByteBuffer(OpenMemoryMappedFile(fileStream)); } public static MappedByteBuffer MapExistingFile(FileInfo location, string descriptionLabel) { CheckFileExists(location, descriptionLabel); return new MappedByteBuffer(OpenMemoryMappedFile(location.FullName)); } public static void Unmap(MappedByteBuffer wrapper) { wrapper?.Dispose(); } public static void CheckFileExists(FileInfo file, string name) { if (!file.Exists) { throw new InvalidOperationException("Missing file for " + name + " : " + file.FullName); } } public static void CheckFileExists(string path) { if (!File.Exists(path)) { throw new InvalidOperationException("Missing file " + path); } } public static void Delete(DirectoryInfo directory, bool b) { if (directory.Exists) { directory.Delete(recursive: true); } } public static void EnsureDirectoryExists(DirectoryInfo directory, string descriptionLabel) { if (!directory.Exists) { directory.Create(); if (!directory.Exists) { throw new ArgumentException("could not create " + descriptionLabel + " directory: " + directory.FullName); } } } } public class MarkFile : IDisposable { private readonly int versionFieldOffset; private readonly int timestampFieldOffset; private readonly DirectoryInfo parentDir; private readonly FileInfo markFile; private readonly MappedByteBuffer mappedBuffer; private readonly UnsafeBuffer buffer; private volatile bool isClosed; public MarkFile(DirectoryInfo directory, string filename, bool warnIfDirectoryExists, bool dirDeleteOnStart, int versionFieldOffset, int timestampFieldOffset, int totalFileLength, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { ValidateOffsets(versionFieldOffset, timestampFieldOffset); EnsureDirectoryExists(directory, filename, warnIfDirectoryExists, dirDeleteOnStart, versionFieldOffset, timestampFieldOffset, timeoutMs, epochClock, versionCheck, logger); parentDir = directory; markFile = new FileInfo(Path.Combine(directory.Name, filename)); mappedBuffer = MapNewFile(markFile, totalFileLength); buffer = new UnsafeBuffer(mappedBuffer.Pointer, totalFileLength); this.versionFieldOffset = versionFieldOffset; this.timestampFieldOffset = timestampFieldOffset; } public MarkFile(FileInfo markFile, bool shouldPreExist, int versionFieldOffset, int timestampFieldOffset, int totalFileLength, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { ValidateOffsets(versionFieldOffset, timestampFieldOffset); parentDir = markFile.Directory; this.markFile = markFile; mappedBuffer = mapNewOrExistingMarkFile(markFile, shouldPreExist, versionFieldOffset, timestampFieldOffset, totalFileLength, timeoutMs, epochClock, versionCheck, logger); buffer = new UnsafeBuffer(mappedBuffer.Pointer, totalFileLength); this.versionFieldOffset = versionFieldOffset; this.timestampFieldOffset = timestampFieldOffset; } public MarkFile(DirectoryInfo directory, string filename, int versionFieldOffset, int timestampFieldOffset, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { ValidateOffsets(versionFieldOffset, timestampFieldOffset); parentDir = directory; markFile = new FileInfo(Path.Combine(directory.FullName, filename)); mappedBuffer = MapExistingMarkFile(markFile, versionFieldOffset, timestampFieldOffset, timeoutMs, epochClock, versionCheck, logger); buffer = new UnsafeBuffer(mappedBuffer); this.versionFieldOffset = versionFieldOffset; this.timestampFieldOffset = timestampFieldOffset; } public MarkFile(MappedByteBuffer mappedBuffer, int versionFieldOffset, int timestampFieldOffset) { ValidateOffsets(versionFieldOffset, timestampFieldOffset); parentDir = null; markFile = null; this.mappedBuffer = mappedBuffer; buffer = new UnsafeBuffer(mappedBuffer); this.versionFieldOffset = versionFieldOffset; this.timestampFieldOffset = timestampFieldOffset; } public MarkFile(UnsafeBuffer buffer, int versionFieldOffset, int timestampFieldOffset) { ValidateOffsets(versionFieldOffset, timestampFieldOffset); parentDir = null; markFile = null; mappedBuffer = null; this.buffer = buffer; this.versionFieldOffset = versionFieldOffset; this.timestampFieldOffset = timestampFieldOffset; } public bool IsClosed() { return isClosed; } public void Dispose() { if (!isClosed) { if (mappedBuffer != null) { IoUtil.Unmap(mappedBuffer); } isClosed = true; } } public void SignalReady(int version) { buffer.PutIntOrdered(versionFieldOffset, version); } public int VersionVolatile() { return buffer.GetIntVolatile(versionFieldOffset); } public int VersionWeak() { return buffer.GetInt(versionFieldOffset); } public void TimestampOrdered(long timestamp) { buffer.PutLongOrdered(timestampFieldOffset, timestamp); } public void TimestampRelease(long timestamp) { buffer.PutLongRelease(timestampFieldOffset, timestamp); } public long TimestampVolatile() { return buffer.GetLongVolatile(timestampFieldOffset); } public long TimestampWeak() { return buffer.GetLong(timestampFieldOffset); } public void DeleteDirectory(bool ignoreFailures) { IoUtil.Delete(parentDir, ignoreFailures); } public DirectoryInfo ParentDirectory() { return parentDir; } public FileInfo FileName() { return markFile; } public MappedByteBuffer MappedByteBuffer() { return mappedBuffer; } public UnsafeBuffer Buffer() { return buffer; } public static void EnsureDirectoryExists(DirectoryInfo directory, string filename, bool warnIfDirectoryExists, bool dirDeleteOnStart, int versionFieldOffset, int timestampFieldOffset, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { FileInfo cncFile = new FileInfo(Path.Combine(directory.FullName, filename)); if (directory.Exists) { if (warnIfDirectoryExists) { logger?.Invoke("WARNING: " + directory?.ToString() + " already exists."); } if (!dirDeleteOnStart) { int num = Math.Min(versionFieldOffset, timestampFieldOffset); int num2 = Math.Max(versionFieldOffset, timestampFieldOffset) + 8 - num; MappedByteBuffer mappedByteBuffer = MapExistingFile(cncFile, logger, num, num2); try { if (IsActive(mappedByteBuffer, epochClock, timeoutMs, versionFieldOffset, timestampFieldOffset, versionCheck, logger)) { throw new InvalidOperationException("active mark file detected"); } } finally { IoUtil.Unmap(mappedByteBuffer); } } IoUtil.Delete(directory, b: false); } IoUtil.EnsureDirectoryExists(directory, directory.ToString()); } public static MappedByteBuffer MapExistingMarkFile(FileInfo markFile, int versionFieldOffset, int timestampFieldOffset, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { long num = epochClock.Time(); while (!markFile.Exists) { if (epochClock.Time() > num + timeoutMs) { throw new InvalidOperationException("CnC file not found: " + markFile.FullName); } Sleep(16); } MappedByteBuffer result = MapExistingFile(markFile, logger); UnsafeBuffer unsafeBuffer = new UnsafeBuffer(result); int intVolatile; while ((intVolatile = unsafeBuffer.GetIntVolatile(versionFieldOffset)) == 0) { if (epochClock.Time() > num + timeoutMs) { throw new InvalidOperationException("CnC file is created but not initialised."); } Sleep(1); } versionCheck(intVolatile); while (unsafeBuffer.GetLongVolatile(timestampFieldOffset) == 0L) { if (epochClock.Time() > num + timeoutMs) { throw new InvalidOperationException("No non-0 timestamp detected."); } Sleep(1); } return result; } public static MappedByteBuffer mapNewOrExistingMarkFile(FileInfo markFile, bool shouldPreExist, int versionFieldOffset, int timestampFieldOffset, long totalFileLength, long timeoutMs, IEpochClock epochClock, Action<int> versionCheck, Action<string> logger) { MappedByteBuffer mappedByteBuffer = null; try { mappedByteBuffer = IoUtil.MapNewOrExistingFile(markFile, totalFileLength); UnsafeBuffer unsafeBuffer = new UnsafeBuffer(mappedByteBuffer); if (shouldPreExist) { int intVolatile = unsafeBuffer.GetIntVolatile(versionFieldOffset); logger?.Invoke("INFO: Mark file exists: " + markFile); versionCheck(intVolatile); long longVolatile = unsafeBuffer.GetLongVolatile(timestampFieldOffset); long num = epochClock.Time() - longVolatile; logger?.Invoke("INFO: heartbeat is (ms): " + num); if (num < timeoutMs) { throw new InvalidOperationException("Active mark file detected"); } } } catch (Exception) { if (mappedByteBuffer != null) { IoUtil.Unmap(mappedByteBuffer); } throw; } return mappedByteBuffer; } public static MappedByteBuffer MapExistingFile(FileInfo cncFile, Action<string> logger, long offset, long length) { if (cncFile.Exists) { logger?.Invoke("INFO: Mark file exists: " + cncFile); return IoUtil.MapExistingFile(cncFile, offset, length); } return null; } public static MappedByteBuffer MapExistingFile(FileInfo cncFile, Action<string> logger) { if (cncFile.Exists) { logger?.Invoke("INFO: Mark file exists: " + cncFile); return IoUtil.MapExistingFile(cncFile, cncFile.ToString()); } return null; } public static MappedByteBuffer MapNewFile(FileInfo cncFile, long length) { return IoUtil.MapNewFile(cncFile, length); } public static bool IsActive(MappedByteBuffer cncByteBuffer, IEpochClock epochClock, long timeoutMs, int versionFieldOffset, int timestampFieldOffset, Action<int> versionCheck, Action<string> logger) { if (cncByteBuffer == null) { return false; } UnsafeBuffer unsafeBuffer = new UnsafeBuffer(cncByteBuffer); long num = epochClock.Time(); int intVolatile; while ((intVolatile = unsafeBuffer.GetIntVolatile(versionFieldOffset)) == 0) { if (epochClock.Time() > num + timeoutMs) { throw new InvalidOperationException("Mark file is created but not initialised."); } Sleep(1); } versionCheck(intVolatile); long longVolatile = unsafeBuffer.GetLongVolatile(timestampFieldOffset); long num2 = epochClock.Time() - longVolatile; logger?.Invoke("INFO: heartbeat is (ms): " + num2); return num2 <= timeoutMs; } private static void ValidateOffsets(int versionFieldOffset, int timestampFieldOffset) { if (versionFieldOffset + 4 > timestampFieldOffset) { throw new ArgumentException("version field must precede the timestamp field"); } } public static void EnsureMarkFileLink(DirectoryInfo serviceDir, FileInfo actualFile, string linkFilename) { string fullName; try { fullName = serviceDir.FullName; } catch (Exception) { throw new ArgumentException("Failed to resolve canonical path for serviceDir=" + serviceDir); } string fullName2; try { fullName2 = actualFile.Directory.FullName; } catch (Exception) { throw new ArgumentException("Failed to resolve canonical path for markFile parent dir of " + actualFile); } string path = Path.Combine(fullName, linkFilename); if (fullName.Equals(fullName2, StringComparison.OrdinalIgnoreCase)) { try { if (File.Exists(path)) { File.Delete(path); } return; } catch (IOException innerException) { throw new Exception("Failed to remove old link file", innerException); } } try { File.WriteAllText(path, fullName2, Encoding.ASCII); } catch (IOException innerException2) { throw new Exception("Failed to create link for mark file directory", innerException2); } } internal static void Sleep(int durationMs) { try { Thread.Sleep(durationMs); } catch (ThreadInterruptedException) { Thread.CurrentThread.Interrupt(); } } } public static class Objects { public static T RequireNonNull<T>(T obj, string name) { if (obj == null) { throw new NullReferenceException(name); } return obj; } public static T RequireNonNull<T>(T obj) { if (obj == null) { throw new NullReferenceException(); } return obj; } } public class SemanticVersion { public static int Compose(int major, int minor, int patch) { if (major < 0 || major > 255) { throw new ArgumentException("major must be 0-255: " + major); } if (minor < 0 || minor > 255) { throw new ArgumentException("minor must be 0-255: " + minor); } if (patch < 0 || patch > 255) { throw new ArgumentException("patch must be 0-255: " + patch); } if (major + minor + patch == 0) { throw new ArgumentException("all parts cannot be zero"); } return (major << 16) | (minor << 8) | patch; } public static int Major(int version) { return (version >> 16) & 0xFF; } public static int Minor(int version) { return (version >> 8) & 0xFF; } public static int Patch(int version) { return version & 0xFF; } public static string ToString(int version) { return Major(version) + "." + Minor(version) + "." + Patch(version); } } public class SystemUtil { private const long MAX_G_VALUE = 8589934591L; private const long MAX_M_VALUE = 8796093022207L; private const long MAX_K_VALUE = 9007199254739968L; private const long SECONDS_TO_NANOS = 1000000000L; private const long MILLS_TO_NANOS = 1000000L; private const long MICROS_TO_NANOS = 1000L; public static long ParseSize(string propertyName, string propertyValue) { int num = propertyValue.Length - 1; char c = propertyValue[num]; if (char.IsDigit(c)) { return long.Parse(propertyValue); } long num2 = Convert.ToInt64(propertyValue.Substring(0, num)); switch (c) { case 'K': case 'k': if (num2 > 9007199254739968L) { throw new FormatException(propertyName + " would overflow long: " + propertyValue); } return num2 * 1024; case 'M': case 'm': if (num2 > 8796093022207L) { throw new FormatException(propertyName + " would overflow long: " + propertyValue); } return num2 * 1024 * 1024; case 'G': case 'g': if (num2 > 8589934591L) { throw new FormatException(propertyName + " would overflow long: " + propertyValue); } return num2 * 1024 * 1024 * 1024; default: throw new FormatException(propertyName + ": " + propertyValue + " should end with: k, m, or g."); } } public static long ParseDuration(string propertyName, string propertyValue) { char c = propertyValue[propertyValue.Length - 1]; if (char.IsDigit(c)) { return long.Parse(propertyValue); } if (c != 's' && c != 'S') { throw new FormatException(propertyName + ": " + propertyValue + " should end with: s, ms, us, or ns."); } char c2 = propertyValue[propertyValue.Length - 2]; if (char.IsDigit(c2)) { long num = Convert.ToInt64(propertyValue.Substring(0, propertyValue.Length - 1)); return 1000000000 * num; } long num2 = Convert.ToInt64(propertyValue.Substring(0, propertyValue.Length - 2)); switch (c2) { case 'N': case 'n': return num2; case 'U': case 'u': return 1000 * num2; case 'M': case 'm': return 1000000 * num2; default: throw new FormatException(propertyName + ": " + propertyValue + " should end with: s, ms, us, or ns."); } } } public class TimeUnit { public static readonly TimeUnit NANOSECONDS = new TimeUnit(); public static readonly TimeUnit MILLIS = new TimeUnit(); private TimeUnit() { } public long Convert(long sourceValue, TimeUnit destinationTimeUnit) { if (destinationTimeUnit == NANOSECONDS) { if (this == MILLIS) { return sourceValue * 1000000; } if (this == NANOSECONDS) { return sourceValue; } } if (destinationTimeUnit == MILLIS) { if (this == MILLIS) { return sourceValue; } if (this == NANOSECONDS) { return sourceValue / 1000000; } } throw new ArgumentException(); } public long ToMillis(long value) { return Convert(value, MILLIS); } public long ToNanos(long value) { return Convert(value, NANOSECONDS); } } } namespace Adaptive.Agrona.Util { public class ByteUtil { [StructLayout(LayoutKind.Sequential, Pack = 32, Size = 32)] internal struct CopyChunk32 { private readonly long _l1; private readonly long _l2; private readonly long _l3; private readonly long _l4; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe static void MemoryCopy(byte* destination, byte* source, uint length) { int i = 0; for (int j = i + 32; j <= length; j += 32) { *(CopyChunk32*)(destination + i) = *(CopyChunk32*)(source + i); i = j; } for (int j = i + 8; j <= length; j += 8) { *(long*)(destination + i) = *(long*)(source + i); i = j; } for (; i < length; i++) { destination[i] = source[i]; } } } public static class IntUtil { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NumberOfTrailingZeros(int i) { if (i == 0) { return 32; } int num = 31; int num2 = i << 16; if (num2 != 0) { num -= 16; i = num2; } num2 = i << 8; if (num2 != 0) { num -= 8; i = num2; } num2 = i << 4; if (num2 != 0) { num -= 4; i = num2; } num2 = i << 2; if (num2 != 0) { num -= 2; i = num2; } return num - (i << 1 >>> 31); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int NumberOfLeadingZeros(int i) { if (i == 0) { return 32; } int num = 1; if (i >>> 16 == 0) { num += 16; i <<= 16; } if (i >>> 24 == 0) { num += 8; i <<= 8; } if (i >>> 28 == 0) { num += 4; i <<= 4; } if (i >>> 30 == 0) { num += 2; i <<= 2; } return num - (i >>> 31); } } public static class LockSupport { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ParkNanos(long nanos) { Thread.SpinWait((int)(15 * nanos / 1000)); } } public class MappedByteBuffer : IDisposable { private readonly MemoryMappedFile _memoryMappedFile; private readonly MemoryMappedViewAccessor _view; private bool _disposed; public IntPtr Pointer { get; } public long Capacity { get; } public unsafe MappedByteBuffer(MemoryMappedFile memoryMappedFile) { _memoryMappedFile = memoryMappedFile; byte* pointer = null; _view = memoryMappedFile.CreateViewAccessor(); _view.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer); Pointer = new IntPtr(pointer); Capacity = _view.Capacity; } public unsafe MappedByteBuffer(MemoryMappedFile memoryMappedFile, long offset, long length) { _memoryMappedFile = memoryMappedFile; byte* pointer = null; _view = memoryMappedFile.CreateViewAccessor(offset, length); _view.SafeMemoryMappedViewHandle.AcquirePointer(ref pointer); Pointer = new IntPtr(pointer); Capacity = length; } public void FillWithZeros() { for (int i = 0; i < Capacity; i++) { _view.Write((long)i, (byte)0); } } public void Force() { _view.Flush(); } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } ~MappedByteBuffer() { Dispose(disposing: false); } private void Dispose(bool disposing) { if (!_disposed) { if (_view != null) { _view.SafeMemoryMappedViewHandle.ReleasePointer(); _view.Dispose(); } _memoryMappedFile?.Dispose(); _disposed = true; } } } public static class NanoUtil { public static long FromSeconds(long seconds) { return seconds * 1000 * 1000 * 1000; } public static long FromMilliseconds(long milliseconds) { return milliseconds * 1000 * 1000; } public static int ToMillis(long resourceLingerDurationNs) { return (int)(resourceLingerDurationNs / 1000000); } } public static class ThrowHelper { [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentException() { throw GetArgumentException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentException(string message) { throw GetArgumentException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentOutOfRangeException() { throw GetArgumentOutOfRangeException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentOutOfRangeException(string argument) { throw GetArgumentOutOfRangeException(argument); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowIndexOutOfRangeException(string message) { throw GetIndexOutOfRangeException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowInvalidOperationException() { throw GetInvalidOperationException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowInvalidCastException() { throw GetInvalidCastException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowInvalidOperationException(string message) { throw GetInvalidOperationException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowInvalidOperationException_ForVariantTypeMissmatch() { throw GetInvalidOperationException_ForVariantTypeMissmatch(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotImplementedException() { throw GetNotImplementedException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotImplementedException(string message) { throw GetNotImplementedException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowNotSupportedException() { throw GetNotSupportedException(); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowKeyNotFoundException(string message) { throw GetKeyNotFoundException(message); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowArgumentNullException(string argument) { throw new ArgumentNullException(argument); } [MethodImpl(MethodImplOptions.NoInlining)] public static void ThrowObjectDisposedException(string objectName) { throw GetObjectDisposedException(objectName); } [MethodImpl(MethodImplOptions.NoInlining)] private static ArgumentException GetArgumentException() { return new ArgumentException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static ArgumentException GetArgumentException(string message) { return new ArgumentException(message); } [MethodImpl(MethodImplOptions.NoInlining)] private static ArgumentOutOfRangeException GetArgumentOutOfRangeException() { return new ArgumentOutOfRangeException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(string argument) { return new ArgumentOutOfRangeException(argument); } [MethodImpl(MethodImplOptions.NoInlining)] private static IndexOutOfRangeException GetIndexOutOfRangeException(string message) { return new IndexOutOfRangeException(message); } [MethodImpl(MethodImplOptions.NoInlining)] private static InvalidOperationException GetInvalidOperationException() { return new InvalidOperationException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static InvalidCastException GetInvalidCastException() { return new InvalidCastException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static InvalidOperationException GetInvalidOperationException(string message) { return new InvalidOperationException(message); } [MethodImpl(MethodImplOptions.NoInlining)] private static InvalidOperationException GetInvalidOperationException_ForVariantTypeMissmatch() { return new InvalidOperationException("Variant type doesn't match typeof(T)"); } [MethodImpl(MethodImplOptions.NoInlining)] private static NotImplementedException GetNotImplementedException() { return new NotImplementedException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static NotImplementedException GetNotImplementedException(string message) { return new NotImplementedException(message); } [MethodImpl(MethodImplOptions.NoInlining)] private static NotSupportedException GetNotSupportedException() { return new NotSupportedException(); } [MethodImpl(MethodImplOptions.NoInlining)] private static KeyNotFoundException GetKeyNotFoundException(string message) { return new KeyNotFoundException(message); } [MethodImpl(MethodImplOptions.NoInlining)] private static ObjectDisposedException GetObjectDisposedException(string objectName) { return new ObjectDisposedException(objectName); } } public static class UnixTimeConverter { private static readonly DateTime Jan1st1970 = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static long CurrentUnixTimeMillis() { return (long)(DateTime.UtcNow - Jan1st1970).TotalMilliseconds; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static DateTime FromUnixTimeMillis(long epoch) { DateTime jan1st = Jan1st1970; return jan1st.AddMilliseconds(epoch); } } } namespace Adaptive.Agrona.SBE { public interface ICompositeDecoderFlyweight : IDecoderFlyweight, IFlyweight { ICompositeDecoderFlyweight Wrap(IDirectBuffer buffer, int offset); } public interface ICompositeEncoderFlyweight : IEncoderFlyweight, IFlyweight { } public interface IDecoderFlyweight : IFlyweight { } public interface IEncoderFlyweight : IFlyweight { IEncoderFlyweight Wrap(IMutableDirectBuffer buffer, int offset); } public interface IFlyweight { int EncodedLength(); } public interface IMessageDecoderFlyweight : IMessageFlyweight, IFlyweight, IDecoderFlyweight { IMessageDecoderFlyweight Wrap(IDirectBuffer buffer, int offset, int actingBlockLength, int actingVersion); } public interface IMessageEncoderFlyweight : IMessageFlyweight, IFlyweight, IEncoderFlyweight { } public interface IMessageFlyweight : IFlyweight { int SbeBlockLength(); int SbeTemplateId(); int SbeSchemaId(); int SbeSchemaVersion(); string SbeSemanticType(); int Offset(); } } namespace Adaptive.Agrona.Concurrent { public class AgentInvoker : IDisposable { private readonly AtomicCounter _errorCounter; private readonly IErrorHandler _errorHandler; private readonly IAgent _agent; public bool IsClosed { get; private set; } public bool IsStarted { get; private set; } public bool IsRunning { get; private set; } public AgentInvoker(IErrorHandler errorHandler, AtomicCounter errorCounter, IAgent agent) { Objects.RequireNonNull(errorHandler, "errorHandler"); Objects.RequireNonNull(agent, "agent"); _errorHandler = errorHandler; _errorCounter = errorCounter; _agent = agent; } public IAgent Agent() { return _agent; } public void Start() { try { if (!IsStarted) { IsStarted = true; _agent.OnStart(); IsRunning = true; } } catch (Exception exception) { HandleError(exception); Dispose(); } } public int Invoke() { int result = 0; if (IsRunning) { try { result = _agent.DoWork(); } catch (ThreadInterruptedException) { Dispose(); Thread.CurrentThread.Interrupt(); } catch (AgentTerminationException exception) { HandleError(exception); Dispose(); } catch (Exception exception2) { if (_errorCounter != null) { _errorCounter.Increment(); } _errorHandler.OnError(exception2); } } return result; } public void Dispose() { try { if (!IsClosed) { IsRunning = false; IsClosed = true; _agent.OnClose(); } } catch (Exception exception) { HandleError(exception); } } private void HandleError(Exception exception) { if (_errorCounter != null) { _errorCounter.Increment(); } _errorHandler.OnError(exception); } } public class AgentRunner : IDisposable { private static readonly Thread TOMBSTONE = new Thread((ThreadStart)delegate { }); public static readonly int RETRY_CLOSE_TIMEOUT_MS = 3000; private volatile bool _isRunning = true; private readonly AtomicCounter _errorCounter; private readonly IErrorHandler _errorHandler; private readonly IIdleStrategy _idleStrategy; private readonly IAgent _agent; private readonly AtomicReference<Thread> _thread = new AtomicReference<Thread>(); public bool IsClosed { get; private set; } public AgentRunner(IIdleStrategy idleStrategy, IErrorHandler errorHandler, AtomicCounter errorCounter, IAgent agent) { if (idleStrategy == null) { throw new ArgumentNullException("idleStrategy"); } if (errorHandler == null) { throw new ArgumentNullException("errorHandler"); } if (agent == null) { throw new ArgumentNullException("agent"); } _idleStrategy = idleStrategy; _errorHandler = errorHandler; _errorCounter = errorCounter; _agent = agent; } public static Thread StartOnThread(AgentRunner runner) { Thread thread = new Thread(runner.Run); ConfigureThread(thread, runner); thread.Start(); return thread; } public static Thread StartOnThread(AgentRunner runner, IThreadFactory threadFactory) { Thread thread = threadFactory.NewThread(runner.Run); ConfigureThread(thread, runner); thread.Start(); return thread; } private static void ConfigureThread(Thread thread, AgentRunner runner) { thread.Name = runner.Agent().RoleName(); thread.IsBackground = true; } public IAgent Agent() { return _agent; } public Thread Thread() { return _thread.Get(); } public void Run() { try { if (!_thread.CompareAndSet(null, System.Threading.Thread.CurrentThread)) { return; } IIdleStrategy idleStrategy = _idleStrategy; IAgent agent = _agent; try { agent.OnStart(); } catch (Exception exception) { HandleError(exception); _isRunning = false; } while (_isRunning && !DoDutyCycle(idleStrategy, agent)) { } try { agent.OnClose(); } catch (Exception exception2) { HandleError(exception2); } } finally { IsClosed = true; } } public void Dispose() { _isRunning = false; Thread andSet = _thread.GetAndSet(TOMBSTONE); if (andSet == null) { try { IsClosed = true; _agent.OnClose(); } catch (Exception exception) { _errorHandler.OnError(exception); } } if (TOMBSTONE == andSet) { return; } while (true) { try { andSet.Join(RETRY_CLOSE_TIMEOUT_MS); if (!andSet.IsAlive || IsClosed) { break; } Console.Error.WriteLine("Timeout waiting for agent '" + _agent.RoleName() + "' to close, Retrying..."); andSet.Interrupt(); } catch (ThreadInterruptedException) { System.Threading.Thread.CurrentThread.Interrupt(); break; } } } private bool DoDutyCycle(IIdleStrategy idleStrategy, IAgent agent) { try { idleStrategy.Idle(agent.DoWork()); } catch (ThreadInterruptedException) { System.Threading.Thread.CurrentThread.Interrupt(); return true; } catch (AgentTerminationException exception) { HandleError(exception); return true; } catch (Exception exception2) { HandleError(exception2); } return false; } private void HandleError(Exception exception) { if (_isRunning) { _errorCounter?.Increment(); _errorHandler.OnError(exception); } } } public class AgentTerminationException : Exception { public AgentTerminationException() { } public AgentTerminationException(string message) : base(message) { } } public class AtomicBoolean { private int _value; private const int TRUE = 1; private const int FALSE = 0; public AtomicBoolean(bool initialValue) { Interlocked.Exchange(ref _value, initialValue ? 1 : 0); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool CompareAndSet(bool comparand, bool newValue) { int value = ToInt(newValue); int num = ToInt(comparand); return Interlocked.CompareExchange(ref _value, value, num) == num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Get() { return ToBool(Volatile.Read(ref _value)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator bool(AtomicBoolean value) { return value.Get(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static bool ToBool(int value) { if (value != 0 && value != 1) { ThrowHelper.ThrowArgumentOutOfRangeException("value"); } return value == 1; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int ToInt(bool value) { return value ? 1 : 0; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void Set(bool value) { Volatile.Write(ref _value, ToInt(value)); } } public class AtomicLong { private long _long; public long Get() { return Interlocked.Read(ref _long); } public void LazySet(long newValue) { Interlocked.Exchange(ref _long, newValue); } public void Set(long value) { Interlocked.Exchange(ref _long, value); } public void Add(long add) { Interlocked.Add(ref _long, add); } public long IncrementAndGet() { return Interlocked.Increment(ref _long); } } public class AtomicReference<T> where T : class { private T _value; public T Get() { return Volatile.Read(ref _value); } public void LazySet(T newValue) { Volatile.Write(ref _value, newValue); } public T GetAndSet(T value) { return Interlocked.Exchange(ref _value, value); } public bool CompareAndSet(T compareValue, T newValue) { return Interlocked.CompareExchange(ref _value, newValue, compareValue) == compareValue; } } public class BackgroundThreadFactory : IThreadFactory { public static readonly BackgroundThreadFactory Instance = new BackgroundThreadFactory(); public Thread NewThread(ThreadStart runner) { return new Thread(runner) { IsBackground = true }; } } public class BackoffIdleStrategy : IIdleStrategy { private enum State { NOT_IDLE, SPINNING, YIELDING, PARKING } private readonly long _maxSpins; private readonly long _maxYields; private readonly int _minParkPeriodMs; private readonly int _maxParkPeriodMs; private State _state; private long _spins; private long _yields; private int _parkPeriodMs; public BackoffIdleStrategy(long maxSpins, long maxYields, long minParkPeriodMs, long maxParkPeriodMs) { _maxSpins = maxSpins; _maxYields = maxYields; _minParkPeriodMs = (int)minParkPeriodMs; _maxParkPeriodMs = (int)maxParkPeriodMs; _state = State.NOT_IDLE; } public void Idle(int workCount) { if (workCount > 0) { Reset(); } else { Idle(); } } public void Idle() { switch (_state) { case State.NOT_IDLE: _state = State.SPINNING; _spins++; break; case State.SPINNING: if (++_spins > _maxSpins) { _state = State.YIELDING; _yields = 0L; } break; case State.YIELDING: if (++_yields > _maxYields) { _state = State.PARKING; _parkPeriodMs = _minParkPeriodMs; } else { Thread.Yield(); } break; case State.PARKING: Thread.Sleep(_parkPeriodMs); _parkPeriodMs = Math.Min(_parkPeriodMs << 1, _maxParkPeriodMs); break; } } public void Reset() { _spins = 0L; _yields = 0L; _state = State.NOT_IDLE; } } public sealed class BusySpinIdleStrategy : IIdleStrategy { public void Idle(int workCount) { if (workCount <= 0) { Thread.SpinWait(0); } } public void Idle() { Thread.SpinWait(0); } public void Reset() { } } public class CachedEpochClock : IEpochClock { private long timeMs; public long Time() { return timeMs; } public void Update(long timeMs) { this.timeMs = timeMs; } } public class CompositeAgent : IAgent { private readonly IAgent[] _agents; private readonly string _roleName; private int _workIndex; public CompositeAgent(List<IAgent> agents) : this(agents.ToArray()) { } public CompositeAgent(params IAgent[] agents) { if (agents.Length == 0) { throw new ArgumentException("CompsiteAgent requires at least one sub-agent"); } _agents = agents; StringBuilder stringBuilder = new StringBuilder(agents.Length * 16); stringBuilder.Append('['); foreach (IAgent agent in agents) { Objects.RequireNonNull(agent, "Agent cannot be null"); stringBuilder.Append(agent.RoleName()).Append(','); } stringBuilder[stringBuilder.Length - 1] = ']'; _roleName = stringBuilder.ToString(); } public string RoleName() { return _roleName; } public void OnStart() { Exception ex = null; IAgent[] agents = _agents; foreach (IAgent agent in agents) { try { agent.OnStart(); } catch (Exception innerException) { if (ex == null) { ex = new Exception("CompositeAgent: underlying agent error on start", innerException); } } } if (ex != null) { throw ex; } } public int DoWork() { int num = 0; IAgent[] agents = _agents; while (_workIndex < agents.Length) { IAgent agent = agents[_workIndex++]; num += agent.DoWork(); } _workIndex = 0; return num; } public void OnClose() { Exception ex = null; IAgent[] agents = _agents; foreach (IAgent agent in agents) { try { agent.OnClose(); } catch (Exception innerException) { if (ex == null) { ex = new Exception("CompositeAgent: underlying agent error on close", innerException); } } } if (ex != null) { throw ex; } } } public class Configuration { public const long IDLE_MAX_SPINS = 10L; public const long IDLE_MAX_YIELDS = 40L; public const long IDLE_MIN_PARK_MS = 1L; public static readonly long IDLE_MAX_PARK_MS = 16L; } public class ControllableIdleStrategy : IIdleStrategy { public const int NOT_CONTROLLED = 0; public const int NOOP = 1; public const int BUSY_SPIN = 2; public const int YIELD = 3; public const int PARK = 4; private const long PARK_PERIOD_NANOSECONDS = 1000L; private readonly StatusIndicatorReader statusIndicatorReader; public ControllableIdleStrategy(StatusIndicatorReader statusIndicatorReader) { this.statusIndicatorReader = statusIndicatorReader; } public void Idle(int workCount) { if (workCount <= 0) { Idle(); } } public void Idle() { switch ((int)statusIndicatorReader.GetVolatile()) { case 2: Thread.SpinWait(0); break; case 3: Thread.Yield(); break; default: LockSupport.ParkNanos(1000L); break; case 1: break; } } public void Reset() { } public override string ToString() { return "ControllableIdleStrategy{statusIndicatorReader=" + statusIndicatorReader?.ToString() + "}"; } } public class CountedErrorHandler : IErrorHandler { private readonly IErrorHandler _errorHandler; private readonly AtomicCounter _errorCounter; public readonly ErrorHandler AsErrorHandler; public CountedErrorHandler(IErrorHandler errorHandler, AtomicCounter errorCounter) { Objects.RequireNonNull(errorHandler, "errorHandler"); Objects.RequireNonNull(errorCounter, "errorCounter"); _errorHandler = errorHandler; _errorCounter = errorCounter; AsErrorHandler = OnError; } public void OnError(Exception throwable) { _errorCounter.Increment(); _errorHandler.OnError(throwable); } } public class DefaultThreadFactory : IThreadFactory { public Thread NewThread(ThreadStart runner) { return new Thread(runner); } } public interface IAgent { void OnStart(); int DoWork(); void OnClose(); string RoleName(); } public interface IAtomicBuffer : IMutableDirectBuffer, IDirectBuffer, IComparable<IDirectBuffer> { void VerifyAlignment(); long GetLongVolatile(int index); void PutLongVolatile(int index, long value); void PutLongOrdered(int index, long value); void PutLongRelease(int index, long value); long AddLongOrdered(int index, long increment); bool CompareAndSetLong(int index, long expectedValue, long updateValue); long GetAndAddLong(int index, long delta); int GetIntVolatile(int index); void PutIntVolatile(int index, int value); void PutIntOrdered(int index, int value); void PutIntRelease(int index, int value); int AddIntOrdered(int index, int increment); bool CompareAndSetInt(int index, int expectedValue, int updateValue); int GetAndAddInt(int index, int delta); short GetShortVolatile(int index); void PutShortVolatile(int index, short value); byte GetByteVolatile(int index); void PutByteVolatile(int index, byte value); } public static class IdleStrategyFactory { public static IIdleStrategy Create(string strategyName, StatusIndicator controllableStatus) { switch (strategyName) { case "ControllableIdleStrategy": { ControllableIdleStrategy result = new ControllableIdleStrategy(controllableStatus); controllableStatus.SetOrdered(4L); return result; } case "YieldingIdleStrategy": return new YieldingIdleStrategy(); case "SleepingIdleStrategy": return new SleepingIdleStrategy(1); case "BusySpinIdleStrategy": return new BusySpinIdleStrategy(); case "NoOpIdleStrategy": return new NoOpIdleStrategy(); default: return new BackoffIdleStrategy(10L, 40L, 1L, Configuration.IDLE_MAX_PARK_MS); } } } public interface IEpochClock { long Time(); } public interface IIdleStrategy { void Idle(int workCount); void Idle(); void Reset(); } public interface ILock { void Lock(); void Unlock(); bool TryLock(); } public interface INanoClock { long NanoTime(); } public interface IThreadFactory { Thread NewThread(ThreadStart runner); } public delegate void MessageHandler(int msgTypeId, IMutableDirectBuffer buffer, int index, int length); public sealed class NoOpIdleStrategy : IIdleStrategy { public void Idle(int workCount) { } public void Idle() { } public void Reset() { } } public class NoOpLock : ILock { public static readonly NoOpLock Instance = new NoOpLock(); public void Lock() { } public void Unlock() { } public bool TryLock() { return true; } } public class NullEpochClock : IEpochClock { public long Time() { return 0L; } } public class ReentrantLock : ILock { private readonly object _lockObj = new object(); public void Lock() { Monitor.Enter(_lockObj); } public void Unlock() { Monitor.Exit(_lockObj); } public bool TryLock() { return Monitor.TryEnter(_lockObj); } } public sealed class ShutdownSignalBarrier : IDisposable { public delegate void SignalHandler(); private static readonly SignalHandler NO_OP_SIGNAL_HANDLER; private static readonly ConcurrentDictionary<ShutdownSignalBarrier, byte> BARRIERS; private readonly ManualResetEventSlim _waitEvent = new ManualResetEventSlim(initialState: false); private readonly ManualResetEventSlim _closeEvent = new ManualResetEventSlim(initialState: false); private int _signaled; private readonly SignalHandler _signalHandler; static ShutdownSignalBarrier() { NO_OP_SIGNAL_HANDLER = delegate { }; BARRIERS = new ConcurrentDictionary<ShutdownSignalBarrier, byte>(); AppDomain.CurrentDomain.ProcessExit += delegate { AwaitTermination(SignalAndClearAll(), TimeSpan.FromSeconds(10.0), Console.Out); }; Console.CancelKeyPress += delegate(object sender, ConsoleCancelEventArgs e) { AwaitTermination(SignalAndClearAll(), TimeSpan.FromSeconds(10.0), Console.Out); e.Cancel = false; }; } public ShutdownSignalBarrier() : this(NO_OP_SIGNAL_HANDLER) { } public ShutdownSignalBarrier(SignalHandler signalHandler) { if (signalHandler == null) { throw new ArgumentNullException("signalHandler"); } _signalHandler = signalHandler; BARRIERS.TryAdd(this, 0); } public void Signal() { if (Interlocked.CompareExchange(ref _signaled, 1, 0) == 0) { BARRIERS.TryRemove(this, out var _); _waitEvent.Set(); _signalHandler(); } } public void SignalAll() { SignalAndClearAll(); } public void Remove() { BARRIERS.TryRemove(this, out var _); } public void Await() { try { _waitEvent.Wait(); } catch (ThreadInterruptedException) { try { Signal(); } finally { Thread.CurrentThread.Interrupt(); } } } public void Close() { try { Signal(); } finally { _closeEvent.Set(); } } public void Dispose() { Close(); } public override string ToString() { return "ShutdownSignalBarrier{waitEvent=" + _waitEvent.IsSet + ", closeEvent=" + _closeEvent.IsSet + ", signaled=" + (_signaled == 1) + "}"; } private static ShutdownSignalBarrier[] SignalAndClearAll() { ShutdownSignalBarrier[] array = new ShutdownSignalBarrier[BARRIERS.Count]; BARRIERS.Keys.CopyTo(array, 0); BARRIERS.Clear(); List<Exception> list = null; for (int i = 0; i < array.Length; i++) { try { array[i].Signal(); } catch (Exception item) { if (list == null) { list = new List<Exception>(4); } list.Add(item); } } if (list != null && list.Count > 0) { throw new AggregateException("One or more barriers threw during Signal()", list); } return array; } private static void AwaitTermination(ShutdownSignalBarrier[] barriers, TimeSpan timeoutPerBarrier, TextWriter output) { if (barriers == null || barriers.Length == 0) { return; } bool flag = false; try { ShutdownSignalBarrier[] array = (ShutdownSignalBarrier[])barriers.Clone(); int num = 0; do { for (int i = 0; i < array.Length; i++) { ShutdownSignalBarrier shutdownSignalBarrier = array[i]; if (shutdownSignalBarrier == null) { continue; } try { if (shutdownSignalBarrier._closeEvent.Wait(timeoutPerBarrier)) { num++; array[i] = null; } else { output.WriteLine("WARN: ShutdownSignalBarrier hasn't terminated in " + timeoutPerBarrier.TotalSeconds.ToString("N0") + " seconds! Did you forget to call Close()/Dispose() on it?"); } } catch (ThreadInterruptedException) { flag = true; break; } } } while (num < array.Length); } finally { if (flag) { Thread.CurrentThread.Interrupt(); } } } } public sealed class SleepingIdleStrategy : IIdleStrategy { private readonly int _sleepPeriodMs; public SleepingIdleStrategy(int sleepPeriodMs) { _sleepPeriodMs = sleepPeriodMs; } public void Idle(int workCount) { if (workCount <= 0) { Thread.Sleep(_sleepPeriodMs); } } public void Idle() { Thread.Sleep(_sleepPeriodMs); } public void Reset() { } } public class SpinWaitIdleStrategy : IIdleStrategy { private SpinWait _spinWait; public void Idle(int workCount) { if (workCount > 0) { Reset(); } else { _spinWait.SpinOnce(); } } public void Idle() { _spinWait.SpinOnce(); } public void Reset() { _spinWait.Reset(); } } public abstract class StatusIndicator : StatusIndicatorReader { public abstract void SetOrdered(long value); } public abstract class StatusIndicatorReader { public abstract int Id { get; } public abstract long GetVolatile(); } public class StopwatchClock : INanoClock { private readonly Stopwatch _stopwatch; public StopwatchClock() { _stopwatch = Stopwatch.StartNew(); } public long NanoTime() { return _stopwatch.ElapsedTicks / Stopwatch.Frequency * 1000000000; } } public class SystemEpochClock : IEpochClock { public static readonly SystemEpochClock INSTANCE = new SystemEpochClock(); [MethodImpl(MethodImplOptions.AggressiveInlining)] public long Time() { return UnixTimeConverter.CurrentUnixTimeMillis(); } } public class SystemNanoClock : INanoClock { public static readonly SystemNanoClock INSTANCE = new SystemNanoClock(); private readonly Stopwatch _stopwatch; public SystemNanoClock() { _stopwatch = Stopwatch.StartNew(); } public long NanoTime() { return _stopwatch.ElapsedMilliseconds * 1000 * 1000; } } public class UnsafeBuffer : IAtomicBuffer, IMutableDirectBuffer, IDirectBuffer, IComparable<IDirectBuffer>, IDisposable { public const int ALIGNMENT = 8; public static readonly string DISABLE_BOUNDS_CHECKS_PROP_NAME = "AGRONA_DISABLE_BOUNDS_CHECKS"; private static readonly bool SHOULD_BOUNDS_CHECK = !bool.Parse(Environment.GetEnvironmentVariable(DISABLE_BOUNDS_CHECKS_PROP_NAME) ?? "false"); private unsafe byte* _pBuffer; private bool _disposed; private GCHandle _pinnedGcHandle; private bool _needToFreeGcHandle; public unsafe IntPtr BufferPointer { [MethodImpl(MethodImplOptions.AggressiveInlining)] get { return new IntPtr(_pBuffer); } } public byte[] ByteArray { get; private set; } public ByteBuffer ByteBuffer { get; private set; } public int Capacity { get; private set; } public bool IsExpandable => false; public UnsafeBuffer(byte[] buffer) { Wrap(buffer); } public UnsafeBuffer() { Wrap(Array.Empty<byte>()); } public UnsafeBuffer(byte[] buffer, int offset, int length) { Wrap(buffer, offset, length); } public UnsafeBuffer(ByteBuffer buffer) { Wrap(buffer); } public UnsafeBuffer(IDirectBuffer buffer) { Wrap(buffer); } public UnsafeBuffer(IDirectBuffer buffer, int offset, int length) { Wrap(buffer, offset, length); } public UnsafeBuffer(IntPtr address, int length) { Wrap(address, length); } public UnsafeBuffer(IntPtr address, int offset, int length) { Wrap(address, offset, length); } public UnsafeBuffer(MappedByteBuffer buffer) { Wrap(buffer.Pointer, 0, (int)buffer.Capacity); } public UnsafeBuffer(MappedByteBuffer buffer, int offset, int length) { Wrap(buffer.Pointer, offset, length); } public unsafe void Wrap(byte[] buffer) { if (buffer == null) { ThrowHelper.ThrowArgumentNullException("buffer"); } FreeGcHandle(); _pinnedGcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); _needToFreeGcHandle = true; _pBuffer = (byte*)_pinnedGcHandle.AddrOfPinnedObject().ToPointer(); Capacity = buffer.Length; ByteArray = buffer; ByteBuffer = null; } public unsafe void Wrap(byte[] buffer, int offset, int length) { if (buffer == null) { ThrowHelper.ThrowArgumentException("buffer"); } if (SHOULD_BOUNDS_CHECK) { int num = buffer.Length; if (offset != 0 && (offset < 0 || offset > num - 1)) { ThrowHelper.ThrowArgumentException("offset=" + offset + " not valid for capacity=" + num); } if (length < 0 || length > num - offset) { ThrowHelper.ThrowArgumentException("offset=" + offset + " length=" + length + " not valid for capacity=" + num); } } FreeGcHandle(); _pinnedGcHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); _needToFreeGcHandle = true; _pBuffer = (byte*)_pinnedGcHandle.AddrOfPinnedObject().ToPointer() + offset; Capacity = length; ByteArray = buffer; ByteBuffer = null; } public unsafe void Wrap(IDirectBuffer buffer) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = (byte*)buffer.BufferPointer.ToPointer(); Capacity = buffer.Capacity; ByteArray = buffer.ByteArray; ByteBuffer = buffer.ByteBuffer; } public unsafe void Wrap(ByteBuffer buffer) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = (byte*)buffer.BufferPointer.ToPointer(); Capacity = buffer.Capacity; ByteArray = null; ByteBuffer = buffer; } public unsafe void Wrap(IDirectBuffer buffer, int offset, int length) { if (SHOULD_BOUNDS_CHECK) { int capacity = buffer.Capacity; if (offset != 0 && (offset < 0 || offset > capacity - 1)) { ThrowHelper.ThrowArgumentException("offset=" + offset + " not valid for capacity=" + capacity); } if (length < 0 || length > capacity - offset) { ThrowHelper.ThrowArgumentException("offset=" + offset + " length=" + length + " not valid for capacity=" + capacity); } } FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = (byte*)buffer.BufferPointer.ToPointer() + offset; Capacity = length; ByteArray = buffer.ByteArray; ByteBuffer = buffer.ByteBuffer; } public unsafe void Wrap(IntPtr pointer, int length) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = (byte*)pointer.ToPointer(); Capacity = length; ByteBuffer = null; ByteArray = null; } public void Wrap(int memoryAddress, int length) { } public unsafe void Wrap(IntPtr pointer, int offset, int length) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = (byte*)pointer.ToPointer() + offset; Capacity = length; ByteBuffer = null; ByteArray = null; } public unsafe void Wrap(byte* pointer, int length) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = pointer; Capacity = length; ByteBuffer = null; ByteArray = null; } public unsafe void Wrap(byte* pointer, int offset, int length) { FreeGcHandle(); _needToFreeGcHandle = false; _pBuffer = pointer + offset; Capacity = length; ByteBuffer = null; ByteArray = null; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void SetMemory(int index, int length, byte value) { BoundsCheck0(index, length); Unsafe.InitBlock(_pBuffer + index, value, (uint)length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void CheckLimit(int limit) { if (limit > Capacity) { ThrowHelper.ThrowIndexOutOfRangeException($"limit={limit:D} is beyond capacity={Capacity:D}"); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void VerifyAlignment() { long num = new IntPtr(_pBuffer).ToInt64(); if ((num & 7) != 0L) { ThrowHelper.ThrowInvalidOperationException($"AtomicBuffer is not correctly aligned: addressOffset={num:D} in not divisible by {8:D}"); } } public unsafe long GetLong(int index, ByteOrder byteOrder) { BoundsCheck0(index, 8); long value = *(long*)(_pBuffer + index); return EndianessConverter.ApplyInt64(byteOrder, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe long GetLong(int index) { BoundsCheck0(index, 8); return *(long*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutLong(int index, long value) { BoundsCheck0(index, 8); *(long*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutLong(int index, long value, ByteOrder byteOrder) { BoundsCheck0(index, 8); value = EndianessConverter.ApplyInt64(byteOrder, value); *(long*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe long GetLongVolatile(int index) { BoundsCheck0(index, 8); return Volatile.Read(ref *(long*)(_pBuffer + index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutLongVolatile(int index, long value) { BoundsCheck0(index, 8); Interlocked.Exchange(ref *(long*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutLongOrdered(int index, long value) { BoundsCheck0(index, 8); Volatile.Write(ref *(long*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutLongRelease(int index, long value) { BoundsCheck0(index, 8); Volatile.Write(ref *(long*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public long AddLongOrdered(int index, long increment) { BoundsCheck0(index, 8); long @long = GetLong(index); PutLongOrdered(index, @long + increment); return @long; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool CompareAndSetLong(int index, long expectedValue, long updateValue) { BoundsCheck0(index, 8); return Interlocked.CompareExchange(ref *(long*)(_pBuffer + index), updateValue, expectedValue) == expectedValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe long GetAndAddLong(int index, long delta) { BoundsCheck0(index, 8); return Interlocked.Add(ref *(long*)(_pBuffer + index), delta) - delta; } public unsafe void PutInt(int index, int value, ByteOrder byteOrder) { BoundsCheck0(index, 4); value = EndianessConverter.ApplyInt32(byteOrder, value); *(int*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe int GetInt(int index) { BoundsCheck0(index, 4); return *(int*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe int GetInt(int index, ByteOrder byteOrder) { BoundsCheck0(index, 4); int value = *(int*)(_pBuffer + index); return EndianessConverter.ApplyInt32(byteOrder, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutInt(int index, int value) { BoundsCheck0(index, 4); *(int*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe int GetIntVolatile(int index) { BoundsCheck0(index, 4); return Volatile.Read(ref *(int*)(_pBuffer + index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutIntVolatile(int index, int value) { BoundsCheck0(index, 4); Interlocked.Exchange(ref *(int*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutIntOrdered(int index, int value) { BoundsCheck0(index, 4); Volatile.Write(ref *(int*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutIntRelease(int index, int value) { BoundsCheck0(index, 4); Volatile.Write(ref *(int*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int AddIntOrdered(int index, int increment) { BoundsCheck0(index, 4); int @int = GetInt(index); PutIntOrdered(index, @int + increment); return @int; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe bool CompareAndSetInt(int index, int expectedValue, int updateValue) { BoundsCheck0(index, 4); return Interlocked.CompareExchange(ref *(int*)(_pBuffer + index), updateValue, expectedValue) == expectedValue; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe int GetAndAddInt(int index, int delta) { BoundsCheck0(index, 4); return Interlocked.Add(ref *(int*)(_pBuffer + index), delta) - delta; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe double GetDouble(int index, ByteOrder byteOrder) { BoundsCheck0(index, 8); return EndianessConverter.ApplyDouble(byteOrder, *(double*)(_pBuffer + index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutDouble(int index, double value, ByteOrder byteOrder) { BoundsCheck0(index, 8); value = EndianessConverter.ApplyDouble(byteOrder, value); *(double*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe double GetDouble(int index) { BoundsCheck0(index, 8); return *(double*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutDouble(int index, double value) { BoundsCheck0(index, 8); *(double*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe float GetFloat(int index, ByteOrder byteOrder) { BoundsCheck0(index, 4); return EndianessConverter.ApplyFloat(byteOrder, *(float*)(_pBuffer + index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutFloat(int index, float value, ByteOrder byteOrder) { BoundsCheck0(index, 4); value = EndianessConverter.ApplyFloat(byteOrder, value); *(float*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe float GetFloat(int index) { BoundsCheck0(index, 4); return *(float*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutFloat(int index, float value) { BoundsCheck0(index, 4); *(float*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe short GetShort(int index) { BoundsCheck0(index, 2); return *(short*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe short GetShort(int index, ByteOrder byteOrder) { BoundsCheck0(index, 2); short value = *(short*)(_pBuffer + index); return EndianessConverter.ApplyInt16(byteOrder, value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutShort(int index, short value) { BoundsCheck0(index, 2); *(short*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutShort(int index, short value, ByteOrder byteOrder) { BoundsCheck0(index, 2); value = EndianessConverter.ApplyInt16(byteOrder, value); *(short*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe short GetShortVolatile(int index) { BoundsCheck0(index, 2); return Volatile.Read(ref *(short*)(_pBuffer + index)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutShortVolatile(int index, short value) { BoundsCheck0(index, 2); Volatile.Write(ref *(short*)(_pBuffer + index), value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe byte GetByte(int index) { BoundsCheck(index); return _pBuffer[index]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutByte(int index, byte value) { BoundsCheck(index); _pBuffer[index] = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe byte GetByteVolatile(int index) { BoundsCheck(index); return Volatile.Read(ref _pBuffer[index]); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutByteVolatile(int index, byte value) { BoundsCheck(index); Volatile.Write(ref _pBuffer[index], value); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GetBytes(int index, byte[] dst) { GetBytes(index, dst, 0, dst.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void GetBytes(int index, byte[] dst, int offset, int length) { if (length != 0) { BoundsCheck0(index, length); if (SHOULD_BOUNDS_CHECK) { BufferUtil.BoundsCheck(dst, offset, length); } byte* source = _pBuffer + index; fixed (byte* destination = &dst[offset]) { ByteUtil.MemoryCopy(destination, source, (uint)length); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void GetBytes(int index, IMutableDirectBuffer dstBuffer, int dstIndex, int length) { dstBuffer.PutBytes(dstIndex, this, index, length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void PutBytes(int index, byte[] src) { PutBytes(index, src, 0, src.Length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutBytes(int index, byte[] src, int offset, int length) { if (length != 0) { BoundsCheck0(index, length); if (SHOULD_BOUNDS_CHECK) { BufferUtil.BoundsCheck(src, offset, length); } byte* destination = _pBuffer + index; fixed (byte* source = &src[offset]) { ByteUtil.MemoryCopy(destination, source, (uint)length); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutBytes(int index, IDirectBuffer srcBuffer, int srcIndex, int length) { if (length != 0) { BoundsCheck0(index, length); srcBuffer.BoundsCheck(srcIndex, length); byte* destination = _pBuffer + index; byte* source = (byte*)srcBuffer.BufferPointer.ToPointer() + srcIndex; ByteUtil.MemoryCopy(destination, source, (uint)length); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe char GetChar(int index) { BoundsCheck0(index, 2); return *(char*)(_pBuffer + index); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe void PutChar(int index, char value) { BoundsCheck0(index, 2); *(char*)(_pBuffer + index) = value; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringUtf8(int index) { int @int = GetInt(index); return GetStringUtf8(index, @int); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringAscii(int index) { int @int = GetInt(index); return GetStringAscii(index, @int); } public int GetStringAscii(int index, StringBuilder appendable) { int @int = GetInt(index); return GetStringAscii(index, @int, appendable); } public unsafe int GetStringAscii(int index, int length, StringBuilder appendable) { int i = index + 4; for (int num = index + 4 + length; i < num; i++) { char c = *(char*)(_pBuffer + index); appendable.Append((c > '\u007f') ? '?' : c); } return length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringUtf8(int index, int length) { byte[] array = new byte[length]; GetBytes(index + 4, array); return Encoding.UTF8.GetString(array); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringAscii(int index, int length) { byte[] array = new byte[length]; GetBytes(index + 4, array); return Encoding.ASCII.GetString(array); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int PutStringUtf8(int index, string value) { return PutStringUtf8(index, value, int.MaxValue); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int PutStringAscii(int index, string value) { return PutStringAscii(index, value, int.MaxValue); } public unsafe int PutStringWithoutLengthAscii(int index, string value) { int num = value?.Length ?? 0; BoundsCheck0(index, num); for (int i = 0; i < num; i++) { char c = value[i]; if (c > '\u007f') { c = '?'; } *(char*)(_pBuffer + index + i) = c; } return num; } public unsafe int PutStringWithoutLengthAscii(int index, string value, int valueOffset, int length) { int num = ((value != null) ? Math.Min(value.Length - valueOffset, length) : 0); BoundsCheck0(index, num); for (int i = 0; i < num; i++) { char c = value[valueOffset + i]; if (c > '\u007f') { c = '?'; } *(char*)(_pBuffer + index + i) = c; } return num; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int PutStringUtf8(int index, string value, int maxEncodedSize) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.UTF8.GetBytes(value)); if (array.Length > maxEncodedSize) { ThrowHelper.ThrowArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } PutInt(index, array.Length); PutBytes(index + 4, array); return 4 + array.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int PutStringAscii(int index, string value, int maxEncodedSize) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.ASCII.GetBytes(value)); if (array.Length > maxEncodedSize) { ThrowHelper.ThrowArgumentException("Encoded string larger than maximum size: " + maxEncodedSize); } PutInt(index, array.Length); PutBytes(index + 4, array); return 4 + array.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringWithoutLengthUtf8(int index, int length) { byte[] array = new byte[length]; GetBytes(index, array); return Encoding.UTF8.GetString(array); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public string GetStringWithoutLengthAscii(int index, int length) { byte[] array = new byte[length]; GetBytes(index, array); return Encoding.ASCII.GetString(array); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public int PutStringWithoutLengthUtf8(int index, string value) { byte[] array = ((value == null) ? BufferUtil.NullBytes : Encoding.UTF8.GetBytes(value)); PutBytes(index, array); return array.Length; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BoundsCheck(int index) { if (SHOULD_BOUNDS_CHECK && (index < 0 || index >= Capacity)) { ThrowHelper.ThrowIndexOutOfRangeException($"index={index:D}, capacity={Capacity:D}"); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BoundsCheck0(int index, int length) { if (SHOULD_BOUNDS_CHECK) { long num = (long)index + (long)length; if (index < 0 || num > Capacity) { ThrowHelper.ThrowIndexOutOfRangeException($"index={index:D}, length={length:D}, capacity={Capacity:D}"); } } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public void BoundsCheck(int index, int length) { BoundsCheck0(index, length); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public unsafe int CompareTo(IDirectBuffer that) { int capacity = Capacity; int capacity2 = that.Capacity; byte* pBuffer = _pBuffer; byte* ptr = (byte*)that.BufferPointer.ToPointer(); int i = 0; for (int num = Math.Min(capacity, capacity2); i < num; i++) { int num2 = pBuffer[i] - ptr[i]; if (num2 != 0) { return num2; } } if (capacity != capacity2) { return capacity - capacity2; } return 0; } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } ~UnsafeBuffer() { Dispose(disposing: false); } private void Dispose(bool disposing) { if (!_disposed) { FreeGcHandle(); ByteArray = null; ByteBuffer = null; _disposed = true; } } private void FreeGcHandle() { if (_needToFreeGcHandle) { _pinnedGcHandle.Free(); _needToFreeGcHandle = false; } } } public sealed class YieldingIdleStrategy : IIdleStrategy { public static readonly YieldingIdleStrategy INSTANCE = new YieldingIdleStrategy(); public void Idle(int workCount) { if (workCount <= 0) { Thread.Yiel