Esempio n. 1
0
        internal RetainedMemory(Memory <T> memory)
        {
            if (MemoryMarshal.TryGetMemoryManager <T, RetainableMemory <T> >(memory, out var manager))
            {
                manager.Increment();
                _manager = manager;
                _start   = 0;
                _length  = memory.Length;
            }
            else if (MemoryMarshal.TryGetArray <T>(memory, out var segment))
            {
                _manager = ArrayMemory <T> .Create(segment.Array, segment.Offset, segment.Count, externallyOwned : true);

                _manager.Increment();
                _start  = 0;
                _length = _manager.Length;
            }
            else
            {
                ThrowNotSupportedMemoryType();
                _manager = default;
                _start   = 0;
                _length  = 0;
            }

#if DETECT_LEAKS
            _finalizeChecker = new PanicOnFinalize();
#endif
        }
Esempio n. 2
0
        public static unsafe RetainedVec Create <T>(RetainableMemory <T> memorySource, int start, int length, bool externallyOwned = false)
        {
            if (!memorySource.IsBlittableOffheap)
            {
                ThrowHelper.ThrowInvalidOperationException("Memory source must have IsBlittableOffheap = true to be used in RetainedVec.");
            }

            RetainedVec vs;

            if (TypeHelper <T> .IsReferenceOrContainsReferences)
            {
                ThrowHelper.DebugAssert(memorySource.Pointer == default && memorySource._array != default);
                // RM's offset goes to _pointerOrOffset
                vs = new RetainedVec(externallyOwned ? null : memorySource,
                                     memorySource._array,
                                     (IntPtr)memorySource._offset,
                                     memorySource.Length,
                                     VecTypeHelper <T> .RuntimeTypeId);
            }
            else
            {
                ThrowHelper.DebugAssert(memorySource.Pointer != default && memorySource._array == default);
                // RM's offset added to _pointerOrOffset
                vs = new RetainedVec(externallyOwned ? null : memorySource, array: null, (IntPtr)Unsafe.Add <T>(memorySource.Pointer, memorySource._offset), memorySource.Length,
                                     VecTypeHelper <T> .RuntimeTypeId);
            }

            return(vs.Clone(start, length, externallyOwned));
        }
Esempio n. 3
0
            internal RetainableMemory <T> Rent()
            {
                RetainableMemory <T>[] buffers = _buffers;
                RetainableMemory <T>   buffer  = null;

                // While holding the lock, grab whatever is at the next available index and
                // update the index.  We do as little work as possible while holding the spin
                // lock to minimize contention with other threads.  The try/finally is
                // necessary to properly handle thread aborts on platforms which have them.
                // bool lockTaken = false;
                var allocateBuffer = false;

#if !NETCOREAPP
                try
#endif
                {
                    var spinner = new SpinWait();
                    while (0 != Interlocked.CompareExchange(ref _locker, 1, 0))
                    {
                        spinner.SpinOnce();
                    }

                    if (_index < buffers.Length)
                    {
                        buffer            = buffers[_index];
                        buffers[_index++] = null;
                        allocateBuffer    = buffer == null;
                    }
                }
#if !NETCOREAPP
                finally
#endif
                {
                    Volatile.Write(ref _locker, 0);
                }

                // While we were holding the lock, we grabbed whatever was at the next available index, if
                // there was one.  If we tried and if we got back null, that means we hadn't yet allocated
                // for that slot, in which case we should do so now.
                if (allocateBuffer)
                {
                    buffer = CreateNew();

                    var log = RetainableMemoryPoolEventSource.Log;
                    if (log.IsEnabled())
                    {
                        log.BufferAllocated(buffer.GetHashCode(), _bufferLength, _poolId, Id,
                                            RetainableMemoryPoolEventSource.BufferAllocatedReason.Pooled);
                    }
                }
                else
                {
                    if (buffer != null && !buffer._isPooled)
                    {
                        ThrowNotFromPool <RetainableMemory <T> >();
                    }
                }

                return(buffer);
            }
