using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace System.Reactive.Concurrency
{
	public sealed class AsyncLock : IDisposable
	{
		public void Wait(Action action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			this.Wait<Action>(action, delegate(Action closureAction)
			{
				closureAction();
			});
		}

		internal void Wait<TState>(TState state, Action<TState> action)
		{
			if (action == null)
			{
				throw new ArgumentNullException("action");
			}
			this.Wait(state, action, delegate(Delegate actionObject, object stateObject)
			{
				((Action<TState>)actionObject)((TState)((object)stateObject));
			});
		}

		private void Wait(object state, Delegate @delegate, Action<Delegate, object> action)
		{
			object obj = this._guard;
			lock (obj)
			{
				if (this._hasFaulted)
				{
					return;
				}
				if (this._isAcquired)
				{
					Queue<ValueTuple<Action<Delegate, object>, Delegate, object>> queue = this._queue;
					if (queue == null)
					{
						queue = new Queue<ValueTuple<Action<Delegate, object>, Delegate, object>>();
						this._queue = queue;
					}
					queue.Enqueue(new ValueTuple<Action<Delegate, object>, Delegate, object>(action, @delegate, state));
					return;
				}
				this._isAcquired = true;
			}
			try
			{
				IL_0066:
				action(@delegate, state);
			}
			catch
			{
				obj = this._guard;
				lock (obj)
				{
					this._queue = null;
					this._hasFaulted = true;
				}
				throw;
			}
			obj = this._guard;
			lock (obj)
			{
				Queue<ValueTuple<Action<Delegate, object>, Delegate, object>> queue2 = this._queue;
				if (queue2 == null || queue2.Count == 0)
				{
					this._isAcquired = false;
					return;
				}
				ValueTuple<Action<Delegate, object>, Delegate, object> valueTuple = queue2.Dequeue();
				action = valueTuple.Item1;
				@delegate = valueTuple.Item2;
				state = valueTuple.Item3;
			}
			goto IL_0066;
		}

		public void Dispose()
		{
			object guard = this._guard;
			lock (guard)
			{
				this._queue = null;
				this._hasFaulted = true;
			}
		}

		private bool _isAcquired;

		private bool _hasFaulted;

		private readonly object _guard = new object();

		[TupleElementNames(new string[] { "action", "delegate", "state" })]
		private Queue<ValueTuple<Action<Delegate, object>, Delegate, object>> _queue;
	}
}
