summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/IO/Stream.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/IO/Stream.cs')
-rw-r--r--src/mscorlib/src/System/IO/Stream.cs355
1 files changed, 208 insertions, 147 deletions
diff --git a/src/mscorlib/src/System/IO/Stream.cs b/src/mscorlib/src/System/IO/Stream.cs
index 790f0a09ab..92fe374f19 100644
--- a/src/mscorlib/src/System/IO/Stream.cs
+++ b/src/mscorlib/src/System/IO/Stream.cs
@@ -14,6 +14,7 @@
**
**
===========================================================*/
+
using System;
using System.Buffers;
using System.Threading;
@@ -27,10 +28,11 @@ using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Reflection;
-namespace System.IO {
+namespace System.IO
+{
[Serializable]
- public abstract class Stream : MarshalByRefObject, IDisposable {
-
+ public abstract class Stream : MarshalByRefObject, IDisposable
+ {
public static readonly Stream Null = new NullStream();
//We pick a value that is the largest multiple of 4096 that is still smaller than the large object heap threshold (85K).
@@ -52,55 +54,68 @@ namespace System.IO {
return LazyInitializer.EnsureInitialized(ref _asyncActiveSemaphore, () => new SemaphoreSlim(1, 1));
}
- public abstract bool CanRead {
+ public abstract bool CanRead
+ {
[Pure]
get;
}
// If CanSeek is false, Position, Seek, Length, and SetLength should throw.
- public abstract bool CanSeek {
+ public abstract bool CanSeek
+ {
[Pure]
get;
}
- public virtual bool CanTimeout {
+ public virtual bool CanTimeout
+ {
[Pure]
- get {
+ get
+ {
return false;
}
}
-
- public abstract bool CanWrite {
+
+ public abstract bool CanWrite
+ {
[Pure]
get;
}
- public abstract long Length {
+ public abstract long Length
+ {
get;
}
- public abstract long Position {
+ public abstract long Position
+ {
get;
set;
}
- public virtual int ReadTimeout {
- get {
+ public virtual int ReadTimeout
+ {
+ get
+ {
Contract.Ensures(Contract.Result<int>() >= 0);
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
+ throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
- set {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
+ set
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
}
- public virtual int WriteTimeout {
- get {
+ public virtual int WriteTimeout
+ {
+ get
+ {
Contract.Ensures(Contract.Result<int>() >= 0);
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
+ throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
- set {
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_TimeoutsNotSupported"));
+ set
+ {
+ throw new InvalidOperationException(SR.InvalidOperation_TimeoutsNotSupported);
}
}
@@ -127,7 +142,7 @@ namespace System.IO {
// because it would be a breaking change if the stream's override didn't throw before,
// or in a different order. So for simplicity, we just set the bufferSize to 1
// (not 0 since the default implementation throws for 0) and forward to the virtual method.
- bufferSize = 1;
+ bufferSize = 1;
}
else
{
@@ -295,7 +310,7 @@ namespace System.IO {
}
internal IAsyncResult BeginReadInternal(
- byte[] buffer, int offset, int count, AsyncCallback callback, Object state,
+ byte[] buffer, int offset, int count, AsyncCallback callback, Object state,
bool serializeAsynchronously, bool apm)
{
Contract.Ensures(Contract.Result<IAsyncResult>() != null);
@@ -341,7 +356,7 @@ namespace System.IO {
{
thisTask._stream.FinishTrackingAsyncOperation();
}
-
+
thisTask.ClearBeginState(); // just to help alleviate some memory pressure
}
}, state, this, buffer, offset, count, callback);
@@ -352,7 +367,7 @@ namespace System.IO {
else
RunReadWriteTask(asyncResult);
-
+
return asyncResult; // return it
}
@@ -367,18 +382,18 @@ namespace System.IO {
if (readTask == null)
{
- throw new ArgumentException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple"));
+ throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple);
}
else if (readTask != asyncResult)
{
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple"));
+ throw new InvalidOperationException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple);
}
else if (!readTask._isRead)
{
- throw new ArgumentException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple"));
+ throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndReadCalledMultiple);
}
-
- try
+
+ try
{
return readTask.GetAwaiter().GetResult(); // block until completion, then get result / propagate any exception
}
@@ -437,12 +452,12 @@ namespace System.IO {
}
internal IAsyncResult BeginWriteInternal(
- byte[] buffer, int offset, int count, AsyncCallback callback, Object state,
+ byte[] buffer, int offset, int count, AsyncCallback callback, Object state,
bool serializeAsynchronously, bool apm)
{
Contract.Ensures(Contract.Result<IAsyncResult>() != null);
if (!CanWrite) __Error.WriteNotSupported();
-
+
// To avoid a race condition with a stream's position pointer & generating conditions
// with internal buffer indexes in our own streams that
// don't natively support async IO operations when there are multiple
@@ -472,7 +487,7 @@ namespace System.IO {
try
{
// Do the Write
- thisTask._stream.Write(thisTask._buffer, thisTask._offset, thisTask._count);
+ thisTask._stream.Write(thisTask._buffer, thisTask._offset, thisTask._count);
return 0; // not used, but signature requires a value be returned
}
finally
@@ -501,7 +516,7 @@ namespace System.IO {
private void RunReadWriteTaskWhenReady(Task asyncWaiter, ReadWriteTask readWriteTask)
{
Debug.Assert(readWriteTask != null); // Should be Contract.Requires, but CCRewrite is doing a poor job with
- // preconditions in async methods that await.
+ // preconditions in async methods that await.
Debug.Assert(asyncWaiter != null); // Ditto
// If the wait has already completed, run the task.
@@ -509,10 +524,11 @@ namespace System.IO {
{
Debug.Assert(asyncWaiter.IsRanToCompletion, "The semaphore wait should always complete successfully.");
RunReadWriteTask(readWriteTask);
- }
+ }
else // Otherwise, wait for our turn, and then run the task.
{
- asyncWaiter.ContinueWith((t, state) => {
+ asyncWaiter.ContinueWith((t, state) =>
+ {
Debug.Assert(t.IsRanToCompletion, "The semaphore wait should always complete successfully.");
var rwt = (ReadWriteTask)state;
rwt._stream.RunReadWriteTask(rwt); // RunReadWriteTask(readWriteTask);
@@ -536,32 +552,32 @@ namespace System.IO {
private void FinishTrackingAsyncOperation()
{
- _activeReadWriteTask = null;
+ _activeReadWriteTask = null;
Debug.Assert(_asyncActiveSemaphore != null, "Must have been initialized in order to get here.");
_asyncActiveSemaphore.Release();
}
public virtual void EndWrite(IAsyncResult asyncResult)
{
- if (asyncResult==null)
+ if (asyncResult == null)
throw new ArgumentNullException(nameof(asyncResult));
Contract.EndContractBlock();
var writeTask = _activeReadWriteTask;
if (writeTask == null)
{
- throw new ArgumentException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple"));
+ throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple);
}
else if (writeTask != asyncResult)
{
- throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple"));
+ throw new InvalidOperationException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple);
}
else if (writeTask._isRead)
{
- throw new ArgumentException(Environment.GetResourceString("InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple"));
+ throw new ArgumentException(SR.InvalidOperation_WrongAsyncResultOrEndWriteCalledMultiple);
}
- try
+ try
{
writeTask.GetAwaiter().GetResult(); // block until completion, then propagate any exceptions
Debug.Assert(writeTask.Status == TaskStatus.RanToCompletion);
@@ -590,10 +606,10 @@ namespace System.IO {
// with a single allocation.
private sealed class ReadWriteTask : Task<int>, ITaskCompletionAction
{
- internal readonly bool _isRead;
+ internal readonly bool _isRead;
internal readonly bool _apm; // true if this is from Begin/EndXx; false if it's from XxAsync
internal Stream _stream;
- internal byte [] _buffer;
+ internal byte[] _buffer;
internal readonly int _offset;
internal readonly int _count;
private AsyncCallback _callback;
@@ -608,7 +624,7 @@ namespace System.IO {
public ReadWriteTask(
bool isRead,
bool apm,
- Func<object,int> function, object state,
+ Func<object, int> function, object state,
Stream stream, byte[] buffer, int offset, int count, AsyncCallback callback) :
base(function, state, CancellationToken.None, TaskCreationOptions.DenyChildAttach)
{
@@ -647,23 +663,23 @@ namespace System.IO {
}
private static ContextCallback s_invokeAsyncCallback;
-
+
void ITaskCompletionAction.Invoke(Task completingTask)
{
// Get the ExecutionContext. If there is none, just run the callback
// directly, passing in the completed task as the IAsyncResult.
// If there is one, process it with ExecutionContext.Run.
var context = _context;
- if (context == null)
+ if (context == null)
{
var callback = _callback;
_callback = null;
callback(completingTask);
}
- else
+ else
{
_context = null;
-
+
var invokeAsyncCallback = s_invokeAsyncCallback;
if (invokeAsyncCallback == null) s_invokeAsyncCallback = invokeAsyncCallback = InvokeAsyncCallback; // benign race condition
@@ -704,14 +720,14 @@ namespace System.IO {
// Otherwise, we need to wrap calls to Begin/EndWrite to ensure we use the derived type's functionality.
return TaskFactory<VoidTaskResult>.FromAsyncTrim(
- this, new ReadWriteParameters { Buffer=buffer, Offset=offset, Count=count },
+ this, new ReadWriteParameters { Buffer = buffer, Offset = offset, Count = count },
(stream, args, callback, state) => stream.BeginWrite(args.Buffer, args.Offset, args.Count, callback, state), // cached by compiler
(stream, asyncResult) => // cached by compiler
{
stream.EndWrite(asyncResult);
return default(VoidTaskResult);
});
- }
+ }
public abstract long Seek(long offset, SeekOrigin origin);
@@ -732,7 +748,7 @@ namespace System.IO {
byte[] oneByteArray = new byte[1];
int r = Read(oneByteArray, 0, 1);
- if (r==0)
+ if (r == 0)
return -1;
return oneByteArray[0];
}
@@ -751,20 +767,20 @@ namespace System.IO {
Write(oneByteArray, 0, 1);
}
- public static Stream Synchronized(Stream stream)
+ public static Stream Synchronized(Stream stream)
{
- if (stream==null)
+ if (stream == null)
throw new ArgumentNullException(nameof(stream));
Contract.Ensures(Contract.Result<Stream>() != null);
Contract.EndContractBlock();
if (stream is SyncStream)
return stream;
-
+
return new SyncStream(stream);
}
[Obsolete("Do not call or override this method.")]
- protected virtual void ObjectInvariant()
+ protected virtual void ObjectInvariant()
{
}
@@ -778,16 +794,19 @@ namespace System.IO {
// async requests outstanding, we will block the application's main
// thread and do the IO synchronously.
// This can't perform well - use a different approach.
- SynchronousAsyncResult asyncResult;
- try {
+ SynchronousAsyncResult asyncResult;
+ try
+ {
int numRead = Read(buffer, offset, count);
asyncResult = new SynchronousAsyncResult(numRead, state);
}
- catch (IOException ex) {
+ catch (IOException ex)
+ {
asyncResult = new SynchronousAsyncResult(ex, state, isWrite: false);
}
-
- if (callback != null) {
+
+ if (callback != null)
+ {
callback(asyncResult);
}
@@ -812,15 +831,18 @@ namespace System.IO {
// thread and do the IO synchronously.
// This can't perform well - use a different approach.
SynchronousAsyncResult asyncResult;
- try {
+ try
+ {
Write(buffer, offset, count);
asyncResult = new SynchronousAsyncResult(state);
}
- catch (IOException ex) {
+ catch (IOException ex)
+ {
asyncResult = new SynchronousAsyncResult(ex, state, isWrite: true);
}
- if (callback != null) {
+ if (callback != null)
+ {
callback(asyncResult);
}
@@ -835,45 +857,50 @@ namespace System.IO {
[Serializable]
private sealed class NullStream : Stream
{
- internal NullStream() {}
+ internal NullStream() { }
- public override bool CanRead {
+ public override bool CanRead
+ {
[Pure]
get { return true; }
}
- public override bool CanWrite {
+ public override bool CanWrite
+ {
[Pure]
get { return true; }
}
- public override bool CanSeek {
+ public override bool CanSeek
+ {
[Pure]
get { return true; }
}
- public override long Length {
+ public override long Length
+ {
get { return 0; }
}
- public override long Position {
+ public override long Position
+ {
get { return 0; }
- set {}
+ set { }
}
-
+
public override void CopyTo(Stream destination, int bufferSize)
{
StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
-
+
// After we validate arguments this is a nop.
}
-
+
public override Task CopyToAsync(Stream destination, int bufferSize, CancellationToken cancellationToken)
{
// Validate arguments here for compat, since previously this method
// was inherited from Stream (which did check its arguments).
StreamHelpers.ValidateCopyToArgs(this, destination, bufferSize);
-
+
return cancellationToken.IsCancellationRequested ?
Task.FromCanceled(cancellationToken) :
Task.CompletedTask;
@@ -935,7 +962,7 @@ namespace System.IO {
public override Task<int> ReadAsync(Byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var nullReadTask = s_nullReadTask;
- if (nullReadTask == null)
+ if (nullReadTask == null)
s_nullReadTask = nullReadTask = new Task<int>(false, 0, (TaskCreationOptions)InternalTaskOptions.DoNotDispose, CancellationToken.None); // benign race condition
return nullReadTask;
}
@@ -971,11 +998,11 @@ namespace System.IO {
}
}
-
+
/// <summary>Used as the IAsyncResult object when using asynchronous IO methods on the base Stream class.</summary>
- internal sealed class SynchronousAsyncResult : IAsyncResult {
-
- private readonly Object _stateObject;
+ internal sealed class SynchronousAsyncResult : IAsyncResult
+ {
+ private readonly Object _stateObject;
private readonly bool _isWrite;
private ManualResetEvent _waitHandle;
private ExceptionDispatchInfo _exceptionInfo;
@@ -983,49 +1010,58 @@ namespace System.IO {
private bool _endXxxCalled;
private Int32 _bytesRead;
- internal SynchronousAsyncResult(Int32 bytesRead, Object asyncStateObject) {
+ internal SynchronousAsyncResult(Int32 bytesRead, Object asyncStateObject)
+ {
_bytesRead = bytesRead;
_stateObject = asyncStateObject;
//_isWrite = false;
}
- internal SynchronousAsyncResult(Object asyncStateObject) {
+ internal SynchronousAsyncResult(Object asyncStateObject)
+ {
_stateObject = asyncStateObject;
_isWrite = true;
}
- internal SynchronousAsyncResult(Exception ex, Object asyncStateObject, bool isWrite) {
+ internal SynchronousAsyncResult(Exception ex, Object asyncStateObject, bool isWrite)
+ {
_exceptionInfo = ExceptionDispatchInfo.Capture(ex);
_stateObject = asyncStateObject;
- _isWrite = isWrite;
+ _isWrite = isWrite;
}
- public bool IsCompleted {
+ public bool IsCompleted
+ {
// We never hand out objects of this type to the user before the synchronous IO completed:
get { return true; }
}
- public WaitHandle AsyncWaitHandle {
- get {
- return LazyInitializer.EnsureInitialized(ref _waitHandle, () => new ManualResetEvent(true));
+ public WaitHandle AsyncWaitHandle
+ {
+ get
+ {
+ return LazyInitializer.EnsureInitialized(ref _waitHandle, () => new ManualResetEvent(true));
}
}
- public Object AsyncState {
+ public Object AsyncState
+ {
get { return _stateObject; }
}
- public bool CompletedSynchronously {
+ public bool CompletedSynchronously
+ {
get { return true; }
}
- internal void ThrowIfError() {
+ internal void ThrowIfError()
+ {
if (_exceptionInfo != null)
_exceptionInfo.Throw();
- }
-
- internal static Int32 EndRead(IAsyncResult asyncResult) {
+ }
+ internal static Int32 EndRead(IAsyncResult asyncResult)
+ {
SynchronousAsyncResult ar = asyncResult as SynchronousAsyncResult;
if (ar == null || ar._isWrite)
__Error.WrongAsyncResult();
@@ -1039,8 +1075,8 @@ namespace System.IO {
return ar._bytesRead;
}
- internal static void EndWrite(IAsyncResult asyncResult) {
-
+ internal static void EndWrite(IAsyncResult asyncResult)
+ {
SynchronousAsyncResult ar = asyncResult as SynchronousAsyncResult;
if (ar == null || !ar._isWrite)
__Error.WrongAsyncResult();
@@ -1069,64 +1105,83 @@ namespace System.IO {
Contract.EndContractBlock();
_stream = stream;
}
-
- public override bool CanRead {
+
+ public override bool CanRead
+ {
[Pure]
get { return _stream.CanRead; }
}
-
- public override bool CanWrite {
+
+ public override bool CanWrite
+ {
[Pure]
get { return _stream.CanWrite; }
}
-
- public override bool CanSeek {
+
+ public override bool CanSeek
+ {
[Pure]
get { return _stream.CanSeek; }
}
-
- public override bool CanTimeout {
+
+ public override bool CanTimeout
+ {
[Pure]
- get {
+ get
+ {
return _stream.CanTimeout;
}
}
- public override long Length {
- get {
- lock(_stream) {
+ public override long Length
+ {
+ get
+ {
+ lock (_stream)
+ {
return _stream.Length;
}
}
}
-
- public override long Position {
- get {
- lock(_stream) {
+
+ public override long Position
+ {
+ get
+ {
+ lock (_stream)
+ {
return _stream.Position;
}
}
- set {
- lock(_stream) {
+ set
+ {
+ lock (_stream)
+ {
_stream.Position = value;
}
}
}
- public override int ReadTimeout {
- get {
+ public override int ReadTimeout
+ {
+ get
+ {
return _stream.ReadTimeout;
}
- set {
+ set
+ {
_stream.ReadTimeout = value;
}
}
- public override int WriteTimeout {
- get {
+ public override int WriteTimeout
+ {
+ get
+ {
return _stream.WriteTimeout;
}
- set {
+ set
+ {
_stream.WriteTimeout = value;
}
}
@@ -1135,48 +1190,54 @@ namespace System.IO {
// semantics for Close vs. Dispose, let's preserve that.
public override void Close()
{
- lock(_stream) {
- try {
+ lock (_stream)
+ {
+ try
+ {
_stream.Close();
}
- finally {
+ finally
+ {
base.Dispose(true);
}
}
}
-
+
protected override void Dispose(bool disposing)
{
- lock(_stream) {
- try {
+ lock (_stream)
+ {
+ try
+ {
// Explicitly pick up a potentially methodimpl'ed Dispose
if (disposing)
((IDisposable)_stream).Dispose();
}
- finally {
+ finally
+ {
base.Dispose(disposing);
}
}
}
-
+
public override void Flush()
{
- lock(_stream)
+ lock (_stream)
_stream.Flush();
}
-
+
public override int Read([In, Out]byte[] bytes, int offset, int count)
{
- lock(_stream)
+ lock (_stream)
return _stream.Read(bytes, offset, count);
}
-
+
public override int ReadByte()
{
- lock(_stream)
+ lock (_stream)
return _stream.ReadByte();
}
-
+
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
{
bool overridesBeginRead = _stream.HasOverriddenBeginEndRead();
@@ -1194,7 +1255,7 @@ namespace System.IO {
_stream.BeginReadInternal(buffer, offset, count, callback, state, serializeAsynchronously: true, apm: true);
}
}
-
+
public override int EndRead(IAsyncResult asyncResult)
{
if (asyncResult == null)
@@ -1202,34 +1263,34 @@ namespace System.IO {
Contract.Ensures(Contract.Result<int>() >= 0);
Contract.EndContractBlock();
- lock(_stream)
+ lock (_stream)
return _stream.EndRead(asyncResult);
}
-
+
public override long Seek(long offset, SeekOrigin origin)
{
- lock(_stream)
+ lock (_stream)
return _stream.Seek(offset, origin);
}
-
+
public override void SetLength(long length)
{
- lock(_stream)
+ lock (_stream)
_stream.SetLength(length);
}
-
+
public override void Write(byte[] bytes, int offset, int count)
{
- lock(_stream)
+ lock (_stream)
_stream.Write(bytes, offset, count);
}
-
+
public override void WriteByte(byte b)
{
- lock(_stream)
+ lock (_stream)
_stream.WriteByte(b);
}
-
+
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, Object state)
{
bool overridesBeginWrite = _stream.HasOverriddenBeginEndWrite();
@@ -1247,14 +1308,14 @@ namespace System.IO {
_stream.BeginWriteInternal(buffer, offset, count, callback, state, serializeAsynchronously: true, apm: true);
}
}
-
+
public override void EndWrite(IAsyncResult asyncResult)
{
if (asyncResult == null)
throw new ArgumentNullException(nameof(asyncResult));
Contract.EndContractBlock();
- lock(_stream)
+ lock (_stream)
_stream.EndWrite(asyncResult);
}
}