Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / System.Core / System.Threading / ReaderWriterLockSlim.cs
index a52c7ed430636d878580b10a0c9dc8efd8a37728..512f97b27cb15619cd97894d61102b3cb895806d 100644 (file)
@@ -1,21 +1,11 @@
 //
 // System.Threading.ReaderWriterLockSlim.cs
 //
-// Authors:
-//   Miguel de Icaza (miguel@novell.com) 
-//   Dick Porter (dick@ximian.com)
-//   Jackson Harper (jackson@ximian.com)
-//   Lluis Sanchez Gual (lluis@ximian.com)
-//   Marek Safar (marek.safar@gmail.com)
+// Author:
+//       Jérémie "Garuma" Laval <jeremie.laval@gmail.com>
 //
-// Copyright 2004-2008 Novell, Inc (http://www.novell.com)
-// Copyright 2003, Ximian, Inc.
+// Copyright (c) 2010 Jérémie "Garuma" Laval
 //
-// NoRecursion code based on the blog post from Vance Morrison:
-//   http://blogs.msdn.com/vancem/archive/2006/03/28/563180.aspx
-//
-// Recursion code based on Mono's implementation of ReaderWriterLock.
-// 
 // Permission is hereby granted, free of charge, to any person obtaining
 // a copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
@@ -42,69 +32,89 @@ using System.Collections.Generic;
 using System.Security.Permissions;
 using System.Diagnostics;
 using System.Threading;
