Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Thread Local Storage be faked/hacked?

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?

like image 357
AshleysBrain Avatar asked Dec 01 '22 07:12

AshleysBrain


2 Answers

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.

like image 158
Vyacheslav Egorov Avatar answered Dec 09 '22 14:12

Vyacheslav Egorov


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

  1. 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).

  2. In all your functions that call v8 (and are not guaranteed to be internal) you must enter your isolate (use v8::Isolate::Scope) and

  3. 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()) {}
};
like image 45
Fozi Avatar answered Dec 09 '22 14:12

Fozi