Created
March 13, 2014 00:18
-
-
Save dmh2000/9519489 to your computer and use it in GitHub Desktop.
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
#include <unistd.h> | |
#include <node.h> | |
#include <string.h> | |
#include <v8.h> | |
using namespace v8; | |
unsigned long long count = 0; | |
// native blocking/compute intensive function | |
void delay(int seconds) { | |
int i; | |
int j; | |
// a long computation | |
for(i=0;i<2000000;++i) { | |
for(j=0;j<400;++j) { | |
count = count * seconds; | |
} | |
} | |
/** | |
* or a blocking call | |
* sleep(seconds); | |
*/ | |
} | |
// the 'baton' is the carrier for data between functions | |
struct DelayBaton | |
{ | |
// required | |
uv_work_t request; // libuv | |
Persistent<Function> callback; // javascript callback | |
// optional : data goes here. | |
// data that doesn't go back to javascript can be any typedef | |
// data that goes back to javascript needs to be a supported type | |
int seconds; | |
char greeting[256]; | |
}; | |
// called by libuv worker in separate thread | |
static void DelayAsync(uv_work_t *req) | |
{ | |
DelayBaton *baton = static_cast<DelayBaton *>(req->data); | |
delay(baton->seconds); | |
} | |
// called by libuv in event loop when async function completes | |
static void DelayAsyncAfter(uv_work_t *req,int status) | |
{ | |
// get the reference to the baton from the request | |
DelayBaton *baton = static_cast<DelayBaton *>(req->data); | |
// set up return arguments | |
Handle<Value> argv[] = | |
{ | |
Handle<Value>(Int32::New(baton->seconds)), | |
Handle<Value>(String::New(baton->greeting)) | |
}; | |
// execute the callback | |
baton->callback->Call(Context::GetCurrent()->Global(),2,argv); | |
// dispose the callback object from the baton | |
baton->callback.Dispose(); | |
// delete the baton object | |
delete baton; | |
} | |
// javascript callable function | |
Handle<Value> Delay(const Arguments &args) | |
{ | |
// create 'baton' data carrier | |
DelayBaton *baton = new DelayBaton; | |
// get callback argument | |
Handle<Function> cb = Handle<Function>::Cast(args[2]); | |
// attach baton to uv work request | |
baton->request.data = baton; | |
// assign incoming arguments to baton | |
baton->seconds = args[0]->Int32Value(); | |
// point at the argument as a string, then copy it to the baton | |
v8::String::Utf8Value str(args[1]); | |
strncpy(baton->greeting,*str,sizeof(baton->greeting)); | |
// assign callback to baton | |
baton->callback = Persistent<Function>::New(cb); | |
// queue the async function to the event loop | |
// the uv default loop is the node.js event loop | |
uv_queue_work(uv_default_loop(),&baton->request,DelayAsync,DelayAsyncAfter); | |
// nothing returned | |
return Undefined(); | |
} | |
void init(Handle<Object> exports) { | |
// add the async function to the exports for this object | |
exports->Set( | |
String::NewSymbol("delay"), // javascript function name | |
FunctionTemplate::New(Delay)->GetFunction() // attach 'Delay' function to javascript name | |
); | |
} | |
NODE_MODULE(delay, init) | |
/** | |
* server.js | |
var addon = require('./build/Release/delay'); | |
var i = 0; | |
setInterval(function() { | |
console.log(i++); | |
},500); | |
// test the delay function | |
addon.delay(3,'hello world',function(a,b) { | |
console.log('delay : ' + a + ',' + b); | |
}); | |
*/ | |
/** | |
* binding.gyp | |
{ | |
"targets": [ | |
{ | |
"target_name": "delay", | |
"sources": [ "delay.cpp" ] | |
} | |
] | |
} | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@dmh2000 :
I wanted NodeJS to call C code which accepts a function pointer to give back the result asynchronously to the caller. I stumbled upon this and it's very helpful 👍 as I know almost nothing about NodeJS (javascript in general). I was expecting two have only 2 threads in total in my setup - a main thread which is the JS event loop and a background event loop which is in C.
C code:
So calling
foo
is non-blocking.However it seems that i need to code a wrapper around
foo
(which equivalently would bedelay()
in your example) which will callfoo
giving it a callback written in C and block until result is obtained via passed callback. This wrapper (the equivalent ofdelay
) will be called in a worker thread spawned by libuv according to your explanation. This means that each time NodeJS wants to callfoo
a new thread will be spawned by the libuv intermediary, thus could end up having potentially 100s or threads assuming rate of callingfoo
is higher than C processing the result and returning it via callback.Is that true ? Is this a standard idiom or is there a way around it (to have just 2 or 3 threads like described) ?