443 lines
17 KiB
C#
443 lines
17 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
//
|
|
// <OWNER>[....]</OWNER>
|
|
|
|
/*
|
|
* This files defines the following types:
|
|
* - NativeOverlapped
|
|
* - _IOCompletionCallback
|
|
* - OverlappedData
|
|
* - Overlapped
|
|
* - OverlappedDataCache
|
|
*/
|
|
|
|
/*=============================================================================
|
|
**
|
|
** Class: Overlapped
|
|
**
|
|
**
|
|
** Purpose: Class for converting information to and from the native
|
|
** overlapped structure used in asynchronous file i/o
|
|
**
|
|
**
|
|
=============================================================================*/
|
|
|
|
|
|
namespace System.Threading
|
|
{
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Runtime.CompilerServices;
|
|
using System.Runtime.Versioning;
|
|
using System.Security;
|
|
using System.Security.Permissions;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using System.Diagnostics.Contracts;
|
|
using System.Collections.Concurrent;
|
|
|
|
#region struct NativeOverlapped
|
|
|
|
// Valuetype that represents the (unmanaged) Win32 OVERLAPPED structure
|
|
// the layout of this structure must be identical to OVERLAPPED.
|
|
// The first five matches OVERLAPPED structure.
|
|
// The remaining are reserved at the end
|
|
[System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public struct NativeOverlapped
|
|
{
|
|
public IntPtr InternalLow;
|
|
public IntPtr InternalHigh;
|
|
public int OffsetLow;
|
|
public int OffsetHigh;
|
|
public IntPtr EventHandle;
|
|
}
|
|
|
|
#endregion struct NativeOverlapped
|
|
|
|
|
|
#region class _IOCompletionCallback
|
|
|
|
unsafe internal class _IOCompletionCallback
|
|
{
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
IOCompletionCallback _ioCompletionCallback;
|
|
ExecutionContext _executionContext;
|
|
uint _errorCode; // Error code
|
|
uint _numBytes; // No. of bytes transferred
|
|
[SecurityCritical]
|
|
NativeOverlapped* _pOVERLAP;
|
|
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
static _IOCompletionCallback()
|
|
{
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback, ref StackCrawlMark stackMark)
|
|
{
|
|
_ioCompletionCallback = ioCompletionCallback;
|
|
// clone the exection context
|
|
_executionContext = ExecutionContext.Capture(
|
|
ref stackMark,
|
|
ExecutionContext.CaptureOptions.IgnoreSyncCtx | ExecutionContext.CaptureOptions.OptimizeDefaultCase);
|
|
}
|
|
// Context callback: same sig for SendOrPostCallback and ContextCallback
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
#endif
|
|
static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
|
|
[System.Security.SecurityCritical]
|
|
static internal void IOCompletionCallback_Context(Object state)
|
|
{
|
|
_IOCompletionCallback helper = (_IOCompletionCallback)state;
|
|
Contract.Assert(helper != null,"_IOCompletionCallback cannot be null");
|
|
helper._ioCompletionCallback(helper._errorCode, helper._numBytes, helper._pOVERLAP);
|
|
}
|
|
|
|
|
|
// call back helper
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
static unsafe internal void PerformIOCompletionCallback(uint errorCode, // Error code
|
|
uint numBytes, // No. of bytes transferred
|
|
NativeOverlapped* pOVERLAP // ptr to OVERLAP structure
|
|
)
|
|
{
|
|
Overlapped overlapped;
|
|
_IOCompletionCallback helper;
|
|
|
|
do
|
|
{
|
|
overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
|
|
helper = overlapped.iocbHelper;
|
|
|
|
if (helper == null || helper._executionContext == null || helper._executionContext.IsDefaultFTContext(true))
|
|
{
|
|
// We got here because of UnsafePack (or) Pack with EC flow supressed
|
|
IOCompletionCallback callback = overlapped.UserCallback;
|
|
callback( errorCode, numBytes, pOVERLAP);
|
|
}
|
|
else
|
|
{
|
|
// We got here because of Pack
|
|
helper._errorCode = errorCode;
|
|
helper._numBytes = numBytes;
|
|
helper._pOVERLAP = pOVERLAP;
|
|
using (ExecutionContext executionContext = helper._executionContext.CreateCopy())
|
|
ExecutionContext.Run(executionContext, _ccb, helper, true);
|
|
}
|
|
|
|
//Quickly check the VM again, to see if a packet has arrived.
|
|
|
|
OverlappedData.CheckVMForIOPacket(out pOVERLAP, out errorCode, out numBytes);
|
|
|
|
} while (pOVERLAP != null);
|
|
|
|
}
|
|
}
|
|
|
|
#endregion class _IOCompletionCallback
|
|
|
|
|
|
#region class OverlappedData
|
|
|
|
sealed internal class OverlappedData
|
|
{
|
|
// ! If you make any change to the layout here, you need to make matching change
|
|
// ! to OverlappedObject in vm\nativeoverlapped.h
|
|
internal IAsyncResult m_asyncResult;
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
internal IOCompletionCallback m_iocb;
|
|
internal _IOCompletionCallback m_iocbHelper;
|
|
internal Overlapped m_overlapped;
|
|
private Object m_userObject;
|
|
private IntPtr m_pinSelf;
|
|
private IntPtr m_userObjectInternal;
|
|
private int m_AppDomainId;
|
|
#pragma warning disable 414 // Field is not used from managed.
|
|
#pragma warning disable 169
|
|
private byte m_isArray;
|
|
private byte m_toBeCleaned;
|
|
#pragma warning restore 414
|
|
#pragma warning restore 169
|
|
internal NativeOverlapped m_nativeOverlapped;
|
|
|
|
#if FEATURE_CORECLR
|
|
// Adding an empty default ctor for annotation purposes
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
internal OverlappedData(){}
|
|
#endif // FEATURE_CORECLR
|
|
|
|
|
|
[System.Security.SecurityCritical]
|
|
internal void ReInitialize()
|
|
{
|
|
m_asyncResult = null;
|
|
m_iocb = null;
|
|
m_iocbHelper = null;
|
|
m_overlapped = null;
|
|
m_userObject = null;
|
|
Contract.Assert(m_pinSelf.IsNull(), "OverlappedData has not been freed: m_pinSelf");
|
|
m_pinSelf = (IntPtr)0;
|
|
m_userObjectInternal = (IntPtr)0;
|
|
Contract.Assert(m_AppDomainId == 0 || m_AppDomainId == AppDomain.CurrentDomain.Id, "OverlappedData is not in the current domain");
|
|
m_AppDomainId = 0;
|
|
m_nativeOverlapped.EventHandle = (IntPtr)0;
|
|
m_isArray = 0;
|
|
m_nativeOverlapped.InternalLow = (IntPtr)0;
|
|
m_nativeOverlapped.InternalHigh = (IntPtr)0;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
[MethodImplAttribute(MethodImplOptions.NoInlining)] // Methods containing StackCrawlMark local var has to be marked non-inlineable
|
|
unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
|
|
{
|
|
if (!m_pinSelf.IsNull()) {
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
|
|
}
|
|
StackCrawlMark stackMark = StackCrawlMark.LookForMyCaller;
|
|
|
|
if (iocb != null)
|
|
{
|
|
m_iocbHelper = new _IOCompletionCallback(iocb, ref stackMark);
|
|
m_iocb = iocb;
|
|
}
|
|
else
|
|
{
|
|
m_iocbHelper = null;
|
|
m_iocb = null;
|
|
}
|
|
m_userObject = userData;
|
|
if (m_userObject != null)
|
|
{
|
|
if (m_userObject.GetType() == typeof(Object[]))
|
|
{
|
|
m_isArray = 1;
|
|
}
|
|
else
|
|
{
|
|
m_isArray = 0;
|
|
}
|
|
}
|
|
return AllocateNativeOverlapped();
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
unsafe internal NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
|
|
{
|
|
if (!m_pinSelf.IsNull()) {
|
|
throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_Overlapped_Pack"));
|
|
}
|
|
m_userObject = userData;
|
|
if (m_userObject != null)
|
|
{
|
|
if (m_userObject.GetType() == typeof(Object[]))
|
|
{
|
|
m_isArray = 1;
|
|
}
|
|
else
|
|
{
|
|
m_isArray = 0;
|
|
}
|
|
}
|
|
m_iocb = iocb;
|
|
m_iocbHelper = null;
|
|
return AllocateNativeOverlapped();
|
|
}
|
|
|
|
[ComVisible(false)]
|
|
internal IntPtr UserHandle
|
|
{
|
|
get { return m_nativeOverlapped.EventHandle; }
|
|
set { m_nativeOverlapped.EventHandle = value; }
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
unsafe private extern NativeOverlapped* AllocateNativeOverlapped();
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
unsafe internal static extern void FreeNativeOverlapped(NativeOverlapped* nativeOverlappedPtr);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
unsafe internal static extern OverlappedData GetOverlappedFromNative(NativeOverlapped* nativeOverlappedPtr);
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
unsafe internal static extern void CheckVMForIOPacket(out NativeOverlapped* pOVERLAP, out uint errorCode, out uint numBytes);
|
|
}
|
|
|
|
#endregion class OverlappedData
|
|
|
|
|
|
#region class Overlapped
|
|
|
|
/// <internalonly/>
|
|
[System.Runtime.InteropServices.ComVisible(true)]
|
|
public class Overlapped
|
|
{
|
|
private OverlappedData m_overlappedData;
|
|
private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", ()=> new OverlappedData());
|
|
|
|
#if FEATURE_CORECLR
|
|
[System.Security.SecuritySafeCritical] // auto-generated
|
|
#endif
|
|
public Overlapped()
|
|
{
|
|
m_overlappedData = (OverlappedData) s_overlappedDataCache.Allocate();
|
|
m_overlappedData.m_overlapped = this;
|
|
}
|
|
|
|
public Overlapped(int offsetLo, int offsetHi, IntPtr hEvent, IAsyncResult ar)
|
|
{
|
|
m_overlappedData = (OverlappedData) s_overlappedDataCache.Allocate();
|
|
m_overlappedData.m_overlapped = this;
|
|
m_overlappedData.m_nativeOverlapped.OffsetLow = offsetLo;
|
|
m_overlappedData.m_nativeOverlapped.OffsetHigh = offsetHi;
|
|
m_overlappedData.UserHandle = hEvent;
|
|
m_overlappedData.m_asyncResult = ar;
|
|
}
|
|
|
|
[Obsolete("This constructor is not 64-bit compatible. Use the constructor that takes an IntPtr for the event handle. http://go.microsoft.com/fwlink/?linkid=14202")]
|
|
public Overlapped(int offsetLo, int offsetHi, int hEvent, IAsyncResult ar) : this(offsetLo, offsetHi, new IntPtr(hEvent), ar)
|
|
{
|
|
}
|
|
|
|
public IAsyncResult AsyncResult
|
|
{
|
|
get { return m_overlappedData.m_asyncResult; }
|
|
set { m_overlappedData.m_asyncResult = value; }
|
|
}
|
|
|
|
public int OffsetLow
|
|
{
|
|
get { return m_overlappedData.m_nativeOverlapped.OffsetLow; }
|
|
set { m_overlappedData.m_nativeOverlapped.OffsetLow = value; }
|
|
}
|
|
|
|
public int OffsetHigh
|
|
{
|
|
get { return m_overlappedData.m_nativeOverlapped.OffsetHigh; }
|
|
set { m_overlappedData.m_nativeOverlapped.OffsetHigh = value; }
|
|
}
|
|
|
|
[Obsolete("This property is not 64-bit compatible. Use EventHandleIntPtr instead. http://go.microsoft.com/fwlink/?linkid=14202")]
|
|
public int EventHandle
|
|
{
|
|
get { return m_overlappedData.UserHandle.ToInt32(); }
|
|
set { m_overlappedData.UserHandle = new IntPtr(value); }
|
|
}
|
|
|
|
[ComVisible(false)]
|
|
public IntPtr EventHandleIntPtr
|
|
{
|
|
get { return m_overlappedData.UserHandle; }
|
|
set { m_overlappedData.UserHandle = value; }
|
|
}
|
|
|
|
internal _IOCompletionCallback iocbHelper
|
|
{
|
|
get { return m_overlappedData.m_iocbHelper; }
|
|
}
|
|
|
|
internal IOCompletionCallback UserCallback
|
|
{
|
|
[System.Security.SecurityCritical]
|
|
get { return m_overlappedData.m_iocb; }
|
|
}
|
|
|
|
/*====================================================================
|
|
* Packs a managed overlapped class into native Overlapped struct.
|
|
* Roots the iocb and stores it in the ReservedCOR field of native Overlapped
|
|
* Pins the native Overlapped struct and returns the pinned index.
|
|
====================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[Obsolete("This method is not safe. Use Pack (iocb, userData) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
|
|
[CLSCompliant(false)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb)
|
|
{
|
|
return Pack (iocb, null);
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[CLSCompliant(false),ComVisible(false)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
|
|
{
|
|
return m_overlappedData.Pack(iocb, userData);
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[Obsolete("This method is not safe. Use UnsafePack (iocb, userData) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
|
|
[CLSCompliant(false)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb)
|
|
{
|
|
return UnsafePack (iocb, null);
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated_required
|
|
[CLSCompliant(false), ComVisible(false)]
|
|
[ResourceExposure(ResourceScope.AppDomain)]
|
|
[ResourceConsumption(ResourceScope.AppDomain)]
|
|
unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
|
|
{
|
|
return m_overlappedData.UnsafePack(iocb, userData);
|
|
}
|
|
|
|
/*====================================================================
|
|
* Unpacks an unmanaged native Overlapped struct.
|
|
* Unpins the native Overlapped struct
|
|
====================================================================*/
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
unsafe public static Overlapped Unpack(NativeOverlapped* nativeOverlappedPtr)
|
|
{
|
|
if (nativeOverlappedPtr == null)
|
|
throw new ArgumentNullException("nativeOverlappedPtr");
|
|
Contract.EndContractBlock();
|
|
|
|
Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
|
|
|
|
return overlapped;
|
|
}
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[CLSCompliant(false)]
|
|
unsafe public static void Free(NativeOverlapped* nativeOverlappedPtr)
|
|
{
|
|
if (nativeOverlappedPtr == null)
|
|
throw new ArgumentNullException("nativeOverlappedPtr");
|
|
Contract.EndContractBlock();
|
|
|
|
Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
|
|
OverlappedData.FreeNativeOverlapped(nativeOverlappedPtr);
|
|
OverlappedData overlappedData = overlapped.m_overlappedData;
|
|
overlapped.m_overlappedData = null;
|
|
overlappedData.ReInitialize();
|
|
s_overlappedDataCache.Free(overlappedData);
|
|
}
|
|
|
|
}
|
|
|
|
#endregion class Overlapped
|
|
|
|
} // namespace
|