File: src\libraries\System.Private.CoreLib\src\System\Threading\Overlapped.cs
Web Access
Project: src\src\coreclr\System.Private.CoreLib\System.Private.CoreLib.csproj (System.Private.CoreLib)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using System.Diagnostics.Tracing;
using System.Runtime.InteropServices;
 
namespace System.Threading
{
    public unsafe class Overlapped
    {
        private IAsyncResult? _asyncResult;
        internal object? _callback; // IOCompletionCallback or IOCompletionCallbackHelper
        private NativeOverlapped* _pNativeOverlapped;
        private IntPtr _eventHandle;
        private int _offsetLow;
        private int _offsetHigh;
 
        public Overlapped()
        {
        }
 
        public Overlapped(int offsetLo, int offsetHi, IntPtr hEvent, IAsyncResult? ar)
        {
            _offsetLow = offsetLo;
            _offsetHigh = offsetHi;
            _eventHandle = hEvent;
            _asyncResult = ar;
        }
 
        [Obsolete("This constructor is not 64-bit compatible and has been deprecated. Use the constructor that accepts an IntPtr for the event handle instead.")]
        public Overlapped(int offsetLo, int offsetHi, int hEvent, IAsyncResult? ar)
            : this(offsetLo, offsetHi, new IntPtr(hEvent), ar)
        {
        }
 
        public IAsyncResult AsyncResult
        {
            get => _asyncResult!;
            set => _asyncResult = value;
        }
 
        public int OffsetLow
        {
            get => (_pNativeOverlapped != null) ? _pNativeOverlapped->OffsetLow : _offsetLow;
            set => ((_pNativeOverlapped != null) ? ref _pNativeOverlapped->OffsetLow : ref _offsetLow) = value;
        }
 
        public int OffsetHigh
        {
            get => (_pNativeOverlapped != null) ? _pNativeOverlapped->OffsetHigh : _offsetHigh;
            set => ((_pNativeOverlapped != null) ? ref _pNativeOverlapped->OffsetHigh : ref _offsetHigh) = value;
        }
 
        [Obsolete("Overlapped.EventHandle is not 64-bit compatible and has been deprecated. Use EventHandleIntPtr instead.")]
        public int EventHandle
        {
            get => EventHandleIntPtr.ToInt32();
            set => EventHandleIntPtr = new IntPtr(value);
        }
 
        public IntPtr EventHandleIntPtr
        {
            get => (_pNativeOverlapped != null) ? _pNativeOverlapped->EventHandle : _eventHandle;
            set => ((_pNativeOverlapped != null) ? ref _pNativeOverlapped->EventHandle : ref _eventHandle) = value;
        }
 
        [Obsolete("This overload is not safe and has been deprecated. Use Pack(IOCompletionCallback?, object?) instead.")]
        [CLSCompliant(false)]
        public NativeOverlapped* Pack(IOCompletionCallback? iocb)
            => Pack(iocb, null);
 
        [CLSCompliant(false)]
        public NativeOverlapped* Pack(IOCompletionCallback? iocb, object? userData)
        {
            if (_pNativeOverlapped != null)
            {
                throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
            }
 
            if (iocb != null)
            {
                ExecutionContext? ec = ExecutionContext.Capture();
                _callback = (ec != null && !ec.IsDefault) ? new IOCompletionCallbackHelper(iocb, ec) : (object)iocb;
            }
            else
            {
                _callback = null;
            }
            return AllocateNativeOverlapped(userData);
        }
 
        [Obsolete("This overload is not safe and has been deprecated. Use UnsafePack(IOCompletionCallback?, object?) instead.")]
        [CLSCompliant(false)]
        public NativeOverlapped* UnsafePack(IOCompletionCallback? iocb)
            => UnsafePack(iocb, null);
 
        [CLSCompliant(false)]
        public NativeOverlapped* UnsafePack(IOCompletionCallback? iocb, object? userData)
        {
            if (_pNativeOverlapped != null)
            {
                throw new InvalidOperationException(SR.InvalidOperation_Overlapped_Pack);
            }
            _callback = iocb;
            return AllocateNativeOverlapped(userData);
        }
 
        /*====================================================================
        *  Unpacks an unmanaged native Overlapped struct.
        *  Unpins the native Overlapped struct
        ====================================================================*/
        [CLSCompliant(false)]
        public static Overlapped Unpack(NativeOverlapped* nativeOverlappedPtr)
        {
            ArgumentNullException.ThrowIfNull(nativeOverlappedPtr);
 
            return GetOverlappedFromNative(nativeOverlappedPtr);
        }
 
