fix(lock): properly handle multiple concurrent acquires
This commit is contained in:
parent
878c0e35e4
commit
3d8094b69f
1 changed files with 26 additions and 14 deletions
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue