Comparing version 0.2.1 to 0.2.2
@@ -0,1 +1,6 @@ | ||
# v0.2.2 | ||
* Fixed race condition in ReadWriteLocks | ||
* 100% unit test coverage | ||
# v0.2.1 | ||
@@ -2,0 +7,0 @@ |
@@ -5,3 +5,3 @@ { | ||
"description": "Mutex locks, Read/Write locks, Condition variables and Semaphores", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"scripts": [ | ||
@@ -8,0 +8,0 @@ "index.js", |
@@ -39,18 +39,19 @@ function ReadWriteLock() { | ||
this._waitingToRead.push(function () { | ||
function waiter() { | ||
clearTimeout(timer); | ||
if (!cb) { | ||
that.unlock(); | ||
return; | ||
if (cb) { | ||
var callback = cb; | ||
cb = null; | ||
callback.apply(that, arguments); | ||
} | ||
} | ||
cb.call(this); | ||
cb = null; | ||
}); | ||
this._waitingToRead.push(waiter); | ||
timer = setTimeout(function () { | ||
if (cb) { | ||
cb.call(this, new Error('ReadLock timed out')); | ||
cb = null; | ||
var index = that._waitingToRead.indexOf(waiter); | ||
if (index !== -1) { | ||
that._waitingToRead.splice(index, 1); | ||
waiter(new Error('ReadLock timed out')); | ||
} | ||
@@ -68,18 +69,19 @@ }, ttl); | ||
this._waitingToWrite.push(function () { | ||
function waiter() { | ||
clearTimeout(timer); | ||
if (!cb) { | ||
that.unlock(); | ||
return; | ||
if (cb) { | ||
var callback = cb; | ||
cb = null; | ||
callback.apply(that, arguments); | ||
} | ||
} | ||
cb.call(this); | ||
cb = null; | ||
}); | ||
this._waitingToWrite.push(waiter); | ||
timer = setTimeout(function () { | ||
if (cb) { | ||
cb.call(this, new Error('WriteLock timed out')); | ||
cb = null; | ||
var index = that._waitingToWrite.indexOf(waiter); | ||
if (index !== -1) { | ||
that._waitingToWrite.splice(index, 1); | ||
waiter(new Error('WriteLock timed out')); | ||
} | ||
@@ -86,0 +88,0 @@ }, ttl); |
{ | ||
"name": "locks", | ||
"version": "0.2.1", | ||
"version": "0.2.2", | ||
"description": "Mutex locks, Read/Write locks, Condition variables and Semaphores", | ||
@@ -5,0 +5,0 @@ "keywords": [ |
@@ -12,2 +12,6 @@ var locks = require('..'); | ||
t.throws(function () { | ||
cond.wait({}, function () {}); | ||
}, 'Objects are not valid conditions to wait for') | ||
t.equal(cond.get(), false, 'Condition starts false'); | ||
@@ -14,0 +18,0 @@ |
@@ -10,3 +10,26 @@ var locks = require('..'); | ||
var unlockedByNextLock = false; | ||
var instantTimedLockSuccess = false; | ||
mutex.timedLock(1, function () { | ||
instantTimedLockSuccess = true; | ||
mutex.unlock(); | ||
}); | ||
t.equal(instantTimedLockSuccess, true, 'Timed lock fired instantly'); | ||
t.throws(function () { | ||
mutex.unlock(); | ||
}, 'Cannot unlock an unlocked mutex'); | ||
mutex.lock(function () { | ||
setTimeout(function () { | ||
t.equal(unlockedByNextLock, false, 'Next lock is waiting'); | ||
mutex.unlock(); | ||
t.equal(unlockedByNextLock, true, 'Next lock executed'); | ||
}, 10); | ||
}); | ||
mutex.lock(function () { | ||
unlockedByNextLock = true; | ||
t.equal(mutex.isLocked, true, 'Locked'); | ||
@@ -13,0 +36,0 @@ |
@@ -5,2 +5,9 @@ var locks = require('..'); | ||
function baseTests(t, rwLock) { | ||
t.throws(function () { | ||
rwLock.unlock(); | ||
}, 'Cannot unlock an unlocked ReadWrite lock'); | ||
} | ||
function multiRead(t, rwLock) { | ||
@@ -42,2 +49,6 @@ t.equal(rwLock.isLocked, false, 'Unlocked'); | ||
count += 'W'; | ||
rwLock.readLock(function () { | ||
count += 'R'; | ||
}); | ||
}); | ||
@@ -55,7 +66,61 @@ | ||
rwLock.unlock(); | ||
t.equal(count, 'RRWR', 'Read-locked'); | ||
rwLock.unlock(); | ||
} | ||
function manyWriters(t, rwlock) { | ||
var count = ''; | ||
rwlock.writeLock(function () { | ||
count += 'W'; | ||
}); | ||
rwlock.writeLock(function () { | ||
count += 'W'; | ||
}); | ||
rwlock.writeLock(function () { | ||
count += 'W'; | ||
}); | ||
t.equal(count, 'W'); | ||
rwlock.unlock(); | ||
t.equal(count, 'WW'); | ||
rwlock.unlock(); | ||
t.equal(count, 'WWW'); | ||
rwlock.unlock(); | ||
} | ||
function triers(t, rwLock) { | ||
var success; | ||
success = rwLock.tryWriteLock(); | ||
t.equal(success, true, 'Try WriteLock success'); | ||
success = rwLock.tryWriteLock(); | ||
t.equal(success, false, 'Try WriteLock failure'); | ||
success = rwLock.tryReadLock(); | ||
t.equal(success, false, 'Try ReadLock failure'); | ||
rwLock.unlock(); | ||
success = rwLock.tryReadLock(); | ||
t.equal(success, true, 'Try ReadLock success'); | ||
success = rwLock.tryReadLock(); | ||
t.equal(success, true, 'Try ReadLock success'); | ||
success = rwLock.tryWriteLock(); | ||
t.equal(success, false, 'Try WriteLock failure'); | ||
rwLock.unlock(); | ||
rwLock.unlock(); | ||
} | ||
function timed(t, rwLock, cb) { | ||
rwLock.readLock(function () {}); | ||
// should fire instantly: | ||
rwLock.timedReadLock(10, function () {}); | ||
@@ -77,4 +142,30 @@ t.equal(rwLock.isLocked, 'R', 'Read-locked'); | ||
t.equal(rwLock.isLocked, 'R', 'Read-locked'); | ||
rwLock.unlock(); | ||
cb(); | ||
rwLock.timedWriteLock(10, function () { | ||
t.equal(rwLock.isLocked, 'W', 'Write-locked'); | ||
// write lock that times out: | ||
rwLock.timedWriteLock(1, function (error) { | ||
t.ok(error, 'Write-lock timed out'); | ||
rwLock.unlock(); | ||
t.equal(rwLock.isLocked, false, 'Unlocked'); | ||
// should fire instantly: | ||
rwLock.timedWriteLock(1000, function () {}); | ||
t.equal(rwLock.isLocked, 'W', 'Write-locked'); | ||
// write lock that times out: | ||
rwLock.timedReadLock(1, function (error) { | ||
t.ok(error, 'Read-lock timed out'); | ||
rwLock.unlock(); | ||
cb(); | ||
}); | ||
}); | ||
}); | ||
setTimeout(function () { | ||
rwLock.unlock(); | ||
}, 1); | ||
}); | ||
@@ -92,4 +183,7 @@ | ||
baseTests(t, rwLock); | ||
multiRead(t, rwLock); | ||
readWriteCombo(t, rwLock); | ||
manyWriters(t, rwLock); | ||
triers(t, rwLock); | ||
@@ -96,0 +190,0 @@ timed(t, rwLock, function () { |
@@ -6,5 +6,10 @@ var locks = require('..'); | ||
function testMany(t, cb) { | ||
var sem = locks.createSemaphore(2); // 2 available resources | ||
t.equal(sem._count, 2, 'Starts with 2 available resources'); | ||
var sem; | ||
sem = locks.createSemaphore(); // default resources should be 1 | ||
t.equal(sem._count, 1, 'Defaults to 2 available resources'); | ||
sem = locks.createSemaphore(2); // 2 available resources | ||
t.equal(sem._count, 2, 'Created with 2 available resources'); | ||
function fn() { | ||
@@ -11,0 +16,0 @@ process.nextTick(function () { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
19393
524