        [CLSCompliant(false)]
        public static void Free(NativeOverlapped* nativeOverlappedPtr)
        {
            ArgumentNullException.ThrowIfNull(nativeOverlappedPtr);
 
            GetOverlappedFromNative(nativeOverlappedPtr)._pNativeOverlapped = null;
            FreeNativeOverlapped(nativeOverlappedPtr);
        }
 
        private NativeOverlapped* AllocateNativeOverlapped(object? userData)
        {
            NativeOverlapped* pNativeOverlapped = null;
            try
            {
                nuint handleCount = 1;
 
                if (userData != null)
                {
                    if (userData.GetType() == typeof(object[]))
                    {
                        handleCount += (nuint)((object[])userData).Length;
                    }
                    else
                    {
                        handleCount++;
                    }
                }
 
                pNativeOverlapped = (NativeOverlapped*)NativeMemory.Alloc(
                    (nuint)(sizeof(NativeOverlapped) + sizeof(nuint)) + handleCount * (nuint)sizeof(GCHandle));
 
                GCHandleCountRef(pNativeOverlapped) = 0;
 
                pNativeOverlapped->InternalLow = default;
                pNativeOverlapped->InternalHigh = default;
                pNativeOverlapped->OffsetLow = _offsetLow;
                pNativeOverlapped->OffsetHigh = _offsetHigh;
                pNativeOverlapped->EventHandle = _eventHandle;
 
                GCHandleRef(pNativeOverlapped, 0) = GCHandle.Alloc(this);
                GCHandleCountRef(pNativeOverlapped)++;
 
                if (userData != null)
                {
                    if (userData.GetType() == typeof(object[]))
                    {
                        object[] objArray = (object[])userData;
                        for (int i = 0; i < objArray.Length; i++)
                        {
                            GCHandleRef(pNativeOverlapped, (nuint)(i + 1)) = GCHandle.Alloc(objArray[i], GCHandleType.Pinned);
                            GCHandleCountRef(pNativeOverlapped)++;
                        }
                    }
                    else
                    {
                        GCHandleRef(pNativeOverlapped, 1) = GCHandle.Alloc(userData, GCHandleType.Pinned);
                        GCHandleCountRef(pNativeOverlapped)++;
                    }
                }
 
                Debug.Assert(GCHandleCountRef(pNativeOverlapped) == handleCount);
 
                // Tracing needs _pNativeOverlapped to be initialized
                _pNativeOverlapped = pNativeOverlapped;
 
#if FEATURE_PERFTRACING
                if (NativeRuntimeEventSource.Log.IsEnabled())
                    NativeRuntimeEventSource.Log.ThreadPoolIOPack(pNativeOverlapped);
#endif
 
                NativeOverlapped* pRet = pNativeOverlapped;
                pNativeOverlapped = null;
                return pRet;
            }
            finally
            {
                if (pNativeOverlapped != null)
                {
                    _pNativeOverlapped = null;
                    FreeNativeOverlapped(pNativeOverlapped);
                }
            }
        }
 
        internal static void FreeNativeOverlapped(NativeOverlapped* pNativeOverlapped)
        {
            nuint handleCount = GCHandleCountRef(pNativeOverlapped);
 
            for (nuint i = 0; i < handleCount; i++)
                GCHandleRef(pNativeOverlapped, i).Free();
 
            NativeMemory.Free(pNativeOverlapped);
        }
 
        //
        // The NativeOverlapped structure is followed by GC handle count and inline array of GC handles
        //
        private static ref nuint GCHandleCountRef(NativeOverlapped* pNativeOverlapped)
            => ref *(nuint*)(pNativeOverlapped + 1);
 
        private static ref GCHandle GCHandleRef(NativeOverlapped* pNativeOverlapped, nuint index)
            => ref *((GCHandle*)((nuint*)(pNativeOverlapped + 1) + 1) + index);
 
        internal static Overlapped GetOverlappedFromNative(NativeOverlapped* pNativeOverlapped)
        {
            object? target = GCHandleRef(pNativeOverlapped, 0).Target;
            Debug.Assert(target is Overlapped);
 
            Overlapped overlapped = (Overlapped)target;
            Debug.Assert(overlapped._pNativeOverlapped == pNativeOverlapped);
 
            return overlapped;
        }
    }
}