Permalink
Browse files

Wrap V8 calls with lock

  • Loading branch information...
1 parent 8c64ffb commit a48bc7c7ad03bec4f8abde1fa76c95cccc59f818 @josh josh committed Jun 8, 2011
Showing with 28 additions and 4 deletions.
  1. +28 −4 lib/execjs/ruby_racer_runtime.rb
View
32 lib/execjs/ruby_racer_runtime.rb
@@ -4,8 +4,10 @@ class Context
def initialize(source = "")
source = source.encode('UTF-8') if source.respond_to?(:encode)
- @v8_context = ::V8::Context.new
- @v8_context.eval(source)
+ lock do
+ @v8_context = ::V8::Context.new
+ @v8_context.eval(source)
+ end
end
def exec(source, options = {})
@@ -20,7 +22,9 @@ def eval(source, options = {})
source = source.encode('UTF-8') if source.respond_to?(:encode)
if /\S/ =~ source
- unbox @v8_context.eval("(#{source})")
+ lock do
+ unbox @v8_context.eval("(#{source})")
+ end
end
rescue ::V8::JSError => e
if e.value["name"] == "SyntaxError"
@@ -31,7 +35,9 @@ def eval(source, options = {})
end
def call(properties, *args)
- unbox @v8_context.eval(properties).call(*args)
+ lock do
+ unbox @v8_context.eval(properties).call(*args)
+ end
rescue ::V8::JSError => e
if e.value["name"] == "SyntaxError"
raise RuntimeError, e.message
@@ -59,6 +65,24 @@ def unbox(value)
value
end
end
+
+ private
+ def lock
+ result, exception = nil, nil
+ V8::C::Locker() do
+ begin
+ result = yield
+ rescue Exception => e
+ exception = e
+ end
+ end
+
+ if exception
+ raise exception
+ else
+ result
+ end
+ end
end
def name

2 comments on commit a48bc7c

@cowboyd

Looks good Josh. The one caveat is that if somebody uses V8 from another thread first and does not properly lock, then ExecJS will still die even though it is locking correctly. If ExecJS happens to use V8 first, then the other thread will die if it runs without locking. That should be rare and easily fixed (by wrapping the offender it in a lock), but just wanted to make sure you know in case someone runs into it.

@sheldonh

Awesome, thanks for this. Now rails-3.1 is a pleasure!

Please sign in to comment.