1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
8 * This files defines the following types:
10 * - _IOCompletionCallback
13 * - OverlappedDataCache
16 /*=============================================================================
20 ** Purpose: Class for converting information to and from the native
21 ** overlapped structure used in asynchronous file i/o
24 =============================================================================*/
28 using System.Runtime.InteropServices;
29 using System.Runtime.CompilerServices;
30 using System.Runtime.Versioning;
31 using System.Security;
32 using System.Runtime.ConstrainedExecution;
33 using System.Diagnostics;
34 using System.Collections.Concurrent;
36 namespace System.Threading
38 #region struct NativeOverlapped
40 // Valuetype that represents the (unmanaged) Win32 OVERLAPPED structure
41 // the layout of this structure must be identical to OVERLAPPED.
42 // The first five matches OVERLAPPED structure.
43 // The remaining are reserved at the end
44 [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
45 public struct NativeOverlapped
47 public IntPtr InternalLow;
48 public IntPtr InternalHigh;
50 public int OffsetHigh;
51 public IntPtr EventHandle;
54 #endregion struct NativeOverlapped
57 #region class _IOCompletionCallback
59 unsafe internal class _IOCompletionCallback
61 private IOCompletionCallback _ioCompletionCallback;
62 private ExecutionContext _executionContext;
63 private uint _errorCode; // Error code
64 private uint _numBytes; // No. of bytes transferred
65 private NativeOverlapped* _pOVERLAP;
67 internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
69 _ioCompletionCallback = ioCompletionCallback;
70 // clone the exection context
71 _executionContext = ExecutionContext.Capture();
73 // Context callback: same sig for SendOrPostCallback and ContextCallback
74 static internal ContextCallback _ccb = new ContextCallback(IOCompletionCallback_Context);
75 static internal void IOCompletionCallback_Context(Object state)
77 _IOCompletionCallback helper = (_IOCompletionCallback)state;
78 Debug.Assert(helper != null, "_IOCompletionCallback cannot be null");
79 helper._ioCompletionCallback(helper._errorCode, helper._numBytes, helper._pOVERLAP);
84 static unsafe internal void PerformIOCompletionCallback(uint errorCode, // Error code
85 uint numBytes, // No. of bytes transferred
86 NativeOverlapped* pOVERLAP // ptr to OVERLAP structure
89 Overlapped overlapped;
90 _IOCompletionCallback helper;
94 overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
95 helper = overlapped.iocbHelper;
97 if (helper == null || helper._executionContext == null || helper._executionContext == ExecutionContext.Default)
99 // We got here because of UnsafePack (or) Pack with EC flow supressed
100 IOCompletionCallback callback = overlapped.UserCallback;
101 callback(errorCode, numBytes, pOVERLAP);
105 // We got here because of Pack
106 helper._errorCode = errorCode;
107 helper._numBytes = numBytes;
108 helper._pOVERLAP = pOVERLAP;
109 ExecutionContext.Run(helper._executionContext, _ccb, helper);
112 //Quickly check the VM again, to see if a packet has arrived.
113 OverlappedData.CheckVMForIOPacket(out pOVERLAP, out errorCode, out numBytes);
114 } while (pOVERLAP != null);
118 #endregion class _IOCompletionCallback
121 #region class OverlappedData
123 sealed internal class OverlappedData
125 // ! If you make any change to the layout here, you need to make matching change
126 // ! to OverlappedObject in vm\nativeoverlapped.h
127 internal IAsyncResult m_asyncResult;
128 internal IOCompletionCallback m_iocb;
129 internal _IOCompletionCallback m_iocbHelper;
130 internal Overlapped m_overlapped;
131 private Object m_userObject;
132 private IntPtr m_pinSelf;
133 private IntPtr m_userObjectInternal;
134 private int m_AppDomainId;
135 #pragma warning disable 414 // Field is not used from managed.
136 #pragma warning disable 169
137 private byte m_isArray;
138 private byte m_toBeCleaned;
139 #pragma warning restore 414
140 #pragma warning restore 169
141 internal NativeOverlapped m_nativeOverlapped;
143 // Adding an empty default ctor for annotation purposes
144 internal OverlappedData() { }
146 internal void ReInitialize()
148 m_asyncResult = null;
153 Debug.Assert(m_pinSelf == IntPtr.Zero, "OverlappedData has not been freed: m_pinSelf");
154 m_pinSelf = IntPtr.Zero;
155 m_userObjectInternal = IntPtr.Zero;
156 Debug.Assert(m_AppDomainId == 0 || m_AppDomainId == AppDomain.CurrentDomain.Id, "OverlappedData is not in the current domain");
158 m_nativeOverlapped.EventHandle = IntPtr.Zero;
160 m_nativeOverlapped.InternalLow = IntPtr.Zero;
161 m_nativeOverlapped.InternalHigh = IntPtr.Zero;
164 unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
166 if (m_pinSelf != IntPtr.Zero)
168 throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
173 m_iocbHelper = new _IOCompletionCallback(iocb);
181 m_userObject = userData;
182 if (m_userObject != null)
184 if (m_userObject.GetType() == typeof(Object[]))
193 return AllocateNativeOverlapped();
196 unsafe internal NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
198 if (m_pinSelf != IntPtr.Zero)
200 throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
202 m_userObject = userData;
203 if (m_userObject != null)
205 if (m_userObject.GetType() == typeof(Object[]))
216 return AllocateNativeOverlapped();
219 internal IntPtr UserHandle
221 get { return m_nativeOverlapped.EventHandle; }
222 set { m_nativeOverlapped.EventHandle = value; }
225 [MethodImplAttribute(MethodImplOptions.InternalCall)]
226 unsafe private extern NativeOverlapped* AllocateNativeOverlapped();
228 [MethodImplAttribute(MethodImplOptions.InternalCall)]
229 unsafe internal static extern void FreeNativeOverlapped(NativeOverlapped* nativeOverlappedPtr);
231 [MethodImplAttribute(MethodImplOptions.InternalCall)]
232 unsafe internal static extern OverlappedData GetOverlappedFromNative(NativeOverlapped* nativeOverlappedPtr);
234 [MethodImplAttribute(MethodImplOptions.InternalCall)]
235 unsafe internal static extern void CheckVMForIOPacket(out NativeOverlapped* pOVERLAP, out uint errorCode, out uint numBytes);
238 #endregion class OverlappedData
241 #region class Overlapped
243 public class Overlapped
245 private OverlappedData m_overlappedData;
246 private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", () => new OverlappedData());
250 m_overlappedData = (OverlappedData)s_overlappedDataCache.Allocate();
251 m_overlappedData.m_overlapped = this;
254 public Overlapped(int offsetLo, int offsetHi, IntPtr hEvent, IAsyncResult ar)
256 m_overlappedData = (OverlappedData)s_overlappedDataCache.Allocate();
257 m_overlappedData.m_overlapped = this;
258 m_overlappedData.m_nativeOverlapped.OffsetLow = offsetLo;
259 m_overlappedData.m_nativeOverlapped.OffsetHigh = offsetHi;
260 m_overlappedData.UserHandle = hEvent;
261 m_overlappedData.m_asyncResult = ar;
264 [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")]
265 public Overlapped(int offsetLo, int offsetHi, int hEvent, IAsyncResult ar) : this(offsetLo, offsetHi, new IntPtr(hEvent), ar)
269 public IAsyncResult AsyncResult
271 get { return m_overlappedData.m_asyncResult; }
272 set { m_overlappedData.m_asyncResult = value; }
277 get { return m_overlappedData.m_nativeOverlapped.OffsetLow; }
278 set { m_overlappedData.m_nativeOverlapped.OffsetLow = value; }
281 public int OffsetHigh
283 get { return m_overlappedData.m_nativeOverlapped.OffsetHigh; }
284 set { m_overlappedData.m_nativeOverlapped.OffsetHigh = value; }
287 [Obsolete("This property is not 64-bit compatible. Use EventHandleIntPtr instead. http://go.microsoft.com/fwlink/?linkid=14202")]
288 public int EventHandle
290 get { return m_overlappedData.UserHandle.ToInt32(); }
291 set { m_overlappedData.UserHandle = new IntPtr(value); }
294 public IntPtr EventHandleIntPtr
296 get { return m_overlappedData.UserHandle; }
297 set { m_overlappedData.UserHandle = value; }
300 internal _IOCompletionCallback iocbHelper
302 get { return m_overlappedData.m_iocbHelper; }
305 internal IOCompletionCallback UserCallback
307 get { return m_overlappedData.m_iocb; }
310 /*====================================================================
311 * Packs a managed overlapped class into native Overlapped struct.
312 * Roots the iocb and stores it in the ReservedCOR field of native Overlapped
313 * Pins the native Overlapped struct and returns the pinned index.
314 ====================================================================*/
315 [Obsolete("This method is not safe. Use Pack (iocb, userData) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
316 [CLSCompliant(false)]
317 unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb)
319 return Pack(iocb, null);
322 [CLSCompliant(false)]
323 unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
325 return m_overlappedData.Pack(iocb, userData);
328 [Obsolete("This method is not safe. Use UnsafePack (iocb, userData) instead. http://go.microsoft.com/fwlink/?linkid=14202")]
329 [CLSCompliant(false)]
330 unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb)
332 return UnsafePack(iocb, null);
335 [CLSCompliant(false)]
336 unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
338 return m_overlappedData.UnsafePack(iocb, userData);
341 /*====================================================================
342 * Unpacks an unmanaged native Overlapped struct.
343 * Unpins the native Overlapped struct
344 ====================================================================*/
345 [CLSCompliant(false)]
346 unsafe public static Overlapped Unpack(NativeOverlapped* nativeOverlappedPtr)
348 if (nativeOverlappedPtr == null)
349 throw new ArgumentNullException(nameof(nativeOverlappedPtr));
351 Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
356 [CLSCompliant(false)]
357 unsafe public static void Free(NativeOverlapped* nativeOverlappedPtr)
359 if (nativeOverlappedPtr == null)
360 throw new ArgumentNullException(nameof(nativeOverlappedPtr));
362 Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
363 OverlappedData.FreeNativeOverlapped(nativeOverlappedPtr);
364 OverlappedData overlappedData = overlapped.m_overlappedData;
365 overlapped.m_overlappedData = null;
366 overlappedData.ReInitialize();
367 s_overlappedDataCache.Free(overlappedData);
371 #endregion class Overlapped