public static void DowngradeQuirks_ChangedInDotNetCore() { var trwl = new TestReaderWriterLock(); TestLockCookie tlc; // Downgrade quirk when downgrading from a state where multiple recursive write locks are held, when the lock cookie // was obtained from a state where: // - No lock was held // - When any number of recursive write locks are held // The expectation in both cases is that a downgrade respects the lock cookie and restores the write lock recursion // level to the point indicated by the lock cookie. { // Lock cookie obtained when no lock is held tlc = trwl.UpgradeToWriterLock(); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc); trwl.VerifyIsReaderLockHeld(false); trwl.VerifyIsWriterLockHeld(false); // Lock cookie obtained when write locks are held trwl.AcquireWriterLock(); tlc = trwl.UpgradeToWriterLock(); trwl.AcquireWriterLock(); trwl.DowngradeFromWriterLock(tlc); trwl.VerifyIsReaderLockHeld(false); trwl.VerifyIsWriterLockHeld(true); trwl.ReleaseWriterLock(); trwl.VerifyIsWriterLockHeld(false); } // Cannot downgrade to a recursive write lock level greater than or equal to the current trwl.AcquireWriterLock(); trwl.AcquireWriterLock(); tlc = trwl.UpgradeToWriterLock(); trwl.ReleaseWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.DowngradeFromWriterLock(tlc, InvalidLockCookieExceptionHResult); trwl.ReleaseWriterLock(); trwl.VerifyIsReaderLockHeld(false); trwl.VerifyIsWriterLockHeld(false); trwl.Dispose(); }
public static void ReadersWaitingOnWaitingUpgraderTest() { var trwl = new TestReaderWriterLock(); trwl.AcquireReaderLock(); var waitingUpgraderReady = new AutoResetEvent(false); var continueWaitingUpgrader = new AutoResetEvent(false); Action waitForWaitingUpgrader; Thread waitingUpgrader = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingUpgrader, () => { trwl.AcquireReaderLock(); trwl.UpgradeToWriterLock(); waitingUpgraderReady.Set(); continueWaitingUpgrader.CheckedWait(); trwl.ReleaseWriterLock(); trwl.VerifyIsReaderLockHeld(false); trwl.VerifyIsWriterLockHeld(false); }); waitingUpgrader.IsBackground = true; waitingUpgrader.Start(); ThreadTestHelpers.WaitForCondition(() => (waitingUpgrader.ThreadState & ThreadState.WaitSleepJoin) != 0); Action acquireReleaseReaderLock = () => { trwl.AcquireReaderLock(); trwl.ReleaseReaderLock(); }; Action waitForWaitingReader1, waitForWaitingReader2; Thread waitingReader1 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingReader1, acquireReleaseReaderLock); Thread waitingReader2 = ThreadTestHelpers.CreateGuardedThread(out waitForWaitingReader2, acquireReleaseReaderLock); waitingReader1.IsBackground = true; waitingReader2.IsBackground = true; waitingReader1.Start(); waitingReader2.Start(); ThreadTestHelpers.WaitForCondition(() => (waitingReader1.ThreadState & ThreadState.WaitSleepJoin) != 0); ThreadTestHelpers.WaitForCondition(() => (waitingReader2.ThreadState & ThreadState.WaitSleepJoin) != 0); // Releasing the read lock releases the waiting upgrader trwl.ReleaseReaderLock(); waitingUpgraderReady.CheckedWait(); // Releasing the now-writer's write lock releases all waiting readers continueWaitingUpgrader.Set(); waitForWaitingUpgrader(); waitForWaitingReader1(); waitForWaitingReader2(); trwl.Dispose(); }