Mutex.ts (1136B)
1 /** 2 * @license 3 * Copyright 2024 Google Inc. 4 * SPDX-License-Identifier: Apache-2.0 5 */ 6 import {Deferred} from './Deferred.js'; 7 import {disposeSymbol} from './disposable.js'; 8 9 /** 10 * @internal 11 */ 12 export class Mutex { 13 static Guard = class Guard { 14 #mutex: Mutex; 15 #onRelease?: () => void; 16 constructor(mutex: Mutex, onRelease?: () => void) { 17 this.#mutex = mutex; 18 this.#onRelease = onRelease; 19 } 20 [disposeSymbol](): void { 21 this.#onRelease?.(); 22 return this.#mutex.release(); 23 } 24 }; 25 26 #locked = false; 27 #acquirers: Array<() => void> = []; 28 29 // This is FIFO. 30 async acquire( 31 onRelease?: () => void, 32 ): Promise<InstanceType<typeof Mutex.Guard>> { 33 if (!this.#locked) { 34 this.#locked = true; 35 return new Mutex.Guard(this); 36 } 37 const deferred = Deferred.create<void>(); 38 this.#acquirers.push(deferred.resolve.bind(deferred)); 39 await deferred.valueOrThrow(); 40 return new Mutex.Guard(this, onRelease); 41 } 42 43 release(): void { 44 const resolve = this.#acquirers.shift(); 45 if (!resolve) { 46 this.#locked = false; 47 return; 48 } 49 resolve(); 50 } 51 }