Reduce Execution Context Save+Restore (#15629)
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Threading / Overlapped.cs
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.
4
5 //
6
7 /*
8  * This files defines the following types:
9  *  - NativeOverlapped
10  *  - _IOCompletionCallback
11  *  - OverlappedData
12  *  - Overlapped
13  *  - OverlappedDataCache
14  */
15
16 /*=============================================================================
17 **
18 **
19 **
20 ** Purpose: Class for converting information to and from the native 
21 **          overlapped structure used in asynchronous file i/o
22 **
23 **
24 =============================================================================*/
25
26
27 using System;
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;
35
36 namespace System.Threading
37 {
38     #region struct NativeOverlapped
39
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
46     {
47         public IntPtr InternalLow;
48         public IntPtr InternalHigh;
49         public int OffsetLow;
50         public int OffsetHigh;
51         public IntPtr EventHandle;
52     }
53
54     #endregion struct NativeOverlapped
55
56
57     #region class _IOCompletionCallback
58
59     unsafe internal class _IOCompletionCallback
60     {
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;
66
67         internal _IOCompletionCallback(IOCompletionCallback ioCompletionCallback)
68         {
69             _ioCompletionCallback = ioCompletionCallback;
70             // clone the exection context
71             _executionContext = ExecutionContext.Capture();
72         }
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)
76         {
77             _IOCompletionCallback helper = (_IOCompletionCallback)state;
78             Debug.Assert(helper != null, "_IOCompletionCallback cannot be null");
79             helper._ioCompletionCallback(helper._errorCode, helper._numBytes, helper._pOVERLAP);
80         }
81
82
83         // call back helper
84         static unsafe internal void PerformIOCompletionCallback(uint errorCode, // Error code
85                                                                             uint numBytes, // No. of bytes transferred 
86                                                                             NativeOverlapped* pOVERLAP // ptr to OVERLAP structure
87                                                                             )
88         {
89             Overlapped overlapped;
90             _IOCompletionCallback helper;
91
92             do
93             {
94                 overlapped = OverlappedData.GetOverlappedFromNative(pOVERLAP).m_overlapped;
95                 helper = overlapped.iocbHelper;
96
97                 if (helper == null || helper._executionContext == null || helper._executionContext.IsDefault)
98                 {
99                     // We got here because of UnsafePack (or) Pack with EC flow supressed
100                     IOCompletionCallback callback = overlapped.UserCallback;
101                     callback(errorCode, numBytes, pOVERLAP);
102                 }
103                 else
104                 {
105                     // We got here because of Pack
106                     helper._errorCode = errorCode;
107                     helper._numBytes = numBytes;
108                     helper._pOVERLAP = pOVERLAP;
109                     ExecutionContext.RunInternal(helper._executionContext, _ccb, helper);
110                 }
111
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);
115         }
116     }
117
118     #endregion class _IOCompletionCallback
119
120
121     #region class OverlappedData
122
123     sealed internal class OverlappedData
124     {
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;
142
143         // Adding an empty default ctor for annotation purposes
144         internal OverlappedData() { }
145
146         internal void ReInitialize()
147         {
148             m_asyncResult = null;
149             m_iocb = null;
150             m_iocbHelper = null;
151             m_overlapped = null;
152             m_userObject = 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");
157             m_AppDomainId = 0;
158             m_nativeOverlapped.EventHandle = IntPtr.Zero;
159             m_isArray = 0;
160             m_nativeOverlapped.InternalLow = IntPtr.Zero;
161             m_nativeOverlapped.InternalHigh = IntPtr.Zero;
162         }
163
164         unsafe internal NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
165         {
166             if (m_pinSelf != IntPtr.Zero)
167             {
168                 throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
169             }
170
171             if (iocb != null)
172             {
173                 m_iocbHelper = new _IOCompletionCallback(iocb);
174                 m_iocb = iocb;
175             }
176             else
177             {
178                 m_iocbHelper = null;
179                 m_iocb = null;
180             }
181             m_userObject = userData;
182             if (m_userObject != null)
183             {
184                 if (m_userObject.GetType() == typeof(Object[]))
185                 {
186                     m_isArray = 1;
187                 }
188                 else
189                 {
190                     m_isArray = 0;
191                 }
192             }
193             return AllocateNativeOverlapped();
194         }
195
196         unsafe internal NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
197         {
198             if (m_pinSelf != IntPtr.Zero)
199             {
200                 throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
201             }
202             m_userObject = userData;
203             if (m_userObject != null)
204             {
205                 if (m_userObject.GetType() == typeof(Object[]))
206                 {
207                     m_isArray = 1;
208                 }
209                 else
210                 {
211                     m_isArray = 0;
212                 }
213             }
214             m_iocb = iocb;
215             m_iocbHelper = null;
216             return AllocateNativeOverlapped();
217         }
218
219         internal IntPtr UserHandle
220         {
221             get { return m_nativeOverlapped.EventHandle; }
222             set { m_nativeOverlapped.EventHandle = value; }
223         }
224
225         [MethodImplAttribute(MethodImplOptions.InternalCall)]
226         unsafe private extern NativeOverlapped* AllocateNativeOverlapped();
227
228         [MethodImplAttribute(MethodImplOptions.InternalCall)]
229         unsafe internal static extern void FreeNativeOverlapped(NativeOverlapped* nativeOverlappedPtr);
230
231         [MethodImplAttribute(MethodImplOptions.InternalCall)]
232         unsafe internal static extern OverlappedData GetOverlappedFromNative(NativeOverlapped* nativeOverlappedPtr);
233
234         [MethodImplAttribute(MethodImplOptions.InternalCall)]
235         unsafe internal static extern void CheckVMForIOPacket(out NativeOverlapped* pOVERLAP, out uint errorCode, out uint numBytes);
236     }
237
238     #endregion class OverlappedData
239
240
241     #region class Overlapped
242
243     public class Overlapped
244     {
245         private OverlappedData m_overlappedData;
246         private static PinnableBufferCache s_overlappedDataCache = new PinnableBufferCache("System.Threading.OverlappedData", () => new OverlappedData());
247
248         public Overlapped()
249         {
250             m_overlappedData = (OverlappedData)s_overlappedDataCache.Allocate();
251             m_overlappedData.m_overlapped = this;
252         }
253
254         public Overlapped(int offsetLo, int offsetHi, IntPtr hEvent, IAsyncResult ar)
255         {
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;
262         }
263
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)
266         {
267         }
268
269         public IAsyncResult AsyncResult
270         {
271             get { return m_overlappedData.m_asyncResult; }
272             set { m_overlappedData.m_asyncResult = value; }
273         }
274
275         public int OffsetLow
276         {
277             get { return m_overlappedData.m_nativeOverlapped.OffsetLow; }
278             set { m_overlappedData.m_nativeOverlapped.OffsetLow = value; }
279         }
280
281         public int OffsetHigh
282         {
283             get { return m_overlappedData.m_nativeOverlapped.OffsetHigh; }
284             set { m_overlappedData.m_nativeOverlapped.OffsetHigh = value; }
285         }
286
287         [Obsolete("This property is not 64-bit compatible.  Use EventHandleIntPtr instead.  http://go.microsoft.com/fwlink/?linkid=14202")]
288         public int EventHandle
289         {
290             get { return m_overlappedData.UserHandle.ToInt32(); }
291             set { m_overlappedData.UserHandle = new IntPtr(value); }
292         }
293
294         public IntPtr EventHandleIntPtr
295         {
296             get { return m_overlappedData.UserHandle; }
297             set { m_overlappedData.UserHandle = value; }
298         }
299
300         internal _IOCompletionCallback iocbHelper
301         {
302             get { return m_overlappedData.m_iocbHelper; }
303         }
304
305         internal IOCompletionCallback UserCallback
306         {
307             get { return m_overlappedData.m_iocb; }
308         }
309
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)
318         {
319             return Pack(iocb, null);
320         }
321
322         [CLSCompliant(false)]
323         unsafe public NativeOverlapped* Pack(IOCompletionCallback iocb, Object userData)
324         {
325             return m_overlappedData.Pack(iocb, userData);
326         }
327
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)
331         {
332             return UnsafePack(iocb, null);
333         }
334
335         [CLSCompliant(false)]
336         unsafe public NativeOverlapped* UnsafePack(IOCompletionCallback iocb, Object userData)
337         {
338             return m_overlappedData.UnsafePack(iocb, userData);
339         }
340
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)
347         {
348             if (nativeOverlappedPtr == null)
349                 throw new ArgumentNullException(nameof(nativeOverlappedPtr));
350
351             Overlapped overlapped = OverlappedData.GetOverlappedFromNative(nativeOverlappedPtr).m_overlapped;
352
353             return overlapped;
354         }
355
356         [CLSCompliant(false)]
357         unsafe public static void Free(NativeOverlapped* nativeOverlappedPtr)
358         {
359             if (nativeOverlappedPtr == null)
360                 throw new ArgumentNullException(nameof(nativeOverlappedPtr));
361
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);
368         }
369     }
370
371     #endregion class Overlapped
372 }  // namespace