Permalink
Browse files

Never access V8 from within Ruby GC.

  • Loading branch information...
1 parent ac42a9e commit 05e4c5766f66a301238c1da49691c8ef8a037152 @cowboyd committed Jun 15, 2011
Showing with 42 additions and 14 deletions.
  1. +23 −6 ext/v8/v8_handle.cpp
  2. +3 −4 ext/v8/v8_locker.cpp
  3. +1 −0 lib/v8.rb
  4. +0 −4 lib/v8/portal/proxies.rb
  5. +2 −0 specthread/spec_helper.rb
  6. +13 −0 specthread/threading_spec.rb
View
29 ext/v8/v8_handle.cpp
@@ -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() {
View
7 ext/v8/v8_locker.cpp
@@ -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);
View
1 lib/v8.rb
@@ -4,6 +4,7 @@
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'
View
4 lib/v8/portal/proxies.rb
@@ -43,7 +43,6 @@ def register_javascript_proxy(proxy, options = {})
@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 @@ def register_ruby_proxy(proxy, options = {})
@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 @@ def call(proxy, parameter)
rb = @js2rb[proxy]
@js2rb.delete(proxy)
@rb2js.delete(rb)
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-16 * 1024)
end
end
@@ -146,7 +143,6 @@ def call(proxy_id)
if js = @rb2js[proxy_id]
@rb2js.delete(proxy_id)
@js2rb.delete(js)
- V8::C::V8::AdjustAmountOfExternalAllocatedMemory(-8 * 1024)
end
end
end
View
2 specthread/spec_helper.rb
@@ -0,0 +1,2 @@
+require Pathname(__FILE__).dirname.join('../spec/spec_helper')
+
View
13 specthread/threading_spec.rb
@@ -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

0 comments on commit 05e4c57

Please sign in to comment.