-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
_raw_semaphore.ts
64 lines (59 loc) · 1.45 KB
/
_raw_semaphore.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/**
* @internal
*/
export class RawSemaphore {
#resolves: (() => void)[] = [];
#value: number;
#size: number;
/**
* Creates a new semaphore with the specified limit.
*
* @param size The maximum number of times the semaphore can be acquired before blocking.
* @throws {RangeError} if the size is not a positive safe integer.
*/
constructor(size: number) {
if (size <= 0 || !Number.isSafeInteger(size)) {
throw new RangeError(
`size must be a positive safe integer, got ${size}`,
);
}
this.#value = size;
this.#size = size;
}
/**
* Returns true if the semaphore is currently locked.
*/
get locked(): boolean {
return this.#value === 0;
}
/**
* Returns the number of waiters that are waiting for lock release.
*/
get waiterCount(): number {
return this.#resolves.length;
}
/**
* Acquires the semaphore, blocking until the semaphore is available.
*/
acquire(): Promise<void> {
if (this.#value > 0) {
this.#value -= 1;
return Promise.resolve();
} else {
const { promise, resolve } = Promise.withResolvers<void>();
this.#resolves.push(resolve);
return promise;
}
}
/**
* Releases the semaphore, allowing the next waiting operation to proceed.
*/
release(): void {
const resolve = this.#resolves.shift();
if (resolve) {
resolve();
} else if (this.#value < this.#size) {
this.#value += 1;
}
}
}