I believe that, in Ruby 1.8, Continuation.call raises
RuntimeError.new "continuation called across trap"
in situations that should be allowed.
The error occurs when the current cont_protect context is different from
the one that was stored in the continuation object when it was created
(with callcc).
cont_protect is assigned a new unique value whenever a trap is executed.
The original intent seems to have been to ensure that a continuation
created in one trap context (or in the main context) did not get called
on
another. This certainly makes sense, as I could see where Unix signal
handling would be corrupted if the stack were replaced while processing
a different trap.
However...
cont_protect is also assigned a new unique value whenever as string is
evaluated. It is also assigned by rb_protect(), which is exported from
eval.c and used by extensions to handle exceptions raised by ruby code.
As a consequence, for instance, one cannot call an continuation created
(with callcc) while evaluating a string in any other eval string.
The error message in these cases is incorrect, for the problem has
nothing to do with traps of any kind.
Further, I cannot see why an exception is raised at all.
As an experiment, I modified rb_protect() as follows:
VALUE
rb_protect(proc, data, state)
VALUE (*proc) _((VALUE));
VALUE data;
int * volatile state;
{
VALUE result = Qnil;
int status;
PUSH_TAG(PROT_NONE);
if ((status = EXEC_TAG()) == 0) {
result = (*proc)(data);
}
POP_TAG();
if (state) {
*state = status;
}
return result;
}
And I renamed the original rb_protect() to rb_trap_protect() and
gave it "static" linkage. I then modified rb_trap_eval to call
rb_trap_protect() instead of rb_protect().
With this change cont_protect is *only* modified when a trap is
evaluated.
This suppressed the bogus exceptions that had been raised by
Continuation#call and "fixes" my application.
Note, that I'm not the first person to complain about this.
See:
http://www.ruby-forum.com/topic/82927
The self contained test case presented in topic 82927 deals with
continuations across forks, but the issue is related and both are
corrected by the change I proposed above.
Is there really some reason that Continuation.call should be this
restrictive?
If we agree there is none, would you like me to submit this as a
(trivial) patch? It clearly makes the common case of rb_protect()
faster and leaves the eval_trap case unchanged.
- brent
on 2012-11-30 20:42
Please log in before posting. Registration is free and takes only a minute.
Existing account
(Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
Log in with Google account | Log in with Yahoo account
No account? Register here.