Offload functions to worker threads with shared memory primitives for Node.js.
8
fork

Configure Feed

Select the types of activity you want to include in your feed.

at e2cebd539403475e2f4e79d55ca1a84a0ce3510d 121 lines 3.0 kB view raw
1import { setTimeout } from 'node:timers/promises'; 2import { describe, it } from 'node:test'; 3import assert from 'node:assert/strict'; 4import { rwlock } from 'moroutine'; 5 6describe('RwLock', () => { 7 it('read lock and unlock', async () => { 8 const rw = rwlock(); 9 const guard = await rw.readLock(); 10 assert.equal(typeof guard[Symbol.dispose], 'function'); 11 rw.readUnlock(); 12 }); 13 14 it('write lock and unlock', async () => { 15 const rw = rwlock(); 16 const guard = await rw.writeLock(); 17 assert.equal(typeof guard[Symbol.dispose], 'function'); 18 rw.writeUnlock(); 19 }); 20 21 it('multiple readers can hold the lock concurrently', async () => { 22 const rw = rwlock(); 23 const g1 = await rw.readLock(); 24 const g2 = await rw.readLock(); 25 // Both acquired — success 26 rw.readUnlock(); 27 rw.readUnlock(); 28 }); 29 30 it('writer excludes readers', async () => { 31 const rw = rwlock(); 32 const order: string[] = []; 33 34 await rw.writeLock(); 35 order.push('write-start'); 36 37 const readerDone = (async () => { 38 const g = await rw.readLock(); 39 order.push('read'); 40 rw.readUnlock(); 41 })(); 42 43 await setTimeout(20); 44 order.push('write-end'); 45 rw.writeUnlock(); 46 47 await readerDone; 48 assert.deepEqual(order, ['write-start', 'write-end', 'read']); 49 }); 50 51 it('writer excludes other writers', async () => { 52 const rw = rwlock(); 53 const order: string[] = []; 54 55 await rw.writeLock(); 56 order.push('w1-start'); 57 58 const writer2Done = (async () => { 59 const g = await rw.writeLock(); 60 order.push('w2'); 61 rw.writeUnlock(); 62 })(); 63 64 await setTimeout(20); 65 order.push('w1-end'); 66 rw.writeUnlock(); 67 68 await writer2Done; 69 assert.deepEqual(order, ['w1-start', 'w1-end', 'w2']); 70 }); 71 72 it('ReadGuard dispose calls readUnlock', async () => { 73 const rw = rwlock(); 74 const guard = await rw.readLock(); 75 guard[Symbol.dispose](); 76 const wg = await rw.writeLock(); 77 rw.writeUnlock(); 78 }); 79 80 it('WriteGuard dispose calls writeUnlock', async () => { 81 const rw = rwlock(); 82 const guard = await rw.writeLock(); 83 guard[Symbol.dispose](); 84 const rg = await rw.readLock(); 85 rw.readUnlock(); 86 }); 87 88 it('self-allocates', () => { 89 const rw = rwlock(); 90 assert.ok(rw); 91 }); 92 93 it('exposes byteSize of 4', () => { 94 assert.equal(rwlock.byteSize, 4); 95 }); 96 97 it('wakes all waiting readers when writer unlocks', async () => { 98 const rw = rwlock(); 99 100 await rw.writeLock(); 101 102 const reader1Done = (async () => { 103 const g = await rw.readLock(); 104 rw.readUnlock(); 105 return 'r1'; 106 })(); 107 108 const reader2Done = (async () => { 109 const g = await rw.readLock(); 110 rw.readUnlock(); 111 return 'r2'; 112 })(); 113 114 // Let readers queue up 115 await setTimeout(20); 116 rw.writeUnlock(); 117 118 const results = await Promise.all([reader1Done, reader2Done]); 119 assert.deepEqual(results.sort(), ['r1', 'r2']); 120 }); 121});