diff --git a/Src/Workshell.PE/ImageReader.cs b/Src/Workshell.PE/ImageReader.cs
index 9e5aa2d..edf8d75 100644
--- a/Src/Workshell.PE/ImageReader.cs
+++ b/Src/Workshell.PE/ImageReader.cs
@@ -6,8 +6,6 @@
using System.Text;
using System.Threading.Tasks;
-using Microsoft.IO;
-
using Workshell.PE.Native;
namespace Workshell.PE
@@ -16,7 +14,7 @@ namespace Workshell.PE
public class ImageReader : IDisposable, ISupportsBytes
{
- class PreloadedInformation
+ private class PreloadedInformation
{
public IMAGE_DOS_HEADER DOSHeader;
@@ -35,12 +33,11 @@ class PreloadedInformation
}
- static RecyclableMemoryStreamManager memory_manager;
-
private bool _disposed;
private Stream _stream;
private bool _own_stream;
private LocationCalculator _calc;
+ private IMemoryStreamProvider _memory_stream_provider;
private DOSHeader _dos_header;
private DOSStub _dos_stub;
@@ -53,17 +50,13 @@ class PreloadedInformation
private bool _is_clr;
private bool _is_signed;
- static ImageReader()
- {
- memory_manager = new RecyclableMemoryStreamManager();
- }
-
private ImageReader(Stream sourceStream, bool ownStream)
{
_disposed = false;
_stream = sourceStream;
_own_stream = ownStream;
_calc = null;
+ _memory_stream_provider = new DefaultMemoryStreamProvider();
_dos_header = null;
_dos_stub = null;
@@ -348,7 +341,7 @@ public Stream GetStream()
public byte[] GetBytes()
{
- using (var mem = memory_manager.GetStream())
+ using (var mem = _memory_stream_provider.GetStream())
{
_stream.Seek(0,SeekOrigin.Begin);
_stream.CopyTo(mem,4096);
@@ -410,19 +403,22 @@ private void Load()
#endregion
- #region Static Properties
+ #region Properties
- internal static RecyclableMemoryStreamManager MemoryManager
+ public IMemoryStreamProvider MemoryStreamProvider
{
get
{
- return memory_manager;
+ return _memory_stream_provider;
}
- }
-
- #endregion
+ set
+ {
+ _memory_stream_provider = value;
- #region Properties
+ if (_memory_stream_provider == null)
+ _memory_stream_provider = new DefaultMemoryStreamProvider();
+ }
+ }
public bool Is32Bit
{
diff --git a/Src/Workshell.PE/MemoryStreamProvider.cs b/Src/Workshell.PE/MemoryStreamProvider.cs
new file mode 100644
index 0000000..d38aed2
--- /dev/null
+++ b/Src/Workshell.PE/MemoryStreamProvider.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Workshell.PE
+{
+
+ public interface IMemoryStreamProvider
+ {
+
+ MemoryStream GetStream();
+ MemoryStream GetStream(byte[] buffer);
+
+ }
+
+ public sealed class DefaultMemoryStreamProvider : IMemoryStreamProvider
+ {
+
+ public MemoryStream GetStream()
+ {
+ return new MemoryStream();
+ }
+
+ public MemoryStream GetStream(byte[] buffer)
+ {
+ return new MemoryStream(buffer);
+ }
+
+ }
+
+}
diff --git a/Src/Workshell.PE/Microsoft/Events.cs b/Src/Workshell.PE/Microsoft/Events.cs
deleted file mode 100644
index 9e948e1..0000000
--- a/Src/Workshell.PE/Microsoft/Events.cs
+++ /dev/null
@@ -1,153 +0,0 @@
-// ---------------------------------------------------------------------
-// Copyright (c) 2015 Microsoft
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ---------------------------------------------------------------------
-
-namespace Microsoft.IO
-{
- using System;
- using System.Diagnostics.Tracing;
-
- partial class RecyclableMemoryStreamManager
- {
-
- [EventSource(Name = "Microsoft-IO-RecyclableMemoryStream", Guid = "{B80CD4E4-890E-468D-9CBA-90EB7C82DFC7}")]
- public sealed class Events : EventSource
- {
-
- public static Events Write = new Events();
-
- public enum MemoryStreamBufferType
- {
- Small,
- Large
- }
-
- public enum MemoryStreamDiscardReason
- {
- TooLarge,
- EnoughFree
- }
-
- [Event(1, Level = EventLevel.Verbose)]
- public void MemoryStreamCreated(Guid guid, string tag, int requestedSize)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(1, guid, tag ?? string.Empty, requestedSize);
- }
- }
-
- [Event(2, Level = EventLevel.Verbose)]
- public void MemoryStreamDisposed(Guid guid, string tag)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(2, guid, tag ?? string.Empty);
- }
- }
-
- [Event(3, Level = EventLevel.Critical)]
- public void MemoryStreamDoubleDispose(Guid guid, string tag, string allocationStack, string disposeStack1, string disposeStack2)
- {
- if (this.IsEnabled())
- {
- this.WriteEvent(3, guid, tag ?? string.Empty, allocationStack ?? string.Empty,
- disposeStack1 ?? string.Empty, disposeStack2 ?? string.Empty);
- }
- }
-
- [Event(4, Level = EventLevel.Error)]
- public void MemoryStreamFinalized(Guid guid, string tag, string allocationStack)
- {
- if (this.IsEnabled())
- {
- WriteEvent(4, guid, tag ?? string.Empty, allocationStack ?? string.Empty);
- }
- }
-
- [Event(5, Level = EventLevel.Verbose)]
- public void MemoryStreamToArray(Guid guid, string tag, string stack, int size)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(5, guid, tag ?? string.Empty, stack ?? string.Empty, size);
- }
- }
-
- [Event(6, Level = EventLevel.Informational)]
- public void MemoryStreamManagerInitialized(int blockSize, int largeBufferMultiple, int maximumBufferSize)
- {
- if (this.IsEnabled())
- {
- WriteEvent(6, blockSize, largeBufferMultiple, maximumBufferSize);
- }
- }
-
- [Event(7, Level = EventLevel.Verbose)]
- public void MemoryStreamNewBlockCreated(long smallPoolInUseBytes)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(7, smallPoolInUseBytes);
- }
- }
-
- [Event(8, Level = EventLevel.Verbose)]
- public void MemoryStreamNewLargeBufferCreated(int requiredSize, long largePoolInUseBytes)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(8, requiredSize, largePoolInUseBytes);
- }
- }
-
- [Event(9, Level = EventLevel.Verbose)]
- public void MemoryStreamNonPooledLargeBufferCreated(int requiredSize, string tag, string allocationStack)
- {
- if (this.IsEnabled(EventLevel.Verbose, EventKeywords.None))
- {
- WriteEvent(9, requiredSize, tag ?? string.Empty, allocationStack ?? string.Empty);
- }
- }
-
- [Event(10, Level = EventLevel.Warning)]
- public void MemoryStreamDiscardBuffer(MemoryStreamBufferType bufferType, string tag, MemoryStreamDiscardReason reason)
- {
- if (this.IsEnabled())
- {
- WriteEvent(10, bufferType, tag ?? string.Empty, reason);
- }
- }
-
- [Event(11, Level = EventLevel.Error)]
- public void MemoryStreamOverCapacity(int requestedCapacity, long maxCapacity, string tag, string allocationStack)
- {
- if (this.IsEnabled())
- {
- WriteEvent(11, requestedCapacity, maxCapacity, tag ?? string.Empty, allocationStack ?? string.Empty);
- }
- }
-
- }
-
- }
-
-}
\ No newline at end of file
diff --git a/Src/Workshell.PE/Microsoft/RecyclableMemoryStream.cs b/Src/Workshell.PE/Microsoft/RecyclableMemoryStream.cs
deleted file mode 100644
index 217c027..0000000
--- a/Src/Workshell.PE/Microsoft/RecyclableMemoryStream.cs
+++ /dev/null
@@ -1,873 +0,0 @@
-// ---------------------------------------------------------------------
-// Copyright (c) 2015 Microsoft
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ---------------------------------------------------------------------
-
-namespace Microsoft.IO
-{
- using System;
- using System.IO;
- using System.Collections.Generic;
-
- using Events = RecyclableMemoryStreamManager.Events;
-
- ///
- /// MemoryStream implementation that deals with pooling and managing memory streams which use potentially large
- /// buffers.
- ///
- ///
- /// This class works in tandem with the RecylableMemoryStreamManager to supply MemoryStream
- /// objects to callers, while avoiding these specific problems:
- /// 1. LOH allocations - since all large buffers are pooled, they will never incur a Gen2 GC
- /// 2. Memory waste - A standard memory stream doubles its size when it runs out of room. This
- /// leads to continual memory growth as each stream approaches the maximum allowed size.
- /// 3. Memory copying - Each time a MemoryStream grows, all the bytes are copied into new buffers.
- /// This implementation only copies the bytes when GetBuffer is called.
- /// 4. Memory fragmentation - By using homogeneous buffer sizes, it ensures that blocks of memory
- /// can be easily reused.
- ///
- /// The stream is implemented on top of a series of uniformly-sized blocks. As the stream's length grows,
- /// additional blocks are retrieved from the memory manager. It is these blocks that are pooled, not the stream
- /// object itself.
- ///
- /// The biggest wrinkle in this implementation is when GetBuffer() is called. This requires a single
- /// contiguous buffer. If only a single block is in use, then that block is returned. If multiple blocks
- /// are in use, we retrieve a larger buffer from the memory manager. These large buffers are also pooled,
- /// split by size--they are multiples of a chunk size (1 MB by default).
- ///
- /// Once a large buffer is assigned to the stream the blocks are NEVER again used for this stream. All operations take place on the
- /// large buffer. The large buffer can be replaced by a larger buffer from the pool as needed. All blocks and large buffers
- /// are maintained in the stream until the stream is disposed (unless AggressiveBufferReturn is enabled in the stream manager).
- ///
- ///
- internal sealed class RecyclableMemoryStream : MemoryStream
- {
- private const long MaxStreamLength = Int32.MaxValue;
-
- private static readonly byte[] emptyArray = new byte[0];
-
- ///
- /// All of these blocks must be the same size
- ///
- private readonly List blocks = new List(1);
-
- ///
- /// This is only set by GetBuffer() if the necessary buffer is larger than a single block size, or on
- /// construction if the caller immediately requests a single large buffer.
- ///
- /// If this field is non-null, it contains the concatenation of the bytes found in the individual
- /// blocks. Once it is created, this (or a larger) largeBuffer will be used for the life of the stream.
- ///
- private byte[] largeBuffer;
-
- ///
- /// This list is used to store buffers once they're replaced by something larger.
- /// This is for the cases where you have users of this class that may hold onto the buffers longer
- /// than they should and you want to prevent race conditions which could corrupt the data.
- ///
- private List dirtyBuffers;
-
- private readonly Guid id;
- ///
- /// Unique identifier for this stream across it's entire lifetime
- ///
- /// Object has been disposed
- internal Guid Id { get { this.CheckDisposed(); return this.id; } }
-
- private readonly string tag;
- ///
- /// A temporary identifier for the current usage of this stream.
- ///
- /// Object has been disposed
- internal string Tag { get { this.CheckDisposed(); return this.tag; } }
-
- private readonly RecyclableMemoryStreamManager memoryManager;
-
- ///
- /// Gets the memory manager being used by this stream.
- ///
- /// Object has been disposed
- internal RecyclableMemoryStreamManager MemoryManager
- {
- get
- {
- this.CheckDisposed();
- return this.memoryManager;
- }
- }
-
- private bool disposed;
-
- private readonly string allocationStack;
- private string disposeStack;
-
- ///
- /// Callstack of the constructor. It is only set if MemoryManager.GenerateCallStacks is true,
- /// which should only be in debugging situations.
- ///
- internal string AllocationStack { get { return this.allocationStack; } }
-
- ///
- /// Callstack of the Dispose call. It is only set if MemoryManager.GenerateCallStacks is true,
- /// which should only be in debugging situations.
- ///
- internal string DisposeStack { get { return this.disposeStack; } }
-
- ///
- /// This buffer exists so that WriteByte can forward all of its calls to Write
- /// without creating a new byte[] buffer on every call.
- ///
- private readonly byte[] byteBuffer = new byte[1];
-
- #region Constructors
- ///
- /// Allocate a new RecyclableMemoryStream object.
- ///
- /// The memory manager
- public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager)
- : this(memoryManager, null, 0, null)
- {
- }
-
- ///
- /// Allocate a new RecyclableMemoryStream object
- ///
- /// The memory manager
- /// A string identifying this stream for logging and debugging purposes
- public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag)
- : this(memoryManager, tag, 0, null)
- {
- }
-
- ///
- /// Allocate a new RecyclableMemoryStream object
- ///
- /// The memory manager
- /// A string identifying this stream for logging and debugging purposes
- /// The initial requested size to prevent future allocations
- public RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag, int requestedSize)
- : this(memoryManager, tag, requestedSize, null)
- {
- }
-
- ///
- /// Allocate a new RecyclableMemoryStream object
- ///
- /// The memory manager
- /// A string identifying this stream for logging and debugging purposes
- /// The initial requested size to prevent future allocations
- /// An initial buffer to use. This buffer will be owned by the stream and returned to the memory manager upon Dispose.
- internal RecyclableMemoryStream(RecyclableMemoryStreamManager memoryManager, string tag, int requestedSize,
- byte[] initialLargeBuffer)
- : base(emptyArray)
- {
- this.memoryManager = memoryManager;
- this.id = Guid.NewGuid();
- this.tag = tag;
-
- if (requestedSize < memoryManager.BlockSize)
- {
- requestedSize = memoryManager.BlockSize;
- }
-
- if (initialLargeBuffer == null)
- {
- this.EnsureCapacity(requestedSize);
- }
- else
- {
- this.largeBuffer = initialLargeBuffer;
- }
-
- this.disposed = false;
-
- if (this.memoryManager.GenerateCallStacks)
- {
- this.allocationStack = Environment.StackTrace;
- }
-
- Events.Write.MemoryStreamCreated(this.id, this.tag, requestedSize);
- this.memoryManager.ReportStreamCreated();
- }
- #endregion
-
- #region Dispose and Finalize
- ~RecyclableMemoryStream()
- {
- this.Dispose(false);
- }
-
- ///
- /// Returns the memory used by this stream back to the pool.
- ///
- /// Whether we're disposing (true), or being called by the finalizer (false)
- /// This method is not thread safe and it may not be called more than once.
- [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1816:CallGCSuppressFinalizeCorrectly", Justification = "We have different disposal semantics, so SuppressFinalize is in a different spot.")]
- protected override void Dispose(bool disposing)
- {
- if (this.disposed)
- {
- string doubleDisposeStack = null;
- if (this.memoryManager.GenerateCallStacks)
- {
- doubleDisposeStack = Environment.StackTrace;
- }
-
- Events.Write.MemoryStreamDoubleDispose(this.id, this.tag, this.allocationStack, this.disposeStack, doubleDisposeStack);
- return;
- }
-
- Events.Write.MemoryStreamDisposed(this.id, this.tag);
-
- if (this.memoryManager.GenerateCallStacks)
- {
- this.disposeStack = Environment.StackTrace;
- }
-
- if (disposing)
- {
- // Once this flag is set, we can't access any properties -- use fields directly
- this.disposed = true;
-
- this.memoryManager.ReportStreamDisposed();
-
- GC.SuppressFinalize(this);
- }
- else
- {
- // We're being finalized.
-
- Events.Write.MemoryStreamFinalized(this.id, this.tag, this.allocationStack);
-
- if (AppDomain.CurrentDomain.IsFinalizingForUnload())
- {
- // If we're being finalized because of a shutdown, don't go any further.
- // We have no idea what's already been cleaned up. Triggering events may cause
- // a crash.
- base.Dispose(disposing);
- return;
- }
-
- this.memoryManager.ReportStreamFinalized();
- }
-
- this.memoryManager.ReportStreamLength(this.length);
-
- if (this.largeBuffer != null)
- {
- this.memoryManager.ReturnLargeBuffer(this.largeBuffer, this.tag);
- }
-
- if (this.dirtyBuffers != null)
- {
- foreach (var buffer in this.dirtyBuffers)
- {
- this.memoryManager.ReturnLargeBuffer(buffer, this.tag);
- }
- }
-
- this.memoryManager.ReturnBlocks(this.blocks, this.tag);
-
- base.Dispose(disposing);
- }
-
- ///
- /// Equivalent to Dispose
- ///
- public override void Close()
- {
- this.Dispose(true);
- }
- #endregion
-
- #region MemoryStream overrides
- ///
- /// Gets or sets the capacity
- ///
- /// Capacity is always in multiples of the memory manager's block size, unless
- /// the large buffer is in use. Capacity never decreases during a stream's lifetime.
- /// Explicitly setting the capacity to a lower value than the current value will have no effect.
- /// This is because the buffers are all pooled by chunks and there's little reason to
- /// allow stream truncation.
- ///
- /// Object has been disposed
- public override int Capacity
- {
- get
- {
- this.CheckDisposed();
- if (this.largeBuffer != null)
- {
- return this.largeBuffer.Length;
- }
-
- if (this.blocks.Count > 0)
- {
- return this.blocks.Count * this.memoryManager.BlockSize;
- }
- return 0;
- }
- set
- {
- this.CheckDisposed();
- this.EnsureCapacity(value);
- }
- }
-
- private int length;
-
- ///
- /// Gets the number of bytes written to this stream.
- ///
- /// Object has been disposed
- public override long Length
- {
- get
- {
- this.CheckDisposed();
- return this.length;
- }
- }
-
- private int position;
-
- ///
- /// Gets the current position in the stream
- ///
- /// Object has been disposed
- public override long Position
- {
- get
- {
- this.CheckDisposed();
- return this.position;
- }
- set
- {
- this.CheckDisposed();
- if (value < 0)
- {
- throw new ArgumentOutOfRangeException("value", "value must be non-negative");
- }
-
- if (value > MaxStreamLength)
- {
- throw new ArgumentOutOfRangeException("value", "value cannot be more than " + MaxStreamLength);
- }
-
- this.position = (int)value;
- }
- }
-
- ///
- /// Whether the stream can currently read
- ///
- public override bool CanRead
- {
- get { return !this.disposed; }
- }
-
- ///
- /// Whether the stream can currently seek
- ///
- public override bool CanSeek
- {
- get { return !this.disposed; }
- }
-
- ///
- /// Always false
- ///
- public override bool CanTimeout
- {
- get { return false; }
- }
-
- ///
- /// Whether the stream can currently write
- ///
- public override bool CanWrite
- {
- get { return !this.disposed; }
- }
-
- ///
- /// Returns a single buffer containing the contents of the stream.
- /// The buffer may be longer than the stream length.
- ///
- /// A byte[] buffer
- /// IMPORTANT: Doing a Write() after calling GetBuffer() invalidates the buffer. The old buffer is held onto
- /// until Dispose is called, but the next time GetBuffer() is called, a new buffer from the pool will be required.
- /// Object has been disposed
- public override byte[] GetBuffer()
- {
- this.CheckDisposed();
-
- if (this.largeBuffer != null)
- {
- return this.largeBuffer;
- }
-
- if (this.blocks.Count == 1)
- {
- return this.blocks[0];
- }
-
- // Buffer needs to reflect the capacity, not the length, because
- // it's possible that people will manipulate the buffer directly
- // and set the length afterward. Capacity sets the expectation
- // for the size of the buffer.
- var newBuffer = this.memoryManager.GetLargeBuffer(this.Capacity, this.tag);
-
- // InternalRead will check for existence of largeBuffer, so make sure we
- // don't set it until after we've copied the data.
- this.InternalRead(newBuffer, 0, this.length, 0);
- this.largeBuffer = newBuffer;
-
- if (this.blocks.Count > 0 && this.memoryManager.AggressiveBufferReturn)
- {
- this.memoryManager.ReturnBlocks(this.blocks, this.tag);
- this.blocks.Clear();
- }
-
- return this.largeBuffer;
- }
-
- ///
- /// Returns a new array with a copy of the buffer's contents. You should almost certainly be using GetBuffer combined with the Length to
- /// access the bytes in this stream. Calling ToArray will destroy the benefits of pooled buffers, but it is included
- /// for the sake of completeness.
- ///
- /// Object has been disposed
- [Obsolete("This method has degraded performance vs. GetBuffer and should be avoided.")]
- public override byte[] ToArray()
- {
- this.CheckDisposed();
- var newBuffer = new byte[this.Length];
-
- this.InternalRead(newBuffer, 0, this.length, 0);
- string stack = this.memoryManager.GenerateCallStacks ? Environment.StackTrace : null;
- Events.Write.MemoryStreamToArray(this.id, this.tag, stack, 0);
- this.memoryManager.ReportStreamToArray();
-
- return newBuffer;
- }
-
- ///
- /// Reads from the current position into the provided buffer
- ///
- /// Destination buffer
- /// Offset into buffer at which to start placing the read bytes.
- /// Number of bytes to read.
- /// The number of bytes read
- /// buffer is null
- /// offset or count is less than 0
- /// offset subtracted from the buffer length is less than count
- /// Object has been disposed
- public override int Read(byte[] buffer, int offset, int count)
- {
- return this.SafeRead(buffer, offset, count, ref this.position);
- }
-
- ///
- /// Reads from the specified position into the provided buffer
- ///
- /// Destination buffer
- /// Offset into buffer at which to start placing the read bytes.
- /// Number of bytes to read.
- /// Position in the stream to start reading from
- /// The number of bytes read
- /// buffer is null
- /// offset or count is less than 0
- /// offset subtracted from the buffer length is less than count
- /// Object has been disposed
- public int SafeRead(byte[] buffer, int offset, int count, ref int streamPosition)
- {
- this.CheckDisposed();
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", "offset cannot be negative");
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", "count cannot be negative");
- }
-
- if (offset + count > buffer.Length)
- {
- throw new ArgumentException("buffer length must be at least offset + count");
- }
-
- int amountRead = this.InternalRead(buffer, offset, count, streamPosition);
- streamPosition += amountRead;
- return amountRead;
- }
-
- ///
- /// Writes the buffer to the stream
- ///
- /// Source buffer
- /// Start position
- /// Number of bytes to write
- /// buffer is null
- /// offset or count is negative
- /// buffer.Length - offset is not less than count
- /// Object has been disposed
- public override void Write(byte[] buffer, int offset, int count)
- {
- this.CheckDisposed();
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
-
- if (offset < 0)
- {
- throw new ArgumentOutOfRangeException("offset", offset, "Offset must be in the range of 0 - buffer.Length-1");
- }
-
- if (count < 0)
- {
- throw new ArgumentOutOfRangeException("count", count, "count must be non-negative");
- }
-
- if (count + offset > buffer.Length)
- {
- throw new ArgumentException("count must be greater than buffer.Length - offset");
- }
-
- int blockSize = this.memoryManager.BlockSize;
- long end = (long)this.position + count;
- // Check for overflow
- if (end > MaxStreamLength)
- {
- throw new IOException("Maximum capacity exceeded");
- }
-
- long requiredBuffers = (end + blockSize - 1) / blockSize;
-
- if (requiredBuffers * blockSize > MaxStreamLength)
- {
- throw new IOException("Maximum capacity exceeded");
- }
-
- this.EnsureCapacity((int)end);
-
- if (this.largeBuffer == null)
- {
- int bytesRemaining = count;
- int bytesWritten = 0;
- var blockAndOffset = this.GetBlockAndRelativeOffset(this.position);
-
- while (bytesRemaining > 0)
- {
- byte[] currentBlock = this.blocks[blockAndOffset.Block];
- int remainingInBlock = blockSize - blockAndOffset.Offset;
- int amountToWriteInBlock = Math.Min(remainingInBlock, bytesRemaining);
-
- Buffer.BlockCopy(buffer, offset + bytesWritten, currentBlock, blockAndOffset.Offset, amountToWriteInBlock);
-
- bytesRemaining -= amountToWriteInBlock;
- bytesWritten += amountToWriteInBlock;
-
- ++blockAndOffset.Block;
- blockAndOffset.Offset = 0;
- }
- }
- else
- {
- Buffer.BlockCopy(buffer, offset, this.largeBuffer, this.position, count);
- }
- this.position = (int)end;
- this.length = Math.Max(this.position, this.length);
- }
-
- ///
- /// Returns a useful string for debugging. This should not normally be called in actual production code.
- ///
- public override string ToString()
- {
- return string.Format("Id = {0}, Tag = {1}, Length = {2:N0} bytes", this.Id, this.Tag, this.Length);
- }
-
- ///
- /// Writes a single byte to the current position in the stream.
- ///
- /// byte value to write
- /// Object has been disposed
- public override void WriteByte(byte value)
- {
- this.CheckDisposed();
- this.byteBuffer[0] = value;
- this.Write(this.byteBuffer, 0, 1);
- }
-
- ///
- /// Reads a single byte from the current position in the stream.
- ///
- /// The byte at the current position, or -1 if the position is at the end of the stream.
- /// Object has been disposed
- public override int ReadByte()
- {
- return this.SafeReadByte(ref this.position);
- }
-
- ///
- /// Reads a single byte from the specified position in the stream.
- ///
- /// The position in the stream to read from
- /// The byte at the current position, or -1 if the position is at the end of the stream.
- /// Object has been disposed
- public int SafeReadByte(ref int streamPosition)
- {
- this.CheckDisposed();
- if (streamPosition == this.length)
- {
- return -1;
- }
- byte value = 0;
- if (this.largeBuffer == null)
- {
- var blockAndOffset = this.GetBlockAndRelativeOffset(streamPosition);
- value = this.blocks[blockAndOffset.Block][blockAndOffset.Offset];
- }
- else
- {
- value = this.largeBuffer[streamPosition];
- }
- streamPosition++;
- return value;
- }
-
- ///
- /// Sets the length of the stream
- ///
- /// value is negative or larger than MaxStreamLength
- /// Object has been disposed
- public override void SetLength(long value)
- {
- this.CheckDisposed();
- if (value < 0 || value > MaxStreamLength)
- {
- throw new ArgumentOutOfRangeException("value", "value must be non-negative and at most " + MaxStreamLength);
- }
-
- this.EnsureCapacity((int)value);
-
- this.length = (int)value;
- if (this.position > value)
- {
- this.position = (int)value;
- }
- }
-
- ///
- /// Sets the position to the offset from the seek location
- ///
- /// How many bytes to move
- /// From where
- /// The new position
- /// Object has been disposed
- /// offset is larger than MaxStreamLength
- /// Invalid seek origin
- /// Attempt to set negative position
- public override long Seek(long offset, SeekOrigin loc)
- {
- this.CheckDisposed();
- if (offset > MaxStreamLength)
- {
- throw new ArgumentOutOfRangeException("offset", "offset cannot be larger than " + MaxStreamLength);
- }
-
- int newPosition;
- switch (loc)
- {
- case SeekOrigin.Begin:
- newPosition = (int)offset;
- break;
- case SeekOrigin.Current:
- newPosition = (int)offset + this.position;
- break;
- case SeekOrigin.End:
- newPosition = (int)offset + this.length;
- break;
- default:
- throw new ArgumentException("Invalid seek origin", "loc");
- }
- if (newPosition < 0)
- {
- throw new IOException("Seek before beginning");
- }
- this.position = newPosition;
- return this.position;
- }
-
- ///
- /// Synchronously writes this stream's bytes to the parameter stream.
- ///
- /// Destination stream
- /// Important: This does a synchronous write, which may not be desired in some situations
- public override void WriteTo(Stream stream)
- {
- this.CheckDisposed();
- if (stream == null)
- {
- throw new ArgumentNullException("stream");
- }
-
- if (this.largeBuffer == null)
- {
- int currentBlock = 0;
- int bytesRemaining = this.length;
-
- while (bytesRemaining > 0)
- {
- int amountToCopy = Math.Min(this.blocks[currentBlock].Length, bytesRemaining);
- stream.Write(this.blocks[currentBlock], 0, amountToCopy);
-
- bytesRemaining -= amountToCopy;
-
- ++currentBlock;
- }
- }
- else
- {
- stream.Write(this.largeBuffer, 0, this.length);
- }
- }
- #endregion
-
- #region Helper Methods
- private void CheckDisposed()
- {
- if (this.disposed)
- {
- throw new ObjectDisposedException(string.Format("The stream with Id {0} and Tag {1} is disposed.", this.id, this.tag));
- }
- }
-
- private int InternalRead(byte[] buffer, int offset, int count, int fromPosition)
- {
- if (this.length - fromPosition <= 0)
- {
- return 0;
- }
- if (this.largeBuffer == null)
- {
- var blockAndOffset = this.GetBlockAndRelativeOffset(fromPosition);
- int bytesWritten = 0;
- int bytesRemaining = Math.Min(count, this.length - fromPosition);
-
- while (bytesRemaining > 0)
- {
- int amountToCopy = Math.Min(this.blocks[blockAndOffset.Block].Length - blockAndOffset.Offset, bytesRemaining);
- Buffer.BlockCopy(this.blocks[blockAndOffset.Block], blockAndOffset.Offset, buffer, bytesWritten + offset, amountToCopy);
-
- bytesWritten += amountToCopy;
- bytesRemaining -= amountToCopy;
-
- ++blockAndOffset.Block;
- blockAndOffset.Offset = 0;
- }
- return bytesWritten;
- }
- else
- {
- int amountToCopy = Math.Min(count, this.length - fromPosition);
- Buffer.BlockCopy(this.largeBuffer, fromPosition, buffer, offset, amountToCopy);
- return amountToCopy;
- }
- }
-
- private struct BlockAndOffset
- {
- public int Block;
- public int Offset;
-
- public BlockAndOffset(int block, int offset)
- {
- this.Block = block;
- this.Offset = offset;
- }
- }
-
- private BlockAndOffset GetBlockAndRelativeOffset(int offset)
- {
- var blockSize = this.memoryManager.BlockSize;
- return new BlockAndOffset(offset / blockSize, offset % blockSize);
- }
-
- private void EnsureCapacity(int newCapacity)
- {
- if (newCapacity > this.memoryManager.MaximumStreamCapacity && this.memoryManager.MaximumStreamCapacity > 0)
- {
- Events.Write.MemoryStreamOverCapacity(newCapacity, this.memoryManager.MaximumStreamCapacity, this.tag, this.allocationStack);
- throw new InvalidOperationException("Requested capacity is too large: " + newCapacity + ". Limit is " + this.memoryManager.MaximumStreamCapacity);
- }
-
- if (this.largeBuffer != null)
- {
- if (newCapacity > this.largeBuffer.Length)
- {
- var newBuffer = this.memoryManager.GetLargeBuffer(newCapacity, this.tag);
- this.InternalRead(newBuffer, 0, this.length, 0);
- this.ReleaseLargeBuffer();
- this.largeBuffer = newBuffer;
- }
- }
- else
- {
- while (this.Capacity < newCapacity)
- {
- blocks.Add((this.memoryManager.GetBlock()));
- }
- }
- }
-
- ///
- /// Release the large buffer (either stores it for eventual release or returns it immediately).
- ///
- private void ReleaseLargeBuffer()
- {
- if (this.memoryManager.AggressiveBufferReturn)
- {
- this.memoryManager.ReturnLargeBuffer(this.largeBuffer, this.tag);
- }
- else
- {
- if (this.dirtyBuffers == null)
- {
- // We most likely will only ever need space for one
- this.dirtyBuffers = new List(1);
- }
- this.dirtyBuffers.Add(this.largeBuffer);
- }
-
- this.largeBuffer = null;
- }
- #endregion
- }
-}
\ No newline at end of file
diff --git a/Src/Workshell.PE/Microsoft/RecyclableMemoryStreamManager.cs b/Src/Workshell.PE/Microsoft/RecyclableMemoryStreamManager.cs
deleted file mode 100644
index 8b5d20b..0000000
--- a/Src/Workshell.PE/Microsoft/RecyclableMemoryStreamManager.cs
+++ /dev/null
@@ -1,672 +0,0 @@
-// ---------------------------------------------------------------------
-// Copyright (c) 2015 Microsoft
-//
-// Permission is hereby granted, free of charge, to any person obtaining a copy
-// of this software and associated documentation files (the "Software"), to deal
-// in the Software without restriction, including without limitation the rights
-// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-// copies of the Software, and to permit persons to whom the Software is
-// furnished to do so, subject to the following conditions:
-//
-// The above copyright notice and this permission notice shall be included in
-// all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-// THE SOFTWARE.
-// ---------------------------------------------------------------------
-
-namespace Microsoft.IO
-{
- using System;
- using System.Collections.Concurrent;
- using System.Collections.Generic;
- using System.Diagnostics.CodeAnalysis;
- using System.IO;
- using System.Linq;
- using System.Threading;
-
- ///
- /// Manages pools of RecyclableMemoryStream objects.
- ///
- ///
- /// There are two pools managed in here. The small pool contains same-sized buffers that are handed to streams
- /// as they write more data.
- ///
- /// For scenarios that need to call GetBuffer(), the large pool contains buffers of various sizes, all
- /// multiples of LargeBufferMultiple (1 MB by default). They are split by size to avoid overly-wasteful buffer
- /// usage. There should be far fewer 8 MB buffers than 1 MB buffers, for example.
- ///
- internal sealed partial class RecyclableMemoryStreamManager
- {
- ///
- /// Generic delegate for handling events without any arguments.
- ///
- public delegate void EventHandler();
-
- ///
- /// Delegate for handling large buffer discard reports.
- ///
- /// Reason the buffer was discarded.
- public delegate void LargeBufferDiscardedEventHandler(Events.MemoryStreamDiscardReason reason);
-
- ///
- /// Delegate for handling reports of stream size when streams are allocated
- ///
- /// Bytes allocated.
- public delegate void StreamLengthReportHandler(long bytes);
-
- ///
- /// Delegate for handling periodic reporting of memory use statistics.
- ///
- /// Bytes currently in use in the small pool.
- /// Bytes currently free in the small pool.
- /// Bytes currently in use in the large pool.
- /// Bytes currently free in the large pool.
- public delegate void UsageReportEventHandler(
- long smallPoolInUseBytes, long smallPoolFreeBytes, long largePoolInUseBytes, long largePoolFreeBytes);
-
- public const int DefaultBlockSize = 128 * 1024;
- public const int DefaultLargeBufferMultiple = 1024 * 1024;
- public const int DefaultMaximumBufferSize = 128 * 1024 * 1024;
-
- private readonly int blockSize;
- private readonly long[] largeBufferFreeSize;
- private readonly long[] largeBufferInUseSize;
-
- private readonly int largeBufferMultiple;
-
- ///
- /// pools[0] = 1x largeBufferMultiple buffers
- /// pools[1] = 2x largeBufferMultiple buffers
- /// etc., up to maximumBufferSize
- ///
- private readonly ConcurrentStack[] largePools;
-
- private readonly int maximumBufferSize;
- private readonly ConcurrentStack smallPool;
-
- private long smallPoolFreeSize;
- private long smallPoolInUseSize;
-
- ///
- /// Initializes the memory manager with the default block/buffer specifications.
- ///
- public RecyclableMemoryStreamManager()
- : this(DefaultBlockSize, DefaultLargeBufferMultiple, DefaultMaximumBufferSize) { }
-
- ///
- /// Initializes the memory manager with the given block requiredSize.
- ///
- /// Size of each block that is pooled. Must be > 0.
- /// Each large buffer will be a multiple of this value.
- /// Buffers larger than this are not pooled
- /// blockSize is not a positive number, or largeBufferMultiple is not a positive number, or maximumBufferSize is less than blockSize.
- /// maximumBufferSize is not a multiple of largeBufferMultiple
- public RecyclableMemoryStreamManager(int blockSize, int largeBufferMultiple, int maximumBufferSize)
- {
- if (blockSize <= 0)
- {
- throw new ArgumentOutOfRangeException("blockSize", blockSize, "blockSize must be a positive number");
- }
-
- if (largeBufferMultiple <= 0)
- {
- throw new ArgumentOutOfRangeException("largeBufferMultiple",
- "largeBufferMultiple must be a positive number");
- }
-
- if (maximumBufferSize < blockSize)
- {
- throw new ArgumentOutOfRangeException("maximumBufferSize",
- "maximumBufferSize must be at least blockSize");
- }
-
- this.blockSize = blockSize;
- this.largeBufferMultiple = largeBufferMultiple;
- this.maximumBufferSize = maximumBufferSize;
-
- if (!this.IsLargeBufferMultiple(maximumBufferSize))
- {
- throw new ArgumentException("maximumBufferSize is not a multiple of largeBufferMultiple",
- "maximumBufferSize");
- }
-
- this.smallPool = new ConcurrentStack();
- var numLargePools = maximumBufferSize / largeBufferMultiple;
-
- // +1 to store size of bytes in use that are too large to be pooled
- this.largeBufferInUseSize = new long[numLargePools + 1];
- this.largeBufferFreeSize = new long[numLargePools];
-
- this.largePools = new ConcurrentStack[numLargePools];
-
- for (var i = 0; i < this.largePools.Length; ++i)
- {
- this.largePools[i] = new ConcurrentStack();
- }
-
- Events.Write.MemoryStreamManagerInitialized(blockSize, largeBufferMultiple, maximumBufferSize);
- }
-
- ///
- /// The size of each block. It must be set at creation and cannot be changed.
- ///
- public int BlockSize
- {
- get { return this.blockSize; }
- }
-
- ///
- /// All buffers are multiples of this number. It must be set at creation and cannot be changed.
- ///
- public int LargeBufferMultiple
- {
- get { return this.largeBufferMultiple; }
- }
-
- ///
- /// Gets or sets the maximum buffer size.
- ///
- /// Any buffer that is returned to the pool that is larger than this will be
- /// discarded and garbage collected.
- public int MaximumBufferSize
- {
- get { return this.maximumBufferSize; }
- }
-
- ///
- /// Number of bytes in small pool not currently in use
- ///
- public long SmallPoolFreeSize
- {
- get { return this.smallPoolFreeSize; }
- }
-
- ///
- /// Number of bytes currently in use by stream from the small pool
- ///
- public long SmallPoolInUseSize
- {
- get { return this.smallPoolInUseSize; }
- }
-
- ///
- /// Number of bytes in large pool not currently in use
- ///
- public long LargePoolFreeSize
- {
- get { return this.largeBufferFreeSize.Sum(); }
- }
-
- ///
- /// Number of bytes currently in use by streams from the large pool
- ///
- public long LargePoolInUseSize
- {
- get { return this.largeBufferInUseSize.Sum(); }
- }
-
- ///
- /// How many blocks are in the small pool
- ///
- public long SmallBlocksFree
- {
- get { return this.smallPool.Count; }
- }
-
- ///
- /// How many buffers are in the large pool
- ///
- public long LargeBuffersFree
- {
- get
- {
- long free = 0;
- foreach (var pool in this.largePools)
- {
- free += pool.Count;
- }
- return free;
- }
- }
-
- ///
- /// How many bytes of small free blocks to allow before we start dropping
- /// those returned to us.
- ///
- public long MaximumFreeSmallPoolBytes { get; set; }
-
- ///
- /// How many bytes of large free buffers to allow before we start dropping
- /// those returned to us.
- ///
- public long MaximumFreeLargePoolBytes { get; set; }
-
- ///
- /// Maximum stream capacity in bytes. Attempts to set a larger capacity will
- /// result in an exception.
- ///
- /// A value of 0 indicates no limit.
- public long MaximumStreamCapacity { get; set; }
-
- ///
- /// Whether to save callstacks for stream allocations. This can help in debugging.
- /// It should NEVER be turned on generally in production.
- ///
- public bool GenerateCallStacks { get; set; }
-
- ///
- /// Whether dirty buffers can be immediately returned to the buffer pool. E.g. when GetBuffer() is called on
- /// a stream and creates a single large buffer, if this setting is enabled, the other blocks will be returned
- /// to the buffer pool immediately.
- /// Note when enabling this setting that the user is responsible for ensuring that any buffer previously
- /// retrieved from a stream which is subsequently modified is not used after modification (as it may no longer
- /// be valid).
- ///
- public bool AggressiveBufferReturn { get; set; }
-
- ///
- /// Removes and returns a single block from the pool.
- ///
- /// A byte[] array
- internal byte[] GetBlock()
- {
- byte[] block;
- if (!this.smallPool.TryPop(out block))
- {
- // We'll add this back to the pool when the stream is disposed
- // (unless our free pool is too large)
- block = new byte[this.BlockSize];
- Events.Write.MemoryStreamNewBlockCreated(this.smallPoolInUseSize);
- ReportBlockCreated();
- }
- else
- {
- Interlocked.Add(ref this.smallPoolFreeSize, -this.BlockSize);
- }
-
- Interlocked.Add(ref this.smallPoolInUseSize, this.BlockSize);
- return block;
- }
-
- ///
- /// Returns a buffer of arbitrary size from the large buffer pool. This buffer
- /// will be at least the requiredSize and always be a multiple of largeBufferMultiple.
- ///
- /// The minimum length of the buffer
- /// The tag of the stream returning this buffer, for logging if necessary.
- /// A buffer of at least the required size.
- internal byte[] GetLargeBuffer(int requiredSize, string tag)
- {
- requiredSize = this.RoundToLargeBufferMultiple(requiredSize);
-
- var poolIndex = requiredSize / this.largeBufferMultiple - 1;
-
- byte[] buffer;
- if (poolIndex < this.largePools.Length)
- {
- if (!this.largePools[poolIndex].TryPop(out buffer))
- {
- buffer = new byte[requiredSize];
-
- Events.Write.MemoryStreamNewLargeBufferCreated(requiredSize, this.LargePoolInUseSize);
- ReportLargeBufferCreated();
- }
- else
- {
- Interlocked.Add(ref this.largeBufferFreeSize[poolIndex], -buffer.Length);
- }
- }
- else
- {
- // Buffer is too large to pool. They get a new buffer.
-
- // We still want to track the size, though, and we've reserved a slot
- // in the end of the inuse array for nonpooled bytes in use.
- poolIndex = this.largeBufferInUseSize.Length - 1;
-
- // We still want to round up to reduce heap fragmentation.
- buffer = new byte[requiredSize];
- string callStack = null;
- if (this.GenerateCallStacks)
- {
- // Grab the stack -- we want to know who requires such large buffers
- callStack = Environment.StackTrace;
- }
- Events.Write.MemoryStreamNonPooledLargeBufferCreated(requiredSize, tag, callStack);
- ReportLargeBufferCreated();
- }
-
- Interlocked.Add(ref this.largeBufferInUseSize[poolIndex], buffer.Length);
-
- return buffer;
- }
-
- private int RoundToLargeBufferMultiple(int requiredSize)
- {
- return ((requiredSize + this.LargeBufferMultiple - 1) / this.LargeBufferMultiple) * this.LargeBufferMultiple;
- }
-
- private bool IsLargeBufferMultiple(int value)
- {
- return (value != 0) && (value % this.LargeBufferMultiple) == 0;
- }
-
- ///
- /// Returns the buffer to the large pool
- ///
- /// The buffer to return.
- /// The tag of the stream returning this buffer, for logging if necessary.
- /// buffer is null
- /// buffer.Length is not a multiple of LargeBufferMultiple (it did not originate from this pool)
- internal void ReturnLargeBuffer(byte[] buffer, string tag)
- {
- if (buffer == null)
- {
- throw new ArgumentNullException("buffer");
- }
-
- if (!this.IsLargeBufferMultiple(buffer.Length))
- {
- throw new ArgumentException(
- "buffer did not originate from this memory manager. The size is not a multiple of " +
- this.LargeBufferMultiple);
- }
-
- var poolIndex = buffer.Length / this.largeBufferMultiple - 1;
-
- if (poolIndex < this.largePools.Length)
- {
- if ((this.largePools[poolIndex].Count + 1) * buffer.Length <= this.MaximumFreeLargePoolBytes ||
- this.MaximumFreeLargePoolBytes == 0)
- {
- this.largePools[poolIndex].Push(buffer);
- Interlocked.Add(ref this.largeBufferFreeSize[poolIndex], buffer.Length);
- }
- else
- {
- Events.Write.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag,
- Events.MemoryStreamDiscardReason.EnoughFree);
- ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.EnoughFree);
- }
- }
- else
- {
- // This is a non-poolable buffer, but we still want to track its size for inuse
- // analysis. We have space in the inuse array for this.
- poolIndex = this.largeBufferInUseSize.Length - 1;
-
- Events.Write.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Large, tag,
- Events.MemoryStreamDiscardReason.TooLarge);
- ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason.TooLarge);
- }
-
- Interlocked.Add(ref this.largeBufferInUseSize[poolIndex], -buffer.Length);
-
- ReportUsageReport(this.smallPoolInUseSize, this.smallPoolFreeSize, this.LargePoolInUseSize,
- this.LargePoolFreeSize);
- }
-
- ///
- /// Returns the blocks to the pool
- ///
- /// Collection of blocks to return to the pool
- /// The tag of the stream returning these blocks, for logging if necessary.
- /// blocks is null
- /// blocks contains buffers that are the wrong size (or null) for this memory manager
- internal void ReturnBlocks(ICollection blocks, string tag)
- {
- if (blocks == null)
- {
- throw new ArgumentNullException("blocks");
- }
-
- var bytesToReturn = blocks.Count * this.BlockSize;
- Interlocked.Add(ref this.smallPoolInUseSize, -bytesToReturn);
-
- foreach (var block in blocks)
- {
- if (block == null || block.Length != this.BlockSize)
- {
- throw new ArgumentException("blocks contains buffers that are not BlockSize in length");
- }
- }
-
- foreach (var block in blocks)
- {
- if (this.MaximumFreeSmallPoolBytes == 0 || this.SmallPoolFreeSize < this.MaximumFreeSmallPoolBytes)
- {
- Interlocked.Add(ref this.smallPoolFreeSize, this.BlockSize);
- this.smallPool.Push(block);
- }
- else
- {
- Events.Write.MemoryStreamDiscardBuffer(Events.MemoryStreamBufferType.Small, tag,
- Events.MemoryStreamDiscardReason.EnoughFree);
- ReportBlockDiscarded();
- break;
- }
- }
-
- ReportUsageReport(this.smallPoolInUseSize, this.smallPoolFreeSize, this.LargePoolInUseSize,
- this.LargePoolFreeSize);
- }
-
- internal void ReportBlockCreated()
- {
- var blockCreated = Interlocked.CompareExchange(ref this.BlockCreated, null, null);
- if (blockCreated != null)
- {
- blockCreated();
- }
- }
-
- internal void ReportBlockDiscarded()
- {
- var blockDiscarded = Interlocked.CompareExchange(ref this.BlockDiscarded, null, null);
- if (blockDiscarded != null)
- {
- blockDiscarded();
- }
- }
-
- internal void ReportLargeBufferCreated()
- {
- var largeBufferCreated = Interlocked.CompareExchange(ref this.LargeBufferCreated, null, null);
- if (largeBufferCreated != null)
- {
- largeBufferCreated();
- }
- }
-
- internal void ReportLargeBufferDiscarded(Events.MemoryStreamDiscardReason reason)
- {
- var largeBufferDiscarded = Interlocked.CompareExchange(ref this.LargeBufferDiscarded, null, null);
- if (largeBufferDiscarded != null)
- {
- largeBufferDiscarded(reason);
- }
- }
-
- internal void ReportStreamCreated()
- {
- var streamCreated = Interlocked.CompareExchange(ref this.StreamCreated, null, null);
- if (streamCreated != null)
- {
- streamCreated();
- }
- }
-
- internal void ReportStreamDisposed()
- {
- var streamDisposed = Interlocked.CompareExchange(ref this.StreamDisposed, null, null);
- if (streamDisposed != null)
- {
- streamDisposed();
- }
- }
-
- internal void ReportStreamFinalized()
- {
- var streamFinalized = Interlocked.CompareExchange(ref this.StreamFinalized, null, null);
- if (streamFinalized != null)
- {
- streamFinalized();
- }
- }
-
- internal void ReportStreamLength(long bytes)
- {
- var streamLength = Interlocked.CompareExchange(ref this.StreamLength, null, null);
- if (streamLength != null)
- {
- streamLength(bytes);
- }
- }
-
- internal void ReportStreamToArray()
- {
- var streamConvertedToArray = Interlocked.CompareExchange(ref this.StreamConvertedToArray, null, null);
- if (streamConvertedToArray != null)
- {
- streamConvertedToArray();
- }
- }
-
- internal void ReportUsageReport(
- long smallPoolInUseBytes, long smallPoolFreeBytes, long largePoolInUseBytes, long largePoolFreeBytes)
- {
- var usageReport = Interlocked.CompareExchange(ref this.UsageReport, null, null);
- if (usageReport != null)
- {
- usageReport(smallPoolInUseBytes, smallPoolFreeBytes, largePoolInUseBytes, largePoolFreeBytes);
- }
- }
-
- ///
- /// Retrieve a new MemoryStream object with no tag and a default initial capacity.
- ///
- /// A MemoryStream.
- public MemoryStream GetStream()
- {
- return new RecyclableMemoryStream(this);
- }
-
- ///
- /// Retrieve a new MemoryStream object with the given tag and a default initial capacity.
- ///
- /// A tag which can be used to track the source of the stream.
- /// A MemoryStream.
- public MemoryStream GetStream(string tag)
- {
- return new RecyclableMemoryStream(this, tag);
- }
-
- ///
- /// Retrieve a new MemoryStream object with the given tag and at least the given capacity.
- ///
- /// A tag which can be used to track the source of the stream.
- /// The minimum desired capacity for the stream.
- /// A MemoryStream.
- public MemoryStream GetStream(string tag, int requiredSize)
- {
- return new RecyclableMemoryStream(this, tag, requiredSize);
- }
-
- ///
- /// Retrieve a new MemoryStream object with the given tag and at least the given capacity, possibly using
- /// a single continugous underlying buffer.
- ///
- /// Retrieving a MemoryStream which provides a single contiguous buffer can be useful in situations
- /// where the initial size is known and it is desirable to avoid copying data between the smaller underlying
- /// buffers to a single large one. This is most helpful when you know that you will always call GetBuffer
- /// on the underlying stream.
- /// A tag which can be used to track the source of the stream.
- /// The minimum desired capacity for the stream.
- /// Whether to attempt to use a single contiguous buffer.
- /// A MemoryStream.
- public MemoryStream GetStream(string tag, int requiredSize, bool asContiguousBuffer)
- {
- if (!asContiguousBuffer || requiredSize <= this.BlockSize)
- {
- return this.GetStream(tag, requiredSize);
- }
-
- return new RecyclableMemoryStream(this, tag, requiredSize, this.GetLargeBuffer(requiredSize, tag));
- }
-
- ///
- /// Retrieve a new MemoryStream object with the given tag and with contents copied from the provided
- /// buffer. The provided buffer is not wrapped or used after construction.
- ///
- /// The new stream's position is set to the beginning of the stream when returned.
- /// A tag which can be used to track the source of the stream.
- /// The byte buffer to copy data from.
- /// The offset from the start of the buffer to copy from.
- /// The number of bytes to copy from the buffer.
- /// A MemoryStream.
- [SuppressMessage("Microsoft.Reliability", "CA2000:Dispose objects before losing scope")]
- public MemoryStream GetStream(string tag, byte[] buffer, int offset, int count)
- {
- var stream = new RecyclableMemoryStream(this, tag, count);
- stream.Write(buffer, offset, count);
- stream.Position = 0;
- return stream;
- }
-
- ///
- /// Triggered when a new block is created.
- ///
- public event EventHandler BlockCreated;
-
- ///
- /// Triggered when a new block is created.
- ///
- public event EventHandler BlockDiscarded;
-
- ///
- /// Triggered when a new large buffer is created.
- ///
- public event EventHandler LargeBufferCreated;
-
- ///
- /// Triggered when a new stream is created.
- ///
- public event EventHandler StreamCreated;
-
- ///
- /// Triggered when a stream is disposed.
- ///
- public event EventHandler StreamDisposed;
-
- ///
- /// Triggered when a stream is finalized.
- ///
- public event EventHandler StreamFinalized;
-
- ///
- /// Triggered when a stream is finalized.
- ///
- public event StreamLengthReportHandler StreamLength;
-
- ///
- /// Triggered when a user converts a stream to array.
- ///
- public event EventHandler StreamConvertedToArray;
-
- ///
- /// Triggered when a large buffer is discarded, along with the reason for the discard.
- ///
- public event LargeBufferDiscardedEventHandler LargeBufferDiscarded;
-
- ///
- /// Periodically triggered to report usage statistics.
- ///
- public event UsageReportEventHandler UsageReport;
- }
-}
\ No newline at end of file
diff --git a/Src/Workshell.PE/Workshell.PE.csproj b/Src/Workshell.PE/Workshell.PE.csproj
index 6f2a20e..8a771cb 100644
--- a/Src/Workshell.PE/Workshell.PE.csproj
+++ b/Src/Workshell.PE/Workshell.PE.csproj
@@ -88,9 +88,7 @@
-
-
-
+