Skip to content

Commit

Permalink
fix: ensure releasing locks is idempotent
Browse files Browse the repository at this point in the history
  • Loading branch information
CMCDragonkai committed Jun 28, 2022
1 parent fe20a4f commit 0582b22
Show file tree
Hide file tree
Showing 8 changed files with 70 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/Lock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,11 @@ class Lock implements Lockable {
--this._count;
throw e;
}
let released = false;
return [
async () => {
if (released) return;
released = true;
--this._count;
release();
// Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54
Expand Down
3 changes: 3 additions & 0 deletions src/LockBox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,11 @@ class LockBox<L extends Lockable = Lockable> implements Lockable {
}
locks.push([key, lockRelease, lock]);
}
let released = false;
return [
async () => {
if (released) return;
released = true;
// Release all locks in reverse order
locks.reverse();
for (const [key, lockRelease, lock] of locks) {
Expand Down
6 changes: 6 additions & 0 deletions src/RWLockReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ class RWLockReader implements Lockable {
// Yield for the first reader to finish locking
await yieldMicro();
}
let released= false;
return [
async () => {
if (released) return;
released = true;
readersRelease = await this.readersLock.acquire();
const readerCount = --this._readerCount;
// The last reader unlocks
Expand Down Expand Up @@ -109,8 +112,11 @@ class RWLockReader implements Lockable {
--this._writerCount;
throw e;
}
let released = false;
return [
async () => {
if (released) return;
released = true;
release();
--this._writerCount;
// Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54
Expand Down
6 changes: 6 additions & 0 deletions src/RWLockWriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,11 @@ class RWLockWriter implements Lockable {
// Yield for the first reader to finish locking
await yieldMicro();
}
let released = false;
return [
async () => {
if (released) return;
released = true;
const readerCount = --this._readerCount;
// The last reader unlocks
if (readerCount === 0) {
Expand Down Expand Up @@ -126,8 +129,11 @@ class RWLockWriter implements Lockable {
await yieldMicro();
throw e;
}
let released = false;
return [
async () => {
if (released) return;
released = true;
this.readersRelease();
writersRelease();
--this._writerCount;
Expand Down
13 changes: 13 additions & 0 deletions tests/Lock.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,4 +212,17 @@ describe(Lock.name, () => {
await g.next();
await lock.waitForUnlock(100);
});
test('release is idempotent', async () => {
const lock = new Lock();
let lockAcquire = lock.lock();
let [lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.count).toBe(0);
lockAcquire = lock.lock();
[lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.count).toBe(0);
});
});
13 changes: 13 additions & 0 deletions tests/LockBox.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -347,4 +347,17 @@ describe(LockBox.name, () => {
// NOP
});
});
test('release is idempotent', async () => {
const lockBox = new LockBox();
let lockAcquire = lockBox.lock(['1', Lock], ['2', Lock]);
let [lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lockBox.count).toBe(0);
lockAcquire = lockBox.lock(['2', Lock], ['3', Lock]);
[lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lockBox.count).toBe(0);
});
});
13 changes: 13 additions & 0 deletions tests/RWLockReader.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -484,4 +484,17 @@ describe(RWLockReader.name, () => {
await g.next();
await lock.waitForUnlock(100);
});
test('release is idempotent', async () => {
const lock = new RWLockReader();
let lockAcquire = lock.lock('read');
let [lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.readerCount).toBe(0);
lockAcquire = lock.lock('write');
[lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.writerCount).toBe(0);
});
});
13 changes: 13 additions & 0 deletions tests/RWLockWriter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,4 +476,17 @@ describe(RWLockWriter.name, () => {
await g.next();
await lock.waitForUnlock(100);
});
test('release is idempotent', async () => {
const lock = new RWLockWriter();
let lockAcquire = lock.lock('read');
let [lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.readerCount).toBe(0);
lockAcquire = lock.lock('write');
[lockRelease] = await lockAcquire();
await lockRelease();
await lockRelease();
expect(lock.writerCount).toBe(0);
});
});

0 comments on commit 0582b22

Please sign in to comment.