private ReaderWriterCount GetThreadRWCount(bool dontAllocate) { ReaderWriterCount rwc = t_rwc; ReaderWriterCount empty = null; while (rwc != null) { if (rwc.lockID == _lockID) { return(rwc); } if (!dontAllocate && empty == null && IsRWEntryEmpty(rwc)) { empty = rwc; } rwc = rwc.next; } if (dontAllocate) { return(null); } if (empty == null) { empty = new ReaderWriterCount(); empty.next = t_rwc; t_rwc = empty; } empty.lockID = _lockID; return(empty); }
private ReaderWriterCount GetThreadRWCount(int id, bool DontAllocate) { int index = id & 0xff; ReaderWriterCount count = null; if (this.rwc[index] == null) { if (DontAllocate) { return(null); } this.rwc[index] = new ReaderWriterCount(this.fIsReentrant); } if (this.rwc[index].threadid == id) { return(this.rwc[index]); } if (IsRWEntryEmpty(this.rwc[index]) && !DontAllocate) { if (this.rwc[index].next == null) { this.rwc[index].threadid = id; return(this.rwc[index]); } count = this.rwc[index]; } ReaderWriterCount next = this.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(this.fIsReentrant) { threadid = id, next = this.rwc[index].next }; this.rwc[index].next = next; return(next); } count.threadid = id; return(count); }
public void ExitReadLock() { int id = Thread.CurrentThread.ManagedThreadId; ReaderWriterCount lrwc = null; EnterMyLock(); lrwc = GetThreadRWCount(id, true); if (!fIsReentrant) { if (lrwc == null) { //You have to be holding the read lock to make this call. ExitMyLock(); throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedRead)); } } else { if (lrwc == null || lrwc.readercount < 1) { ExitMyLock(); throw new SynchronizationLockException(SR.GetString(SR.SynchronizationLockException_MisMatchedRead)); } if (lrwc.readercount > 1) { lrwc.readercount--; ExitMyLock(); Thread.EndCriticalRegion(); return; } if (id == upgradeLockOwnerId) { fUpgradeThreadHoldingRead = false; } } Debug.Assert(owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken"); --owners; Debug.Assert(lrwc.readercount == 1); lrwc.readercount--; ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
private static bool IsRWEntryEmpty(ReaderWriterCount rwc) { if (rwc.lockID == 0) { return(true); } else if (rwc.readercount == 0 && rwc.writercount == 0 && rwc.upgradecount == 0) { return(true); } else { return(false); } }
private ReaderWriterCount GetThreadRWCount(int id, bool DontAllocate) { ReaderWriterCount rwc; int index = id & 0xff; ReaderWriterCount count = null; if (this.rwc[index].threadid == id) { return(this.rwc[index]); } if (IsRWEntryEmpty(this.rwc[index]) && !DontAllocate) { if (this.rwc[index].next == null) { this.rwc[index].threadid = id; return(this.rwc[index]); } count = this.rwc[index]; } for (rwc = this.rwc[index].next; rwc != null; rwc = rwc.next) { if (rwc.threadid == id) { return(rwc); } if ((count == null) && IsRWEntryEmpty(rwc)) { count = rwc; } } if (DontAllocate) { return(null); } if (count == null) { rwc = new ReaderWriterCount(this.fIsReentrant); rwc.threadid = id; rwc.next = this.rwc[index].next; this.rwc[index].next = rwc; return(rwc); } count.threadid = id; return(count); }
private static bool IsRWEntryEmpty(ReaderWriterCount rwc) { if (rwc.threadid == -1) { return(true); } else if (rwc.readercount == 0 && rwc.rc == null) { return(true); } else if (rwc.readercount == 0 && rwc.rc.writercount == 0 && rwc.rc.upgradecount == 0) { return(true); } else { return(false); } }
public void ExitUpgradeableReadLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (managedThreadId != this.upgradeLockOwnerId) { throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } this.EnterMyLock(); } else { this.EnterMyLock(); ReaderWriterCount threadRWCount = this.GetThreadRWCount(managedThreadId, true); if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } RecursiveCounts rc = threadRWCount.rc; if (rc.upgradecount < 1) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedUpgrade")); } rc.upgradecount--; if (rc.upgradecount > 0) { this.ExitMyLock(); Thread.EndCriticalRegion(); return; } this.fUpgradeThreadHoldingRead = false; } this.owners--; this.upgradeLockOwnerId = -1; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
public void ExitWriteLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (managedThreadId != this.writeLockOwnerId) { throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } this.EnterMyLock(); } else { this.EnterMyLock(); ReaderWriterCount threadRWCount = this.GetThreadRWCount(managedThreadId, false); if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } RecursiveCounts rc = threadRWCount.rc; if (rc.writercount < 1) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedWrite")); } rc.writercount--; if (rc.writercount > 0) { this.ExitMyLock(); Thread.EndCriticalRegion(); return; } } this.ClearWriterAcquired(); this.writeLockOwnerId = -1; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
public void ExitReadLock() { ReaderWriterCount lrwc = null; EnterMyLock(); lrwc = GetThreadRWCount(true); if (lrwc == null || lrwc.readercount < 1) { //You have to be holding the read lock to make this call. ExitMyLock(); throw new SynchronizationLockException(SR.SynchronizationLockException_MisMatchedRead); } if (_fIsReentrant) { if (lrwc.readercount > 1) { lrwc.readercount--; ExitMyLock(); return; } if (Environment.CurrentManagedThreadId == _upgradeLockOwnerId) { _fUpgradeThreadHoldingRead = false; } } Debug.Assert(_owners > 0, "ReleasingReaderLock: releasing lock and no read lock taken"); --_owners; Debug.Assert(lrwc.readercount == 1); lrwc.readercount--; ExitAndWakeUpAppropriateWaiters(); }
public void ExitReadLock() { int managedThreadId = Thread.CurrentThread.ManagedThreadId; ReaderWriterCount threadRWCount = null; this.EnterMyLock(); threadRWCount = this.GetThreadRWCount(managedThreadId, true); if (!this.fIsReentrant) { if (threadRWCount == null) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedRead")); } } else { if ((threadRWCount == null) || (threadRWCount.readercount < 1)) { this.ExitMyLock(); throw new SynchronizationLockException(System.SR.GetString("SynchronizationLockException_MisMatchedRead")); } if (threadRWCount.readercount > 1) { threadRWCount.readercount--; this.ExitMyLock(); Thread.EndCriticalRegion(); return; } if (managedThreadId == this.upgradeLockOwnerId) { this.fUpgradeThreadHoldingRead = false; } } this.owners--; threadRWCount.readercount--; this.ExitAndWakeUpAppropriateWaiters(); Thread.EndCriticalRegion(); }
private bool TryEnterReadLockCore(TimeoutTracker timeout) { if (_fDisposed) { throw new ObjectDisposedException(null); } ReaderWriterCount lrwc = null; int id = Environment.CurrentManagedThreadId; if (!_fIsReentrant) { if (id == _writeLockOwnerId) { //Check for AW->AR throw new LockRecursionException(SR.LockRecursionException_ReadAfterWriteNotAllowed); } EnterMyLock(); lrwc = GetThreadRWCount(false); //Check if the reader lock is already acquired. Note, we could //check the presence of a reader by not allocating rwc (But that //would lead to two lookups in the common case. It's better to keep //a count in the structure). if (lrwc.readercount > 0) { ExitMyLock(); throw new LockRecursionException(SR.LockRecursionException_RecursiveReadNotAllowed); } else if (id == _upgradeLockOwnerId) { //The upgrade lock is already held. //Update the global read counts and exit. lrwc.readercount++; _owners++; ExitMyLock(); return(true); } } else { EnterMyLock(); lrwc = GetThreadRWCount(false); if (lrwc.readercount > 0) { lrwc.readercount++; ExitMyLock(); return(true); } else if (id == _upgradeLockOwnerId) { //The upgrade lock is already held. //Update the global read counts and exit. lrwc.readercount++; _owners++; ExitMyLock(); _fUpgradeThreadHoldingRead = true; return(true); } else if (id == _writeLockOwnerId) { //The write lock is already held. //Update global read counts here, lrwc.readercount++; _owners++; ExitMyLock(); return(true); } } bool retVal = true; int spincount = 0; for (; ;) { // We can enter a read lock if there are only read-locks have been given out // and a writer is not trying to get in. if (_owners < MAX_READER) { // Good case, there is no contention, we are basically done _owners++; // Indicate we have another reader lrwc.readercount++; break; } if (spincount < MaxSpinCount) { ExitMyLock(); if (timeout.IsExpired) { return(false); } spincount++; SpinWait(spincount); EnterMyLock(); //The per-thread structure may have been recycled as the lock is acquired (due to message pumping), load again. if (IsRwHashEntryChanged(lrwc)) { lrwc = GetThreadRWCount(false); } continue; } // Drat, we need to wait. Mark that we have waiters and wait. if (_readEvent == null) // Create the needed event { LazyCreateEvent(ref _readEvent, false); if (IsRwHashEntryChanged(lrwc)) { lrwc = GetThreadRWCount(false); } continue; // since we left the lock, start over. } retVal = WaitOnEvent(_readEvent, ref _numReadWaiters, timeout, isWriteWaiter: false); if (!retVal) { return(false); } if (IsRwHashEntryChanged(lrwc)) { lrwc = GetThreadRWCount(false); } } ExitMyLock(); return(retVal); }
private ReaderWriterCount GetThreadRWCount(int id, bool DontAllocate) { int index = id & 0xff; ReaderWriterCount count = null; if (this.rwc[index] == null) { if (DontAllocate) { return null; } this.rwc[index] = new ReaderWriterCount(this.fIsReentrant); } if (this.rwc[index].threadid == id) { return this.rwc[index]; } if (IsRWEntryEmpty(this.rwc[index]) && !DontAllocate) { if (this.rwc[index].next == null) { this.rwc[index].threadid = id; return this.rwc[index]; } count = this.rwc[index]; } ReaderWriterCount next = this.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(this.fIsReentrant) { threadid = id, next = this.rwc[index].next }; this.rwc[index].next = next; return next; } count.threadid = id; return count; }
private bool IsRwHashEntryChanged(ReaderWriterCount lrwc) { return(lrwc.lockID != _lockID); }
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)))); }
/// <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; }
public bool TryEnterReadLock(int millisecondsTimeout) { ReaderWriterCount lrwc = null; int id = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (id == this.writeLockOwnerId) { throw new LockRecursionException("LockRecursionException_ReadAfterWriteNotAllowed"); } this.EnterMyLock(); lrwc = this.GetThreadRWCount(id, false); if (lrwc.readercount > 0) { this.ExitMyLock(); throw new LockRecursionException("LockRecursionException_RecursiveReadNotAllowed"); } if (id == this.upgradeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); return(true); } } else { this.EnterMyLock(); lrwc = this.GetThreadRWCount(id, false); if (lrwc.readercount > 0) { lrwc.readercount++; this.ExitMyLock(); return(true); } if (id == this.upgradeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); this.fUpgradeThreadHoldingRead = true; return(true); } if (id == this.writeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); return(true); } } bool flag = true; int spinCount = 0; Label_011F: if (this.owners < 0xffffffe) { this.owners++; lrwc.readercount++; } else { if (spinCount < 20) { this.ExitMyLock(); if (millisecondsTimeout == 0) { return(false); } spinCount++; SpinWait(spinCount); this.EnterMyLock(); if (IsRwHashEntryChanged(lrwc, id)) { lrwc = this.GetThreadRWCount(id, false); } } else if (this.readEvent == null) { this.LazyCreateEvent(ref this.readEvent, false); if (IsRwHashEntryChanged(lrwc, id)) { lrwc = this.GetThreadRWCount(id, false); } } else { flag = this.WaitOnEvent(this.readEvent, ref this.numReadWaiters, millisecondsTimeout); if (!flag) { return(false); } if (IsRwHashEntryChanged(lrwc, id)) { lrwc = this.GetThreadRWCount(id, false); } } goto Label_011F; } this.ExitMyLock(); return(flag); }
/// <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); } else { rwc[hash] = new ReaderWriterCount(fIsReentrant); } } 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]); } else { firstfound = rwc[hash]; } } //SlowPath ReaderWriterCount 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(fIsReentrant); temp.threadid = id; temp.next = rwc[hash].next; rwc[hash].next = temp; return(temp); } else { firstfound.threadid = id; return(firstfound); } }
private bool IsRwHashEntryChanged(ReaderWriterCount lrwc) { return lrwc.lockID != this.lockID; }
private bool TryEnterReadLockCore(int millisecondsTimeout) { if (millisecondsTimeout < -1) { throw new ArgumentOutOfRangeException("millisecondsTimeout"); } if (this.fDisposed) { throw new ObjectDisposedException(null); } ReaderWriterCount lrwc = null; int managedThreadId = Thread.CurrentThread.ManagedThreadId; if (!this.fIsReentrant) { if (managedThreadId == this.writeLockOwnerId) { throw new LockRecursionException(System.SR.GetString("LockRecursionException_ReadAfterWriteNotAllowed")); } this.EnterMyLock(); lrwc = this.GetThreadRWCount(managedThreadId, false); if (lrwc.readercount > 0) { this.ExitMyLock(); throw new LockRecursionException(System.SR.GetString("LockRecursionException_RecursiveReadNotAllowed")); } if (managedThreadId == this.upgradeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); return(true); } } else { this.EnterMyLock(); lrwc = this.GetThreadRWCount(managedThreadId, false); if (lrwc.readercount > 0) { lrwc.readercount++; this.ExitMyLock(); return(true); } if (managedThreadId == this.upgradeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); this.fUpgradeThreadHoldingRead = true; return(true); } if (managedThreadId == this.writeLockOwnerId) { lrwc.readercount++; this.owners++; this.ExitMyLock(); return(true); } } bool flag = true; int spinCount = 0; Label_013D: if (this.owners < 0xffffffe) { this.owners++; lrwc.readercount++; } else { if (spinCount < 20) { this.ExitMyLock(); if (millisecondsTimeout == 0) { return(false); } spinCount++; SpinWait(spinCount); this.EnterMyLock(); if (IsRwHashEntryChanged(lrwc, managedThreadId)) { lrwc = this.GetThreadRWCount(managedThreadId, false); } } else if (this.readEvent == null) { this.LazyCreateEvent(ref this.readEvent, false); if (IsRwHashEntryChanged(lrwc, managedThreadId)) { lrwc = this.GetThreadRWCount(managedThreadId, false); } } else { flag = this.WaitOnEvent(this.readEvent, ref this.numReadWaiters, millisecondsTimeout); if (!flag) { return(false); } if (IsRwHashEntryChanged(lrwc, managedThreadId)) { lrwc = this.GetThreadRWCount(managedThreadId, false); } } goto Label_013D; } this.ExitMyLock(); return(flag); }
private static bool IsRwHashEntryChanged(ReaderWriterCount lrwc, int id) { return (lrwc.threadid != id); }
private static bool IsRWEntryEmpty(ReaderWriterCount rwc) { if (rwc.lockID == 0) return true; else if (rwc.readercount == 0 && rwc.writercount == 0 && rwc.upgradecount == 0) return true; else return false; }
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(bool dontAllocate) { ReaderWriterCount rwc = t_rwc; ReaderWriterCount empty = null; while (rwc != null) { if (rwc.lockID == this.lockID) return rwc; if (!dontAllocate && empty == null && IsRWEntryEmpty(rwc)) empty = rwc; rwc = rwc.next; } if (dontAllocate) return null; if (empty == null) { empty = new ReaderWriterCount(); empty.next = t_rwc; t_rwc = empty; } empty.lockID = this.lockID; return empty; }
private static bool IsRwHashEntryChanged(ReaderWriterCount lrwc, int id) { return(lrwc.threadid != id); }