Пример #1
0
        public static void InvalidLockCookieTest()
        {
            // Invalid lock cookie created by using one up with Upgrade/Downgrade
            var            trwl = new TestReaderWriterLock();
            TestLockCookie tlc  = trwl.UpgradeToWriterLock();

            trwl.DowngradeFromWriterLock(tlc);
            trwl.AcquireWriterLock();
            trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult);
            trwl.ReleaseWriterLock();
            trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult);

            // Invalid lock cookie created by using one up with Release/Restore
            tlc = trwl.ReleaseLock();
            trwl.RestoreLock(tlc);
            trwl.AcquireWriterLock();
            trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult);
            trwl.ReleaseWriterLock();
            trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult);

            // Lock cookie owned by another thread
            ThreadTestHelpers.RunTestInBackgroundThread(() =>
            {
                TestLockCookie tlc2 = trwl.UpgradeToWriterLock();
                tlc = tlc2.Clone();
                trwl.DowngradeFromWriterLock(tlc2);
            });
            trwl.AcquireWriterLock();
            trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult);
            trwl.ReleaseWriterLock();
            trwl.RestoreLock(tlc, InvalidLockCookieExceptionHResult);

            trwl.Dispose();
        }
Пример #2
0
            public void DowngradeFromWriterLock(TestLockCookie tlc, int expectedFailureHResult = 0)
            {
                Assert.NotNull(tlc);

                PerformLockAction(
                    expectedFailureHResult,
                    false /* isBlockingOperation */,
                    () => _rwl.DowngradeFromWriterLock(ref tlc._lockCookie),
                    () =>
                {
                    Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                    Assert.NotEqual(0, _writerLevel);
                    if (tlc._readerLevel == 0)
                    {
                        Assert.True(_writerLevel > tlc._writerLevel);
                        _writerLevel = tlc._writerLevel;
                        if (_writerLevel == 0)
                        {
                            _writerThreadID = InvalidThreadID;
                        }
                    }
                    else
                    {
                        _writerLevel    = 0;
                        _writerThreadID = InvalidThreadID;
                        Assert.True(ThreadReaderLevel == 0);
                        ThreadReaderLevel = tlc._readerLevel;
                    }
                });
            }
Пример #3
0
        public static void AtomicDowngradeTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();
            TestLockCookie tlc = trwl.UpgradeToWriterLock();

            Action waitForWaitingWriter;
            Thread waitingWriter =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingWriter, () =>
            {
                trwl.AcquireWriterLock();
                trwl.ReleaseWriterLock();
            });

            waitingWriter.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingWriter.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Downgrade to a read lock successfully while there is a waiting writer
            trwl.DowngradeFromWriterLock(tlc);

            // Releasing the read lock releases the waiting writer
            trwl.ReleaseReaderLock();
            waitForWaitingWriter();

            trwl.Dispose();
        }
Пример #4
0
        public static void ShouldNotBeOwnerForRestoreLockTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();
            TestLockCookie restoreReadLockTlc = trwl.ReleaseLock();

            trwl.AcquireWriterLock();
            TestLockCookie restoreWriteLockTlc = trwl.ReleaseLock();

            Action verifyCannotRestore =
                () =>
            {
                Assert.Throws <SynchronizationLockException>(() => trwl.RestoreLock(restoreReadLockTlc));
                Assert.Throws <SynchronizationLockException>(() => trwl.RestoreLock(restoreWriteLockTlc));
            };

            trwl.AcquireReaderLock();
            verifyCannotRestore();
            trwl.ReleaseReaderLock();

            trwl.AcquireWriterLock();
            verifyCannotRestore();
            trwl.ReleaseWriterLock();

            trwl.Dispose();
        }
