private bool TryIssueLock()

in src/Microsoft.VisualStudio.Threading/AsyncReaderWriterLock.cs [1068:1185]


        private bool TryIssueLock(Awaiter awaiter, bool previouslyQueued, bool skipPendingWriteLockCheck = false)
        {
            lock (this.syncObject)
            {
                if (this.completeInvoked && !previouslyQueued)
                {
                    // If this is a new top-level lock request, reject it completely.
                    if (awaiter.NestingLock is null)
                    {
                        awaiter.SetFault(new InvalidOperationException(Strings.LockCompletionAlreadyRequested));
                        return false;
                    }
                }

                bool issued = false;
                if (this.reenterConcurrencyPrepRunning is null)
                {
                    if (this.issuedWriteLocks.Count == 0 && this.issuedUpgradeableReadLocks.Count == 0 && this.issuedReadLocks.Count == 0)
                    {
                        issued = true;
                    }
                    else
                    {
                        this.AggregateLockStackKinds(awaiter, out bool hasRead, out bool hasUpgradeableRead, out bool hasWrite);
                        switch (awaiter.Kind)
                        {
                            case LockKind.Read:
                                if (this.issuedWriteLocks.Count == 0 && (skipPendingWriteLockCheck || this.waitingWriters.Count == 0))
                                {
                                    issued = true;
                                }
                                else if (hasWrite)
                                {
                                    // We allow STA threads to not have the sync context applied because it never has it applied,
                                    // and a write lock holder is allowed to transition to an STA tread.
                                    // But if an MTA thread has the write lock but not the sync context, then they're likely
                                    // an accidental execution fork that is exposing concurrency inappropriately.
                                    if (this.CanCurrentThreadHoldActiveLock && !(SynchronizationContext.Current is NonConcurrentSynchronizationContext))
                                    {
#if NETFRAMEWORK || NETCOREAPP // Assertion failures crash on .NET Core < 3.0
                                        Report.Fail("Dangerous request for read lock from fork of write lock.");
#endif
                                        Verify.FailOperation(Strings.DangerousReadLockRequestFromWriteLockFork);
                                    }

                                    issued = true;
                                }
                                else if (hasRead || hasUpgradeableRead)
                                {
                                    issued = true;
                                }

                                break;
                            case LockKind.UpgradeableRead:
                                if (hasUpgradeableRead || hasWrite)
                                {
                                    issued = true;
                                }
                                else if (hasRead)
                                {
                                    // We cannot issue an upgradeable read lock to folks who have (only) a read lock.
                                    throw new InvalidOperationException(Strings.CannotUpgradeNonUpgradeableLock);
                                }
#pragma warning disable CA1508 // Avoid dead conditional code
                                else if (this.issuedUpgradeableReadLocks.Count == 0 && this.issuedWriteLocks.Count == 0)
#pragma warning restore CA1508 // Avoid dead conditional code
                                {
                                    issued = true;
                                }

                                break;
                            case LockKind.Write:
                                if (hasWrite)
                                {
                                    issued = true;
                                }
                                else if (hasRead && !hasUpgradeableRead)
                                {
                                    // We cannot issue a write lock when the caller already holds a read lock.
                                    throw new InvalidOperationException(Strings.CannotUpgradeNonUpgradeableLock);
                                }
                                else if (this.AllHeldLocksAreByThisStack(awaiter.NestingLock))
                                {
                                    issued = true;

                                    Awaiter? stickyWriteAwaiter = this.FindRootUpgradeableReadWithStickyWrite(awaiter);
                                    if (stickyWriteAwaiter is object)
                                    {
                                        // Add the upgradeable reader as a write lock as well.
                                        this.issuedWriteLocks.Add(stickyWriteAwaiter);
                                    }
                                }

                                break;
                            default:
                                throw Assumes.NotReachable();
                        }
                    }
                }

                if (issued)
                {
                    this.GetActiveLockSet(awaiter.Kind).Add(awaiter);
                    this.etw.Issued(awaiter);
                }

                if (!issued)
                {
                    this.etw.WaitStart(awaiter);

                    // If the lock is immediately available, we don't need to coordinate with other threads.
                    // But if it is NOT available, we'd have to wait potentially for other threads to do more work.
                    Debugger.NotifyOfCrossThreadDependency();
                }

                return issued;
            }
        }