Search code examples
v8

V8: Passing object from JavaScript to uv_work function


OK, I have a function in C++ that I need to call from JavaScript, and one of the parameters is a JavaScript object. The JavaScript looks like this:

var message = {
    fieldA: 42,
    fieldB: "moo"
};

myObj.send(message, function (err) { console.log("Result: " + err); });

In the send() routine I need to call a native function in another C library that may block. All functions in this library may block so I've been using uv_queue_work extensively.

This routine is the first time I've hit an issue and it is because of the JavaScript object. The C++ code looks like this:

struct SendMessageRequest
{
    Persistent<Object> message;
    Persistent<Function> callback;
    int result;
};

Handle<Value> MyObj::Send(const Arguments& args)
{
    HandleScope scope;

    // Parameter checking done but not included here
    Local<Object> message = Local<Object>::Cast(args[0]);
    Local<Function> callback = Local<Function>::Cast(args[1]);

    // Send data to worker thread
    SendMessageRequest* request = new SendMessageRequest;
    request->message = Persistent<Object>::New(message);
    request->callback = Persistent<Function>::New(callback);

    uv_work_t* req = new uv_work_t();
    req->data = request;

    uv_queue_work(uv_default_loop(), req, SendMessageWorker, SendMessageWorkerComplete);

    return scope.Close(Undefined());
}

This is all fine, the problem comes when I try to access request->message in the SendMessageWorker function.

void SendMessageWorker(uv_work_t* req)
{
    SendMessageRequest* request = (SendMessageRequest*)req->data;
    Local<Array> names = request->message->GetPropertyNames();
    // CRASH

It seems that calling methods off of request->message causes an Access Violation on a really small address (probably a NULL pointer reference somewhere in V8/node). So using request->message directly must be wrong. I know to access the callback function I need to do this:

request->callback->Call(Context::GetCurrent()->Global(), 1, argv);

Do I need to use Context::GetCurrent()->Global() in order to access methods off of the Object class that is wrapped by the Persistent template? If so how do I do that?


Solution

  • The code in SendMessageWorker is not executed on the JavaScript - what uv_queue_work does is execute your SendMessageWorker in a separate thread, so it can let the node.js code run as well, and when it's ready, SendMessageWorkerComplete is executed back on the JavaScript thread.

    So you can't use JavaScript variables in SendMessageWorker - if you really need to, you'd have to convert them to e.g. C++ string before calling uv_queue_work.