/// <summary> /// Locks the monitor, with the specified timeout. This implementation validates /// the ordering of locks, and maintains the current owner. /// </summary> /// <param name="timeout">The timeout, in milliseconds. Must be Timeout.Infinite, /// or non-negative.</param> /// <returns>A lock token which should be disposed to release the lock</returns> /// <exception cref="LockTimeoutException">The operation times out.</exception> /// <exception cref="LockOrderException"> /// The lock order would be violated if this lock were taken out. (i.e. attempting /// to acquire the lock could cause deadlock.) /// </exception> public override LockToken Lock(int timeout) { // Check whether we should be allowed to take out this lock, according to // the inner locks we have. // Performance note: This would be in a separate method, but the cost of // making a method call (which can't be inlined in this case) is sufficiently // high as to make it worth manually inlining. OrderedLock inner = InnerLock; // Performance note: This would be a single if statement with shortcutting, // but fetching the current thread is mildly expensive. if (inner != null) { Thread currentThread = Thread.CurrentThread; if (Owner != currentThread) { while (inner != null) { if (inner.Owner == currentThread) { throw new LockOrderException("Unable to acquire lock {0} as lock {1} is already held", Name, inner.Name); } inner = inner.InnerLock; } } } LockToken ret = base.Lock(timeout); // Now remember that we've locked, and set the owner if necessary // Performance note: On a single processor, it is slightly cheaper // to assign owner every time, without a test. On multiple processor // boxes, it is cheaper to avoid the volatile write. if (Interlocked.Increment(ref count) == 1) { owner = Thread.CurrentThread; } return(ret); }