You've already forked linux-packaging-mono
Imported Upstream version 4.3.2.467
Former-commit-id: 9c2cb47f45fa221e661ab616387c9cda183f283d
This commit is contained in:
@@ -18,7 +18,9 @@ using System.Text;
|
||||
|
||||
namespace System.IO {
|
||||
|
||||
#if !FEATURE_CORESYSTEM
|
||||
[Serializable]
|
||||
#endif
|
||||
public enum HandleInheritability {
|
||||
None = 0,
|
||||
Inheritable = 1,
|
||||
|
@@ -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,
|
||||
|
@@ -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
|
||||
|
99
external/referencesource/System.Core/System/IO/Pipes/IOCancellationHelper.cs
vendored
Normal file
99
external/referencesource/System.Core/System/IO/Pipes/IOCancellationHelper.cs
vendored
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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")]
|
||||
|
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user