// // Tries to enter the lock in upgrade read mode, activating // the specified cancellers. // public bool TryEnterUpgradeableRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == upgrader) { throw new StLockRecursionException("Recursive upgrade not allowed"); } if (tid == writer) { throw new StLockRecursionException("Upgrade after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } else { // // If the current thread is the current upgrader, increment the // recursive acquisition counter and return. // if (tid == upgrader) { upCount++; return true; } // // If the current thread is the current writer, it can also // becomes the upgrader. If it is also a reader, it will be // accounted as reader on the *upgraderIsReader* flag. // if (tid == writer) { upgrader = tid; upCount = 1; if (rc != null) { upgraderIsReader = true; } return true; } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the lock isn't in write or upgrade read mode, the // current thread becomes the current upgrader. Then, release // the spinlock and return success. // if (writer == UNOWNED && upgrader == UNOWNED) { upgrader = tid; slock.Exit(); upgraderIsReader = false; upCount = 1; return true; } // // The upgrade read lock can't be acquired immediately. // So, if a null timeout was specified, return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the upgrader's queue. // int sc = (upQueue.IsEmpty && wrQueue.IsEmpty) ? spinCount : 0; WaitNode wn; upQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we acquired the upgrade lock, initialize the recursive // acquisition count and the *upgraderIsReader flag and return // success. // if (ws == StParkStatus.Success) { upCount = 1; upgraderIsReader = false; return true; } // // The acquire attemptwas cancelled. So, ensure that the // wait node is unlinked from the wait queue and report // the failure appropriately. // if (wn.next != wn) { slock.Enter(); upQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Recursive enter write not allowed"); } if (rdCounts.Lookup(tid) != null) { throw new StLockRecursionException("Write after read not allowed"); } } else { // // If this is a recursive enter, increment the recursive acquisition // counter and return success. // if (tid == writer) { wrCount++; return true; } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the write lock can be entered - this is, there are no lock // readers, no lock writer or upgrader or the current thread is the // upgrader -, enter the write lock, release the spinlock and // return success. // if (readers == 0 && writer == UNOWNED && (upgrader == tid || upgrader == UNOWNED)) { writer = tid; slock.Exit(); wrCount = 1; return true; } // // If the current thread isn't the current upgrader but is reader, // release the spinlock and throw the appropriate exception. // if (tid != upgrader && rdCounts.Lookup(tid) != null) { slock.Exit(); throw new StLockRecursionException("Write after read not allowed"); } // // The write lock can't be entered immediately. So, if a null timeout // was specified, release the spinlock and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the writers queue. // If the current thread isn't the current upgrader, the wait // node is inserted in the writer's queue; otherwise, the wait // node becomes referenced by the *upgradeToWriteWaiter* field. // int sc; WaitNode wn = new WaitNode(tid); if (tid == upgrader) { upgToWrWaiter = wn; sc = spinCount; } else { sc = wrQueue.IsEmpty ? spinCount : 0; wrQueue.Enqueue(wn); } // // Release spin the lock and park the current thread, activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If the thread entered the write lock, initialize the recursive // acquisition counter and return success. // if (ws == StParkStatus.Success) { wrCount = 1; return true; } // // The enter attempted was cancelled. So, if the wait node was // already remove from the respective queue, report the failure // appropriately. Otherwise, unlink the wait node and, if appropriate, // taking into account the other waiters. // if (wn.next == wn) { goto ReportFailure; } slock.Enter(); if (wn.next != wn) { if (wn == upgToWrWaiter) { upgToWrWaiter = null; } else { wrQueue.Remove(wn); // // If the writers queue becomes empty, it is possible that there // is a waiting upgrader or waiting reader threads that can now // proceed. // if (writer == UNOWNED && upgrader == UNOWNED && wrQueue.IsEmpty && TryWakeupUpgraderAndReaders()) { goto ReportFailure; } } } slock.Exit(); ReportFailure: StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to enter the read lock, activating the // specified cancellers. // public bool TryEnterRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Read after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Recursive read not allowed"); } } else { // // If this is a recursive enter, increment the recursive // acquisition counter and return. // if (rc != null) { rc.count++; return true; } } // // Acquire the spinlock that protected the r/u/w lock shared state. // slock.Enter(); // // If the current thread is the upgrader, it can also enter // the read lock. So, add an entry to the readers table, // release the spinlock and return success. // if (tid == upgrader) { rdCounts.Add(tid); slock.Exit(); upgraderIsReader = true; return true; } // // The read lock can be entered, if the r/w lock isn't in write // mode and no thread is waiting to enter the writer mode. // If these conditions are met, increment the number of lock // readers, add an entry to the readers table, release the // spinlock and return success. // if (writer == UNOWNED && wrQueue.IsEmpty && upgToWrWaiter == null) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // If the r/w lock is reentrant and the current thread is the // current writer, it can also to become a reader. So, increment // the number of lock readers, add an entry to the readers table, // release the spinlock and return success. // if (isReentrant && tid == writer) { readers++; rdCounts.Add(tid); slock.Exit(); return true; } // // The current thread can't enter the read lock immediately. // So, if a null timeout was specified, release the spinlock // and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return false; } // // Create a wait node and insert it in the readers queue. // Compute also the amount of spinning. // int sc = rdQueue.IsEmpty ? spinCount : 0; WaitNode wn; rdQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread, activating // the specified cancellers and spinning if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we entered the read lock, return success. // if (ws == StParkStatus.Success) { return true; } // // The enter attempt was cancelled. So, ensure that the wait node // is unlinked from the queue and report the failure appropriately. // if (wn.next != wn) { slock.Enter(); rdQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return false; }
// // Tries to enter the lock in upgrade read mode, activating // the specified cancellers. // public bool TryEnterUpgradeableRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == upgrader) { throw new StLockRecursionException("Recursive upgrade not allowed"); } if (tid == writer) { throw new StLockRecursionException("Upgrade after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } else { // // If the current thread is the current upgrader, increment the // recursive acquisition counter and return. // if (tid == upgrader) { upCount++; return(true); } // // If the current thread is the current writer, it can also // becomes the upgrader. If it is also a reader, it will be // accounted as reader on the *upgraderIsReader* flag. // if (tid == writer) { upgrader = tid; upCount = 1; if (rc != null) { upgraderIsReader = true; } return(true); } if (rc != null) { throw new StLockRecursionException("Upgrade after read not allowed"); } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the lock isn't in write or upgrade read mode, the // current thread becomes the current upgrader. Then, release // the spinlock and return success. // if (writer == UNOWNED && upgrader == UNOWNED) { upgrader = tid; slock.Exit(); upgraderIsReader = false; upCount = 1; return(true); } // // The upgrade read lock can't be acquired immediately. // So, if a null timeout was specified, return failure. // if (cargs.Timeout == 0) { slock.Exit(); return(false); } // // Create a wait node and insert it in the upgrader's queue. // int sc = (upQueue.IsEmpty && wrQueue.IsEmpty) ? spinCount : 0; WaitNode wn; upQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we acquired the upgrade lock, initialize the recursive // acquisition count and the *upgraderIsReader flag and return // success. // if (ws == StParkStatus.Success) { upCount = 1; upgraderIsReader = false; return(true); } // // The acquire attemptwas cancelled. So, ensure that the // wait node is unlinked from the wait queue and report // the failure appropriately. // if (wn.next != wn) { slock.Enter(); upQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return(false); }
// // Tries to enter the write lock, activating the specified // cancellers. // public bool TryEnterWrite(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Recursive enter write not allowed"); } if (rdCounts.Lookup(tid) != null) { throw new StLockRecursionException("Write after read not allowed"); } } else { // // If this is a recursive enter, increment the recursive acquisition // counter and return success. // if (tid == writer) { wrCount++; return(true); } } // // Acquire the spinlock that protects the r/w lock shared state. // slock.Enter(); // // If the write lock can be entered - this is, there are no lock // readers, no lock writer or upgrader or the current thread is the // upgrader -, enter the write lock, release the spinlock and // return success. // if (readers == 0 && writer == UNOWNED && (upgrader == tid || upgrader == UNOWNED)) { writer = tid; slock.Exit(); wrCount = 1; return(true); } // // If the current thread isn't the current upgrader but is reader, // release the spinlock and throw the appropriate exception. // if (tid != upgrader && rdCounts.Lookup(tid) != null) { slock.Exit(); throw new StLockRecursionException("Write after read not allowed"); } // // The write lock can't be entered immediately. So, if a null timeout // was specified, release the spinlock and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return(false); } // // Create a wait node and insert it in the writers queue. // If the current thread isn't the current upgrader, the wait // node is inserted in the writer's queue; otherwise, the wait // node becomes referenced by the *upgradeToWriteWaiter* field. // int sc; WaitNode wn = new WaitNode(tid); if (tid == upgrader) { upgToWrWaiter = wn; sc = spinCount; } else { sc = wrQueue.IsEmpty ? spinCount : 0; wrQueue.Enqueue(wn); } // // Release spin the lock and park the current thread, activating // the specified cancellers and spinning, if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If the thread entered the write lock, initialize the recursive // acquisition counter and return success. // if (ws == StParkStatus.Success) { wrCount = 1; return(true); } // // The enter attempted was cancelled. So, if the wait node was // already remove from the respective queue, report the failure // appropriately. Otherwise, unlink the wait node and, if appropriate, // taking into account the other waiters. // if (wn.next == wn) { goto ReportFailure; } slock.Enter(); if (wn.next != wn) { if (wn == upgToWrWaiter) { upgToWrWaiter = null; } else { wrQueue.Remove(wn); // // If the writers queue becomes empty, it is possible that there // is a waiting upgrader or waiting reader threads that can now // proceed. // if (writer == UNOWNED && upgrader == UNOWNED && wrQueue.IsEmpty && TryWakeupUpgraderAndReaders()) { goto ReportFailure; } } } slock.Exit(); ReportFailure: StCancelArgs.ThrowIfException(ws); return(false); }
// // Tries to enter the read lock, activating the // specified cancellers. // public bool TryEnterRead(StCancelArgs cargs) { int tid = Thread.CurrentThread.ManagedThreadId; ReaderCounter rc = rdCounts.Lookup(tid); if (!isReentrant) { if (tid == writer) { throw new StLockRecursionException("Read after write not allowed"); } if (rc != null) { throw new StLockRecursionException("Recursive read not allowed"); } } else { // // If this is a recursive enter, increment the recursive // acquisition counter and return. // if (rc != null) { rc.count++; return(true); } } // // Acquire the spinlock that protected the r/u/w lock shared state. // slock.Enter(); // // If the current thread is the upgrader, it can also enter // the read lock. So, add an entry to the readers table, // release the spinlock and return success. // if (tid == upgrader) { rdCounts.Add(tid); slock.Exit(); upgraderIsReader = true; return(true); } // // The read lock can be entered, if the r/w lock isn't in write // mode and no thread is waiting to enter the writer mode. // If these conditions are met, increment the number of lock // readers, add an entry to the readers table, release the // spinlock and return success. // if (writer == UNOWNED && wrQueue.IsEmpty && upgToWrWaiter == null) { readers++; rdCounts.Add(tid); slock.Exit(); return(true); } // // If the r/w lock is reentrant and the current thread is the // current writer, it can also to become a reader. So, increment // the number of lock readers, add an entry to the readers table, // release the spinlock and return success. // if (isReentrant && tid == writer) { readers++; rdCounts.Add(tid); slock.Exit(); return(true); } // // The current thread can't enter the read lock immediately. // So, if a null timeout was specified, release the spinlock // and return failure. // if (cargs.Timeout == 0) { slock.Exit(); return(false); } // // Create a wait node and insert it in the readers queue. // Compute also the amount of spinning. // int sc = rdQueue.IsEmpty ? spinCount : 0; WaitNode wn; rdQueue.Enqueue(wn = new WaitNode(tid)); // // Release the spinlock and park the current thread, activating // the specified cancellers and spinning if appropriate. // slock.Exit(); int ws = wn.Park(sc, cargs); // // If we entered the read lock, return success. // if (ws == StParkStatus.Success) { return(true); } // // The enter attempt was cancelled. So, ensure that the wait node // is unlinked from the queue and report the failure appropriately. // if (wn.next != wn) { slock.Enter(); rdQueue.Remove(wn); slock.Exit(); } StCancelArgs.ThrowIfException(ws); return(false); }