Browse Source

Merge pull request #2327 from stefannikolei/stefannikolei/nullable/memory

Remove nullable disable from Memory.Allocators
pull/2335/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
84dcd187fe
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs
  2. 3
      src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs
  3. 15
      src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs
  4. 7
      src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs
  5. 11
      src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs
  6. 2
      src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs
  7. 2
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
  8. 2
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs
  9. 6
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs
  10. 10
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
  11. 8
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

11
src/ImageSharp/Memory/Allocators/Internals/Gen2GcCallback.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
// Port of BCL internal utility: // Port of BCL internal utility:
// https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.CoreLib/src/System/Gen2GcCallback.cs // https://github.com/dotnet/runtime/blob/57bfe474518ab5b7cfe6bf7424a79ce3af9d6657/src/libraries/System.Private.CoreLib/src/System/Gen2GcCallback.cs
@ -15,8 +14,8 @@ namespace SixLabors.ImageSharp.Memory.Internals;
/// </summary> /// </summary>
internal sealed class Gen2GcCallback : CriticalFinalizerObject internal sealed class Gen2GcCallback : CriticalFinalizerObject
{ {
private readonly Func<bool> callback0; private readonly Func<bool>? callback0;
private readonly Func<object, bool> callback1; private readonly Func<object, bool>? callback1;
private GCHandle weakTargetObj; private GCHandle weakTargetObj;
private Gen2GcCallback(Func<bool> callback) => this.callback0 = callback; private Gen2GcCallback(Func<bool> callback) => this.callback0 = callback;
@ -32,7 +31,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject
if (this.weakTargetObj.IsAllocated) if (this.weakTargetObj.IsAllocated)
{ {
// Check to see if the target object is still alive. // Check to see if the target object is still alive.
object targetObj = this.weakTargetObj.Target; object? targetObj = this.weakTargetObj.Target;
if (targetObj == null) if (targetObj == null)
{ {
// The target object is dead, so this callback object is no longer needed. // The target object is dead, so this callback object is no longer needed.
@ -43,7 +42,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject
// Execute the callback method. // Execute the callback method.
try try
{ {
if (!this.callback1(targetObj)) if (!this.callback1!(targetObj))
{ {
// If the callback returns false, this callback object is no longer needed. // If the callback returns false, this callback object is no longer needed.
this.weakTargetObj.Free(); this.weakTargetObj.Free();
@ -64,7 +63,7 @@ internal sealed class Gen2GcCallback : CriticalFinalizerObject
// Execute the callback method. // Execute the callback method.
try try
{ {
if (!this.callback0()) if (!this.callback0!())
{ {
// If the callback returns false, this callback object is no longer needed. // If the callback returns false, this callback object is no longer needed.
return; return;

3
src/ImageSharp/Memory/Allocators/Internals/RefCountedMemoryLifetimeGuard.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using SixLabors.ImageSharp.Diagnostics; using SixLabors.ImageSharp.Diagnostics;
@ -15,7 +14,7 @@ internal abstract class RefCountedMemoryLifetimeGuard : IDisposable
private int refCount = 1; private int refCount = 1;
private int disposed; private int disposed;
private int released; private int released;
private string allocationStackTrace; private string? allocationStackTrace;
protected RefCountedMemoryLifetimeGuard() protected RefCountedMemoryLifetimeGuard()
{ {

15
src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -22,7 +22,7 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
this.lifetimeGuard = new LifetimeGuard(this.Array); this.lifetimeGuard = new LifetimeGuard(this.Array);
} }
public byte[] Array { get; private set; } public byte[]? Array { get; private set; }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
{ {
@ -41,7 +41,11 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
return MemoryMarshal.Cast<byte, T>(this.Array.AsSpan(0, this.lengthInBytes)); return MemoryMarshal.Cast<byte, T>(this.Array.AsSpan(0, this.lengthInBytes));
} }
protected override object GetPinnableObject() => this.Array; protected override object GetPinnableObject()
{
this.CheckDisposed();
return this.Array;
}
public void AddRef() public void AddRef()
{ {
@ -52,6 +56,7 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
public void ReleaseRef() => this.lifetimeGuard.ReleaseRef(); public void ReleaseRef() => this.lifetimeGuard.ReleaseRef();
[Conditional("DEBUG")] [Conditional("DEBUG")]
[MemberNotNull(nameof(Array))]
private void CheckDisposed() private void CheckDisposed()
{ {
if (this.Array == null) if (this.Array == null)
@ -62,7 +67,7 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard
{ {
private byte[] array; private byte[]? array;
public LifetimeGuard(byte[] array) => this.array = array; public LifetimeGuard(byte[] array) => this.array = array;
@ -73,7 +78,7 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
// This is not ideal, but subsequent leaks will end up returning arrays to per-cpu buckets, // This is not ideal, but subsequent leaks will end up returning arrays to per-cpu buckets,
// meaning likely a different bucket than it was rented from, // meaning likely a different bucket than it was rented from,
// but this is PROBABLY better than not returning the arrays at all. // but this is PROBABLY better than not returning the arrays at all.
ArrayPool<byte>.Shared.Return(this.array); ArrayPool<byte>.Shared.Return(this.array!);
this.array = null; this.array = null;
} }
} }

7
src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Diagnostics; using System.Diagnostics;
@ -13,7 +12,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx
{ {
private static int minTrimPeriodMilliseconds = int.MaxValue; private static int minTrimPeriodMilliseconds = int.MaxValue;
private static readonly List<WeakReference<UniformUnmanagedMemoryPool>> AllPools = new(); private static readonly List<WeakReference<UniformUnmanagedMemoryPool>> AllPools = new();
private static Timer trimTimer; private static Timer? trimTimer;
private static readonly Stopwatch Stopwatch = Stopwatch.StartNew(); private static readonly Stopwatch Stopwatch = Stopwatch.StartNew();
@ -97,7 +96,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx
/// <summary> /// <summary>
/// Rent <paramref name="bufferCount"/> buffers or return 'null' if the pool is full. /// Rent <paramref name="bufferCount"/> buffers or return 'null' if the pool is full.
/// </summary> /// </summary>
public UnmanagedMemoryHandle[] Rent(int bufferCount) public UnmanagedMemoryHandle[]? Rent(int bufferCount)
{ {
UnmanagedMemoryHandle[] buffersLocal = this.buffers; UnmanagedMemoryHandle[] buffersLocal = this.buffers;
@ -248,7 +247,7 @@ internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedEx
foreach (WeakReference<UniformUnmanagedMemoryPool> weakPoolRef in AllPools) foreach (WeakReference<UniformUnmanagedMemoryPool> weakPoolRef in AllPools)
{ {
if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool pool)) if (weakPoolRef.TryGetTarget(out UniformUnmanagedMemoryPool? pool))
{ {
pool.Trim(); pool.Trim();
} }

11
src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs

@ -1,6 +1,5 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -20,7 +19,7 @@ internal struct UnmanagedMemoryHandle : IEquatable<UnmanagedMemoryHandle>
private static long totalOomRetries; private static long totalOomRetries;
// A Monitor to wait/signal when we are low on memory. // A Monitor to wait/signal when we are low on memory.
private static object lowMemoryMonitor; private static object? lowMemoryMonitor;
public static readonly UnmanagedMemoryHandle NullHandle; public static readonly UnmanagedMemoryHandle NullHandle;
@ -114,9 +113,9 @@ internal struct UnmanagedMemoryHandle : IEquatable<UnmanagedMemoryHandle>
if (Volatile.Read(ref lowMemoryMonitor) != null) if (Volatile.Read(ref lowMemoryMonitor) != null)
{ {
// We are low on memory. Signal all threads waiting in AllocateHandle(). // We are low on memory. Signal all threads waiting in AllocateHandle().
Monitor.Enter(lowMemoryMonitor); Monitor.Enter(lowMemoryMonitor!);
Monitor.PulseAll(lowMemoryMonitor); Monitor.PulseAll(lowMemoryMonitor!);
Monitor.Exit(lowMemoryMonitor); Monitor.Exit(lowMemoryMonitor!);
} }
this.lengthInBytes = 0; this.lengthInBytes = 0;
@ -124,7 +123,7 @@ internal struct UnmanagedMemoryHandle : IEquatable<UnmanagedMemoryHandle>
public bool Equals(UnmanagedMemoryHandle other) => this.handle.Equals(other.handle); public bool Equals(UnmanagedMemoryHandle other) => this.handle.Equals(other.handle);
public override bool Equals(object obj) => obj is UnmanagedMemoryHandle other && this.Equals(other); public override bool Equals(object? obj) => obj is UnmanagedMemoryHandle other && this.Equals(other);
public override int GetHashCode() => this.handle.GetHashCode(); public override int GetHashCode() => this.handle.GetHashCode();
} }

2
src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs

@ -135,7 +135,7 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato
} }
// Attempt to rent the whole group from the pool, allocate a group of unmanaged buffers if the attempt fails: // Attempt to rent the whole group from the pool, allocate a group of unmanaged buffers if the attempt fails:
if (MemoryGroup<T>.TryAllocate(this.pool, totalLength, bufferAlignment, options, out MemoryGroup<T> poolGroup)) if (MemoryGroup<T>.TryAllocate(this.pool, totalLength, bufferAlignment, options, out MemoryGroup<T>? poolGroup))
{ {
return poolGroup; return poolGroup;
} }

2
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs

@ -106,7 +106,7 @@ internal static class MemoryGroupExtensions
} }
} }
internal static void CopyTo<T>(this IMemoryGroup<T> source, IMemoryGroup<T> target) internal static void CopyTo<T>(this IMemoryGroup<T>? source, IMemoryGroup<T>? target)
where T : struct where T : struct
{ {
Guard.NotNull(source, nameof(source)); Guard.NotNull(source, nameof(source));

2
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Memory;
internal unsafe struct MemoryGroupSpanCache internal unsafe struct MemoryGroupSpanCache
{ {
public SpanCacheMode Mode; public SpanCacheMode Mode;
public byte[] SingleArray; public byte[]? SingleArray;
public void* SinglePointer; public void* SinglePointer;
public void*[] MultiPointer; public void*[] MultiPointer;

6
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupView{T}.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Memory;
@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Memory;
internal class MemoryGroupView<T> : IMemoryGroup<T> internal class MemoryGroupView<T> : IMemoryGroup<T>
where T : struct where T : struct
{ {
private MemoryGroup<T> owner; private MemoryGroup<T>? owner;
private readonly MemoryOwnerWrapper[] memoryWrappers; private readonly MemoryOwnerWrapper[] memoryWrappers;
public MemoryGroupView(MemoryGroup<T> owner) public MemoryGroupView(MemoryGroup<T> owner)
@ -63,6 +63,7 @@ internal class MemoryGroupView<T> : IMemoryGroup<T>
} }
} }
[MemberNotNullWhen(true, nameof(owner))]
public bool IsValid => this.owner != null; public bool IsValid => this.owner != null;
public Memory<T> this[int index] public Memory<T> this[int index]
@ -99,6 +100,7 @@ internal class MemoryGroupView<T> : IMemoryGroup<T>
this.owner = null; this.owner = null;
} }
[MemberNotNull(nameof(owner))]
private void EnsureIsValid() private void EnsureIsValid()
{ {
if (!this.IsValid) if (!this.IsValid)

10
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs

@ -1,8 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory.Internals; using SixLabors.ImageSharp.Memory.Internals;
@ -15,8 +15,8 @@ internal abstract partial class MemoryGroup<T>
/// </summary> /// </summary>
public sealed class Owned : MemoryGroup<T>, IEnumerable<Memory<T>> public sealed class Owned : MemoryGroup<T>, IEnumerable<Memory<T>>
{ {
private IMemoryOwner<T>[] memoryOwners; private IMemoryOwner<T>[]? memoryOwners;
private RefCountedMemoryLifetimeGuard groupLifetimeGuard; private RefCountedMemoryLifetimeGuard? groupLifetimeGuard;
public Owned(IMemoryOwner<T>[] memoryOwners, int bufferLength, long totalLength, bool swappable) public Owned(IMemoryOwner<T>[] memoryOwners, int bufferLength, long totalLength, bool swappable)
: base(bufferLength, totalLength) : base(bufferLength, totalLength)
@ -149,7 +149,7 @@ internal abstract partial class MemoryGroup<T>
} }
else else
{ {
foreach (IMemoryOwner<T> memoryOwner in this.memoryOwners) foreach (IMemoryOwner<T> memoryOwner in this.memoryOwners!)
{ {
memoryOwner.Dispose(); memoryOwner.Dispose();
} }
@ -161,6 +161,7 @@ internal abstract partial class MemoryGroup<T>
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
[MemberNotNull(nameof(memoryOwners))]
private void EnsureNotDisposed() private void EnsureNotDisposed()
{ {
if (this.memoryOwners is null) if (this.memoryOwners is null)
@ -170,6 +171,7 @@ internal abstract partial class MemoryGroup<T>
} }
[MethodImpl(MethodImplOptions.NoInlining)] [MethodImpl(MethodImplOptions.NoInlining)]
[DoesNotReturn]
private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(MemoryGroup<T>)); private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(MemoryGroup<T>));
// When the MemoryGroup points to multiple buffers via `groupLifetimeGuard`, // When the MemoryGroup points to multiple buffers via `groupLifetimeGuard`,

8
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

@ -1,9 +1,9 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
#nullable disable
using System.Buffers; using System.Buffers;
using System.Collections; using System.Collections;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory.Internals; using SixLabors.ImageSharp.Memory.Internals;
@ -41,7 +41,7 @@ internal abstract partial class MemoryGroup<T> : IMemoryGroup<T>, IDisposable
/// <inheritdoc /> /// <inheritdoc />
public bool IsValid { get; private set; } = true; public bool IsValid { get; private set; } = true;
public MemoryGroupView<T> View { get; private set; } public MemoryGroupView<T> View { get; private set; } = null!;
/// <inheritdoc /> /// <inheritdoc />
public abstract Memory<T> this[int index] { get; } public abstract Memory<T> this[int index] { get; }
@ -150,7 +150,7 @@ internal abstract partial class MemoryGroup<T> : IMemoryGroup<T>, IDisposable
long totalLengthInElements, long totalLengthInElements,
int bufferAlignmentInElements, int bufferAlignmentInElements,
AllocationOptions options, AllocationOptions options,
out MemoryGroup<T> memoryGroup) [NotNullWhen(true)] out MemoryGroup<T>? memoryGroup)
{ {
Guard.NotNull(pool, nameof(pool)); Guard.NotNull(pool, nameof(pool));
Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements)); Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements));
@ -188,7 +188,7 @@ internal abstract partial class MemoryGroup<T> : IMemoryGroup<T>, IDisposable
bufferCount++; bufferCount++;
} }
UnmanagedMemoryHandle[] arrays = pool.Rent(bufferCount); UnmanagedMemoryHandle[]? arrays = pool.Rent(bufferCount);
if (arrays == null) if (arrays == null)
{ {

Loading…
Cancel
Save