I find myself in a bit of a quandry.
I have a large application which has Google's V8 javascript engine. Some calls are made to the V8 engine on the UI thread. To be nice to the user like everyone recommends, some long operations are run on a separate thread, without hanging the UI thread. However, these long running operations also make calls in to the V8 javascript engine. So multiple threads call in to V8.
Thing is, V8 appears to use thread local storage. This seems to be making my application randomly explode. It's definitely in the class of "How was this possibley working up till now?" bugs.
Without significantly re-architecting my application, I propose an ugly, ugly horrible super-hack: can I make V8 think it's running on a different thread?
In other words, the first time I make a call in to V8, I make a note of the thread. Then, for all other calls to V8, I somehow spoof the thread so the thread local storage/whatever else thread-dependent works.
Can it be done? Will it work? Am I stupid to even consider such a scummy hack?
You should not spoof anything. Instead you should tell V8 that you are trying to use it from the different thread.
In V8 prior to the version 3.2 the only way to do that is to use v8::Locker
before using V8 from the different thread. It guarantees both exclusive access to the V8 and initializes internal structures stored in TLS. For more details see http://code.google.com/p/v8/source/browse/branches/3.1/include/v8.h#3189
Starting from the version 3.2 V8 has the concept of isolate. If you are not creating isolates explicitly, V8 implicitly creates the default isolate to keep API compatible. In this case you can still simply use v8::Locker
as in older versions. If you are creating isolates explicitly then in addition to acquiring exclusive access with v8::Locker
you also have to enter&exit them explicitly in your threads using v8::Isolate::Enter
/v8::Isolate::Exit
methods or v8::Isolate::Scope
. For more details see http://code.google.com/p/v8/source/browse/trunk/include/v8.h#3510
So simple answer that will work in most cases is: use v8::Locker
before using V8 from the different thread.
I had the same problem and managed to find the solution partly through this thread. To elaborate on VE's answer, you can not use v8 from multiple threads by default. If you want to, you have to use isolates and locks.
The problem is that you can not go half way, you can't use locks only unless you completely exit and destruct your JS context. Since this is not the case in most non-trivial cases you have to go all the way, and
Create your own v8::Isolate
. You can make this global, but (as I understand it) it can not be the default one (because the default one is already in the entered state).
In all your functions that call v8 (and are not guaranteed to be internal) you must enter your isolate (use v8::Isolate::Scope
) and
also use 'v8::Locker' objects.
I wrote a small helper object that I use in my public methods and it looks a bit like this:
class SessionLock {
private:
v8::Isolate::Scope scope;
v8::Locker lock;
public:
SessionLock() : scope(getSessionIsolate()), lock(getSessionIsolate()) {}
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With