Esempio n. 4
0
        internal bool ReturnInternal(RetainableMemory <T> memory, bool clearMemory = true)
        {
            if (_disposed)
            {
                return(false);
            }

            if (memory._poolIdx != PoolIdx)
            {
                if (memory.IsDisposed)
                {
                    ThrowDisposed <RetainableMemory <T> >();
                }
                else
                {
                    ThrowNotFromPool <RetainableMemory <T> >();
                }
            }

            if (memory._isPooled)
            {
                ThrowAlreadyPooled <RetainableMemory <T> >();
            }

            // Determine with what bucket this array length is associated
            int bucket = SelectBucketIndex(memory.LengthPow2);

            // If we can tell that the buffer was allocated, drop it. Otherwise, check if we have space in the pool
            if (bucket < _buckets.Length)
            {
                // Clear the array if the user requests regardless of pooling result.
                // If not pooled then it should be RM.DisposeFinalize-d and destruction
                // is not always GC.
                if (clearMemory || IsRentAlwaysClean || _typeHasReferences)
                {
                    if (!memory.SkipCleaning)
                    {
                        memory.GetSpan().Clear();
                    }
                }

                memory.SkipCleaning = false;

                // Return the buffer to its bucket.  In the future, we might consider having Return return false
                // instead of dropping a bucket, in which case we could try to return to a lower-sized bucket,
                // just as how in Rent we allow renting from a higher-sized bucket.
                _buckets[bucket].Return(memory);
            }

            // Log that the buffer was returned
            var log = RetainableMemoryPoolEventSource.Log;

            if (log.IsEnabled())
            {
                log.BufferReturned(memory.GetHashCode(), memory.Length, Id);
            }

            return(memory._isPooled);
        }
Esempio n. 5
0
        internal bool ReturnInternal(RetainableMemory <T> memory, bool clearMemory = true)
        {
            if (_disposed)
            {
                return(false);
            }

            if (!memory.IsDisposed)
            {
                ThrowHelper.ThrowInvalidOperationException("Memory must be disposed before returning to RMP.");
            }

            if (memory.PoolIndex != PoolIdx)
            {
                ThrowNotFromPool <RetainableMemory <T> >();
            }

            // Determine with what bucket this buffer length is associated
            var bucketIndex = SelectBucketIndex(memory.LengthPow2);

            var pooled = false;

            // If we can tell that the buffer was allocated, drop it. Otherwise, check if we have space in the pool
            if (bucketIndex < _buckets.Length)
            {
                var bucket = _buckets[bucketIndex];
                if (memory.LengthPow2 != bucket.BufferLength)
                {
                    ThrowNotFromPool <RetainableMemory <T> >();
                }

#pragma warning disable 618
                // Clear the memory if the user requests regardless of pooling result.
                // If not pooled then it should be RM.DisposeFinalize-d and destruction
                // is not always GC.
                if ((clearMemory || IsRentAlwaysClean || _typeHasReferences) && !memory.SkipCleaning)
                {
                    memory.GetSpan().Clear();
                }
                memory.SkipCleaning = false;
#pragma warning restore 618

                pooled = bucket.Return(memory);
            }

            // Log that the buffer was returned
            var log = RetainableMemoryPoolEventSource.Log;
            if (log.IsEnabled())
            {
                log.BufferReturned(memory.GetHashCode(), memory.Length, Id);
            }

            return(pooled);
        }
Esempio n. 6
0
        internal bool Return(RetainableMemory <T> memory, bool clearArray = false)
        {
            // These checks for internal code that could Return directly without Dispose on memory
            memory.EnsureNotRetainedAndNotDisposed();

            if (memory._isPooled)
            {
                ThrowAlreadyPooled <RetainableMemory <T> >();
            }

            return(ReturnNoChecks(memory, clearArray));
        }
Esempio n. 7
0
            internal void Return(RetainableMemory <T> memory)
            {
                // Check to see if the buffer is the correct size for this bucket
                if (memory.LengthPow2 != _bufferLength)
                {
                    ThrowNotFromPool <RetainableMemory <T> >();
                }

                // While holding the spin lock, if there's room available in the bucket,
                // put the buffer into the next available slot.  Otherwise, we just drop it.
                // The try/finally is necessary to properly handle thread aborts on platforms
                // which have them.
                int disposed = 0;

#if !NETCOREAPP
                try
#endif
                {
                    var spinner = new SpinWait();
                    while (0 != Interlocked.CompareExchange(ref _locker, 1, 0))
                    {
                        spinner.SpinOnce();
                    }

                    var pooled = _index != 0;

                    if (pooled)
                    {
                        if ((disposed = AtomicCounter.TryDispose(ref memory.CounterRef)) == 0)
                        {
                            _buffers[--_index] = memory;
                            Debug.Assert(AtomicCounter.GetIsDisposed(ref memory.CounterRef));
                            memory._isPooled = true;
                        }
                    }
                    else
                    {
                        memory.DisposeFinalize();
                    }
                }
#if !NETCOREAPP
                finally
#endif
                {
                    Volatile.Write(ref _locker, 0);
                }
                // after unlock
                if (disposed != 0)
                {
                    AtomicCounter.ThrowNonZeroTryDispose(disposed);
                }
            }
