//
// Taking the Upgradable read lock is like taking a read lock
// but we limit it to a single upgradable at a time.
//
public bool TryEnterUpgradeableReadLock(int millisecondsTimeout)
{
ThreadLockState ctstate = CurrentThreadState;
if (CheckState(ctstate, millisecondsTimeout, LockState.Upgradable))
{
++ctstate.UpgradeableRecursiveCount;
return(true);
}
if (ctstate.LockState.Has(LockState.Read))
{
throw new LockRecursionException("The current thread has already entered read mode");
}
++numUpgradeWaiters;
long start = millisecondsTimeout == -1 ? 0 : sw.ElapsedMilliseconds;
// We first try to obtain the upgradeable right
while (!upgradableEvent.IsSet() || !upgradableTaken.TryRelaxedSet())
{
if (millisecondsTimeout != -1 && (sw.ElapsedMilliseconds - start) > millisecondsTimeout)
{
--numUpgradeWaiters;
return(false);
}
upgradableEvent.Wait(ComputeTimeout(millisecondsTimeout, start));
}
upgradableEvent.Reset();
// Then it's a simple reader lock acquiring
if (TryEnterReadLock(ComputeTimeout(millisecondsTimeout, start)))
{
ctstate.LockState = LockState.Upgradable;
--numUpgradeWaiters;
--ctstate.ReaderRecursiveCount;
++ctstate.UpgradeableRecursiveCount;
return(true);
}
upgradableTaken.Value = false;
upgradableEvent.Set();
--numUpgradeWaiters;
return(false);
}