private RwVaultInternalLockedResource([NotNull] ReadWriteVault <T> owner, [NotNull] Box b, [CanBeNull] Action <TimeSpan?, CancellationToken> upgradeAction, [CanBeNull] Action upgradeForeverAction, AcquisitionMode mode) { _mode = mode.ValueOrThrowIfNDef(); _b = b ?? throw new ArgumentNullException(nameof(b)); _upgradeAction = upgradeAction; _upgradeForeverAction = upgradeForeverAction; _owner = owner ?? throw new ArgumentNullException(nameof(owner)); _releaseFlag = default; _isGood = true; Debug.Assert((_upgradeAction == null) == (_upgradeForeverAction == null), "Both ok, neither ok. Exactly one not ok."); }
/// <summary> /// Try to get the resource until earliest of following happens /// 1- get it successfully, /// 2- cancellation requested via <paramref name="token"/> /// 3- time specified by <paramref name="timeout"/> exceeded /// </summary> /// <param name="timeout">how long should we wait? Null indicates potential infinite wait .</param> /// <param name="token">token by which another thread can cancel the attempt to obtain resource</param> /// <param name="mode">acquisition mode</param> /// <returns>the resource</returns> /// <exception cref="ArgumentOutOfRangeException">non-null, non-positive <paramref name="timeout"/> argument; OR mode not /// a defined value of the <see cref="AcquisitionMode"/> <see langword="enum"/></exception> /// <exception cref="TimeoutException">didn't obtain it within time specified by <paramref name="timeout"/></exception> /// <exception cref="OperationCanceledException">operation was cancelled</exception> /// <exception cref="ObjectDisposedException">the object was disposed</exception> /// <exception cref="LockAlreadyHeldThreadException">the thread attempting to obtain the lock already holds the lock.</exception> /// <remarks>After method returns value, you are responsible for disposal until passing to ultimate user behind a method whose return /// value is annotated by the <see cref="UsingMandatoryAttribute"/>. This means you must dispose of it yourself in all failure/exceptional /// cases after this method returns a value but before ultimately passed to user.</remarks> protected RwVaultInternalLockedResource ExecuteGetInternalLockedResource(TimeSpan?timeout, CancellationToken token, AcquisitionMode mode) { ThrowIfDisposingOrDisposed(); if (timeout.HasValue && timeout.Value <= TimeSpan.Zero) { throw new ArgumentOutOfRangeException(nameof(timeout), timeout, @"Must be positive."); } return(RwVaultInternalLockedResource.CreateInternalLockedResource(this, timeout, token, mode.ValueOrThrowIfNDef())); }
CreateInternalLockedResource <TV>([NotNull] TV owner, TimeSpan?timeout, CancellationToken token, AcquisitionMode mode, bool vaultDisposing = false) where TV : ReadWriteVault <T> { if (owner == null) { throw new ArgumentNullException(nameof(owner)); } if (timeout == null && token == CancellationToken.None) { throw new ArgumentException("Cancellation token may not be none if no timeout is specified."); } if (vaultDisposing && !owner.DisposeInProgress) { throw new InvalidOperationException($"The {nameof(vaultDisposing)} parameter indicates this call is part of a vault disposal routine." + " The vault, however, is not performing such a routine."); } if (!vaultDisposing && owner.IsDisposed) { throw new ArgumentException(@"The vault is disposed.", nameof(owner)); } mode = mode.ValueOrThrowIfNDef(); (Box AcquiredBox, bool Cancelled, bool TimedOut)boxRes = default; try { boxRes = AcquireBoxPointer(owner, timeout, mode, token); if (boxRes.Cancelled) { throw new OperationCanceledException(token); } if (boxRes.TimedOut) { throw new TimeoutException( "Unable to acquire resource within " + $"[{(timeout ?? owner.DefaultTimeout).TotalMilliseconds:F3}] milliseconds."); } (Action <TimeSpan?, CancellationToken> upgradeAction, Action upgradeForeverAction) = GetUpgradeActions(mode); Debug.Assert((upgradeForeverAction == null) == (upgradeAction == null)); return(new RwVaultInternalLockedResource(owner, boxRes.AcquiredBox, upgradeAction, upgradeForeverAction, mode)); } catch (LockRecursionException ex) { Debug.Assert(boxRes.AcquiredBox == null); throw new RwLockAlreadyHeldThreadException(Thread.CurrentThread.ManagedThreadId, ex); } catch (Exception) { if (boxRes.AcquiredBox != null) { ReleaseLock(owner._locker, mode); } throw; } (Action <TimeSpan?, CancellationToken> UpgradeAction, Action UpgradeForeverAction) GetUpgradeActions(AcquisitionMode m) { return(m == AcquisitionMode.UpgradableReadOnly ? ( (TimeSpan? ts, CancellationToken tkn) => Upgrade(ts, tkn), () => UpgradeForever()) : (NullUpgradeAction, NullUpgradeForeverAction)); } void Upgrade(TimeSpan?ts, CancellationToken tkn) => CreateInternalLockedResource(owner, ts, tkn, AcquisitionMode.ReadWrite); void UpgradeForever() => CreateInternalLockedResourceBlockForever(owner, AcquisitionMode.ReadWrite); }
/// <summary> /// Try to get the locked resource. This thread will block (potentially forever) /// until the resource is obtained or an exception is thrown. /// </summary> /// <returns>The locked resource</returns> /// <exception cref="ObjectDisposedException">object was disposed</exception> /// <exception cref="LockAlreadyHeldThreadException">the thread attempting to obtain the lock, /// already holds the lock.</exception> protected RwVaultInternalLockedResource ExecuteGetInternalLockedResourceBlockForever(AcquisitionMode mode) { ThrowIfDisposingOrDisposed(); return(RwVaultInternalLockedResource.CreateInternalLockedResourceBlockForever(this, mode.ValueOrThrowIfNDef())); }