V8 order of instantiating the variables (multi-thread) - c++

I'm new with Google's V8 and I'm not sure how to fully use the variable types they give. I'll start by explaining what i wish to flow to be:
In the main thread I want to compile the JS scripts.
In several threads I want to run scripts when I "add" to the context different information using instance->SetAccessor(...) or prototype->Set(...) (or any other option if there is.
I am not sure when I need to do the following:
where and when to create the v8::handleScope? is creating one in the main thread is enough? or I need one for each thread?
where and when to create v8::isolate and v8::locker? should it be per thread or not? should it be before or after the v8::handleScope?
Any info will help (:

If you want to run the scripts in parallel from each thread with no cross-thread sharing, then each thread needs its own isolate. You may or may not actually need one for the main thread, or you could maybe use the default isolate. I'd recommend making sure that the default isolate has been initialized before running any threads though, just in case one of your other threads ends up initializing it. You should be ok if you are using isolates but it won't do any harm to be sure.
If you need cross-thread sharing of objects etc then you'll need to research this and it is likely to be difficult. Not even sure if v8 can really support it yet or not. Having separate isolates and avoiding sharing of objects is much easier.
You should be able to compile your scripts in the context of an isolate intended for the thread that is going to execute it in the main thread and then pass the script and the isolate to the thread and not touch either again in the main thread until the worker thread is done with it. This ought to work, but I've not checked if v8 checks the thread-id that the isolate was created in and the one it executes in. It's worth writing a little test app to check that this will work.
The other option is to check the compilation in the main thread and compile it again in the worker thread and encapsulate the isolate in the thread. This is the way I have done it in the past. It's easier but less efficient.
The handle scope should be allocated on the stack only in the functions where it is needed. Don't use a global variable for the handle scope or allocate it on the heap.
Your compiled script should use a persistent handle.
Enter the handle scope after you have entered the isolate scope.

Related

Is it correct to use std::async for background tasks inside an internal thread (not from main process's thread)

I would like to have your opinion for this general technical concept. (I am working on microsoft windows OS)
There is a Process, this process creates multiple threads for different tasks.
Main process: it is a windows service written by C# code.
There are several threads that are create inside the main process: Thread_01, Thread_02, ...
Inside Thread_01: There is a Wrapper dll written in managed C++ to consume DLL_01. (DLL_01 is a dll written by me in native C++ code, that provides some APIs: Add, Remove, Connect)
Add and Remove can run very fast, but Connect may take more than 10 seconds and blocks the caller until it finishes.
I am thinking to use std::async to do the Connect function code, and send the result through a callback to the caller (main process).
Is it a good approach? I heard we cannot create or it is better not to create any thread inside inner threads, is it true? If so, how about std::async ?
Any recommendation is appreciated.
Thanks in advance,
None of what you describe makes the use of threads inacceptable for your code.
As usual, threads have issues that need to be cared for:
Data races due to access to shared data.
Problems of ownership of resources is now not just "Who own what?" but "Who and when owns what?".
When a thread is blocked and you want to abort this operation, how do you cancel it without causing issues down the line? In your case, you must avoid calling the callback, when the receiver doesn't exist any more.
Concerning your approach of using a callback, consider std::future<> instead. This takes care of a few of the issues above, though some are only shifted to the caller instead.

How do I use v8 in a thread?

I'm trying to use v8 from c++ inside a thread that isn't the main thread. There's no multi-threading as far as v8 is concerned, all v8 objects are created and destroyed within that thread. Nothing is running in parallel, nothing is being shared. When I run my program from the main thread, everything works fine. When I have the v8 stuff in another thread, I get segmentation fault when I create a v8::HandleScope.
I can't find any useful documentation on how threading is actually addressed with v8. The instruction "use isolates and lockers" pops up often when searching, but I can't find any examples on how this is done. There's this API doc on v8::Isolate, but nothing on that page tells me if I need them in my specific case (I'm not sharing memory or executing in parallel). The docs on v8::Locker() don't even have information about what the class is for. The included samples in the project don't deal with any of this either.
So my questions are...
Do I need to use isolates and/or lockers here?
Could I get a minimal example of how to use them? Even pseudo-code or something would be really useful
You do need V8::Locker in the methods that will be working with the context when calling HandleScope. https://github.com/jasondelponte/go-v8/blob/master/src/v8context.cc#L41 is an example of how I've use the locker with v8. In this example it is used with multiple threads, but I believe the rule applies with single threads also.
Isolates are only needed when you want multiple instances of v8 in parallel.
https://groups.google.com/forum/?fromgroups=#!topic/v8-users/FXpeTYuAqKI Is an old thread I found a bit ago that helped me solve my problem with the library crashing as soon as HandleScope local variable was created.

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?
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()) {}
};

Changing Thread Task?

I know you cannot kill a boost thread, but can you change it's task?
Currently I have an array of 8 threads. When a button is pressed, these threads are assigned a task. The task which they are assigned to do is completely independent of the main thread and the other threads. None of the the threads have to wait or anything like that, so an interruption point is never reach.
What I need is to is, at anytime, change the task that each thread is doing. Is this possible? I have tried looping through the array of threads and changing what each thread object points to to a new one, but of course that doesn't do anything to the old threads.
I know you can interrupt pThreads, but I cannot find a working link to download the library to check it out.
A thread is not some sort of magical object that can be made to do things. It is a separate path of execution through your code. Your code cannot be made to jump arbitrarily around its codebase unless you specifically program it to do so. And even then, it can only be done within the rules of C++ (ie: calling functions).
You cannot kill a boost::thread because killing a thread would utterly wreck some of the most fundamental assumptions a programmer makes. You now have to take into account the possibility that the next line doesn't execute for reasons that you can neither predict nor prevent.
This isn't like exception handling, where C++ specifically requires destructors to be called, and you have the ability to catch exceptions and do special cleanup. You're talking about executing one piece of code, then suddenly inserting a call to some random function in the middle of already compiled code. That's not going to work.
If you want to be able to change the "task" of a thread, then you need to build that thread with "tasks" in mind. It needs to check every so often that it hasn't been given a new task, and if it has, then it switches to doing that. You will have to define when this switching is done, and what state the world is in when switching happens.

Hibernating/restarting a thread

I'm looking for a way to restart a thread, either from inside that thread's context or from outside the thread, possibly from within another process. (Any of these options will work.) I am aware of the difficulty of hibernating entire processes, and I'm pretty sure that those same difficulties attend to threads. However, I'm asking anyway in the hopes that someone has some insight.
My goal is to pause, save to file, and restart a running thread from its exact context with no modification to that thread's code, or rather, modification in only a small area - i.e., I can't go writing serialization functions throughout the code. The main block of code must be unmodified, and will not have any global/system handles (file handles, sockets, mutexes, etc.) Really down-and-dirty details like CPU registers do not need to be saved; but basically the heap, stack, and program counter should be saved, and anything else required to get the thread running again logically correctly from its save point. The resulting state of the program should be no different, if it was saved or not.
This is for a debugging program for high-reliability software; the goal is to run simulations of the software with various scripts for input, and be able to pause a running simulation and then restart it again later - or get the sim to a branch point, save it, make lots of copies and then run further simulations from the common starting point. This is why the main program cannot be modified.
The main thread language is in C++, and should run on Windows and Linux, however if there is a way to only do this on one system, then that's acceptable too.
Thanks in advance.
I think what you're asking is much more complicated than you think. I am not too familiar with Windows programming but here are some of the difficulties you'll face in Linux.
A saved thread can only be restored from the root process that originally spawned the thread, otherwise the dynamic libraries would be broken. Because of this saving to disk is essentially meaningless. The reason is dynamic libraries are loaded at different address each time they're loaded. The only way around this would be to take complete control of dynamically linking, no small feat. It's possible, but pretty scary.
The suspended thread will have variables in the the heap. You'd need to be able to find all globals 'owned' by the thread. The 'owned' state of any piece of the heap cannot be determined. In the future it may be possible with the C++0x's garbage collection ABI. You can't just assume the whole stack belongs to the thread to be paused. The main thread uses the heap when creating threads. So blowing away the heap when deserializing the paused thread would break the main thread.
You need to address the issues with globals. And not just the globals from created in the threads. Globals (or statics) can and often are created in dynamic libraries.
There are more resources to a program than just memory. You have file handles, network sockets, database connections, etc. A file handle is just a number. serializing its memory is completely meaningless without the context of the process the file was opened in.
All that said. I don't think the core problem is impossible, just that you should consider a different approach.
Anyway to try to implement this the thread to paused needs to be in a known state. I imagine the thread to be stoped would call a library function meant the halt the process so it could be resumed.
I think the linux system call fork is your friend. Fork perfectly duplicates a process. Have the system run to the desired point and fork. One fork wait to fork others. The second fork runs one set of input.
once it completes the first fork can for again. Again the second fork can run another set of input.
continue ad infinitum.
Threads run in the context of a process. So if you want to do anything like persist a thread state to disk, you need to "hibernate" the entire process.
You will need to serialise the entire set of the processes data. And you'll need to store the current thread execution point. I think serialising the process is do-able (check out boost::serialize) but the thread stop point is a lot more difficult. I would put places where it can be stopped through the code, but as you say, you cannot modify the code.
Given that problem, you're looking at virtualising the platform the app is running on, and using its suspend functionality to pause the entire thing. You might find more information about how to do this in the virtualisation vendor's features, eg Xen.
As the whole logical address space of the program is part of the thread's context, you would have to hibernate the whole process.
If you can guarantee that the thread only uses local variables, you could save its stack. It is easy to suspend a thread with pthreads, but I don't see how you could access its stack from outside then.
The way you would have to do this is via VM Snapshots; get a copy of VMWare Workstation, then you can write code to automate starting/stopping/snapshotting the machine at different points. Any other approach is pretty untenable, as while you might be able to freeze and dethaw a process, you can't reconstruct the system state it expects (all the stuff that Caspin mentions like file handles et al.)