예제 #1
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);
            }
예제 #2
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);
        }
예제 #3
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);
        }