fix(lock): properly handle multiple concurrent acquires

This commit is contained in:
teidesu 2021-04-20 21:58:50 +03:00
parent 878c0e35e4
commit 3d8094b69f

View file

@ -1,24 +1,36 @@
type LockInfo = [Promise<void>, () => void]
interface OneWayLinkedList<T> {
v: T
n?: OneWayLinkedList<T>
}
/** @internal */ /** @internal */
export class Lock { export class Lock {
private _prom: Promise<void> | null = null private _first?: OneWayLinkedList<LockInfo>
private _unlock: (() => void) | null = null private _last?: OneWayLinkedList<LockInfo>
constructor() {
this._prom = null
this._unlock = null
}
async acquire(): Promise<void> { async acquire(): Promise<void> {
if (this._prom) await this._prom while (this._first) {
this._prom = new Promise((resolve) => { await this._first.v[0]
this._unlock = resolve }
let unlock: () => void
const prom = new Promise<void>((resolve) => {
unlock = resolve
}) })
if (this._last) {
this._last.n = { v: [prom, unlock!] }
this._last = this._last.n
} else {
this._first = this._last = { v: [prom, unlock!] }
}
} }
release(): void { release(): void {
if (!this._unlock) return if (!this._first) throw new Error('Nothing to release')
this._unlock() this._first.v[1]()
this._prom = null this._first = this._first.n
this._unlock = null if (!this._first) this._last = undefined
} }
} }