File: src\System\Threading\Monitor.CoreCLR.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.
 
/*=============================================================================
**
**
**
** Purpose: Synchronizes access to a shared resource or region of code in a multi-threaded
**             program.
**
**
=============================================================================*/
 
using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
 
namespace System.Threading
{
    public static partial class Monitor
    {
        #region Object->Lock mapping
        internal static Lock GetLockObject(object obj)
        {
            IntPtr lockHandle = GetLockHandleIfExists(obj);
            if (lockHandle != 0)
            {
                Lock lockObj = GCHandle<Lock>.FromIntPtr(lockHandle).Target;
                GC.KeepAlive(obj);
                return lockObj;
            }
 
            return GetLockObjectFallback(obj);
 
            [MethodImpl(MethodImplOptions.NoInlining)]
            static Lock GetLockObjectFallback(object obj)
            {
#pragma warning disable CS9216 // A value of type 'System.Threading.Lock' converted to a different type will use likely unintended monitor-based locking in 'lock' statement.
                object lockObj = new Lock();
#pragma warning restore CS9216
                GetOrCreateLockObject(ObjectHandleOnStack.Create(ref obj), ObjectHandleOnStack.Create(ref lockObj));
                return (Lock)lockObj!;
            }
        }
 
        [MethodImpl(MethodImplOptions.InternalCall)]
        private static extern IntPtr GetLockHandleIfExists(object obj);
 
        [LibraryImport(RuntimeHelpers.QCall, EntryPoint = "Monitor_GetOrCreateLockObject")]
        private static partial void GetOrCreateLockObject(ObjectHandleOnStack obj, ObjectHandleOnStack lockObj);
 
        #endregion
 
        #region Public Enter/Exit methods
        public static void Enter(object obj)
        {
            ObjectHeader.HeaderLockResult result = ObjectHeader.TryAcquireThinLock(obj);
            if (result == ObjectHeader.HeaderLockResult.Success)
                return;
 
            GetLockObject(obj).Enter();
        }
 
        public static bool TryEnter(object obj)
        {
            ObjectHeader.HeaderLockResult result = ObjectHeader.TryAcquireThinLock(obj);
            if (result == ObjectHeader.HeaderLockResult.Success)
                return true;
 
            if (result == ObjectHeader.HeaderLockResult.Failure)
                return false;
 
            return GetLockObject(obj).TryEnter();
        }
 
        public static bool TryEnter(object obj, int millisecondsTimeout)
        {
            ArgumentOutOfRangeException.ThrowIfLessThan(millisecondsTimeout, -1);
 
            ObjectHeader.HeaderLockResult result = ObjectHeader.TryAcquireThinLock(obj);
            if (result == ObjectHeader.HeaderLockResult.Success)
                return true;
 
            return GetLockObject(obj).TryEnter(millisecondsTimeout);
        }
 
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static void Exit(object obj)
        {
            ArgumentNullException.ThrowIfNull(obj);
            ObjectHeader.HeaderLockResult result = ObjectHeader.Release(obj);
 
            if (result == ObjectHeader.HeaderLockResult.Success)
            {
                return;
            }
 
            if (result == ObjectHeader.HeaderLockResult.Failure)
            {
                throw new SynchronizationLockException();
            }
 
            GetLockObject(obj).Exit();
        }
 
        // Marked no-inlining to prevent recursive inlining of IsAcquired.
        [MethodImpl(MethodImplOptions.NoInlining)]
        public static bool IsEntered(object obj)
        {
            ObjectHeader.HeaderLockResult result = ObjectHeader.IsAcquired(obj);
            if (result == ObjectHeader.HeaderLockResult.Success)
                return true;
 
            if (result == ObjectHeader.HeaderLockResult.Failure)
                return false;
 
            return GetLockObject(obj).IsHeldByCurrentThread;
        }
        #endregion
 
        internal static void SynchronizedMethodEnter(object obj, ref bool lockTaken)
        {
            ObjectHeader.HeaderLockResult result = ObjectHeader.TryAcquireThinLock(obj);
            if (result == ObjectHeader.HeaderLockResult.Success)
            {
                lockTaken = true;
                return;
            }
 
            GetLockObject(obj).Enter();
            lockTaken = true;
        }
 
        internal static void SynchronizedMethodExit(object obj, ref bool lockTaken)
        {
            // Inlined Monitor.Exit with a few tweaks
            if (!lockTaken)
                return;
 
            ObjectHeader.HeaderLockResult result = ObjectHeader.Release(obj);
 
            if (result == ObjectHeader.HeaderLockResult.Success)
            {
                return;
            }
 
            if (result == ObjectHeader.HeaderLockResult.Failure)
            {
                throw new SynchronizationLockException();
            }
 
            GetLockObject(obj).Exit();
        }
    }
}