}
public bool TryEnterReadLock (int millisecondsTimeout)
+ {
+ bool dummy = false;
+ return TryEnterReadLock (millisecondsTimeout, ref dummy);
+ }
+
+ bool TryEnterReadLock (int millisecondsTimeout, ref bool success)
{
ThreadLockState ctstate = CurrentThreadState;
// Same idea when recursion is allowed and a write thread wants to
// go for a Read too.
if (ctstate.LockState.Has (LockState.Upgradable)
- || recursionPolicy == LockRecursionPolicy.SupportsRecursion) {
+ || (!noRecursion && ctstate.LockState.Has (LockState.Write))) {
RuntimeHelpers.PrepareConstrainedRegions ();
try {}
finally {
Interlocked.Add (ref rwlock, RwRead);
- ctstate.LockState ^= LockState.Read;
+ ctstate.LockState |= LockState.Read;
++ctstate.ReaderRecursiveCount;
+ success = true;
}
return true;
ctstate.LockState ^= LockState.Read;
++ctstate.ReaderRecursiveCount;
--numReadWaiters;
- return true;
+ success = true;
} else {
Interlocked.Add (ref rwlock, -RwRead);
}
}
+ if (success)
+ return true;
writerDoneEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
} while (millisecondsTimeout == -1 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout);
if (!ctstate.LockState.Has (LockState.Read))
throw new SynchronizationLockException ("The current thread has not entered the lock in read mode");
- ctstate.LockState ^= LockState.Read;
- --ctstate.ReaderRecursiveCount;
- if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
- readerDoneEvent.Set ();
+ if (--ctstate.ReaderRecursiveCount == 0) {
+ ctstate.LockState ^= LockState.Read;
+ if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
+ readerDoneEvent.Set ();
+ }
}
}
++numWriteWaiters;
bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
+ bool registered = false;
+ bool success = false;
- /* 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)
- if (Interlocked.Add (ref rwlock, RwWaitUpgrade - RwRead) >> RwReadBit == 0)
- readerDoneEvent.Set ();
+ 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;
+ }
+ }
- int stateCheck = isUpgradable ? RwWaitUpgrade : RwWait;
- long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+ 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) {
- if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state) {
- writerDoneEvent.Reset ();
- ctstate.LockState ^= LockState.Write;
- ++ctstate.WriterRecursiveCount;
- --numWriteWaiters;
- return true;
+ 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;
}
+
state = rwlock;
- }
- // We register our interest in taking the Write lock (if upgradeable it's already done)
- if (!isUpgradable)
- while ((state & RwWait) == 0 && Interlocked.CompareExchange (ref rwlock, state | RwWait, state) != state)
- 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;
+ }
+ }
- // 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));
+ // 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);
- } while (millisecondsTimeout < 0 || (sw.ElapsedMilliseconds - start) < millisecondsTimeout);
- --numWriteWaiters;
+ --numWriteWaiters;
+ } finally {
+ if (registered)
+ Interlocked.Add (ref rwlock, isUpgradable ? -RwWaitUpgrade : -RwWait);
+ }
+
return false;
}
public void ExitWriteLock ()
{
- ThreadLockState ctstate = CurrentThreadState;
+ 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.LockState.Has (LockState.Write))
+ throw new SynchronizationLockException ("The current thread has not entered the lock in write mode");
- bool isUpgradable = ctstate.LockState.Has (LockState.Upgradable);
- ctstate.LockState ^= LockState.Write;
- --ctstate.WriterRecursiveCount;
-
- int value = Interlocked.Add (ref rwlock, isUpgradable ? RwRead - RwWrite : -RwWrite);
- writerDoneEvent.Set ();
- if (isUpgradable && value >> RwReadBit == 1)
- readerDoneEvent.Reset ();
+ 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 ()
++numUpgradeWaiters;
long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
+ bool taken = false;
+ bool success = false;
// We first try to obtain the upgradeable right
- while (!upgradableEvent.IsSet () || !upgradableTaken.TryRelaxedSet ()) {
- if (millisecondsTimeout != -1 && (sw.ElapsedMilliseconds - start) > millisecondsTimeout) {
- --numUpgradeWaiters;
- return false;
+ 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));
}
- upgradableEvent.Wait (ComputeTimeout (millisecondsTimeout, start));
- }
+ upgradableEvent.Reset ();
- 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 ();
+ }
+ }
- // Then it's a simple reader lock acquiring
- if (TryEnterReadLock (ComputeTimeout (millisecondsTimeout, start))) {
- ctstate.LockState = LockState.Upgradable;
--numUpgradeWaiters;
- --ctstate.ReaderRecursiveCount;
- ++ctstate.UpgradeableRecursiveCount;
- return true;
+ } catch {
+ // An async exception occured, if we had taken the upgradable mode, release it
+ if (taken && !success)
+ upgradableTaken.Value = false;
}
- upgradableTaken.Value = false;
- upgradableEvent.Set ();
-
- --numUpgradeWaiters;
-
- return false;
+ return success;
}
public bool TryEnterUpgradeableReadLock (TimeSpan timeout)
public void ExitUpgradeableReadLock ()
{
- ThreadLockState ctstate = CurrentThreadState;
+ 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");
-
- upgradableTaken.Value = false;
- upgradableEvent.Set ();
+ 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 ();
+ }
+ }
- ctstate.LockState ^= LockState.Upgradable;
- --ctstate.UpgradeableRecursiveCount;
- if (Interlocked.Add (ref rwlock, -RwRead) >> RwReadBit == 0)
- readerDoneEvent.Set ();
}
public void Dispose ()
return rwlock >= RwRead && CurrentThreadState.LockState.Has (LockState.Read);
}
}
-
+
public bool IsWriteLockHeld {
get {
return (rwlock & RwWrite) > 0 && CurrentThreadState.LockState.Has (LockState.Write);
// Detect and prevent recursion
LockState ctstate = state.LockState;
- if (ctstate != LockState.None && noRecursion && (ctstate != LockState.Upgradable || validState == LockState.Upgradable))
+ 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");
if (noRecursion)