Created
February 28, 2012 22:43
-
-
Save edhemphill/1935788 to your computer and use it in GitHub Desktop.
C++ threaded extension for node.js w/ gyp build
This file contains 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
// Originally at: | |
// http://bravenewmethod.wordpress.com/2011/03/30/callbacks-from-threaded-node-js-c-extension/ | |
#include <queue> | |
// node headers | |
#include <v8.h> | |
#include <node.h> | |
#include <ev.h> | |
#include <pthread.h> | |
#include <unistd.h> | |
#include <string.h> | |
using namespace node; | |
using namespace v8; | |
// handles required for callback messages | |
static pthread_t texample_thread; | |
static ev_async eio_texample_notifier; | |
Persistent<String> callback_symbol; | |
Persistent<Object> module_handle; | |
// message queue | |
std::queue<int> cb_msg_queue = std::queue<int>(); | |
pthread_mutex_t queue_mutex = PTHREAD_MUTEX_INITIALIZER; | |
// The background thread | |
static void* TheThread(void *) | |
{ | |
int i = 0; | |
while(true) { | |
// fire event every 5 seconds | |
sleep(5); | |
pthread_mutex_lock(&queue_mutex); | |
cb_msg_queue.push(i); | |
pthread_mutex_unlock(&queue_mutex); | |
i++; | |
// wake up callback | |
ev_async_send(EV_DEFAULT_UC_ &eio_texample_notifier); | |
} | |
return NULL; | |
} | |
// callback that runs the javascript in main thread | |
static void Callback(EV_P_ ev_async *watcher, int revents) | |
{ | |
HandleScope scope; | |
assert(watcher == &eio_texample_notifier); | |
assert(revents == EV_ASYNC); | |
// locate callback from the module context if defined by script | |
// texample = require('texample') | |
// texample.callback = function( ... ) { .. | |
Local<Value> callback_v = module_handle->Get(callback_symbol); | |
if (!callback_v->IsFunction()) { | |
// callback not defined, ignore | |
return; | |
} | |
Local<Function> callback = Local<Function>::Cast(callback_v); | |
// dequeue callback message | |
pthread_mutex_lock(&queue_mutex); | |
int number = cb_msg_queue.front(); | |
cb_msg_queue.pop(); | |
pthread_mutex_unlock(&queue_mutex); | |
TryCatch try_catch; | |
// prepare arguments for the callback | |
Local<Value> argv[1]; | |
argv[0] = Local<Value>::New(Integer::New(number)); | |
// call the callback and handle possible exception | |
callback->Call(module_handle, 1, argv); | |
if (try_catch.HasCaught()) { | |
FatalException(try_catch); | |
} | |
} | |
// Start the background thread | |
Handle<Value> Start(const Arguments &args) | |
{ | |
HandleScope scope; | |
// start background thread and event handler for callback | |
ev_async_init(&eio_texample_notifier, Callback); | |
//ev_set_priority(&eio_texample_notifier, EV_MAXPRI); | |
ev_async_start(EV_DEFAULT_UC_ &eio_texample_notifier); | |
ev_unref(EV_DEFAULT_UC); | |
pthread_create(&texample_thread, NULL, TheThread, 0); | |
return True(); | |
} | |
void Initialize(Handle<Object> target) | |
{ | |
HandleScope scope; | |
NODE_SET_METHOD(target, "start", Start); | |
callback_symbol = NODE_PSYMBOL("callback"); | |
// store handle for callback context | |
module_handle = Persistent<Object>::New(target); | |
} | |
extern "C" { | |
static void Init(Handle<Object> target) | |
{ | |
Initialize(target); | |
} | |
NODE_MODULE(texample, Init); | |
} |
This file contains 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
{ | |
'variables': { | |
'node_texample_sources': [ | |
"texample.cpp" | |
], | |
'node_root': '../node-0.7.0', | |
'node_root_win': 'c:\\node', # fill in with Windows info if needed | |
'deps_root_win': 'c:\\dev2', | |
'target_arch' : 'x64' # needed b/c we are on a 64-bit Linux | |
}, | |
'targets': [ | |
{ | |
'target_name': 'texample', | |
'product_name': 'texample', | |
'type': 'loadable_module', | |
'product_prefix': '', | |
'product_extension':'node', | |
'sources': [ | |
'<@(node_texample_sources)' | |
], | |
'defines': [ | |
'PLATFORM="<(OS)"', | |
'_FILE_OFFSET_BITS=64' | |
], | |
'conditions': [ | |
[ 'OS=="linux"', { | |
'cflags': ['-fPIC'], # needed on 64-bit linux, for the .node SO to work | |
'libraries': [ | |
'../mylib/mylib.so' # put your own library requirements here | |
], | |
'include_dirs': [ | |
'src/', | |
'<@(node_root)/include/node', | |
'<@(node_root)/include', | |
'<@(node_root)/deps/uv/include/uv-private', | |
'../expanded-prereqs/include' | |
], | |
'defines': [ | |
#'HAVE_CAIRO', | |
'_LARGEFILE_SOURCE' | |
], | |
}], | |
[ 'OS=="win"', { | |
'defines': [ | |
'HAVE_CAIRO', | |
'PLATFORM="win32"', | |
'_LARGEFILE_SOURCE', | |
'_FILE_OFFSET_BITS=64', | |
'_WINDOWS', | |
'__WINDOWS__', # ltdl | |
'BUILDING_NODE_EXTENSION' | |
], | |
'libraries': [ | |
'mapnik2.lib', | |
'node.lib', | |
'icuuc.lib', | |
'libboost_regex-vc100-mt-1_48.lib', | |
], | |
'include_dirs': [ | |
'c:\\mapnik-2.0\\include', | |
'<@(node_root_win)\\src', | |
'<@(node_root_win)\\deps\\uv\\include\\private', | |
], | |
'msvs_settings': { | |
'VCLinkerTool': { | |
'AdditionalLibraryDirectories': [ | |
'<@(node_root_win)\\Release\\lib', | |
'<@(node_root_win)\\Release', | |
'<@(deps_root_win)\\mapnik-packaging\\windows\\build\\src\\msvc-9.0\\release\\threading-multi', | |
'<@(deps_root_win)\\boost-vc100\\lib', | |
'<@(deps_root_win)\\icu\\lib', | |
], | |
}, | |
}, | |
}, | |
], | |
] | |
}, | |
], | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment