Skip to content

Instantly share code, notes, and snippets.

@je4d
Created December 20, 2012 00:22
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save je4d/4341994 to your computer and use it in GitHub Desktop.
Save je4d/4341994 to your computer and use it in GitHub Desktop.
Demo of isolates with preemptible execution in v8 js
#include <chrono>
#include <memory>
#include <string>
#include <atomic>
#include <thread>
#include <iostream>
#include <v8.h>
int main()
{
v8::Isolate* isolate {v8::Isolate::New()}; // The isolate owns everything. Don't touch v8 without a locker on it.
v8::Persistent<v8::Context> context; // we'll initialize this after taking out a lock on the isolate
v8::Function* rawFunction;
/* setup the JS context, define a crude delay function */
{
v8::Locker locker{isolate}; // acquire a lock on the Isolate
v8::Isolate::Scope isolate_scope{isolate}; // need this to make stuff use the isolate
v8::HandleScope handle_scope;
context = v8::Context::New(); // context created here
v8::Context::Scope context_scope{context};
v8::Script::Compile(v8::String::New(
"function pausecomp(millis) { var date = new Date(); var curDate = null; do { curDate = new Date(); } while(curDate-date < millis); };"
"function inc_val() { this.glob.val += 1; };"
"inc_val.glob = this;"
"val = 0;"
"x = '';"
))->Run();
v8::Handle<v8::Function> incFunc { v8::Handle<v8::Function>::Cast(context->Global()->Get(v8::String::New("inc_val"))) };
v8::Persistent<v8::Function> incFuncPersistent = v8::Persistent<v8::Function>::New(incFunc);
rawFunction = *incFuncPersistent;
}
/* launch a second thread that periodically grabs a lock on the isolate and increments 'val' */
std::atomic<bool> shutdown_thread {false};
std::thread t{[&]{
while (!shutdown_thread) {
std::this_thread::sleep_for(std::chrono::milliseconds {50});
v8::Locker locker{isolate};
v8::Isolate::Scope isolate_scope{isolate};
v8::HandleScope handle_scope;
// v8::Context::Scope context_scope{context}; // needed if the function accesses any globals
v8::Persistent<v8::Function> incFuncPersistent = rawFunction;
incFuncPersistent->Call(incFuncPersistent, 0, 0);
}
}};
/* Do some stuff in the main thread that will be affected by the other thread */
{
v8::Locker locker{isolate};
v8::Isolate::Scope isolate_scope{isolate};
v8::HandleScope handle_scope;
v8::Context::Scope context_scope{context};
// Tells v8 that we're ok with other threads taking out a lock on the isolate while this is running
locker.StartPreemption(1);
v8::Handle<v8::Value> res = v8::Script::Compile(v8::String::New(
"for (i = 0; i < 100; i++) { x += val; pausecomp(10);}"
"x"))->Run();
locker.StopPreemption();
v8::String::AsciiValue ascii(res);
// example output: "0000000000000000001111111222222222333333333334444444445555555555555555555666666666667777777777888888"
std::cout << *ascii << std::endl;
}
/* make sure the other thread is dead */
shutdown_thread = true;
t.join();
/* finally it's safe to tear down the context. Note we need to lock the isolate to do this */
{
v8::Locker locker{isolate};
v8::Isolate::Scope isolate_scope{isolate};
context.Dispose();
}
return 0;
}
// vim: set sw=2 sts=2 et:
@evantorrie
Copy link

I believe the parameter to StartPreemption is in milliseconds. You may be better showing it as a value different than 1, since otherwise readers may think it's just a boolean.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment