mirror of
https://github.com/rubyjs/therubyracer
synced 2023-03-27 23:21:42 -04:00
Never access V8 from within Ruby GC.
This commit is contained in:
parent
ac42a9e295
commit
05e4c5766f
6 changed files with 42 additions and 14 deletions
|
@ -10,13 +10,11 @@ v8_handle::v8_handle(Handle<void> handle) : handle(Persistent<void>::New(handle)
|
||||||
this->dead = false;
|
this->dead = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
v8_handle::~v8_handle() {
|
v8_handle::~v8_handle() {}
|
||||||
handle.Dispose();
|
|
||||||
handle.Clear();
|
|
||||||
dead = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
VALUE handle_queue;
|
||||||
|
|
||||||
void v8_handle_mark(v8_handle* handle) {
|
void v8_handle_mark(v8_handle* handle) {
|
||||||
rb_gc_mark(handle->weakref_callback);
|
rb_gc_mark(handle->weakref_callback);
|
||||||
rb_gc_mark(handle->weakref_callback_parameters);
|
rb_gc_mark(handle->weakref_callback_parameters);
|
||||||
|
@ -26,6 +24,21 @@ namespace {
|
||||||
delete handle;
|
delete handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void v8_handle_enqueue(v8_handle* handle) {
|
||||||
|
handle->dead = true;
|
||||||
|
VALUE zombie = Data_Wrap_Struct(rr_v8_handle_class(), 0, v8_handle_free, handle);
|
||||||
|
rb_ary_unshift(handle_queue, zombie);
|
||||||
|
}
|
||||||
|
|
||||||
|
void v8_handle_dequeue(GCType type, GCCallbackFlags flags) {
|
||||||
|
for (VALUE handle = rb_ary_pop(handle_queue); RTEST(handle); handle = rb_ary_pop(handle_queue)) {
|
||||||
|
v8_handle* dead = NULL;
|
||||||
|
Data_Get_Struct(handle, struct v8_handle, dead);
|
||||||
|
dead->handle.Dispose();
|
||||||
|
dead->handle.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
VALUE New(VALUE self, VALUE handle) {
|
VALUE New(VALUE self, VALUE handle) {
|
||||||
if (RTEST(handle)) {
|
if (RTEST(handle)) {
|
||||||
Persistent<void> that = rr_v8_handle<void>(handle);
|
Persistent<void> that = rr_v8_handle<void>(handle);
|
||||||
|
@ -101,11 +114,15 @@ void rr_init_handle() {
|
||||||
rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0);
|
rr_define_method(HandleClass, "ClearWeak", ClearWeak, 0);
|
||||||
rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0);
|
rr_define_method(HandleClass, "IsNearDeath", IsNearDeath, 0);
|
||||||
rr_define_method(HandleClass, "IsWeak", IsWeak, 0);
|
rr_define_method(HandleClass, "IsWeak", IsWeak, 0);
|
||||||
|
|
||||||
|
handle_queue = rb_ary_new();
|
||||||
|
rb_gc_register_address(&handle_queue);
|
||||||
|
V8::AddGCPrologueCallback(v8_handle_dequeue);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) {
|
VALUE rr_v8_handle_new(VALUE klass, v8::Handle<void> handle) {
|
||||||
v8_handle* new_handle = new v8_handle(handle);
|
v8_handle* new_handle = new v8_handle(handle);
|
||||||
return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_free, new_handle);
|
return Data_Wrap_Struct(klass, v8_handle_mark, v8_handle_enqueue, new_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE rr_v8_handle_class() {
|
VALUE rr_v8_handle_class() {
|
||||||
|
|
|
@ -66,8 +66,8 @@ namespace {
|
||||||
* For details on V8 locking semantics, see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
|
* For details on V8 locking semantics, see the locking {API http://izs.me/v8-docs/classv8_1_1Unlocker.html}
|
||||||
* @return [V8::C::Unocker] the new locker
|
* @return [V8::C::Unocker] the new locker
|
||||||
*/
|
*/
|
||||||
VALUE New(VALUE UnockerClass) {
|
VALUE New(VALUE UnlockerClass) {
|
||||||
Unlocker unlocker = new Unlocker();
|
Unlocker* unlocker = new Unlocker();
|
||||||
return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker);
|
return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ namespace {
|
||||||
*/
|
*/
|
||||||
VALUE Delete(VALUE self) {
|
VALUE Delete(VALUE self) {
|
||||||
Unlocker* unlocker;
|
Unlocker* unlocker;
|
||||||
Data_Get_Struct(self, class Locker, locker);
|
Data_Get_Struct(self, class Unlocker, unlocker);
|
||||||
delete unlocker;
|
delete unlocker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -126,7 +126,6 @@ namespace {
|
||||||
}
|
}
|
||||||
|
|
||||||
void rr_init_v8_locker() {
|
void rr_init_v8_locker() {
|
||||||
VALUE V8 = rb_define_module("V8");
|
|
||||||
VALUE LockerClass = rr_define_class("Locker");
|
VALUE LockerClass = rr_define_class("Locker");
|
||||||
VALUE UnlockerClass = rr_define_class("Unlocker");
|
VALUE UnlockerClass = rr_define_class("Unlocker");
|
||||||
rr_define_singleton_method(LockerClass, "new", Lock::New, 0);
|
rr_define_singleton_method(LockerClass, "new", Lock::New, 0);
|
||||||
|
|
|
@ -4,6 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
||||||
module V8
|
module V8
|
||||||
require 'v8/version'
|
require 'v8/version'
|
||||||
require 'v8/v8' #native glue
|
require 'v8/v8' #native glue
|
||||||
|
require 'v8/c/locker'
|
||||||
require 'v8/portal'
|
require 'v8/portal'
|
||||||
require 'v8/portal/caller'
|
require 'v8/portal/caller'
|
||||||
require 'v8/portal/proxies'
|
require 'v8/portal/proxies'
|
||||||
|
|
|
@ -43,7 +43,6 @@ module V8
|
||||||
@js_proxies_js2rb[proxy] = target
|
@js_proxies_js2rb[proxy] = target
|
||||||
@js_proxies_rb2js[target] = proxy
|
@js_proxies_rb2js[target] = proxy
|
||||||
proxy.MakeWeak(nil, @clear_js_proxy)
|
proxy.MakeWeak(nil, @clear_js_proxy)
|
||||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(16 * 1024)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Lookup the JavaScript proxy for a natively Ruby object
|
# Lookup the JavaScript proxy for a natively Ruby object
|
||||||
|
@ -66,7 +65,6 @@ module V8
|
||||||
@rb_proxies_rb2js[proxy.object_id] = target
|
@rb_proxies_rb2js[proxy.object_id] = target
|
||||||
@rb_proxies_js2rb[target] = proxy.object_id
|
@rb_proxies_js2rb[target] = proxy.object_id
|
||||||
ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
|
ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
|
||||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(8 * 1024)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Looks up the Ruby proxy for an object that is natively JavaScript
|
# Looks up the Ruby proxy for an object that is natively JavaScript
|
||||||
|
@ -115,7 +113,6 @@ module V8
|
||||||
rb = @js2rb[proxy]
|
rb = @js2rb[proxy]
|
||||||
@js2rb.delete(proxy)
|
@js2rb.delete(proxy)
|
||||||
@rb2js.delete(rb)
|
@rb2js.delete(rb)
|
||||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-16 * 1024)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -146,7 +143,6 @@ module V8
|
||||||
if js = @rb2js[proxy_id]
|
if js = @rb2js[proxy_id]
|
||||||
@rb2js.delete(proxy_id)
|
@rb2js.delete(proxy_id)
|
||||||
@js2rb.delete(js)
|
@js2rb.delete(js)
|
||||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-8 * 1024)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
2
specthread/spec_helper.rb
Normal file
2
specthread/spec_helper.rb
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
require Pathname(__FILE__).dirname.join('../spec/spec_helper')
|
||||||
|
|
13
specthread/threading_spec.rb
Normal file
13
specthread/threading_spec.rb
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe "using v8 from multiple threads" do
|
||||||
|
|
||||||
|
it "is possible" do
|
||||||
|
Thread.new do
|
||||||
|
require 'v8'
|
||||||
|
V8::Context.new
|
||||||
|
end.join
|
||||||
|
V8::Context.new
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue