/// <summary> 
    /// This routine retrieves/sets the per-thread counts needed to enforce the
    /// various rules related to acquiring the lock. It's a simple hash table, 
    /// where the first entry is pre-allocated for optimizing the common case.
    /// After the first element has been allocated, duplicates are kept of in
    /// linked-list. The entries are never freed, and the max size of the
    /// table would be bounded by the max number of threads that held the lock 
    /// simultaneously.
    /// 
    /// DontAllocate is set to true if the caller just wants to get an existing 
    /// entry for this thread, but doesn't want to add one if an existing one
    /// could not be found. 
    /// </summary>
    private ReaderWriterCount GetThreadRWCount(int id, bool dontAllocate)
    {
      int hash = id & HashTableSize;
      ReaderWriterCount firstfound = null;
#if DEBUG
      Debug.Assert(MyLockHeld);
#endif

      if (null == _rwc[hash])
      {
        if (dontAllocate)
          return null;
        
        _rwc[hash] = new ReaderWriterCount(_isReentrant);
      }

      if (_rwc[hash].ThreadId == id)
      {
        return _rwc[hash];
      }

      if (IsRWEntryEmpty(_rwc[hash]) && !dontAllocate)
      {
        //No more entries in chain, so no more searching required. 
        if (_rwc[hash].Next == null)
        {
          _rwc[hash].ThreadId = id;
          return _rwc[hash];
        }
        
        firstfound = _rwc[hash];
      }

      //SlowPath

      var temp = _rwc[hash].Next;

      while (temp != null)
      {
        if (temp.ThreadId == id)
        {
          return temp;
        }

        if (firstfound == null)
        {
          if (IsRWEntryEmpty(temp))
            firstfound = temp;
        }

        temp = temp.Next;
      }

      if (dontAllocate)
        return null;

      if (firstfound == null)
      {
        temp = new ReaderWriterCount(_isReentrant)
        {
          ThreadId = id,
          Next = _rwc[hash].Next
        };
        _rwc[hash].Next = temp;
        return temp;
      }
      
      firstfound.ThreadId = id;
      return firstfound;
    }
 private static bool IsRwHashEntryChanged(ReaderWriterCount lrwc, int id)
 {
   return lrwc.ThreadId != id;
 }
    private static bool IsRWEntryEmpty(ReaderWriterCount rwc)
    {
      if (rwc.ThreadId == -1)
        return true;

      if (rwc.ReaderCount == 0 && rwc.Rc == null)
        return true;

      if (rwc.ReaderCount == 0 && rwc.Rc.WriterCount == 0 && rwc.Rc.UpgradeCount == 0)
        return true;

      return false;
    }
 private static bool IsRwHashEntryChanged(ReaderWriterCount lrwc, int id)
 {
     return (lrwc.threadid != id);
 }
 private static bool IsRwEntryEmpty(ReaderWriterCount rwc)
 {
     return ((rwc.threadid == -1) ||
             (((rwc.readercount == 0) && (rwc.rc == null)) ||
              (((rwc.readercount == 0) && (rwc.rc.Writercount == 0)) && (rwc.rc.Upgradecount == 0))));
 }
 private ReaderWriterCount GetThreadRwCount(int id, bool dontAllocate)
 {
     int index = id & 0xff;
     ReaderWriterCount count = null;
     if (_rwc[index] == null)
     {
         if (dontAllocate)
         {
             return null;
         }
         _rwc[index] = new ReaderWriterCount(_fIsReentrant);
     }
     if (_rwc[index].threadid == id)
     {
         return _rwc[index];
     }
     if (IsRwEntryEmpty(_rwc[index]) && !dontAllocate)
     {
         if (_rwc[index].next == null)
         {
             _rwc[index].threadid = id;
             return _rwc[index];
         }
         count = _rwc[index];
     }
     ReaderWriterCount next = _rwc[index].next;
     while (next != null)
     {
         if (next.threadid == id)
         {
             return next;
         }
         if ((count == null) && IsRwEntryEmpty(next))
         {
             count = next;
         }
         next = next.next;
     }
     if (dontAllocate)
     {
         return null;
     }
     if (count == null)
     {
         next = new ReaderWriterCount(_fIsReentrant)
                    {
                        threadid = id,
                        next = _rwc[index].next
                    };
         _rwc[index].next = next;
         return next;
     }
     count.threadid = id;
     return count;
 }