mirror of
https://github.com/rubyjs/mini_racer
synced 2023-03-27 23:21:28 -04:00
FIX: issues with timeouts that happen in rubyland
(or timeouts that happen between rubyland and js land) still imperfect, but an improvement
This commit is contained in:
parent
671628d99d
commit
bcb3027e8f
2 changed files with 61 additions and 6 deletions
|
@ -110,11 +110,28 @@ static void init_v8() {
|
|||
platform_lock.unlock();
|
||||
}
|
||||
|
||||
static VALUE
|
||||
ruby_timeout_thread(VALUE data) {
|
||||
rb_funcall(data, rb_intern("raise"), 1, rb_eScriptTerminatedError);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
void* breaker(void *d) {
|
||||
EvalParams* data = (EvalParams*)d;
|
||||
Isolate* isolate = data->context_info->isolate_info->isolate;
|
||||
|
||||
usleep(data->timeout*1000);
|
||||
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
|
||||
V8::TerminateExecution(data->context_info->isolate_info->isolate);
|
||||
|
||||
// flag for termination
|
||||
isolate->SetData(2, (void*)true);
|
||||
|
||||
VALUE* ruby_thread = (VALUE*)isolate->GetData(1);
|
||||
if (ruby_thread == NULL) {
|
||||
V8::TerminateExecution(isolate);
|
||||
} else {
|
||||
rb_thread_create((VALUE(*)(...))&ruby_timeout_thread, (void*)*ruby_thread);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -131,7 +148,12 @@ nogvl_context_eval(void* arg) {
|
|||
Local<Context> context = eval_params->context_info->context->Get(isolate);
|
||||
Context::Scope context_scope(context);
|
||||
|
||||
// in gvl flag
|
||||
isolate->SetData(0, (void*)false);
|
||||
// ruby thread value
|
||||
isolate->SetData(1, (void*)NULL);
|
||||
// terminate ASAP
|
||||
isolate->SetData(2, (void*)false);
|
||||
|
||||
MaybeLocal<Script> parsed_script = Script::Compile(context, *eval_params->eval);
|
||||
result->parsed = !parsed_script.IsEmpty();
|
||||
|
@ -645,9 +667,19 @@ gvl_ruby_callback(void* data) {
|
|||
callback_data.args = ruby_args;
|
||||
callback_data.failed = false;
|
||||
|
||||
if ((bool)args->GetIsolate()->GetData(2) == true) {
|
||||
args->GetIsolate()->ThrowException(String::NewFromUtf8(args->GetIsolate(), "Terminated execution during tansition from Ruby to JS"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VALUE thread = rb_funcall(rb_cThread, rb_intern("current"), 0);
|
||||
args->GetIsolate()->SetData(1, (void*)&thread);
|
||||
|
||||
result = rb_rescue((VALUE(*)(...))&protected_callback, (VALUE)(&callback_data),
|
||||
(VALUE(*)(...))&rescue_callback, (VALUE)(&callback_data));
|
||||
|
||||
args->GetIsolate()->SetData(1, (void*)NULL);
|
||||
|
||||
if(callback_data.failed) {
|
||||
VALUE parent = rb_iv_get(self, "@parent");
|
||||
rb_iv_set(parent, "@current_exception", result);
|
||||
|
@ -663,6 +695,10 @@ gvl_ruby_callback(void* data) {
|
|||
xfree(ruby_args);
|
||||
}
|
||||
|
||||
if ((bool)args->GetIsolate()->GetData(2) == true) {
|
||||
V8::TerminateExecution(args->GetIsolate());
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -524,23 +524,42 @@ raise FooError, "I like foos"
|
|||
|
||||
def test_ruby_based_property_in_rval
|
||||
v8 = MiniRacer::Context.new
|
||||
v8.attach 'print', proc{|x| puts x}
|
||||
puts v8.eval "var o = {get bar() { print(42); }}; o"
|
||||
v8.attach 'echo', proc{|x| x}
|
||||
assert_equal({"bar" => 42}, v8.eval("var o = {get bar() { return echo(42); }}; o"))
|
||||
end
|
||||
|
||||
def test_function_rval
|
||||
context = MiniRacer::Context.new
|
||||
context.attach("print", proc{|msg| puts msg})
|
||||
context.eval "print('foo')"
|
||||
context.attach("echo", proc{|msg| msg})
|
||||
assert_equal("foo", context.eval("echo('foo')"))
|
||||
end
|
||||
|
||||
def test_timeout_in_ruby_land
|
||||
skip("This fails and should be fixed")
|
||||
context = MiniRacer::Context.new(timeout: 50)
|
||||
context.attach('sleep', proc{ sleep 0.1 })
|
||||
assert_raises(MiniRacer::ScriptTerminatedError) do
|
||||
context.eval('sleep(); "hi";')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
def test_undef_mem
|
||||
context = MiniRacer::Context.new(timeout: 5)
|
||||
|
||||
context.attach("marsh", proc do |a, b, c|
|
||||
return [a,b,c] if a.is_a?(MiniRacer::FailedV8Conversion) || b.is_a?(MiniRacer::FailedV8Conversion) || c.is_a?(MiniRacer::FailedV8Conversion)
|
||||
|
||||
a[rand(10000).to_s] = "a"
|
||||
b[rand(10000).to_s] = "b"
|
||||
c[rand(10000).to_s] = "c"
|
||||
[a,b,c]
|
||||
end)
|
||||
|
||||
assert_raises do
|
||||
# TODO make it raise the correct exception!
|
||||
context.eval("var a = [{},{},{}]; while(true) { a = marsh(a[0],a[1],a[2]); }")
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
class TestPlatform < MiniRacer::Platform
|
||||
|
|
Loading…
Add table
Reference in a new issue