Fix ReaderWriterLockSlim Exit methods in SupportsRecursion mode and add corresponding...
authorJérémie Laval <jeremie.laval@gmail.com>
Tue, 23 Nov 2010 10:59:07 +0000 (10:59 +0000)
committerJérémie Laval <jeremie.laval@gmail.com>
Tue, 23 Nov 2010 10:59:07 +0000 (10:59 +0000)
mcs/class/System.Core/System.Threading/ReaderWriterLockSlim.cs
mcs/class/System.Core/Test/System.Threading/ReaderWriterLockSlimTest.cs

index 3afe4c6ae2973bfa1de85cac2b648d809eb2b78c..1c619122a64f4b1eb4f7634d4364beda57cbe8bc 100644 (file)
@@ -210,10 +210,11 @@ namespace System.Threading {
                                if (!ctstate.LockState.Has (LockState.Read))
                                        throw new SynchronizationLockException ("The current thread has not entered the lock in read mode");
 
-                               ctstate.LockState ^= LockState.Read;
-                               --ctstate.ReaderRecursiveCount;
-                               if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
-                                       readerDoneEvent.Set ();
+                               if (--ctstate.ReaderRecursiveCount == 0) {
+                                       ctstate.LockState ^= LockState.Read;
+                                       if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+                                               readerDoneEvent.Set ();
+                               }
                        }
                }
 
@@ -325,14 +326,15 @@ namespace System.Threading {
                                if (!ctstate.LockState.Has (LockState.Write))
                                        throw new SynchronizationLockException ("The current thread has not entered the lock in write mode");
                        
-                               bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
-                               ctstate.LockState ^= LockState.Write;
-                               --ctstate.WriterRecursiveCount;
-
-                               int value = Interlocked.Add (ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite);
-                               writerDoneEvent.Set ();
-                               if (isUpgradable && value >> RwReadBit == 1)
-                                       readerDoneEvent.Reset ();
+                               if (--ctstate.WriterRecursiveCount == 0) {
+                                       bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
+                                       ctstate.LockState ^= LockState.Write;
+
+                                       int value = Interlocked.Add (ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite);
+                                       writerDoneEvent.Set ();
+                                       if (isUpgradable && value >> RwReadBit == 1)
+                                               readerDoneEvent.Reset ();
+                               }
                        }
                }
 
@@ -404,13 +406,14 @@ namespace System.Threading {
                                if (!ctstate.LockState.Has (LockState.Upgradable | LockState.Read))
                                        throw new SynchronizationLockException ("The current thread has not entered the lock in upgradable mode");
 
-                               upgradableTaken.Value = false;
-                               upgradableEvent.Set ();
+                               if (--ctstate.UpgradeableRecursiveCount == 0) {
+                                       upgradableTaken.Value = false;
+                                       upgradableEvent.Set ();
 
-                               ctstate.LockState ^= LockState.Upgradable;
-                               --ctstate.UpgradeableRecursiveCount;
-                               if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
-                                       readerDoneEvent.Set ();
+                                       ctstate.LockState ^= LockState.Upgradable;
+                                       if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+                                               readerDoneEvent.Set ();
+                               }
                        }
                }
 
index 7676388dfff4e8083fdc9739936c2d834b0bc4a8..664bf163e0c6dfa3c42f27a86da7d40b612449f7 100644 (file)
@@ -576,5 +576,60 @@ namespace MonoTests.System.Threading
                        Assert.AreEqual (false, wLock, "#1b");
                        Assert.AreEqual (0, rWrite, "#3b");
                }
+
+               [Test]
+               public void RecursiveEnterExitReadTest ()
+               {
+                       var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+                       v.EnterReadLock ();
+                       v.EnterReadLock ();
+                       v.EnterReadLock ();
+
+                       Assert.IsTrue (v.IsReadLockHeld);
+                       Assert.AreEqual (3, v.RecursiveReadCount);
+
+                       v.ExitReadLock ();
+
+                       Assert.IsTrue (v.IsReadLockHeld);
+                       Assert.AreEqual (2, v.RecursiveReadCount);
+               }
+
+               [Test]
+               public void RecursiveEnterExitWriteTest ()
+               {
+                       var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+                       v.EnterWriteLock ();
+                       v.EnterWriteLock ();
+                       v.EnterWriteLock ();
+
+                       Assert.IsTrue (v.IsWriteLockHeld);
+                       Assert.AreEqual (3, v.RecursiveWriteCount);
+
+                       v.ExitWriteLock ();
+                       v.ExitWriteLock ();
+
+                       Assert.IsTrue (v.IsWriteLockHeld);
+                       Assert.AreEqual (1, v.RecursiveWriteCount);
+               }
+
+               [Test]
+               public void RecursiveEnterExitUpgradableTest ()
+               {
+                       var v = new ReaderWriterLockSlim (LockRecursionPolicy.SupportsRecursion);
+
+                       v.EnterUpgradeableReadLock ();
+                       v.EnterUpgradeableReadLock ();
+                       v.EnterUpgradeableReadLock ();
+
+                       Assert.IsTrue (v.IsUpgradeableReadLockHeld);
+                       Assert.AreEqual (3, v.RecursiveUpgradeCount);
+
+                       v.ExitUpgradeableReadLock ();
+
+                       Assert.IsTrue (v.IsUpgradeableReadLockHeld);
+                       Assert.AreEqual (2, v.RecursiveUpgradeCount);
+               }
        }
 }