Created
December 20, 2012 00:22
-
-
Save je4d/4341994 to your computer and use it in GitHub Desktop.
Demo of isolates with preemptible execution in v8 js
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.