/// <summary> /// This does actual copy. It should be called only when we /// hold locks on both this and other objects. /// </summary> private void DoCopy( int offset, NativeMemoryChunk other, int otherOffset, int count) { Preconditions.CheckState(!Closed); Preconditions.CheckState(!other.Closed); CheckBounds(offset, other.Size, otherOffset, count); NativeMethods.nativeMemcpy( other._nativePtr + otherOffset, _nativePtr + offset, count); }
/// <summary> /// Reallocate the local buffer to hold the new length specified. /// Also copy over existing data to this new buffer. /// </summary> /// <param name="newLength">New length of buffer.</param> /// <exception cref="InvalidStreamException"> /// If the stream is invalid. /// </exception> /// <exception cref="SizeTooLargeException"> /// If the allocation from the pool fails. /// </exception> internal void Realloc(int newLength) { EnsureValid(); /* Can the buffer handle @i more bytes, if not expand it */ if (newLength <= _bufRef.Get().Size) { return; } NativeMemoryChunk newbuf = _pool.Get(newLength); _bufRef.Get().Copy(0, newbuf, 0, _count); _bufRef.Dispose(); _bufRef = CloseableReference <NativeMemoryChunk> .of(newbuf, _pool); }
/// <summary> /// Copy bytes from native memory wrapped by this /// NativeMemoryChunk instance to native memory wrapped /// by other NativeMemoryChunk. /// </summary> /// <param name="offset"> /// Number of first byte to copy. /// </param> /// <param name="other"> /// Other NativeMemoryChunk to copy to. /// </param> /// <param name="otherOffset"> /// Number of first byte to write to. /// </param> /// <param name="count">Number of bytes to copy.</param> public virtual void Copy( int offset, NativeMemoryChunk other, int otherOffset, int count) { Preconditions.CheckNotNull(other); // This implementation acquires locks on this and other objects // and then delegates to DoCopy which does actual copy. In order // to avoid deadlocks we have to establish some linear order on // all NativeMemoryChunks and acquire locks according to this // order. Fortunately we can use _nativePtr for that purpose. // So we have to address 3 cases: // Case 1: other memory chunk == this memory chunk if (other._nativePtr == _nativePtr) { // we do not allow copying to the same address // lets log warning and not copy Debug.WriteLine($"Copying from NativeMemoryChunk { GetHashCode().ToString("X4") } to NativeMemoryChunk { other.GetHashCode().ToString("X4") } which share the same address { _nativePtr.GetHashCode().ToString("X4") }"); Preconditions.CheckArgument(false); } // Case 2: other memory chunk < this memory chunk if (other._nativePtr < _nativePtr) { lock (_memoryChunkGate) { DoCopy(offset, other, otherOffset, count); } return; } // Case 3: other memory chunk > this memory chunk lock (_memoryChunkGate) { DoCopy(offset, other, otherOffset, count); } }