From 40e917f2d20a2d0f7a9460d8e1908ba2f5fe18a7 Mon Sep 17 00:00:00 2001 From: Christian Speckner Date: Fri, 2 Sep 2022 15:05:08 +0200 Subject: [PATCH] Fixes'n'tests. --- src/Semaphore.ts | 5 +++- src/withTimeout.ts | 4 +-- test/semaphore.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++- test/withTimeout.ts | 2 +- 4 files changed, 77 insertions(+), 5 deletions(-) diff --git a/src/Semaphore.ts b/src/Semaphore.ts index b0dc8d9..a385628 100644 --- a/src/Semaphore.ts +++ b/src/Semaphore.ts @@ -68,9 +68,12 @@ class Semaphore implements SemaphoreInterface { if (!queueEntry) continue; const previousValue = this._value; + const previousWeight = weight; + this._value -= weight; + weight = this._value + 1; - queueEntry.resolve([previousValue, this._newReleaser(weight)]); + queueEntry.resolve([previousValue, this._newReleaser(previousWeight)]); } this._drainUnlockWaiters(); diff --git a/src/withTimeout.ts b/src/withTimeout.ts index 6d32b42..f841ee5 100644 --- a/src/withTimeout.ts +++ b/src/withTimeout.ts @@ -56,8 +56,8 @@ export function withTimeout(sync: MutexInterface | SemaphoreInterface, timeout: } }, - release(): void { - sync.release(); + release(weight?: number): void { + sync.release(weight); }, cancel(): void { diff --git a/test/semaphore.ts b/test/semaphore.ts index 6627dce..1a3a4b0 100644 --- a/test/semaphore.ts +++ b/test/semaphore.ts @@ -81,7 +81,27 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => assert.strictEqual(value, 2); }); - test('release is idempotent', async () => { + test('a semaphore can be initialized to negative values', async () => { + semaphore = factory(-2); + + let value: number | undefined = undefined; + semaphore.acquire().then(([x]) => { + value = x; + }); + + await clock.tickAsync(0); + assert.strictEqual(value, undefined); + + semaphore.release(2); + await clock.tickAsync(0); + assert.strictEqual(value, undefined); + + semaphore.release(2); + await clock.tickAsync(0); + assert.strictEqual(value, 2); + }); + + test('the releaser is idempotent', async () => { const values: Array = []; semaphore.acquire().then(([value, release]) => { @@ -115,6 +135,20 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => assert.deepStrictEqual(values.sort(), [1, 1, 1, 2]); }); + test('the releaser increments by the correct weight', async () => { + await semaphore.acquire(2); + assert.strictEqual(semaphore.getValue(), 0); + + semaphore.release(2); + assert.strictEqual(semaphore.getValue(), 2); + + await semaphore.acquire(); + assert.strictEqual(semaphore.getValue(), 1); + + semaphore.release(); + assert.strictEqual(semaphore.getValue(), 2); + }); + test('runExclusive passes semaphore value', async () => { let value = -1; @@ -191,6 +225,14 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => assert(flag); }); + test('runExclusive passes the correct weight', async () => { + semaphore.runExclusive(() => undefined, 2); + assert.strictEqual(semaphore.getValue(), 0); + + await clock.runAllAsync(); + assert.strictEqual(semaphore.getValue(), 2); + }); + test('new semaphore is unlocked', () => { assert(!semaphore.isLocked()); }); @@ -220,6 +262,33 @@ export const semaphoreSuite = (factory: (maxConcurrency: number, err?: Error) => assert(!semaphore.isLocked()); }); + test("getValue returns the Semaphore's value", () => { + assert.strictEqual(semaphore.getValue(), 2); + semaphore.acquire(); + + assert.strictEqual(semaphore.getValue(), 1); + }); + + test('setValue sets the semaphore value and runs all applicable waiters', async () => { + semaphore = factory(0); + + let flag1 = false; + let flag2 = false; + let flag3 = false; + + semaphore.acquire(1).then(() => (flag1 = true)); + semaphore.acquire(2).then(() => (flag2 = true)); + semaphore.acquire(4).then(() => (flag3 = true)); + + semaphore.setValue(3); + + await clock.runAllAsync(); + + assert.strictEqual(flag1, true); + assert.strictEqual(flag2, true); + assert.strictEqual(flag3, false); + }); + test('the release method releases a locked semaphore', async () => { semaphore = factory(1); diff --git a/test/withTimeout.ts b/test/withTimeout.ts index 88eaa66..64e7364 100644 --- a/test/withTimeout.ts +++ b/test/withTimeout.ts @@ -11,7 +11,7 @@ import { mutexSuite } from './mutex'; import { semaphoreSuite } from './semaphore'; import { withTimeout } from '../src/withTimeout'; -suite('waitFor', () => { +suite('withTimeout', () => { suite('Mutex', () => { suite('timeout behavior', () => { let clock: InstalledClock;