Esempio n. 8
0
        public static VecStorage Create <T>(RetainableMemory <T> memorySource,
                                            int start,
                                            int length,
                                            bool externallyOwned = false)
        {
            var ms  = memorySource ?? throw new ArgumentNullException(nameof(memorySource));
            var vec = ms.GetVec().AsVec().Slice(start, length);

            if (!externallyOwned)
            {
                ms.Increment();
            }

            var vs = new VecStorage(externallyOwned ? null : ms, vec);

            return(vs);
        }
Esempio n. 9
0
        public static RetainedVec Create <T>(RetainableMemory <T>?memorySource, int start, int length, bool externallyOwned = false)
        {
            if (!memorySource.IsBlittableOffheap)
            {
                ThrowHelper.ThrowInvalidOperationException("Memory source must have IsBlittableOffheap = true to be used in RetainedVec.");
            }
            var ms  = memorySource ?? throw new ArgumentNullException(nameof(memorySource));
            var vec = ms.GetVec().AsVec().Slice(start, length);

            if (!externallyOwned)
            {
                ms.Increment();
            }

            var vs = new RetainedVec(externallyOwned ? null : ms, vec);

            return(vs);
        }
Esempio n. 10
0
        internal RetainedMemory(RetainableMemory <T> memory, int offset, int length, bool borrow)
#endif
        {
            Debug.Assert(unchecked ((uint)offset + (uint)length <= memory.Length));

            if (borrow)
            {
                memory.Increment();
            }

            _manager = memory;
            _offset  = offset;
            _length  = length;

            // We do not need to Pin arrays, they do not have ref count. Will be pinned when Pointer is accessed.
#if DETECT_LEAKS
            _finalizeChecker = borrow ? new PanicOnFinalize() : checker;
#endif
        }
Esempio n. 11
0
        public RetainedMemory(Memory <T> memory, bool pin = true) // TODO pin param added later and before it behaved like with true, but better to change to false and review usage
        {
            if (MemoryMarshal.TryGetMemoryManager <T, RetainableMemory <T> >(memory, out var manager))
            {
                if (!manager.IsPinned && pin)
                {
                    // TODO review. This uses implementation detail of RetainableMemory:
                    // if pointer is null then it is an non-pinned array for which we did not create
                    // a GCHandle (very expensive). Call to Pin() checks if pointer is null and
                    // creates a GCHandle + pointer. Try to avoid pinning non-pooled ArrayMemory
                    // because it is very expensive.
                    manager.Pin();
                }
                else
                {
                    manager.Increment();
                }
                _manager = manager;
                _offset  = 0;
                _length  = memory.Length;
            }
            else if (MemoryMarshal.TryGetArray <T>(memory, out var segment))
            {
                _manager = ArrayMemory <T> .Create(segment.Array, segment.Offset, segment.Count, externallyOwned : true, pin);

                _manager.Increment();
                _offset = 0;
                _length = _manager.Length;
            }
            else
            {
                ThrowNotSupportedMemoryType();
                _manager = default;
                _offset  = 0;
                _length  = 0;
            }

#if DETECT_LEAKS
            _finalizeChecker = new PanicOnFinalize();
#endif
        }
Esempio n. 12
0
        internal RetainedMemory(RetainableMemory <T> memory, int start, int length, bool borrow)
        {
            if (memory.IsDisposed)
            {
                BuffersThrowHelper.ThrowDisposed <RetainableMemory <T> >();
            }

            Debug.Assert(unchecked ((uint)start + (uint)length <= memory.Length));

            if (borrow)
            {
                memory.Increment();
            }

            _manager = memory;
            _start   = start;
            _length  = length;

#if DETECT_LEAKS
            _finalizeChecker = new PanicOnFinalize();
#endif
        }
Esempio n. 13
0
 public bool Return(RetainableMemory <T> obj)
 {
     return(Pool.Return(obj));
 }
Esempio n. 14
0
 internal RetainedMemory(RetainableMemory <T> memory, int offset, int length, bool borrow, PanicOnFinalize checker = null)
Esempio n. 15
0
 public bool Return(RetainableMemory <T> memory, bool clearMemory = true)
 {
     return(ReturnInternal(memory, clearMemory));
 }