Something went wrong. Try again.
Offload functions to worker threads with shared memory primitives for Node.js.
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182import { setTimeout } from 'node:timers/promises';import { describe, it } from 'node:test';import assert from 'node:assert/strict';import { rwlock } from 'moroutine';
describe('RwLock', () => { it('read lock and unlock', async () => { const rw = rwlock(); const guard = await rw.readLock(); assert.equal(typeof guard[Symbol.dispose], 'function'); rw.readUnlock(); });
it('write lock and unlock', async () => { const rw = rwlock(); const guard = await rw.writeLock(); assert.equal(typeof guard[Symbol.dispose], 'function'); rw.writeUnlock(); });
it('multiple readers can hold the lock concurrently', async () => { const rw = rwlock(); const g1 = await rw.readLock(); const g2 = await rw.readLock(); // Both acquired — success rw.readUnlock(); rw.readUnlock(); });
it('writer excludes readers', async () => { const rw = rwlock(); const order: string[] = [];
await rw.writeLock(); order.push('write-start');
const readerDone = (async () => { const g = await rw.readLock(); order.push('read'); rw.readUnlock(); })();
await setTimeout(20); order.push('write-end'); rw.writeUnlock();
await readerDone; assert.deepEqual(order, ['write-start', 'write-end', 'read']); });
it('writer excludes other writers', async () => { const rw = rwlock(); const order: string[] = [];
await rw.writeLock(); order.push('w1-start');
const writer2Done = (async () => { const g = await rw.writeLock(); order.push('w2'); rw.writeUnlock(); })();
await setTimeout(20); order.push('w1-end'); rw.writeUnlock();
await writer2Done; assert.deepEqual(order, ['w1-start', 'w1-end', 'w2']); });
it('ReadGuard dispose calls readUnlock', async () => { const rw = rwlock(); const guard = await rw.readLock(); guard[Symbol.dispose](); const wg = await rw.writeLock(); rw.writeUnlock(); });
it('WriteGuard dispose calls writeUnlock', async () => { const rw = rwlock(); const guard = await rw.writeLock(); guard[Symbol.dispose](); const rg = await rw.readLock(); rw.readUnlock(); });
it('self-allocates', () => { const rw = rwlock(); assert.ok(rw); });
it('exposes byteSize of 4', () => { assert.equal(rwlock.byteSize, 4); });
it('wakes all waiting readers when writer unlocks', async () => { const rw = rwlock();
await rw.writeLock();
const reader1Done = (async () => { const g = await rw.readLock(); rw.readUnlock(); return 'r1'; })();
const reader2Done = (async () => { const g = await rw.readLock(); rw.readUnlock(); return 'r2'; })();
// Let readers queue up await setTimeout(20); rw.writeUnlock();
const results = await Promise.all([reader1Done, reader2Done]); assert.deepEqual(results.sort(), ['r1', 'r2']); });
it('tryReadLock returns a guard when unlocked', async () => { const rw = rwlock(); const guard = rw.tryReadLock(); assert.ok(guard); assert.equal(typeof guard[Symbol.dispose], 'function'); guard[Symbol.dispose](); // writeLock only succeeds if readUnlock was called (reader count back to 0) await rw.writeLock(); rw.writeUnlock(); });
it('multiple concurrent tryReadLock calls all succeed', () => { const rw = rwlock(); const g1 = rw.tryReadLock(); const g2 = rw.tryReadLock(); const g3 = rw.tryReadLock(); assert.ok(g1); assert.ok(g2); assert.ok(g3); rw.readUnlock(); rw.readUnlock(); rw.readUnlock(); });
it('tryReadLock returns null when write-locked', async () => { const rw = rwlock(); await rw.writeLock(); const guard = rw.tryReadLock(); assert.equal(guard, null); rw.writeUnlock(); });
it('tryWriteLock returns a guard when unlocked', () => { const rw = rwlock(); const guard = rw.tryWriteLock(); assert.ok(guard); assert.equal(typeof guard[Symbol.dispose], 'function'); guard[Symbol.dispose](); // Should be able to re-acquire after dispose (proves writeUnlock was called) const guard2 = rw.tryWriteLock(); assert.ok(guard2); rw.writeUnlock(); });
it('tryWriteLock returns null when read-locked', async () => { const rw = rwlock(); await rw.readLock(); const guard = rw.tryWriteLock(); assert.equal(guard, null); rw.readUnlock(); });
it('tryWriteLock returns null when write-locked', async () => { const rw = rwlock(); await rw.writeLock(); const guard = rw.tryWriteLock(); assert.equal(guard, null); rw.writeUnlock(); });});