System.Threading.Tests.ReaderWriterLockTests.TestReaderWriterLock.PerformLockAction C# (CSharp) Method

PerformLockAction() private method

private PerformLockAction ( int expectedFailureHResult, bool isBlockingOperation, Action rwlAction, Action makeStateChangesOnSuccess ) : void
expectedFailureHResult int
isBlockingOperation bool
rwlAction Action
makeStateChangesOnSuccess Action
return void
            private void PerformLockAction(
                int expectedFailureHResult,
                bool isBlockingOperation,
                Action rwlAction,
                Action makeStateChangesOnSuccess)
            {
                // Blocking operations are inherently nondeterministic in the order in which they are performed, so record a
                // pending change before performing the operation. Since the state changes following some blocking operations
                // may occur in any order, state verification is only done once there are no pending state changes. Non-blocking
                // operations appear atomic and the relevant state changes need to occur in the requested order, so take a
                // single lock over the operation and state changes.
                if (isBlockingOperation)
                {
                    lock (_rwl)
                    {
                        ++_pendingStateChanges;
                    }
                }
                else
                {
                    Monitor.Enter(_rwl);
                }

                try
                {
                    ApplicationException ex = null;
                    bool isHandledCase = false;
                    try
                    {
                        rwlAction();
                        isHandledCase = true;
                    }
                    catch (ApplicationException ex2)
                    {
                        ex = ex2;
                        isHandledCase = true;
                    }
                    finally
                    {
                        if (!isHandledCase && isBlockingOperation)
                        {
                            // Some exception other than ones handled above occurred. Decrement the pending state changes. For
                            // handled cases, the decrement needs to occur in the same lock that also verifies the exception,
                            // makes state changes, and verifies the state.
                            lock (_rwl)
                            {
                                --_pendingStateChanges;
                                // This exception will cause the test to fail, so don't verify state
                            }
                        }
                    }

                    if (isBlockingOperation)
                    {
                        Monitor.Enter(_rwl);
                    }
                    try
                    {
                        if (isBlockingOperation)
                        {
                            // Decrementing the pending state changes needs to occur in the same lock that makes state changes
                            // and verifies state, in order to guarantee that when there are no pending state changes based on
                            // the count, all state changes are reflected in the fields as well.
                            --_pendingStateChanges;
                        }

                        Assert.Equal(expectedFailureHResult, ex == null ? 0 : ex.HResult);
                        if (ex == null)
                        {
                            makeStateChangesOnSuccess();
                        }

                        if (_pendingStateChanges == 0)
                        {
                            VerifyState();
                        }
                    }
                    finally
                    {
                        if (isBlockingOperation)
                        {
                            Monitor.Exit(_rwl);
                        }
                    }
                }
                finally
                {
                    if (!isBlockingOperation)
                    {
                        Monitor.Exit(_rwl);
                    }
                }
            }