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;
|
||||
}
|
||||
|
||||
v8_handle::~v8_handle() {
|
||||
handle.Dispose();
|
||||
handle.Clear();
|
||||
dead = true;
|
||||
}
|
||||
v8_handle::~v8_handle() {}
|
||||
|
||||
namespace {
|
||||
VALUE handle_queue;
|
||||
|
||||
void v8_handle_mark(v8_handle* handle) {
|
||||
rb_gc_mark(handle->weakref_callback);
|
||||
rb_gc_mark(handle->weakref_callback_parameters);
|
||||
|
@ -26,6 +24,21 @@ namespace {
|
|||
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) {
|
||||
if (RTEST(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, "IsNearDeath", IsNearDeath, 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) {
|
||||
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() {
|
||||
|
|
|
@ -66,8 +66,8 @@ namespace {
|
|||
* 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
|
||||
*/
|
||||
VALUE New(VALUE UnockerClass) {
|
||||
Unlocker unlocker = new Unlocker();
|
||||
VALUE New(VALUE UnlockerClass) {
|
||||
Unlocker* unlocker = new Unlocker();
|
||||
return Data_Wrap_Struct(UnlockerClass, 0, 0, (void*)unlocker);
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ namespace {
|
|||
*/
|
||||
VALUE Delete(VALUE self) {
|
||||
Unlocker* unlocker;
|
||||
Data_Get_Struct(self, class Locker, locker);
|
||||
Data_Get_Struct(self, class Unlocker, unlocker);
|
||||
delete unlocker;
|
||||
}
|
||||
}
|
||||
|
@ -126,7 +126,6 @@ namespace {
|
|||
}
|
||||
|
||||
void rr_init_v8_locker() {
|
||||
VALUE V8 = rb_define_module("V8");
|
||||
VALUE LockerClass = rr_define_class("Locker");
|
||||
VALUE UnlockerClass = rr_define_class("Unlocker");
|
||||
rr_define_singleton_method(LockerClass, "new", Lock::New, 0);
|
||||
|
|
|
@ -4,6 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|||
module V8
|
||||
require 'v8/version'
|
||||
require 'v8/v8' #native glue
|
||||
require 'v8/c/locker'
|
||||
require 'v8/portal'
|
||||
require 'v8/portal/caller'
|
||||
require 'v8/portal/proxies'
|
||||
|
|
|
@ -43,7 +43,6 @@ module V8
|
|||
@js_proxies_js2rb[proxy] = target
|
||||
@js_proxies_rb2js[target] = proxy
|
||||
proxy.MakeWeak(nil, @clear_js_proxy)
|
||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(16 * 1024)
|
||||
end
|
||||
|
||||
# Lookup the JavaScript proxy for a natively Ruby object
|
||||
|
@ -66,7 +65,6 @@ module V8
|
|||
@rb_proxies_rb2js[proxy.object_id] = target
|
||||
@rb_proxies_js2rb[target] = proxy.object_id
|
||||
ObjectSpace.define_finalizer(proxy, @clear_rb_proxy)
|
||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(8 * 1024)
|
||||
end
|
||||
|
||||
# Looks up the Ruby proxy for an object that is natively JavaScript
|
||||
|
@ -115,7 +113,6 @@ module V8
|
|||
rb = @js2rb[proxy]
|
||||
@js2rb.delete(proxy)
|
||||
@rb2js.delete(rb)
|
||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-16 * 1024)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -146,7 +143,6 @@ module V8
|
|||
if js = @rb2js[proxy_id]
|
||||
@rb2js.delete(proxy_id)
|
||||
@js2rb.delete(js)
|
||||
V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-8 * 1024)
|
||||
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