/*---------------------------------------------------------
 * Copyright 2021 The Go Authors. All rights reserved.
 * Licensed under the MIT License. See LICENSE in the project root for license information.
 *--------------------------------------------------------*/

'use strict';

/* Mutex provides mutex feature by building a promise chain.

  const m = new Mutex();

  const unlock = await m.lock();
  try {
	  // critical section
  } finally {
	  unlock();
  }
*/
export class Mutex {
	private mutex = Promise.resolve();

	public lock(): PromiseLike<() => void> {
		// Based on https://spin.atomicobject.com/2018/09/10/javascript-concurrency/

		let x: (unlock: () => void) => void;

		// add to the promise chain of this mutex.
		// When all the prior promises in the chain are resolved,
		// x, which will be the resolve callback of promise B,
		// will run and cause to unblock the waiter of promise B.
		this.mutex = this.mutex.then(() => {
			return new Promise(x); // promise A
		});

		return new Promise((resolve) => {
			// promise B
			x = resolve;
		});
		// the returned Promise will resolve when all the previous
		// promises chained in this.mutex resolve.
	}
}