Пример #5
0
            public TestLockCookie ReleaseLock()
            {
                TestLockCookie tlc        = null;
                LockCookie     lockCookie = default(LockCookie);

                PerformLockAction(
                    0 /* expectedFailureHResult */,
                    false /* isBlockingOperation */,
                    () => lockCookie = _rwl.ReleaseLock(),
                    () =>
                {
                    tlc = new TestLockCookie()
                    {
                        _lockCookie  = lockCookie,
                        _readerLevel = ThreadReaderLevel,
                        _writerLevel = _writerLevel
                    };

                    if (_writerLevel != 0)
                    {
                        Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                    }
                    ThreadReaderLevel = 0;
                    _writerLevel      = 0;
                    _writerThreadID   = InvalidThreadID;
                });
                return(tlc);
            }
Пример #6
0
            public TestLockCookie UpgradeToWriterLock(int expectedFailureHResult = 0)
            {
                TestLockCookie tlc        = null;
                LockCookie     lockCookie = default(LockCookie);

                PerformLockAction(
                    expectedFailureHResult,
                    true /* isBlockingOperation */,
                    () => lockCookie = _rwl.UpgradeToWriterLock(GetTimeoutMilliseconds(expectedFailureHResult)),
                    () =>
                {
                    tlc = new TestLockCookie()
                    {
                        _lockCookie  = lockCookie,
                        _readerLevel = ThreadReaderLevel,
                        _writerLevel = _writerLevel
                    };

                    ThreadReaderLevel = 0;
                    if (_writerLevel == 0)
                    {
                        Assert.Equal(InvalidThreadID, _writerThreadID);
                        _writerThreadID = Environment.CurrentManagedThreadId;
                        ++_writerSeqNum;
                    }
                    else
                    {
                        Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                    }
                    ++_writerLevel;
                });
                return(tlc);
            }
Пример #7
0
        public static void WaitingUpgradersTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.AcquireReaderLock();

            var    waitingUpgrader1AcquiredReadLock = new ManualResetEvent(false);
            Action waitForWaitingUpgrader1, waitForWaitingUpgrader2, waitForWaitingUpgrader3;
            Thread waitingUpgrader1 =
                ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader1, () =>
            {
                trwl.AcquireReaderLock();
                waitingUpgrader1AcquiredReadLock.Set();
                TestLockCookie tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
                trwl.ReleaseReaderLock();
            });
            Action upgradeDowngradeLock =
                () =>
            {
                TestLockCookie tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
            };
            Thread waitingUpgrader2 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader2, upgradeDowngradeLock);
            Thread waitingUpgrader3 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader3, upgradeDowngradeLock);

            waitingUpgrader1.IsBackground = true;
            waitingUpgrader2.IsBackground = true;
            waitingUpgrader1.Start();
            waitingUpgrader1AcquiredReadLock.CheckedWait();
            waitingUpgrader2.Start();
            waitingUpgrader3.Start();
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader1.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader2.ThreadState & ThreadState.WaitSleepJoin) != 0);
            ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader3.ThreadState & ThreadState.WaitSleepJoin) != 0);

            // Releasing the read lock releases a waiting upgrader, that writer downgrades its write lock, in turn releasing the
            // other upgrader, and so on
            trwl.ReleaseReaderLock();
            waitForWaitingUpgrader1();
            waitForWaitingUpgrader2();
            waitForWaitingUpgrader3();

            trwl.Dispose();
        }
Пример #8
0
        public static void NotOwnerTest()
        {
            var trwl = new TestReaderWriterLock();

            trwl.ReleaseReaderLock(NotOwnerExceptionHResult);
            trwl.ReleaseWriterLock(NotOwnerExceptionHResult);
            trwl.DowngradeFromWriterLock(new TestLockCookie(), NotOwnerExceptionHResult);

            {
                trwl.AcquireReaderLock();

                trwl.ReleaseWriterLock(NotOwnerExceptionHResult);

                TestLockCookie tlc  = trwl.UpgradeToWriterLock();
                TestLockCookie tlc2 = tlc.Clone();
                trwl.DowngradeFromWriterLock(tlc); // tlc is invalid, tlc2 is valid
                trwl.DowngradeFromWriterLock(tlc2, NotOwnerExceptionHResult);

                trwl.ReleaseReaderLock();
            }

            trwl.Dispose();
        }
