Merge pull request #1426 from ignacionr/webclient-delay-file-creation
[mono.git] / mcs / class / corlib / Test / System.Threading / ReaderWriterLockTest.cs
index 7cb66350503b22e2a9fe699e002a9f77274b332a..ef398486a2abf25cc43216147d98e004e077f454 100644 (file)
-//\r
-// ReaderWriterLockTest.cs - NUnit Test Cases for System.Threading.ReaderWriterLock\r
-//\r
-// Author:\r
-//   Lluis Sanchez Gual (lluis@ximian.com)\r
-//\r
-// (C) 2004 Novell, Inc (http://www.novell.com)\r
-// \r
-\r
-using NUnit.Framework;\r
-using System;\r
-using System.Threading;\r
-\r
-namespace MonoTests.System.Threading\r
-{\r
-       [TestFixture]\r
-       public class ReaderWriterLockTest : Assertion\r
-       {\r
-               ReaderWriterLock rwlock;\r
-               \r
-               Exception resultException;\r
-               ThreadStart secondaryThread;\r
-               \r
-               void StartThread (ThreadStart ts)\r
-               {\r
-                       secondaryThread = ts;\r
-                       resultException = null;\r
-                       Thread t = new Thread (new ThreadStart (ThreadRunner));\r
-                       t.Start ();\r
-                       t.Join ();\r
-                       if (resultException != null) throw resultException;\r
-               }\r
-               \r
-               void ThreadRunner ()\r
-               {\r
-                       try\r
-                       {\r
-                               secondaryThread();\r
-                       }\r
-                       catch (Exception ex)\r
-                       {\r
-                               resultException = ex;\r
-                       }\r
-               }\r
-               \r
+//
+// ReaderWriterLockTest.cs - NUnit Test Cases for System.Threading.ReaderWriterLock
+//
+// Author:
+//   Lluis Sanchez Gual (lluis@ximian.com)
+//
+// (C) 2004 Novell, Inc (http://www.novell.com)
+// 
+
+using NUnit.Framework;
+using System;
+using System.Threading;
+
+namespace MonoTests.System.Threading
+{
+       [TestFixture]
+       public class ReaderWriterLockTest
+       {
+               ReaderWriterLock rwlock;
+               
+               class ThreadRunner
+               {
+                       public ThreadStart SecondaryThread;
+                       public Exception ResultException;
+                       public Thread RunningThread;
+                       
+                       public void Run ()
+                       {
+                               try
+                               {
+                                       SecondaryThread();
+                               }
+                               catch (Exception ex)
+                               {
+                                       ResultException = ex;
+                               }
+                       }
+                       
+                       public void Join ()
+                       {
+                               RunningThread.Join (5000);
+                               if (ResultException != null) throw ResultException;
+                       }
+               }
+               
+               void RunThread (ThreadStart ts)
+               {
+                       ThreadRunner tr = StartThread (ts);
+                       tr.Join ();
+               }
+               
+               ThreadRunner StartThread (ThreadStart ts)
+               {
+                       ThreadRunner tr = new ThreadRunner();
+                       tr.SecondaryThread = ts;
+                       Thread t = new Thread (new ThreadStart (tr.Run));
+                       tr.RunningThread = t;
+                       t.Start ();
+                       return tr;
+               }
+               
                [Test]
-               public void TestIsReaderLockHeld ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       Assert ("a1", !rwlock.IsReaderLockHeld);\r
-                       rwlock.AcquireReaderLock (500);\r
-                       Assert ("a2", rwlock.IsReaderLockHeld);\r
-                       StartThread (new ThreadStart (IsReaderLockHeld_2));\r
-                       rwlock.ReleaseReaderLock ();\r
-               }\r
-               \r
-               private void IsReaderLockHeld_2 ()\r
-               {\r
-                       Assert ("a3", !rwlock.IsReaderLockHeld);\r
-               }\r
-               \r
-               [Test]\r
-               public void TestIsWriterLockHeld ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       Assert ("a1", !rwlock.IsWriterLockHeld);\r
-                       rwlock.AcquireWriterLock (500);\r
-                       Assert ("a2", rwlock.IsWriterLockHeld);\r
-                       StartThread (new ThreadStart (IsWriterLockHeld_2));\r
-                       rwlock.ReleaseWriterLock ();\r
-               }\r
-               \r
-               private void IsWriterLockHeld_2 ()\r
-               {\r
-                       Assert ("a3", !rwlock.IsWriterLockHeld);\r
-               }\r
-                               \r
-               [Test]\r
-               public void TestAcquireLocks ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       rwlock.AcquireReaderLock (500);\r
-                       rwlock.AcquireReaderLock (500);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("a1", rwlock.IsReaderLockHeld);                 \r
-                       StartThread (new ThreadStart (AcquireLock_readerWorks));\r
-                       Assert ("a2", rwlock.IsReaderLockHeld);\r
-                       \r
-                       StartThread (new ThreadStart (AcquireLock_writerFails));\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("a6", !rwlock.IsReaderLockHeld);\r
-                       \r
-                       StartThread (new ThreadStart (AcquireLock_writerWorks));\r
-                       \r
-                       rwlock.AcquireWriterLock (200);\r
-                       StartThread (new ThreadStart (AcquireLock_writerFails));\r
-                       StartThread (new ThreadStart (AcquireLock_readerFails));\r
-                       rwlock.ReleaseWriterLock ();\r
-               }\r
-               \r
-               void AcquireLock_readerWorks ()\r
-               {\r
-                       rwlock.AcquireReaderLock (200);\r
-                       rwlock.AcquireReaderLock (200);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("a3", rwlock.IsReaderLockHeld);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("a4", !rwlock.IsReaderLockHeld);\r
-               }\r
-               \r
-               void AcquireLock_writerFails ()\r
-               {\r
-                       try\r
-                       {\r
-                               rwlock.AcquireWriterLock (200);\r
-                               rwlock.ReleaseWriterLock ();\r
-                               throw new Exception ("Should not get writer lock");\r
-                       }\r
-                       catch (Exception ex)\r
-                       {\r
-                       }\r
-               }\r
-               \r
-               void AcquireLock_writerWorks ()\r
-               {\r
-                       rwlock.AcquireWriterLock (200);\r
-                       rwlock.ReleaseWriterLock ();\r
-               }\r
-               \r
-               void AcquireLock_readerFails ()\r
-               {\r
-                       try\r
-                       {\r
-                               rwlock.AcquireReaderLock (200);\r
-                               rwlock.ReleaseReaderLock ();\r
-                               throw new Exception ("Should not get reader lock");\r
-                       }\r
-                       catch (Exception ex)\r
-                       {\r
-                       }\r
-               }\r
-               \r
-               [Test]\r
-               public void TestReleaseRestoreReaderLock ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       rwlock.AcquireReaderLock (500);\r
-                       rwlock.AcquireReaderLock (500);\r
-                       Assert ("r1", rwlock.IsReaderLockHeld);\r
-                       \r
-                       LockCookie co = rwlock.ReleaseLock ();\r
-                       StartThread (new ThreadStart (AcquireLock_writerWorks));\r
-                       \r
-                       rwlock.RestoreLock (ref co);\r
-                       StartThread (new ThreadStart (AcquireLock_writerFails));\r
-                       \r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("r2", rwlock.IsReaderLockHeld);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("r3", !rwlock.IsReaderLockHeld);\r
-               }\r
-               \r
-               [Test]\r
-               public void TestReleaseRestoreWriterLock ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       rwlock.AcquireWriterLock (500);\r
-                       rwlock.AcquireWriterLock (500);\r
-                       Assert ("w1", rwlock.IsWriterLockHeld);\r
-                       \r
-                       LockCookie co = rwlock.ReleaseLock ();\r
-                       StartThread (new ThreadStart (AcquireLock_readerWorks));\r
-                       \r
-                       rwlock.RestoreLock (ref co);\r
-                       StartThread (new ThreadStart (AcquireLock_readerFails));\r
-                       \r
-                       rwlock.ReleaseWriterLock ();\r
-                       Assert ("w2", rwlock.IsWriterLockHeld);\r
-                       rwlock.ReleaseWriterLock ();\r
-                       Assert ("w3", !rwlock.IsWriterLockHeld);\r
-               }\r
-               \r
-               [Test]\r
-               public void TestUpgradeDowngradeLock ()\r
-               {\r
-                       rwlock = new ReaderWriterLock ();\r
-                       rwlock.AcquireReaderLock (200);\r
-                       rwlock.AcquireReaderLock (200);\r
-                       \r
-                       LockCookie co = rwlock.UpgradeToWriterLock (200);\r
-                       Assert ("u1", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u2", rwlock.IsWriterLockHeld);\r
-                       StartThread (new ThreadStart (AcquireLock_writerFails));\r
-                       \r
-                       rwlock.DowngradeFromWriterLock (ref co);\r
-                       Assert ("u3", rwlock.IsReaderLockHeld);\r
-                       Assert ("u4", !rwlock.IsWriterLockHeld);\r
-                       StartThread (new ThreadStart (AcquireLock_readerWorks));\r
-                       \r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("u5", rwlock.IsReaderLockHeld);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("u6", !rwlock.IsReaderLockHeld);\r
-               }\r
-               \r
-               [Test]\r
-               public void TestReaderInsideWriter ()\r
-               {\r
-                       // Reader acquires and releases work like the writer equivalent\r
-                       \r
-                       rwlock = new ReaderWriterLock ();\r
-                       rwlock.AcquireWriterLock (-1);\r
-                       rwlock.AcquireReaderLock (-1);\r
-                       Assert ("u1", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u2", rwlock.IsWriterLockHeld);\r
-                       rwlock.AcquireReaderLock (-1);\r
-                       Assert ("u3", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u4", rwlock.IsWriterLockHeld);\r
-                       rwlock.ReleaseWriterLock ();\r
-                       Assert ("u5", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u6", rwlock.IsWriterLockHeld);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("u7", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u8", rwlock.IsWriterLockHeld);\r
-                       rwlock.ReleaseReaderLock ();\r
-                       Assert ("u9", !rwlock.IsReaderLockHeld);\r
-                       Assert ("u10", !rwlock.IsWriterLockHeld);\r
-               }\r
-       }\r
+               public void TestIsReaderLockHeld ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld, "#1");
+                       rwlock.AcquireReaderLock (500);
+                       Assert.IsTrue (rwlock.IsReaderLockHeld, "#1");
+                       RunThread (new ThreadStart (IsReaderLockHeld_2));
+                       rwlock.ReleaseReaderLock ();
+               }
+               
+               private void IsReaderLockHeld_2 ()
+               {
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+               }
+               
+               [Test]
+               public void TestIsWriterLockHeld ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       Assert.IsTrue (!rwlock.IsWriterLockHeld, "#1");
+                       rwlock.AcquireWriterLock (500);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "#2");
+                       RunThread (new ThreadStart (IsWriterLockHeld_2));
+                       rwlock.ReleaseWriterLock ();
+               }
+               
+               private void IsWriterLockHeld_2 ()
+               {
+                       Assert.IsTrue (!rwlock.IsWriterLockHeld);
+               }
+                               
+               [Test]
+               public void TestAcquireLocks ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireReaderLock (500);
+                       rwlock.AcquireReaderLock (500);
+                       rwlock.ReleaseReaderLock ();
+                               Assert.IsTrue (rwlock.IsReaderLockHeld, "#1");                  
+                       RunThread (new ThreadStart (AcquireLock_readerWorks));
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       
+                       RunThread (new ThreadStart (AcquireLock_writerFails));
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       
+                       RunThread (new ThreadStart (AcquireLock_writerWorks));
+                       
+                       rwlock.AcquireWriterLock (200);
+                       RunThread (new ThreadStart (AcquireLock_writerFails));
+                       RunThread (new ThreadStart (AcquireLock_readerFails));
+                       rwlock.ReleaseWriterLock ();
+               }
+               
+               void AcquireLock_readerWorks ()
+               {
+                       rwlock.AcquireReaderLock (200);
+                       rwlock.AcquireReaderLock (200);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+               }
+               
+               void AcquireLock_writerFails ()
+               {
+                       try
+                       {
+                               rwlock.AcquireWriterLock (200);
+                               rwlock.ReleaseWriterLock ();
+                               throw new Exception ("Should not get writer lock");
+                       }
+                       catch (Exception)
+                       {
+                       }
+               }
+               
+               void AcquireLock_writerWorks ()
+               {
+                       rwlock.AcquireWriterLock (200);
+                       rwlock.ReleaseWriterLock ();
+               }
+               
+               void AcquireLock_readerFails ()
+               {
+                       try
+                       {
+                               rwlock.AcquireReaderLock (200);
+                               rwlock.ReleaseReaderLock ();
+                               throw new Exception ("Should not get reader lock");
+                       }
+                       catch (Exception)
+                       {
+                       }
+               }
+               
+               [Test]
+               public void TestReleaseRestoreReaderLock ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireReaderLock (500);
+                       rwlock.AcquireReaderLock (500);
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       
+                       LockCookie co = rwlock.ReleaseLock ();
+                       RunThread (new ThreadStart (AcquireLock_writerWorks));
+                       
+                       rwlock.RestoreLock (ref co);
+                       RunThread (new ThreadStart (AcquireLock_writerFails));
+                       
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+               }
+               
+               [Test]
+               public void TestReleaseRestoreWriterLock ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireWriterLock (500);
+                       rwlock.AcquireWriterLock (500);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       
+                       LockCookie co = rwlock.ReleaseLock ();
+                       RunThread (new ThreadStart (AcquireLock_readerWorks));
+                       
+                       rwlock.RestoreLock (ref co);
+                       RunThread (new ThreadStart (AcquireLock_readerFails));
+                       
+                       rwlock.ReleaseWriterLock ();
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       rwlock.ReleaseWriterLock ();
+                       Assert.IsTrue (!rwlock.IsWriterLockHeld);
+               }
+               
+               [Test]
+               public void TestUpgradeDowngradeLock ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireReaderLock (200);
+                       rwlock.AcquireReaderLock (200);
+                       
+                       LockCookie co = rwlock.UpgradeToWriterLock (200);
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       RunThread (new ThreadStart (AcquireLock_writerFails));
+                       
+                       rwlock.DowngradeFromWriterLock (ref co);
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (!rwlock.IsWriterLockHeld);
+                       RunThread (new ThreadStart (AcquireLock_readerWorks));
+                       
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (rwlock.IsReaderLockHeld);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+               }
+               
+               [Test]
+               public void TestReaderInsideWriter ()
+               {
+                       // Reader acquires and releases work like the writer equivalent
+                       
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireWriterLock (-1);
+                       rwlock.AcquireReaderLock (-1);
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       rwlock.AcquireReaderLock (-1);
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       rwlock.ReleaseWriterLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (rwlock.IsWriterLockHeld);
+                       rwlock.ReleaseReaderLock ();
+                       Assert.IsTrue (!rwlock.IsReaderLockHeld);
+                       Assert.IsTrue (!rwlock.IsWriterLockHeld);
+               }
+               
+               [Test]
+               public void TestReaderMustWaitWriter ()
+               {
+                       // A thread cannot get the reader lock if there are other threads
+                       // waiting for the writer lock.
+                       
+                       rwlock = new ReaderWriterLock ();
+                       rwlock.AcquireWriterLock (200);
+                       
+                       ThreadRunner tr = StartThread (new ThreadStart (ReaderMustWaitWriter_2));
+                       Thread.Sleep (200);
+                       
+                       RunThread (new ThreadStart (AcquireLock_readerFails));
+                       
+                       rwlock.ReleaseReaderLock ();
+                       tr.Join ();
+               }
+               
+               void ReaderMustWaitWriter_2 ()
+               {
+                       rwlock.AcquireWriterLock (2000);
+                       rwlock.ReleaseWriterLock ();
+               }
+               
+               [Test]
+               public void TestBug_55911 ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       try {
+                               LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                       }
+                       finally { rwlock.ReleaseReaderLock(); }
+                       
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       try {
+                               LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                       }
+                       finally { rwlock.ReleaseReaderLock(); }
+               }
+               
+               [Test]
+               public void TestBug_55909 ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       ThreadRunner tr = StartThread (new ThreadStart(Bug_55909_Thread2));
+                       Thread.Sleep (200);
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       try {
+                               LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                               Thread.Sleep (500);
+                       }
+                       finally { rwlock.ReleaseReaderLock(); }
+                       
+                       tr.Join ();
+               }
+               
+               public void Bug_55909_Thread2 ()
+               {
+                       rwlock.AcquireReaderLock(Timeout.Infinite);
+                       try {
+                               Thread.Sleep (1000);
+                               LockCookie lc = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                               Thread.Sleep (500);
+                       }
+                       finally { rwlock.ReleaseReaderLock(); }
+               }
+               
+               [Test]
+               public void TestBug_55909_bis ()
+               {
+                       rwlock = new ReaderWriterLock ();
+                       ThreadRunner tr1 = StartThread (new ThreadStart(Bug_55909_bis_ReaderWriter));
+                       Thread.Sleep(100);
+                       ThreadRunner tr2 = StartThread (new ThreadStart(Bug_55909_bis_Reader));
+                       Thread.Sleep(100);
+                       ThreadRunner tr3 = StartThread (new ThreadStart(Bug_55909_bis_Writer));
+                       Thread.Sleep(100);
+                       ThreadRunner tr4 = StartThread (new ThreadStart(Bug_55909_bis_Reader));
+                       tr1.Join ();
+                       tr2.Join ();
+                       tr3.Join ();
+                       tr4.Join ();
+               }
+               
+               void Bug_55909_bis_Reader ()
+               {
+                       rwlock.AcquireReaderLock(-1);
+                       Thread.Sleep(2000);
+                       rwlock.ReleaseReaderLock();
+               }
+
+               void Bug_55909_bis_ReaderWriter ()
+               {
+                       rwlock.AcquireReaderLock(-1);
+                       LockCookie lc = rwlock.UpgradeToWriterLock(-1);
+                       Thread.Sleep(1000);
+                       rwlock.DowngradeFromWriterLock(ref lc);
+                       rwlock.ReleaseReaderLock();
+               }
+
+               void Bug_55909_bis_Writer ()
+               {
+                       rwlock.AcquireWriterLock(-1);
+                       rwlock.ReleaseWriterLock();
+               }
+               
+
+               [Test]
+               public void TestBug_475124 ()
+               {
+                       LockCookie lc1, lc2;
+
+                       rwlock = new ReaderWriterLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "A1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "A2");
+
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+
+                       Assert.IsTrue (rwlock.IsReaderLockHeld, "B1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "B2");
+
+                       lc1 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "C1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "C2");
+
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "D1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "D2");
+
+                       lc2 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "E1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "E2");
+
+                       rwlock.DowngradeFromWriterLock (ref lc2);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "F1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "F2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "G1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "G2");
+
+                       rwlock.DowngradeFromWriterLock (ref lc1);
+
+                       Assert.IsTrue (rwlock.IsReaderLockHeld, "H1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "H2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "I1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "I2");
+               }
+
+               // this tests how downgrade works when multiple writer locks
+               // are acquired - as long as the LockCookie referes to an
+               // upgrade where there was already a writer lock, downgrade
+               // behaves like a non-blocking ReleaseWriterLock
+               [Test]
+               public void DowngradeTest ()
+               {
+                       LockCookie lc1, lc2, lc3, lc4;
+
+                       rwlock = new ReaderWriterLock ();
+
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       lc1 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       lc2 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       lc3 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+                       rwlock.AcquireReaderLock (Timeout.Infinite);
+                       lc4 = rwlock.UpgradeToWriterLock (Timeout.Infinite);
+
+                       rwlock.DowngradeFromWriterLock (ref lc2);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "A1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "A2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "B1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "B2");
+
+                       rwlock.DowngradeFromWriterLock (ref lc4);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "C1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "C2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "D1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "D2");
+
+                       rwlock.DowngradeFromWriterLock (ref lc3);
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "E1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "E2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "F1");
+                       Assert.IsTrue (rwlock.IsWriterLockHeld, "F2");
+
+                       rwlock.DowngradeFromWriterLock (ref lc1);
+
+                       Assert.IsTrue (rwlock.IsReaderLockHeld, "G1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "G2");
+
+                       rwlock.ReleaseReaderLock ();
+
+                       Assert.IsFalse (rwlock.IsReaderLockHeld, "H1");
+                       Assert.IsFalse (rwlock.IsWriterLockHeld, "H2");
+               }
+       }
 }