private static int GetRemainingTimeout(int millisecondsTimeout, long initialTicks)
 {
     return(millisecondsTimeout == Timeout.Infinite ? Timeout.Infinite :
            (int)Math.Max(0, millisecondsTimeout -
                          (TimeUtils.GetTimestampTicks(true) - initialTicks) / 10000));
 }
        /// <summary>
        /// Tries to asynchronously enter the lock in write mode, with an optional integer time-out.
        /// </summary>
        /// <param name="millisecondsTimeout">The number of milliseconds to wait, or -1
        /// (<see cref="Timeout.Infinite"/>) to wait indefinitely.</param>
        /// <param name="cancellationToken">The <see cref="CancellationToken"/> to observe.</param>
        /// <returns>A task that will complete with a result of <c>true</c> if the lock has been entered,
        /// otherwise with a result of <c>false</c>.</returns>
        /// <exception cref="ArgumentOutOfRangeException"><paramref name="millisecondsTimeout"/> is a negative number
        /// other than -1, which represents an infinite time-out.</exception>
        /// <exception cref="OperationCanceledException"><paramref name="cancellationToken"/> was canceled.</exception>
        /// <exception cref="ObjectDisposedException">The current instance has already been disposed.</exception>
        public async Task <bool> TryEnterWriteLockAsync(
            int millisecondsTimeout             = 0,
            CancellationToken cancellationToken = default)
        {
            DenyIfDisposed();
            if (millisecondsTimeout < Timeout.Infinite)
            {
                throw new ArgumentOutOfRangeException(nameof(millisecondsTimeout));
            }

            cancellationToken.ThrowIfCancellationRequested();

            long initialTicks = millisecondsTimeout == Timeout.Infinite ? 0 :
                                TimeUtils.GetTimestampTicks(true);

            // Enter the write lock semaphore before doing anything else.
            if (!EnterWriteLockPreface(out bool waitForReadLocks))
            {
                bool writeLockWaitResult = false;
                try
                {
                    writeLockWaitResult = await this.writeLockSemaphore.WaitAsync(
                        millisecondsTimeout,
                        cancellationToken);
                }
                finally
                {
                    EnterWriteLockPostface(writeLockWaitResult, out waitForReadLocks);
                }
                if (!writeLockWaitResult)
                {
                    return(false);
                }
            }

            // After we set the write lock state, we might need to wait for existing read
            // locks to be released.
            // In this state, no new read locks can be entered until we release the write
            // lock state.
            // We only wait one time since only the last active read lock will release
            // the semaphore.
            if (waitForReadLocks)
            {
                bool waitResult = false;
                try
                {
                    // This may throw an OperationCanceledException.
                    waitResult = await this.readLockReleaseSemaphore.WaitAsync(
                        GetRemainingTimeout(millisecondsTimeout, initialTicks),
                        cancellationToken);
                }
                finally
                {
                    if (!waitResult)
                    {
                        // Timeout has been exceeded or a OperationCancelledException has
                        // been thrown.
                        HandleEnterWriteLockWaitFailure();
                    }
                }

                if (!waitResult)
                {
                    return(false); // Timeout exceeded
                }
            }

            return(true);
        }