+using System.Runtime.CompilerServices;
 
 namespace System.Threading {
 
-       //
-       // This implementation is based on the light-weight
-       // Reader/Writer lock sample from Vance Morrison's blog:
-       //
-       // http://blogs.msdn.com/vancem/archive/2006/03/28/563180.aspx
-       //
-       // And in Mono's ReaderWriterLock
-       //
        [HostProtectionAttribute(SecurityAction.LinkDemand, MayLeakOnAbort = true)]
        [HostProtectionAttribute(SecurityAction.LinkDemand, Synchronization = true, ExternalThreading = true)]
-       public class ReaderWriterLockSlim : IDisposable {
-               // Are we on a multiprocessor?
-               static readonly bool smp;
-               
-               // Lock specifiation for myLock:  This lock protects exactly the local fields associted
-               // instance of MyReaderWriterLock.  It does NOT protect the memory associted with the
-               // the events that hang off this lock (eg writeEvent, readEvent upgradeEvent).
-               int myLock;
-
-               // Who owns the lock owners > 0 => readers
-               // owners = -1 means there is one writer, Owners must be >= -1.  
-               int owners;
-               Thread upgradable_thread;
-               
-               // These variables allow use to avoid Setting events (which is expensive) if we don't have to. 
-               uint numWriteWaiters;        // maximum number of threads that can be doing a WaitOne on the writeEvent 
-               uint numReadWaiters;         // maximum number of threads that can be doing a WaitOne on the readEvent
-               uint numUpgradeWaiters;      // maximum number of threads that can be doing a WaitOne on the upgradeEvent (at most 1). 
+       public class ReaderWriterLockSlim : IDisposable
+       {
+               /* Position of each bit isn't really important 
+                * but their relative order is
+                */
+               const int RwReadBit = 3;
+
+               /* These values are used to manipulate the corresponding flags in rwlock field
+                */
+               const int RwWait = 1;
+               const int RwWaitUpgrade = 2;
+               const int RwWrite = 4;
+               const int RwRead = 8;
+
+               /* Some explanations: this field is the central point of the lock and keep track of all the requests
+                * that are being made. The 3 lowest bits are used as flag to track "destructive" lock entries
+                * (i.e attempting to take the write lock with or without having acquired an upgradeable lock beforehand).
+                * All the remaining bits are intepreted as the actual number of reader currently using the lock
+                * (which mean the lock is limited to 4294967288 concurrent readers but since it's a high number there
+                * is no overflow safe guard to remain simple).
+                */
+               int rwlock;
                
-               // conditions we wait on. 
-               EventWaitHandle writeEvent;    // threads waiting to aquire a write lock go here.
-               EventWaitHandle readEvent;     // threads waiting to aquire a read lock go here (will be released in bulk)
-               EventWaitHandle upgradeEvent;  // thread waiting to upgrade a read lock to a write lock go here (at most one)
-
-               //int lock_owner;
-
-               // Only set if we are a recursive lock
-               //Dictionary<int,int> reader_locks;
-
                readonly LockRecursionPolicy recursionPolicy;
-               bool is_disposed;
-               
-               static ReaderWriterLockSlim ()
-               {
-                       smp = Environment.ProcessorCount > 1;
-               }
-               
-               public ReaderWriterLockSlim ()
+               readonly bool noRecursion;
+
+               AtomicBoolean upgradableTaken = new AtomicBoolean ();
+
+               /* These events are just here for the sake of having a CPU-efficient sleep
+                * when the wait for acquiring the lock is too long
+                */
+#if NET_4_0
+               ManualResetEventSlim upgradableEvent = new ManualResetEventSlim (true);
+               ManualResetEventSlim writerDoneEvent = new ManualResetEventSlim (true);
+               ManualResetEventSlim readerDoneEvent = new ManualResetEventSlim (true);
+#else
+               ManualResetEvent upgradableEvent = new ManualResetEvent (true);
+               ManualResetEvent writerDoneEvent = new ManualResetEvent (true);
+               ManualResetEvent readerDoneEvent = new ManualResetEvent (true);
+#endif
+
+               // This Stopwatch instance is used for all threads since .Elapsed is thread-safe
+               readonly static Stopwatch sw = Stopwatch.StartNew ();
+
+               /* For performance sake, these numbers are manipulated via classic increment and
+                * decrement operations and thus are (as hinted by MSDN) not meant to be precise
+                */
+               int numReadWaiters, numUpgradeWaiters, numWriteWaiters;
+               bool disposed;
+
+               static int idPool = int.MinValue;
+               readonly int id = Interlocked.Increment (ref idPool);
+
+               /* This dictionary is instanciated per thread for all existing ReaderWriterLockSlim instance.
+                * Each instance is defined by an internal integer id value used as a key in the dictionary.
+                * to avoid keeping unneeded reference to the instance and getting in the way of the GC.
+                * Since there is no LockCookie type here, all the useful per-thread infos concerning each
+                * instance are kept here.
+                */
+               [ThreadStatic]
+               static IDictionary<int, ThreadLockState> currentThreadState;
+
+               /* Rwls tries to use this array as much as possible to quickly retrieve the thread-local
+                * informations so that it ends up being only an array lookup. When the number of thread
+                * using the instance goes past the length of the array, the code fallback to the normal
+                * dictionary
+                */
+               ThreadLockState[] fastStateCache = new ThreadLockState[64];
+
+               public ReaderWriterLockSlim () : this (LockRecursionPolicy.NoRecursion)
                {
-                       // NoRecursion (0) is the default value
                }
 
                public ReaderWriterLockSlim (LockRecursionPolicy recursionPolicy)
                {
                        this.recursionPolicy = recursionPolicy;
-                       
-                       if (recursionPolicy != LockRecursionPolicy.NoRecursion){
-                               //reader_locks = new Dictionary<int,int> ();
-                               throw new NotImplementedException ("recursionPolicy != NoRecursion not currently implemented");
-                       }
+                       this.noRecursion = recursionPolicy == LockRecursionPolicy.NoRecursion;
                }
 
                public void EnterReadLock ()
@@ -114,58 +124,104 @@ namespace System.Threading {
 
                public bool TryEnterReadLock (int millisecondsTimeout)
                {
-                       if (millisecondsTimeout < Timeout.Infinite)
-                               throw new ArgumentOutOfRangeException ("millisecondsTimeout");
-                       
-                       if (is_disposed)
-                               throw new ObjectDisposedException (null);
-                       
-                       EnterMyLock ();
-                       
-                       while (true){
-                               // Easy case, no contention
-                               // owners >= 0 means there might be readers (but no writer)
-                               if (owners >= 0 && numWriteWaiters == 0){
-                                       owners++;
-                                       break;
-                               }
-                               
-                               // If the request is to probe.
-                               if (millisecondsTimeout == 0){
-                                       ExitMyLock ();
-                                       return false;
-                               }
+                       bool dummy = false;
+                       return TryEnterReadLock (millisecondsTimeout, ref dummy);
+               }
 
-                               // We need to wait.  Mark that we have waiters and wait.  
-                               if (readEvent == null) {
-                                       LazyCreateEvent (ref readEvent, false);
-                                       // since we left the lock, start over. 
-                                       continue;
+               bool TryEnterReadLock (int millisecondsTimeout, ref bool success)
+               {
+                       ThreadLockState ctstate = CurrentThreadState;
+
+                       if (CheckState (ctstate, millisecondsTimeout, LockState.Read)) {
+                               ++ctstate.ReaderRecursiveCount;
+                               return true;
+                       }
+
+                       // This is downgrading from upgradable, no need for check since
+                       // we already have a sort-of read lock that's going to disappear
+                       // after user calls ExitUpgradeableReadLock.
+                       // Same idea when recursion is allowed and a write thread wants to
+                       // go for a Read too.
+                       if (ctstate.LockState.Has (LockState.Upgradable)
+                           || (!noRecursion && ctstate.LockState.Has (LockState.Write))) {
+                               RuntimeHelpers.PrepareConstrainedRegions ();
+                               try {}
+                               finally {
+                                       Interlocked.Add (ref rwlock, RwRead);
+                                       ctstate.LockState |= LockState.Read;
+                                       ++ctstate.ReaderRecursiveCount;
+                                       success = true;
                                }
 
-                               if (!WaitOnEvent (readEvent, ref numReadWaiters, millisecondsTimeout))
-                                       return false;
+                               return true;
                        }
-                       ExitMyLock ();
                        
-                       return true;
+                       ++numReadWaiters;
+                       int val = 0;
+                       long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+
+                       do {
+                               /* Check if a writer is present (RwWrite) or if there is someone waiting to
+                                * acquire a writer lock in the queue (RwWait | RwWaitUpgrade).
+                                */
+                               if ((rwlock & (RwWrite | RwWait | RwWaitUpgrade)) > 0) {
+                                       writerDoneEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
+                                       continue;
+                               }
+
+                               /* Optimistically try to add ourselves to the reader value
+                                * if the adding was too late and another writer came in between
+                                * we revert the operation.
+                                */
+                               RuntimeHelpers.PrepareConstrainedRegions ();
+                               try {}
+                               finally {
+                                       if (((val = Interlocked.Add (ref rwlock, RwRead)) & (RwWrite | RwWait | RwWaitUpgrade)) == 0) {
+                                               /* If we are the first reader, reset the event to let other threads
+                                                * sleep correctly if they try to acquire write lock
+                                                */
+                                               if (val >> RwReadBit == 1)
+                                                       readerDoneEvent.Reset ();
+
+                                               ctstate.LockState ^= LockState.Read;
+                                               ++ctstate.ReaderRecursiveCount;
+                                               --numReadWaiters;
+                                               success = true;
+                                       } else {
+                                               Interlocked.Add (ref rwlock, -RwRead);
+                                       }
+                               }
+                               if (success)
+                                       return true;
+
+                               writerDoneEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
+                       } while (millisecondsTimeout == -1 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout);
+
+                       --numReadWaiters;
+                       return false;
                }
 
                public bool TryEnterReadLock (TimeSpan timeout)
                {
-                       int ms = CheckTimeout (timeout);
-                       return TryEnterReadLock (ms);
+                       return TryEnterReadLock (CheckTimeout (timeout));
                }
 
-               //
-               // TODO: What to do if we are releasing a ReadLock and we do not own it?
-               //
                public void ExitReadLock ()
                {
-                       EnterMyLock ();
-                       Debug.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken");
-                       --owners;
-                       ExitAndWakeUpAppropriateWaiters ();
+                       RuntimeHelpers.PrepareConstrainedRegions ();
+                       try {}
+                       finally {
+                               ThreadLockState ctstate = CurrentThreadState;
+
+                               if (!ctstate.LockState.Has (LockState.Read))
+                                       throw new SynchronizationLockException ("The current thread has not entered the lock in read mode");
+
+                               if (--ctstate.ReaderRecursiveCount == 0) {
+                                       ctstate.LockState ^= LockState.Read;
+                                       if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+                                               readerDoneEvent.Set ();
+                               }
+                       }
                }
 
                public void EnterWriteLock ()
@@ -175,62 +231,92 @@ namespace System.Threading {
                
                public bool TryEnterWriteLock (int millisecondsTimeout)
                {
-                       EnterMyLock ();
-
-                       while (true){
-                               // There is no contention, we are done
-                               if (owners == 0){
-                                       // Indicate that we have a writer
-                                       owners = -1;
-                                       break;
-                               }
+                       ThreadLockState ctstate = CurrentThreadState;
 
-                               // If we are the thread that took the Upgradable read lock
-                               if (owners == 1 && upgradable_thread == Thread.CurrentThread){
-                                       owners = -1;
-                                       break;
-                               }
-
-                               // If the request is to probe.
-                               if (millisecondsTimeout == 0){
-                                       ExitMyLock ();
-                                       return false;
-                               }
+                       if (CheckState (ctstate, millisecondsTimeout, LockState.Write)) {
+                               ++ctstate.WriterRecursiveCount;
+                               return true;
+                       }
 
-                               // We need to wait, figure out what kind of waiting.
-                               
-                               if (upgradable_thread == Thread.CurrentThread){
-                                       // We are the upgradable thread, register our interest.
-                                       
-                                       if (upgradeEvent == null){
-                                               LazyCreateEvent (ref upgradeEvent, false);
+                       ++numWriteWaiters;
+                       bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
+                       bool registered = false;
+                       bool success = false;
 
-                                               // since we left the lock, start over.
-                                               continue;
+                       RuntimeHelpers.PrepareConstrainedRegions ();
+                       try {
+                               /* If the code goes there that means we had a read lock beforehand
+                                * that need to be suppressed, we also take the opportunity to register
+                                * our interest in the write lock to avoid other write wannabe process
+                                * coming in the middle
+                                */
+                               if (isUpgradable && rwlock >= RwRead) {
+                                       try {}
+                                       finally {
+                                               if (Interlocked.Add (ref rwlock, RwWaitUpgrade - RwRead) >> RwReadBit == 0)
+                                                       readerDoneEvent.Set ();
+                                               registered = true;
                                        }
+                               }
 
-                                       if (numUpgradeWaiters > 0){
-                                               ExitMyLock ();
-                                               throw new ApplicationException ("Upgrading lock to writer lock already in process, deadlock");
+                               int stateCheck = isUpgradable ? RwWaitUpgrade + RwWait : RwWait;
+                               long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+                               int registration = isUpgradable ? RwWaitUpgrade : RwWait;
+
+                               do {
+                                       int state = rwlock;
+
+                                       if (state <= stateCheck) {
+                                               try {}
+                                               finally {
+                                                       var toWrite = state + RwWrite - (registered ? registration : 0);
+                                                       if (Interlocked.CompareExchange (ref rwlock, toWrite, state) == state) {
+                                                               writerDoneEvent.Reset ();
+                                                               ctstate.LockState ^= LockState.Write;
+                                                               ++ctstate.WriterRecursiveCount;
+                                                               --numWriteWaiters;
+                                                               registered = false;
+                                                               success = true;
+                                                       }
+                                               }
+                                               if (success)
+                                                       return true;
                                        }
-                                       
-                                       if (!WaitOnEvent (upgradeEvent, ref numUpgradeWaiters, millisecondsTimeout))
-                                               return false;
-                               } else {
-                                       if (writeEvent == null){
-                                               LazyCreateEvent (ref writeEvent, true);
 
-                                               // since we left the lock, retry
-                                               continue;
+                                       state = rwlock;
+
+                                       // We register our interest in taking the Write lock (if upgradeable it's already done)
+                                       if (!isUpgradable) {
+                                               while ((state & RwWait) == 0) {
+                                                       try {}
+                                                       finally {
+                                                               if (Interlocked.CompareExchange (ref rwlock, state | RwWait, state) == state)
+                                                                       registered = true;
+                                                       }
+                                                       if (registered)
+                                                               break;
+                                                       state = rwlock;
+                                               }
                                        }
-                                       if (!WaitOnEvent (writeEvent, ref numWriteWaiters, millisecondsTimeout))
-                                               return false;
-                               }
+
+                                       // Before falling to sleep
+                                       do {
+                                               if (rwlock <= stateCheck)
+                                                       break;
+                                               if ((rwlock & RwWrite) != 0)
+                                                       writerDoneEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
+                                               else if ((rwlock >> RwReadBit) > 0)
+                                                       readerDoneEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
+                                       } while (millisecondsTimeout < 0 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout);
+                               } while (millisecondsTimeout < 0 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout);
+
+                               --numWriteWaiters;
+                       } finally {
+                               if (registered)
+                                       Interlocked.Add (ref rwlock, isUpgradable ? -RwWaitUpgrade : -RwWait);
                        }
 
-                       Debug.Assert (owners == -1, "Owners is not -1");
-                       ExitMyLock ();
-                       return true;
+                       return false;
                }
 
                public bool TryEnterWriteLock (TimeSpan timeout)
@@ -240,12 +326,24 @@ namespace System.Threading {
 
                public void ExitWriteLock ()
                {
-                       EnterMyLock ();
-                       Debug.Assert (owners == -1, "Calling ReleaseWriterLock when no write lock is held");
-                       Debug.Assert (numUpgradeWaiters > 0);
-                       upgradable_thread = null;
-                       owners = 0;
-                       ExitAndWakeUpAppropriateWaiters ();
+                       RuntimeHelpers.PrepareConstrainedRegions ();
+                       try {}
+                       finally {
+                               ThreadLockState ctstate = CurrentThreadState;
+
+                               if (!ctstate.LockState.Has (LockState.Write))
+                                       throw new SynchronizationLockException ("The current thread has not entered the lock in write mode");
+                       
+                               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 ();
+                               }
+                       }
                }
 
                public void EnterUpgradeableReadLock ()
@@ -259,32 +357,64 @@ namespace System.Threading {
                //
                public bool TryEnterUpgradeableReadLock (int millisecondsTimeout)
                {
-                       EnterMyLock ();
-                       while (true){
-                               if (owners == 0 && numWriteWaiters == 0 && upgradable_thread == null){
-                                       owners++;
-                                       upgradable_thread = Thread.CurrentThread;
-                                       break;
-                               }
+                       ThreadLockState ctstate = CurrentThreadState;
 
-                               // If the request is to probe
-                               if (millisecondsTimeout == 0){
-                                       ExitMyLock ();
-                                       return false;
+                       if (CheckState (ctstate, millisecondsTimeout, LockState.Upgradable)) {
+                               ++ctstate.UpgradeableRecursiveCount;
+                               return true;
+                       }
+
+                       if (ctstate.LockState.Has (LockState.Read))
+                               throw new LockRecursionException ("The current thread has already entered read mode");
+
+                       ++numUpgradeWaiters;
+                       long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+                       bool taken = false;
+                       bool success = false;
+
+                       // We first try to obtain the upgradeable right
+                       try {
+                               while (!upgradableEvent.IsSet () || !taken) {
+                                       try {}
+                                       finally {
+                                               taken = upgradableTaken.TryRelaxedSet ();
+                                       }
+                                       if (taken)
+                                               break;
+                                       if (millisecondsTimeout != -1 && (sw.ElapsedMilliseconds - start) > millisecondsTimeout) {
+                                               --numUpgradeWaiters;
+                                               return false;
+                                       }
+
+                                       upgradableEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
                                }
 
-                               if (readEvent == null){
-                                       LazyCreateEvent (ref readEvent, false);
-                                       // since we left the lock, start over.
-                                       continue;
+                               upgradableEvent.Reset ();
+
+                               RuntimeHelpers.PrepareConstrainedRegions ();
+                               try {
+                                       // Then it's a simple reader lock acquiring
+                                       TryEnterReadLock (ComputeTimeout (millisecondsTimeout, start), ref success);
+                               } finally {
+                                       if (success) {
+                                               ctstate.LockState |= LockState.Upgradable;
+                                               ctstate.LockState &= ~LockState.Read;
+                                               --ctstate.ReaderRecursiveCount;
+                                               ++ctstate.UpgradeableRecursiveCount;
+                                       } else {
+                                               upgradableTaken.Value = false;
+                                               upgradableEvent.Set ();
+                                       }
                                }
 
-                               if (!WaitOnEvent (readEvent, ref numReadWaiters, millisecondsTimeout))
-                                       return false;
+                               --numUpgradeWaiters;
+                       } catch {
+                               // An async exception occured, if we had taken the upgradable mode, release it
+                               if (taken && !success)
+                                       upgradableTaken.Value = false;
                        }
 
-                       ExitMyLock ();
-                       return true;
+                       return success;
                }
 
                public bool TryEnterUpgradeableReadLock (TimeSpan timeout)
@@ -294,181 +424,160 @@ namespace System.Threading {
               
                public void ExitUpgradeableReadLock ()
                {
-                       EnterMyLock ();
-                       Debug.Assert (owners > 0, "Releasing an upgradable lock, but there was no reader!");
-                       --owners;
-                       upgradable_thread = null;
-                       ExitAndWakeUpAppropriateWaiters ();
+                       RuntimeHelpers.PrepareConstrainedRegions ();
+                       try {}
+                       finally {
+                               ThreadLockState ctstate = CurrentThreadState;
+
+                               if (!ctstate.LockState.Has (LockState.Upgradable | LockState.Read))
+                                       throw new SynchronizationLockException ("The current thread has not entered the lock in upgradable mode");
+
+                               if (--ctstate.UpgradeableRecursiveCount == 0) {
+                                       upgradableTaken.Value = false;
+                                       upgradableEvent.Set ();
+
+                                       ctstate.LockState &= ~LockState.Upgradable;
+                                       if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+                                               readerDoneEvent.Set ();
+                               }
+                       }
+
                }
 
                public void Dispose ()
                {
-                       is_disposed = true;
+                       disposed = true;
                }
 
                public bool IsReadLockHeld {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return rwlock >= RwRead && CurrentThreadState.LockState.Has (LockState.Read);
+                       }
                }
-               
+
                public bool IsWriteLockHeld {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return (rwlock & RwWrite) > 0 && CurrentThreadState.LockState.Has (LockState.Write);
+                       }
                }
                
                public bool IsUpgradeableReadLockHeld {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return upgradableTaken.Value && CurrentThreadState.LockState.Has (LockState.Upgradable);
+                       }
                }
 
                public int CurrentReadCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return (rwlock >> RwReadBit) - (upgradableTaken.Value ? 1 : 0);
+                       }
                }
                
                public int RecursiveReadCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return CurrentThreadState.ReaderRecursiveCount;
+                       }
                }
 
                public int RecursiveUpgradeCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return CurrentThreadState.UpgradeableRecursiveCount;
+                       }
                }
 
                public int RecursiveWriteCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return CurrentThreadState.WriterRecursiveCount;
+                       }
                }
 
                public int WaitingReadCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return numReadWaiters;
+                       }
                }
 
                public int WaitingUpgradeCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return numUpgradeWaiters;
+                       }
                }
 
                public int WaitingWriteCount {
-                       get { throw new NotImplementedException (); }
+                       get {
+                               return numWriteWaiters;
+                       }
                }
 
                public LockRecursionPolicy RecursionPolicy {
-                       get { return recursionPolicy; }
-               }
-               
-#region Private methods
-               void EnterMyLock ()
-               {
-                       if (Interlocked.CompareExchange(ref myLock, 1, 0) != 0)
-                               EnterMyLockSpin ();
+                       get {
+                               return recursionPolicy;
+                       }
                }
 
-               void EnterMyLockSpin ()
-               {
+               ThreadLockState CurrentThreadState {
+                       get {
+                               int tid = Thread.CurrentThread.ManagedThreadId;
+
+                               if (tid < fastStateCache.Length)
+                                       return fastStateCache[tid] == null ? (fastStateCache[tid] = new ThreadLockState ()) : fastStateCache[tid];
 
-                       for (int i = 0; ;i++) {
-                               if (i < 3 && smp)
-                                       Thread.SpinWait (20);    // Wait a few dozen instructions to let another processor release lock. 
-                               else 
-                                       Thread.Sleep (0);        // Give up my quantum.  
+                               if (currentThreadState == null)
+                                       currentThreadState = new Dictionary<int, ThreadLockState> ();
 
-                               if (Interlocked.CompareExchange(ref myLock, 1, 0) == 0)
-                                       return;
+                               ThreadLockState state;
+                               if (!currentThreadState.TryGetValue (id, out state))
+                                       currentThreadState[id] = state = new ThreadLockState ();
+
+                               return state;
                        }
                }
 
-               void ExitMyLock()
+               bool CheckState (ThreadLockState state, int millisecondsTimeout, LockState validState)
                {
-                       Debug.Assert (myLock != 0, "Exiting spin lock that is not held");
-                       myLock = 0;
-               }
+                       if (disposed)
+                               throw new ObjectDisposedException ("ReaderWriterLockSlim");
 
-               bool MyLockHeld { get { return myLock != 0; } }
+                       if (millisecondsTimeout < -1)
+                               throw new ArgumentOutOfRangeException ("millisecondsTimeout");
 
-               /// <summary>
-               /// Determines the appropriate events to set, leaves the locks, and sets the events. 
-               /// </summary>
-               private void ExitAndWakeUpAppropriateWaiters()
-               {
-                       Debug.Assert (MyLockHeld);
-
-                       // First a writing thread waiting on being upgraded
-                       if (owners == 1 && numUpgradeWaiters != 0){
-                               // Exit before signaling to improve efficiency (wakee will need the lock)
-                               ExitMyLock ();
-                               // release all upgraders (however there can be at most one). 
-                               upgradeEvent.Set ();
-                               //
-                               // TODO: What does the following comment mean?
-                               // two threads upgrading is a guarenteed deadlock, so we throw in that case. 
-                       } else if (owners == 0 && numWriteWaiters > 0) {
-                               // Exit before signaling to improve efficiency (wakee will need the lock)
-                               ExitMyLock ();
-                               // release one writer. 
-                               writeEvent.Set ();
-                       }
-                       else if (owners >= 0 && numReadWaiters != 0) {
-                               // Exit before signaling to improve efficiency (wakee will need the lock)
-                               ExitMyLock ();
-                               // release all readers.
-                               readEvent.Set();
-                       } else
-                               ExitMyLock();
-               }
-
-               /// <summary>
-               /// A routine for lazily creating a event outside the lock (so if errors
-               /// happen they are outside the lock and that we don't do much work
-               /// while holding a spin lock).  If all goes well, reenter the lock and
-               /// set 'waitEvent' 
-               /// </summary>
-               void LazyCreateEvent(ref EventWaitHandle waitEvent, bool makeAutoResetEvent)
-               {
-                       Debug.Assert (MyLockHeld);
-                       Debug.Assert (waitEvent == null);
-                       
-                       ExitMyLock ();
-                       EventWaitHandle newEvent;
-                       if (makeAutoResetEvent) 
-                               newEvent = new AutoResetEvent (false);
-                       else 
-                               newEvent = new ManualResetEvent (false);
+                       // Detect and prevent recursion
+                       LockState ctstate = state.LockState;
 
-                       EnterMyLock ();
+                       if (ctstate != LockState.None && noRecursion && (!ctstate.Has (LockState.Upgradable) || validState == LockState.Upgradable))
+                               throw new LockRecursionException ("The current thread has already a lock and recursion isn't supported");
 
-                       // maybe someone snuck in. 
-                       if (waitEvent == null)
-                               waitEvent = newEvent;
-               }
+                       if (noRecursion)
+                               return false;
 
-               /// <summary>
-               /// Waits on 'waitEvent' with a timeout of 'millisceondsTimeout.  
-               /// Before the wait 'numWaiters' is incremented and is restored before leaving this routine.
-               /// </summary>
-               bool WaitOnEvent (EventWaitHandle waitEvent, ref uint numWaiters, int millisecondsTimeout)
-               {
-                       Debug.Assert (MyLockHeld);
+                       // If we already had right lock state, just return
+                       if (ctstate.Has (validState))
+                               return true;
 
-                       waitEvent.Reset ();
-                       numWaiters++;
+                       CheckRecursionAuthorization (ctstate, validState);
 
-                       bool waitSuccessful = false;
+                       return false;
+               }
 
-                       // Do the wait outside of any lock 
-                       ExitMyLock();      
-                       try {
-                               waitSuccessful = waitEvent.WaitOne (millisecondsTimeout, false);
-                       } finally {
-                               EnterMyLock ();
-                               --numWaiters;
-                               if (!waitSuccessful)
-                                       ExitMyLock ();
-                       }
-                       return waitSuccessful;
+               static void CheckRecursionAuthorization (LockState ctstate, LockState desiredState)
+               {
+                       // In read mode you can just enter Read recursively
+                       if (ctstate == LockState.Read)
+                               throw new LockRecursionException ();                            
                }
-               
+
                static int CheckTimeout (TimeSpan timeout)
                {
                        try {
-                               return checked((int) timeout.TotalMilliseconds);
+                               return checked ((int)timeout.TotalMilliseconds);
                        } catch (System.OverflowException) {
-                               throw new ArgumentOutOfRangeException ("timeout");                              
+                               throw new ArgumentOutOfRangeException ("timeout");
                        }
                }
-#endregion
+
+               static int ComputeTimeout (int millisecondsTimeout, long start)
+               {
+                       return millisecondsTimeout == -1 ? -1 : (int)Math.Max (sw.ElapsedMilliseconds - start - millisecondsTimeout, 1);
+               }
        }
 }