Пример #9
0
            public void RestoreLock(TestLockCookie tlc, int expectedFailureHResult = 0)
            {
                Assert.NotNull(tlc);
                Assert.NotEqual(TimeoutExceptionHResult, expectedFailureHResult);

                PerformLockAction(
                    expectedFailureHResult,
                    true /* isBlockingOperation */,
                    () => _rwl.RestoreLock(ref tlc._lockCookie),
                    () =>
                {
                    Assert.Equal(0, ThreadReaderLevel);
                    Assert.Equal(InvalidThreadID, _writerThreadID);
                    Assert.Equal(0, _writerLevel);
                    ThreadReaderLevel = tlc._readerLevel;
                    _writerLevel      = tlc._writerLevel;
                    if (_writerLevel != 0)
                    {
                        Assert.Equal(InvalidThreadID, _writerThreadID);
                        _writerThreadID = Environment.CurrentManagedThreadId;
                        ++_writerSeqNum;
                    }
                });
            }
Пример #10
0
        public static void BasicLockTest()
        {
            var            trwl = new TestReaderWriterLock();
            TestLockCookie tlc;
            var            threadReady = new AutoResetEvent(false);
            var            continueThread = new AutoResetEvent(false);
            Action         checkForThreadErrors, waitForThread;
            Thread         t =
                ThreadTestHelpers.CreateGuardedThread(out checkForThreadErrors, out waitForThread, () =>
            {
                TestLockCookie tlc2;
                Action switchToMainThread =
                    () =>
                {
                    threadReady.Set();
                    continueThread.CheckedWait();
                };

                switchToMainThread();

                // Multiple readers from multiple threads
                {
                    trwl.AcquireReaderLock();
                    trwl.AcquireReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();
                }

                // What can be done when a read lock is held
                {
                    trwl.AcquireReaderLock();
                    switchToMainThread();

                    // Any thread can take a read lock
                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // No thread can take a write lock
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // Owning thread releases read lock when upgrading
                    trwl.AcquireWriterLock();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();

                    // Owning thread cannot upgrade if there are other readers or writers
                    trwl.AcquireReaderLock();
                    switchToMainThread();
                    trwl.ReleaseReaderLock();
                    trwl.AcquireWriterLock();
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();
                }

                // What can be done when a write lock is held
                {
                    // Write lock acquired through AcquireWriteLock is exclusive
                    trwl.AcquireWriterLock();
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();

                    // Write lock acquired through upgrading is also exclusive
                    trwl.AcquireReaderLock();
                    tlc2 = trwl.UpgradeToWriterLock();
                    switchToMainThread();
                    trwl.DowngradeFromWriterLock(tlc2);
                    trwl.ReleaseReaderLock();
                    switchToMainThread();

                    // Write lock acquired through restore is also exclusive
                    trwl.AcquireWriterLock();
                    tlc = trwl.ReleaseLock();
                    trwl.RestoreLock(tlc);
                    switchToMainThread();
                    trwl.ReleaseWriterLock();
                    switchToMainThread();
                }
            });

            t.IsBackground = true;
            t.Start();

            Action beginSwitchToBackgroundThread = () => continueThread.Set();
            Action endSwitchToBackgroundThread   =
                () =>
            {
                try
                {
                    threadReady.CheckedWait();
                }
                finally
                {
                    checkForThreadErrors();
                }
            };
            Action switchToBackgroundThread =
                () =>
            {
                beginSwitchToBackgroundThread();
                endSwitchToBackgroundThread();
            };

            endSwitchToBackgroundThread();

            // Multiple readers from muliple threads
            {
                trwl.AcquireReaderLock();
                trwl.AcquireReaderLock();
                switchToBackgroundThread(); // AcquireReaderLock * 2
                trwl.ReleaseReaderLock();
                switchToBackgroundThread(); // ReleaseReaderLock

                // Release/restore the read lock while a read lock is held by another thread
                tlc = trwl.ReleaseLock();
                trwl.RestoreLock(tlc);

                switchToBackgroundThread(); // ReleaseReaderLock

                // Downgrade to read lock allows another thread to acquire read lock
                tlc = trwl.UpgradeToWriterLock();
                trwl.DowngradeFromWriterLock(tlc);
                switchToBackgroundThread(); // AcquireReaderLock, ReleaseReaderLock

                trwl.ReleaseReaderLock();
            }

            // What can be done when a read lock is held
            {
                switchToBackgroundThread(); // AcquireReaderLock
                {
                    // Any thread can take a read lock
                    trwl.AcquireReaderLock();
                    trwl.ReleaseReaderLock();
                    switchToBackgroundThread(); // same as above

                    // No thread can take a write lock
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    switchToBackgroundThread(); // same as above
                    trwl.ReleaseReaderLock();

                    // Other threads cannot upgrade to a write lock, but the owning thread can
                    trwl.AcquireReaderLock();
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                    trwl.ReleaseReaderLock();
                }
                switchToBackgroundThread(); // ReleaseReaderLock

                // Owning thread releases read lock when upgrading
                trwl.AcquireReaderLock();
                beginSwitchToBackgroundThread(); // AcquireWriterLock: background thread gets blocked
                trwl.UpgradeToWriterLock();      // unblocks background thread: ReleaseWriterLock
                trwl.ReleaseWriterLock();
                endSwitchToBackgroundThread();

                // Owning thread cannot upgrade if there are other readers or writers
                trwl.AcquireReaderLock();
                switchToBackgroundThread(); // AcquireReaderLock
                trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                trwl.ReleaseReaderLock();
                switchToBackgroundThread(); // ReleaseReaderLock, AcquireWriterLock
                trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                switchToBackgroundThread(); // ReleaseWriterLock
            }

            // What can be done when a write lock is held
            {
                trwl.AcquireWriterLock();
                TestLockCookie restoreToWriteLockTlc   = trwl.ReleaseLock();
                Action         verifyCannotAcquireLock =
                    () =>
                {
                    trwl.AcquireReaderLock(TimeoutExceptionHResult);
                    trwl.AcquireWriterLock(TimeoutExceptionHResult);
                    trwl.UpgradeToWriterLock(TimeoutExceptionHResult);
                };
                Action verifyCanAcquireLock =
                    () =>
                {
                    trwl.AcquireReaderLock();
                    tlc = trwl.UpgradeToWriterLock();
                    trwl.DowngradeFromWriterLock(tlc);
                    trwl.ReleaseReaderLock();
                    trwl.AcquireWriterLock();
                    trwl.ReleaseWriterLock();
                    trwl.RestoreLock(restoreToWriteLockTlc.Clone());
                    trwl.ReleaseWriterLock();
                };

                // Write lock acquired through AcquireWriteLock is exclusive
                switchToBackgroundThread(); // AcquireWriterLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // ReleaseWriterLock
                verifyCanAcquireLock();

                // Write lock acquired through upgrading is also exclusive
                switchToBackgroundThread(); // AcquireReaderLock, UpgradeToWriterLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // DowngradeFromWriterLock, ReleaseReaderLock
                verifyCanAcquireLock();

                // Write lock acquired through restore is also exclusive
                switchToBackgroundThread(); // AcquireWriterLock, ReleaseLock, RestoreLock
                verifyCannotAcquireLock();
                switchToBackgroundThread(); // ReleaseWriterLock
                verifyCanAcquireLock();
            }

            beginSwitchToBackgroundThread();
            waitForThread();
            trwl.Dispose();
        }
