File: src\runtime\src\libraries\System.Private.CoreLib\src\System\Threading\WaitSubsystem.HandleManager.Unix.cs
Web Access
Project: src\runtime\src\coreclr\nativeaot\System.Private.CoreLib\src\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.Collections.Generic;
using System.Diagnostics;
using System.Runtime;
using System.Runtime.InteropServices;

namespace System.Threading
{
    internal static partial class WaitSubsystem
    {
        public interface IWaitableObject
        {
            void OnDeleteHandle();
            int Wait_Locked(ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool interruptible, ref LockHolder lockHolder);
            void Signal(int count, ref LockHolder lockHolder);
        }

        public static int Wait(this IWaitableObject waitable, ThreadWaitInfo waitInfo, int timeoutMilliseconds, bool interruptible)
        {
            Debug.Assert(waitInfo.Thread == Thread.CurrentThread);

            Debug.Assert(timeoutMilliseconds >= -1);

            var lockHolder = new LockHolder(s_lock);
            try
            {
                if (interruptible && waitInfo.CheckAndResetPendingInterrupt)
                {
                    lockHolder.Dispose();
                    throw new ThreadInterruptedException();
                }

                return waitable.Wait_Locked(waitInfo, timeoutMilliseconds, interruptible, ref lockHolder);
            }
            finally
            {
                lockHolder.Dispose();
            }
        }

        private static class HandleManager
        {
            public static IntPtr NewHandle(IWaitableObject waitableObject)
            {
                Debug.Assert(waitableObject != null);

                IntPtr handle = GCHandle.ToIntPtr(GCHandle.Alloc(waitableObject, GCHandleType.Normal));

                // SafeWaitHandle treats -1 and 0 as invalid, and the handle should not be these values anyway
                Debug.Assert(handle != IntPtr.Zero);
                Debug.Assert(handle != new IntPtr(-1));
                return handle;
            }

            public static IWaitableObject FromHandle(IntPtr handle)
            {
                if (handle == IntPtr.Zero || handle == new IntPtr(-1))
                {
                    WaitHandle.ThrowInvalidHandleException();
                }

                // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by
                // design, IntPtr is unsafe by nature.
                return (IWaitableObject)GCHandle.FromIntPtr(handle).Target!;
            }

            /// <summary>
            /// Unlike on Windows, a handle may not be deleted more than once with this implementation
            /// </summary>
            public static void DeleteHandle(IntPtr handle)
            {
                if (handle == IntPtr.Zero || handle == new IntPtr(-1))
                {
                    return;
                }

                // We don't know if any other handles are invalid, and this may crash or otherwise do bad things, that is by
                // design, IntPtr is unsafe by nature.
                FromHandle(handle).OnDeleteHandle();
                GCHandle.FromIntPtr(handle).Free();
            }
        }
    }
}