Imported Upstream version 4.3.2.467

Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
Xamarin Public Jenkins
2016-02-22 11:00:01 -05:00
parent f302175246
commit f3e3aab35a
4097 changed files with 122406 additions and 82300 deletions

View File

@@ -18,7 +18,9 @@ using System.Text;
namespace System.IO {
#if !FEATURE_CORESYSTEM
[Serializable]
#endif
public enum HandleInheritability {
None = 0,
Inheritable = 1,

View File

@@ -181,6 +181,12 @@ namespace System.IO.MemoryMappedFiles {
return new MemoryMappedFile(handle, fileStream, false);
}
public static MemoryMappedFile CreateFromFile(FileStream fileStream, String mapName, Int64 capacity,
MemoryMappedFileAccess access,
HandleInheritability inheritability, bool leaveOpen) {
return CreateFromFile(fileStream, mapName, capacity, access, null, inheritability, leaveOpen);
}
[System.Security.SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static MemoryMappedFile CreateFromFile(FileStream fileStream, String mapName, Int64 capacity,
@@ -250,6 +256,12 @@ namespace System.IO.MemoryMappedFiles {
HandleInheritability.None);
}
public static MemoryMappedFile CreateNew(String mapName, Int64 capacity, MemoryMappedFileAccess access,
MemoryMappedFileOptions options,
HandleInheritability inheritability) {
return CreateNew(mapName, capacity, access, options, null, inheritability);
}
[System.Security.SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static MemoryMappedFile CreateNew(String mapName, Int64 capacity, MemoryMappedFileAccess access,
@@ -305,6 +317,12 @@ namespace System.IO.MemoryMappedFiles {
return CreateOrOpen(mapName, capacity, access, MemoryMappedFileOptions.None, null, HandleInheritability.None);
}
public static MemoryMappedFile CreateOrOpen(String mapName, Int64 capacity,
MemoryMappedFileAccess access, MemoryMappedFileOptions options,
HandleInheritability inheritability) {
return CreateOrOpen(mapName, capacity, access, options, null, inheritability);
}
[System.Security.SecurityCritical]
[SecurityPermissionAttribute(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static MemoryMappedFile CreateOrOpen(String mapName, Int64 capacity,

View File

@@ -102,7 +102,7 @@ namespace System.IO.MemoryMappedFiles {
// if request is >= than total virtual, then MapViewOfFile will fail with meaningless error message
// "the parameter is incorrect"; this provides better error message in advance
UnsafeNativeMethods.MEMORYSTATUSEX memStatus = new UnsafeNativeMethods.MEMORYSTATUSEX();
bool result = UnsafeNativeMethods.GlobalMemoryStatusEx(memStatus);
bool result = UnsafeNativeMethods.GlobalMemoryStatusEx(ref memStatus);
ulong totalVirtual = memStatus.ullTotalVirtual;
if (nativeSize >= totalVirtual) {
throw new IOException(SR.GetString(SR.IO_NotEnoughMemory));
@@ -125,14 +125,32 @@ namespace System.IO.MemoryMappedFiles {
ulong viewSize = (ulong)viewInfo.RegionSize;
// allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
if ((viewInfo.State & UnsafeNativeMethods.MEM_RESERVE) != 0) {
IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)viewSize, UnsafeNativeMethods.MEM_COMMIT,
// Allocate the pages if we were using the MemoryMappedFileOptions.DelayAllocatePages option
// OR check if the allocated view size is smaller than the expected native size
// If multiple overlapping views are created over the file mapping object, the pages in a given region
// could have different attributes(MEM_RESERVE OR MEM_COMMIT) as MapViewOfFile preserves coherence between
// views created on a mapping object backed by same file.
// In which case, the viewSize will be smaller than nativeSize required and viewState could be MEM_COMMIT
// but more pages may need to be committed in the region.
// This is because, VirtualQuery function(that internally invokes VirtualQueryEx function) returns the attributes
// and size of the region of pages with matching attributes starting from base address.
// VirtualQueryEx: http://msdn.microsoft.com/en-us/library/windows/desktop/aa366907(v=vs.85).aspx
if (((viewInfo.State & UnsafeNativeMethods.MEM_RESERVE) != 0) || (viewSize < nativeSize)) {
ulong allocSize = (nativeSize == 0) ? viewSize : nativeSize;
IntPtr tempHandle = UnsafeNativeMethods.VirtualAlloc(viewHandle, (UIntPtr)allocSize, UnsafeNativeMethods.MEM_COMMIT,
MemoryMappedFile.GetPageAccess(access));
int lastError = Marshal.GetLastWin32Error();
if (viewHandle.IsInvalid) {
__Error.WinIOError(lastError, String.Empty);
}
// The following is commented out for backward compatibility.
// Previously releases failed to check for this error so introducing this check
// could cause new/different exceptions in existing code paths.
// if (tempHandle == IntPtr.Zero) {
// __Error.WinIOError(lastError, String.Empty);
// }
// again query the view for its new size
viewInfo = new UnsafeNativeMethods.MEMORY_BASIC_INFORMATION();
UnsafeNativeMethods.VirtualQuery(viewHandle, ref viewInfo, (IntPtr)Marshal.SizeOf(viewInfo));
viewSize = (ulong)viewInfo.RegionSize;
}
// if the user specified DefaultSize as the size, we need to get the actual size

View File

@@ -0,0 +1,99 @@
//------------------------------------------------------------------------------
// <copyright company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Runtime.InteropServices;
using System.Security;
using System.Threading;
using UnsafeNativeMethods = Microsoft.Win32.UnsafeNativeMethods;
namespace System.IO.Pipes {
internal unsafe class IOCancellationHelper {
private CancellationToken _cancellationToken;
private CancellationTokenRegistration _cancellationRegistration;
[SecurityCritical]
private SafeHandle _handle;
[SecurityCritical]
private NativeOverlapped* _overlapped;
public IOCancellationHelper(CancellationToken cancellationToken) {
this._cancellationToken = cancellationToken;
}
/// <summary>
/// Marking that from this moment on
/// user can cancel operation using cancellationToken
/// </summary>
[SecurityCritical]
public void AllowCancellation(SafeHandle handle, NativeOverlapped* overlapped) {
Contract.Assert(handle != null, "Handle cannot be null");
Contract.Assert(!handle.IsInvalid, "Handle cannot be invalid");
Contract.Assert(overlapped != null, "Overlapped cannot be null");
Contract.Assert(this._handle == null && this._overlapped == null, "Cancellation is already allowed.");
if (!_cancellationToken.CanBeCanceled) {
return;
}
this._handle = handle;
this._overlapped = overlapped;
if (this._cancellationToken.IsCancellationRequested) {
this.Cancel();
}
else {
this._cancellationRegistration = this._cancellationToken.Register(Cancel);
}
}
/// <summary>
/// Marking that operation is completed and
/// from this moment cancellation is no longer possible.
/// This MUST happen before Overlapped is freed and Handle is disposed.
/// </summary>
[SecurityCritical]
public void SetOperationCompleted() {
if (this._overlapped != null) {
this._cancellationRegistration.Dispose();
this._handle = null;
this._overlapped = null;
}
}
public void ThrowIOOperationAborted() {
this._cancellationToken.ThrowIfCancellationRequested();
// If we didn't throw that means that this is unexpected abortion
__Error.OperationAborted();
}
/// <summary>
/// Cancellation is not guaranteed to succeed.
/// We ignore all errors here because operation could
/// succeed just before it was called or someone already
/// cancelled this operation without using token which should
/// be manually detected - when operation finishes we should
/// compare error code to ERROR_OPERATION_ABORTED and if cancellation
/// token was not used to cancel we will throw.
/// </summary>
[SecurityCritical]
private void Cancel() {
// Storing to locals to avoid data ----s
SafeHandle handle = this._handle;
NativeOverlapped* overlapped = this._overlapped;
if (handle != null && !handle.IsInvalid && overlapped != null) {
if (!UnsafeNativeMethods.CancelIoEx(handle, overlapped))
{
// This case should not have any consequences although
// it will be easier to debug if there exists any special case
// we are not aware of.
int errorCode = Marshal.GetLastWin32Error();
Debug.WriteLine("CancelIoEx finished with error code {0}.", errorCode);
}
SetOperationCompleted();
}
}
}
}

View File

@@ -28,6 +28,7 @@ using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Win32;
using Microsoft.Win32.SafeHandles;
@@ -623,6 +624,24 @@ namespace System.IO.Pipes {
}
}
public Task WaitForConnectionAsync(CancellationToken cancellationToken) {
if (cancellationToken.IsCancellationRequested) {
return Task.FromCancellation(cancellationToken);
}
if (!IsAsync) {
return Task.Factory.StartNew(WaitForConnection, cancellationToken);
}
// Avoiding allocation if the task cannot be cancelled
IOCancellationHelper cancellationHelper = cancellationToken.CanBeCanceled ? new IOCancellationHelper(cancellationToken) : null;
return Task.Factory.FromAsync(BeginWaitForConnection, EndWaitForConnection, cancellationHelper);
}
public Task WaitForConnectionAsync() {
return WaitForConnectionAsync(CancellationToken.None);
}
// Async version of WaitForConnection. See the comments above for more info.
[System.Security.SecurityCritical]
[HostProtection(ExternalThreading = true)]
@@ -640,6 +659,8 @@ namespace System.IO.Pipes {
asyncResult._userCallback = callback;
asyncResult._userStateObject = state;
IOCancellationHelper cancellationHelper = state as IOCancellationHelper;
// Create wait handle and store in async result
ManualResetEvent waitHandle = new ManualResetEvent(false);
asyncResult._waitHandle = waitHandle;
@@ -655,8 +676,12 @@ namespace System.IO.Pipes {
if (!UnsafeNativeMethods.ConnectNamedPipe(InternalHandle, intOverlapped)) {
int errorCode = Marshal.GetLastWin32Error();
if (errorCode == UnsafeNativeMethods.ERROR_IO_PENDING)
if (errorCode == UnsafeNativeMethods.ERROR_IO_PENDING) {
if (cancellationHelper != null) {
cancellationHelper.AllowCancellation(InternalHandle, intOverlapped);
}
return asyncResult;
}
// WaitForConnectionCallback will not be called becasue we completed synchronously.
// Either the pipe is already connected, or there was an error. Unpin and free the overlapped again.
@@ -676,6 +701,9 @@ namespace System.IO.Pipes {
__Error.WinIOError(errorCode, String.Empty);
}
// will set state to Connected when EndWait is called
if (cancellationHelper != null) {
cancellationHelper.AllowCancellation(InternalHandle, intOverlapped);
}
return asyncResult;
}
@@ -704,6 +732,11 @@ namespace System.IO.Pipes {
__Error.EndWaitForConnectionCalledTwice();
}
IOCancellationHelper cancellationHelper = afsar.AsyncState as IOCancellationHelper;
if (cancellationHelper != null) {
cancellationHelper.SetOperationCompleted();
}
// Obtain the WaitHandle, but don't use public property in case we
// delay initialize the manual reset event in the future.
WaitHandle wh = afsar._waitHandle;
@@ -728,6 +761,11 @@ namespace System.IO.Pipes {
// Now check for any error during the read.
if (afsar._errorCode != 0) {
if (afsar._errorCode == UnsafeNativeMethods.ERROR_OPERATION_ABORTED) {
if (cancellationHelper != null) {
cancellationHelper.ThrowIOOperationAborted();
}
}
__Error.WinIOError(afsar._errorCode, String.Empty);
}
@@ -939,6 +977,9 @@ namespace System.IO.Pipes {
[System.Security.Permissions.HostProtection(MayLeakOnAbort = true)]
public sealed class NamedPipeClientStream : PipeStream {
// Maximum interval in miliseconds between which cancellation is checked.
// Used by ConnectInternal. 50ms is fairly responsive time but really long time for processor.
private const int CancellationCheckIntervalInMilliseconds = 50;
private string m_normalizedPipePath;
private TokenImpersonationLevel m_impersonationLevel;
private PipeOptions m_pipeOptions;
@@ -1193,6 +1234,127 @@ namespace System.IO.Pipes {
throw new TimeoutException();
}
public Task ConnectAsync() {
// We cannot avoid creating lambda here by using Connect method
// unless we don't care about start time to be measured before the thread is started
return ConnectAsync(Timeout.Infinite, CancellationToken.None);
}
public Task ConnectAsync(int timeout) {
return ConnectAsync(timeout, CancellationToken.None);
}
public Task ConnectAsync(CancellationToken cancellationToken) {
return ConnectAsync(Timeout.Infinite, cancellationToken);
}
public Task ConnectAsync(int timeout, CancellationToken cancellationToken) {
CheckConnectOperationsClient();
if (timeout < 0 && timeout != Timeout.Infinite) {
throw new ArgumentOutOfRangeException("timeout", SR.GetString(SR.ArgumentOutOfRange_InvalidTimeout));
}
if (cancellationToken.IsCancellationRequested) {
return Task.FromCancellation(cancellationToken);
}
// We need to measure time here, not in the lambda
int startTime = Environment.TickCount;
return Task.Factory.StartNew(() => ConnectInternal(timeout, cancellationToken, startTime), cancellationToken);
}
// Waits for a pipe instance to become available. This method may return before WaitForConnection is called
// on the server end, but WaitForConnection will not return until we have returned. Any data writen to the
// pipe by us after we have connected but before the server has called WaitForConnection will be available
// to the server after it calls WaitForConnection.
[System.Security.SecuritySafeCritical]
private void ConnectInternal(int timeout, CancellationToken cancellationToken, int startTime) {
UnsafeNativeMethods.SECURITY_ATTRIBUTES secAttrs = PipeStream.GetSecAttrs(m_inheritability);
int _pipeFlags = (int)m_pipeOptions;
if (m_impersonationLevel != TokenImpersonationLevel.None) {
_pipeFlags |= UnsafeNativeMethods.SECURITY_SQOS_PRESENT;
_pipeFlags |= (((int)m_impersonationLevel - 1) << 16);
}
// This is the main connection loop. It will loop until the timeout expires. Most of the
// time, we will be waiting in the WaitNamedPipe win32 blocking function; however, there are
// cases when we will need to loop: 1) The server is not created (WaitNamedPipe returns
// straight away in such cases), and 2) when another client connects to our server in between
// our WaitNamedPipe and CreateFile calls.
int elapsed = 0;
do {
// We want any other exception and and success to have priority over cancellation.
cancellationToken.ThrowIfCancellationRequested();
// Wait for pipe to become free (this will block unless the pipe does not exist).
int timeLeft = timeout - elapsed;
int waitTime;
if (cancellationToken.CanBeCanceled) {
waitTime = Math.Min(CancellationCheckIntervalInMilliseconds, timeLeft);
}
else {
waitTime = timeLeft;
}
if (!UnsafeNativeMethods.WaitNamedPipe(m_normalizedPipePath, waitTime)) {
int errorCode = Marshal.GetLastWin32Error();
// Server is not yet created so let's keep looping.
if (errorCode == UnsafeNativeMethods.ERROR_FILE_NOT_FOUND) {
continue;
}
// The timeout has expired.
if (errorCode == UnsafeNativeMethods.ERROR_SUCCESS) {
if (cancellationToken.CanBeCanceled) {
// It may not be real timeout and only checking for cancellation
// let the while condition check it and decide
continue;
}
else {
break;
}
}
__Error.WinIOError(errorCode, String.Empty);
}
// Pipe server should be free. Let's try to connect to it.
SafePipeHandle handle = UnsafeNativeMethods.CreateNamedPipeClient(m_normalizedPipePath,
m_access, // read and write access
0, // sharing: none
secAttrs, // security attributes
FileMode.Open, // open existing
_pipeFlags, // impersonation flags
UnsafeNativeMethods.NULL); // template file: null
if (handle.IsInvalid) {
int errorCode = Marshal.GetLastWin32Error();
// Handle the possible race condition of someone else connecting to the server
// between our calls to WaitNamedPipe & CreateFile.
if (errorCode == UnsafeNativeMethods.ERROR_PIPE_BUSY) {
continue;
}
__Error.WinIOError(errorCode, String.Empty);
}
// Success!
InitializeHandle(handle, false, (m_pipeOptions & PipeOptions.Asynchronous) != 0);
State = PipeState.Connected;
return;
}
while (timeout == Timeout.Infinite || (elapsed = unchecked(Environment.TickCount - startTime)) < timeout);
// BUGBUG: SerialPort does not use unchecked arithmetic when calculating elapsed times. This is needed
// because Environment.TickCount can overflow (though only every 49.7 days).
throw new TimeoutException();
}
public int NumberOfServerInstances {
[System.Security.SecurityCritical]
[SuppressMessage("Microsoft.Security","CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands", Justification="Security model of pipes: demand at creation but no subsequent demands")]

View File

@@ -217,5 +217,8 @@ namespace System.IO {
throw new NotSupportedException(SR.GetString(SR.NotSupported_UnwritableStream));
}
internal static void OperationAborted() {
throw new IOException(SR.GetString(SR.IO_OperationAborted));
}
}
}