/// <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; }