chasing a double-release

This commit is contained in:
Danny Yoo 2011-12-04 20:04:03 -05:00
parent ccdb0c88f6
commit 46f314ea35
3 changed files with 40 additions and 22 deletions

View File

@ -128,16 +128,24 @@
var coerseClosureToJavaScript = function (v, MACHINE) { var coerseClosureToJavaScript = function (v, MACHINE) {
var f = function (succ, fail) { var f = function (succ, fail) {
var args = [];
var i;
for (i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
MACHINE.exclusiveLock.acquire( MACHINE.exclusiveLock.acquire(
"js-as-closure", "js-as-closure",
function(releaseLock) { function(releaseLock) {
succ = succ || function () {}; succ = succ || function () {};
fail = fail || function () {}; fail = fail || function () {};
if (!(baselib.arity.isArityMatching(v.racketArity, arguments.length - 2))) { releaseLock();
if (!(baselib.arity.isArityMatching(v.racketArity, args.length - 2))) {
var msg = baselib.format.format( var msg = baselib.format.format(
"arity mismatch: ~s expected ~s argument(s) but received ~s", "arity mismatch: ~s expected ~s argument(s) but received ~s",
[v.displayName, v.racketArity, arguments.length - 2]); [v.displayName, v.racketArity, args.length - 2]);
return fail(new baselib.exceptions.RacketError( return fail(new baselib.exceptions.RacketError(
msg, msg,
baselib.exceptions.makeExnFailContractArity(msg, baselib.exceptions.makeExnFailContractArity(msg,
@ -177,10 +185,10 @@
MACHINE.c.push( MACHINE.c.push(
new baselib.frames.CallFrame(afterGoodInvoke, v)); new baselib.frames.CallFrame(afterGoodInvoke, v));
MACHINE.a = arguments.length - 2; MACHINE.a = args.length - 2;
var i; var i;
for (i = 0; i < arguments.length - 2; i++) { for (i = 0; i < args.length - 2; i++) {
MACHINE.e.push(arguments[arguments.length - 1 - i]); MACHINE.e.push(args[args.length - 1 - i]);
} }
MACHINE.p = v; MACHINE.p = v;
MACHINE.params['currentErrorHandler'] = function (MACHINE, e) { MACHINE.params['currentErrorHandler'] = function (MACHINE, e) {
@ -191,7 +199,6 @@
fail(e); fail(e);
}; };
releaseLock();
MACHINE.trampoline(v.label); MACHINE.trampoline(v.label);
}); });
}; };
@ -222,15 +229,20 @@
// internallCallDuringPause: call a Racket procedure and get its results. // internallCallDuringPause: call a Racket procedure and get its results.
// The use assumes the machine is in a running-but-paused state. // The use assumes the machine is in a running-but-paused state.
var internalCallDuringPause = function (MACHINE, proc, success, fail) { var internalCallDuringPause = function (MACHINE, proc, success, fail) {
var args = [];
var i;
for (i = 0; i < arguments.length; i++) {
args.push(arguments[i]);
}
MACHINE.exclusiveLock.acquire( MACHINE.exclusiveLock.acquire(
"internal call during pause", "internal call during pause",
function(releaseLock) { function(releaseLock) {
releaseLock();
var i; var i;
var oldArgcount, oldVal, oldProc, oldErrorHandler; var oldArgcount, oldVal, oldProc, oldErrorHandler;
if (! baselib.arity.isArityMatching(proc.racketArity, arguments.length - 4)) { if (! baselib.arity.isArityMatching(proc.racketArity, args.length - 4)) {
var msg = baselib.format.format("arity mismatch: ~s expected ~s arguments, but received ~s", var msg = baselib.format.format("arity mismatch: ~s expected ~s arguments, but received ~s",
[proc.displayName, proc.racketArity, arguments.length - 4]); [proc.displayName, proc.racketArity, args.length - 4]);
return fail(baselib.exceptions.makeExnFailContractArity(msg, return fail(baselib.exceptions.makeExnFailContractArity(msg,
MACHINE.captureContinuationMarks())); MACHINE.captureContinuationMarks()));
} }
@ -268,9 +280,9 @@
MACHINE.c.push( MACHINE.c.push(
new baselib.frames.CallFrame(afterGoodInvoke, proc)); new baselib.frames.CallFrame(afterGoodInvoke, proc));
MACHINE.a = arguments.length - 4; MACHINE.a = args.length - 4;
for (i = 0; i < arguments.length - 4; i++) { for (i = 0; i < args.length - 4; i++) {
MACHINE.e.push(arguments[arguments.length - 1 - i]); MACHINE.e.push(args[args.length - 1 - i]);
} }
MACHINE.p = proc; MACHINE.p = proc;
MACHINE.params['currentErrorHandler'] = function (MACHINE, e) { MACHINE.params['currentErrorHandler'] = function (MACHINE, e) {
@ -281,7 +293,6 @@
fail(e); fail(e);
}; };
releaseLock();
MACHINE.trampoline(proc.label); MACHINE.trampoline(proc.label);
} else { } else {

View File

@ -191,29 +191,36 @@
if (id === undefined) { if (id === undefined) {
id = ExclusiveLock.makeRandomNonce(); id = ExclusiveLock.makeRandomNonce();
} }
var alreadyReleased = false;
// Allow for re-entrancy if the id is the same as the // Allow for re-entrancy if the id is the same as the
// entity who is locking. // entity who is locking.
if (this.locked === false || this.locked === id) { if (this.locked === false || this.locked === id) {
this.locked = id; this.locked = id;
setTimeout(
function() {
onAcquire.call( onAcquire.call(
that, that,
// NOTE: the caller must release the lock or else deadlock! // releaseLock
function() {
setTimeout(
function() { function() {
var waiter; var waiter;
if (alreadyReleased) {
throw new Error(
"Internal error: trying to release the lock, but already released");
}
if (that.locked === false) { if (that.locked === false) {
throw new Error( throw new Error(
"Internal error: trying to unlock the lock, but already unlocked"); "Internal error: trying to unlock the lock, but already unlocked");
} }
that.locked = false; that.locked = false;
alreadyReleased = true;
if (that.waiters.length > 0) { if (that.waiters.length > 0) {
waiter = that.waiters.shift(); waiter = that.waiters.shift();
that.acquire(waiter.id, waiter.onAcquire); that.acquire(waiter.id, waiter.onAcquire);
} }
}, 0);
}); });
},
0);
} else { } else {
this.waiters.push({ id: id, this.waiters.push({ id: id,
onAcquire: onAcquire } ); onAcquire: onAcquire } );

View File

@ -7,4 +7,4 @@
(provide version) (provide version)
(: version String) (: version String)
(define version "1.100") (define version "1.101")