Skip to content

Commit 3c0bf55

Browse files
committed
fix: ensure releasing locks is idempotent
1 parent fe20a4f commit 3c0bf55

File tree

6 files changed

+54
-0
lines changed

6 files changed

+54
-0
lines changed

src/Lock.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ class Lock implements Lockable {
2424
--this._count;
2525
throw e;
2626
}
27+
let released = false;
2728
return [
2829
async () => {
30+
if (released) return;
31+
released = true;
2932
--this._count;
3033
release();
3134
// Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54

src/RWLockReader.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,11 @@ class RWLockReader implements Lockable {
7474
// Yield for the first reader to finish locking
7575
await yieldMicro();
7676
}
77+
let released= false;
7778
return [
7879
async () => {
80+
if (released) return;
81+
released = true;
7982
readersRelease = await this.readersLock.acquire();
8083
const readerCount = --this._readerCount;
8184
// The last reader unlocks
@@ -109,8 +112,11 @@ class RWLockReader implements Lockable {
109112
--this._writerCount;
110113
throw e;
111114
}
115+
let released = false;
112116
return [
113117
async () => {
118+
if (released) return;
119+
released = true;
114120
release();
115121
--this._writerCount;
116122
// Allow semaphore to settle https://github.com/DirtyHairy/async-mutex/issues/54

src/RWLockWriter.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,11 @@ class RWLockWriter implements Lockable {
7474
// Yield for the first reader to finish locking
7575
await yieldMicro();
7676
}
77+
let released = false;
7778
return [
7879
async () => {
80+
if (released) return;
81+
released = true;
7982
const readerCount = --this._readerCount;
8083
// The last reader unlocks
8184
if (readerCount === 0) {
@@ -126,8 +129,11 @@ class RWLockWriter implements Lockable {
126129
await yieldMicro();
127130
throw e;
128131
}
132+
let released = false;
129133
return [
130134
async () => {
135+
if (released) return;
136+
released = true;
131137
this.readersRelease();
132138
writersRelease();
133139
--this._writerCount;

tests/Lock.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,17 @@ describe(Lock.name, () => {
212212
await g.next();
213213
await lock.waitForUnlock(100);
214214
});
215+
test('release is idempotent', async () => {
216+
const lock = new Lock();
217+
let lockAcquire = lock.lock();
218+
let [lockRelease] = await lockAcquire();
219+
await lockRelease();
220+
await lockRelease();
221+
expect(lock.count).toBe(0);
222+
lockAcquire = lock.lock();
223+
[lockRelease] = await lockAcquire();
224+
await lockRelease();
225+
await lockRelease();
226+
expect(lock.count).toBe(0);
227+
});
215228
});

tests/RWLockReader.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,4 +484,17 @@ describe(RWLockReader.name, () => {
484484
await g.next();
485485
await lock.waitForUnlock(100);
486486
});
487+
test('release is idempotent', async () => {
488+
const lock = new RWLockReader();
489+
let lockAcquire = lock.lock('read');
490+
let [lockRelease] = await lockAcquire();
491+
await lockRelease();
492+
await lockRelease();
493+
expect(lock.readerCount).toBe(0);
494+
lockAcquire = lock.lock('write');
495+
[lockRelease] = await lockAcquire();
496+
await lockRelease();
497+
await lockRelease();
498+
expect(lock.writerCount).toBe(0);
499+
});
487500
});

tests/RWLockWriter.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,4 +476,17 @@ describe(RWLockWriter.name, () => {
476476
await g.next();
477477
await lock.waitForUnlock(100);
478478
});
479+
test('release is idempotent', async () => {
480+
const lock = new RWLockWriter();
481+
let lockAcquire = lock.lock('read');
482+
let [lockRelease] = await lockAcquire();
483+
await lockRelease();
484+
await lockRelease();
485+
expect(lock.readerCount).toBe(0);
486+
lockAcquire = lock.lock('write');
487+
[lockRelease] = await lockAcquire();
488+
await lockRelease();
489+
await lockRelease();
490+
expect(lock.writerCount).toBe(0);
491+
});
479492
});

0 commit comments

Comments
 (0)