Пример #11
0
            public TestLockCookie ReleaseLock()
            {
                TestLockCookie tlc = null;
                LockCookie lockCookie = default(LockCookie);
                PerformLockAction(
                    0 /* expectedFailureHResult */,
                    false /* isBlockingOperation */,
                    () => lockCookie = _rwl.ReleaseLock(),
                    () =>
                    {
                        tlc = new TestLockCookie()
                        {
                            _lockCookie = lockCookie,
                            _readerLevel = ThreadReaderLevel,
                            _writerLevel = _writerLevel
                        };

                        if (_writerLevel != 0)
                        {
                            Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                        }
                        ThreadReaderLevel = 0;
                        _writerLevel = 0;
                        _writerThreadID = InvalidThreadID;
                    });
                return tlc;
            }
Пример #12
0
            public void DowngradeFromWriterLock(TestLockCookie tlc, int expectedFailureHResult = 0)
            {
                Assert.NotNull(tlc);

                PerformLockAction(
                    expectedFailureHResult,
                    false /* isBlockingOperation */,
                    () => _rwl.DowngradeFromWriterLock(ref tlc._lockCookie),
                    () =>
                    {
                        Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                        Assert.NotEqual(0, _writerLevel);
                        if (tlc._readerLevel == 0)
                        {
                            Assert.True(_writerLevel > tlc._writerLevel);
                            _writerLevel = tlc._writerLevel;
                            if (_writerLevel == 0)
                            {
                                _writerThreadID = InvalidThreadID;
                            }
                        }
                        else
                        {
                            _writerLevel = 0;
                            _writerThreadID = InvalidThreadID;
                            Assert.True(ThreadReaderLevel == 0);
                            ThreadReaderLevel = tlc._readerLevel;
                        }
                    });
            }
Пример #13
0
            public TestLockCookie UpgradeToWriterLock(int expectedFailureHResult = 0)
            {
                TestLockCookie tlc = null;
                LockCookie lockCookie = default(LockCookie);
                PerformLockAction(
                    expectedFailureHResult,
                    true /* isBlockingOperation */,
                    () => lockCookie = _rwl.UpgradeToWriterLock(GetTimeoutMilliseconds(expectedFailureHResult)),
                    () =>
                    {
                        tlc = new TestLockCookie()
                        {
                            _lockCookie = lockCookie,
                            _readerLevel = ThreadReaderLevel,
                            _writerLevel = _writerLevel
                        };

                        ThreadReaderLevel = 0;
                        if (_writerLevel == 0)
                        {
                            Assert.Equal(InvalidThreadID, _writerThreadID);
                            _writerThreadID = Environment.CurrentManagedThreadId;
                            ++_writerSeqNum;
                        }
                        else
                        {
                            Assert.Equal(Environment.CurrentManagedThreadId, _writerThreadID);
                        }
                        ++_writerLevel;
                    });
                return tlc;
            }
Пример #14
0
            public void RestoreLock(TestLockCookie tlc, int expectedFailureHResult = 0)
            {
                Assert.NotNull(tlc);
                Assert.NotEqual(TimeoutExceptionHResult, expectedFailureHResult);

                PerformLockAction(
                    expectedFailureHResult,
                    true /* isBlockingOperation */,
                    () => _rwl.RestoreLock(ref tlc._lockCookie),
                    () =>
                    {
                        Assert.Equal(0, ThreadReaderLevel);
                        Assert.Equal(InvalidThreadID, _writerThreadID);
                        Assert.Equal(0, _writerLevel);
                        ThreadReaderLevel = tlc._readerLevel;
                        _writerLevel = tlc._writerLevel;
                        if (_writerLevel != 0)
                        {
                            Assert.Equal(InvalidThreadID, _writerThreadID);
                            _writerThreadID = Environment.CurrentManagedThreadId;
                            ++_writerSeqNum;
                        }
                    });
            }