V8: передача объекта из JavaScript в функцию uv_work

Хорошо, у меня есть функция на C++, которую мне нужно вызвать из JavaScript, и один из параметров является объектом JavaScript. JavaScript выглядит следующим образом:

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

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

В подпрограмме send() мне нужно вызвать нативную функцию в другой библиотеке C, которая может заблокироваться. Все функции в этой библиотеке могут блокироваться, поэтому я активно использую uv_queue_work.

Эта подпрограмма — первый раз, когда я столкнулся с проблемой, и это из-за объекта JavaScript. Код С++ выглядит так:

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());
}

Все в порядке, проблема возникает, когда я пытаюсь получить доступ к запросу-> сообщению в функции SendMessageWorker.

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

Кажется, что вызов методов запроса-> сообщения вызывает нарушение прав доступа на очень маленьком адресе (вероятно, ссылка на указатель NULL где-то в V8/узле). Таким образом, использование request- > message напрямую должно быть неправильным. Я знаю, что для доступа к функции обратного вызова мне нужно сделать следующее:

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

Нужно ли мне использовать Context::GetCurrent()->Global() для доступа к методам вне класса Object, обернутого шаблоном Persistent? Если да, то как мне это сделать?


v8
person Zik    schedule 19.06.2012    source источник


Ответы (1)


Код в SendMessageWorker не выполняется в JavaScript — uv_queue_work выполняет ваш SendMessageWorker в отдельном потоке, поэтому он также может запускать код node.js, а когда он готов, SendMessageWorkerComplete выполняется обратно в потоке JavaScript.

Таким образом, вы не можете использовать переменные JavaScript в SendMessageWorker - если вам это действительно нужно, вам придется преобразовать их, например, в. Строка C++ перед вызовом uv_queue_work.

person Ivan Vergiliev    schedule 19.06.2012
comment
Ага, хорошо. Это имеет смысл. Спасибо! - person Zik; 20.06.2012
comment
Быстрый дополнительный вопрос - функция WorkerComplete использует HandleScope, нужно ли мне вызывать scope.Close() в конце или он будет правильно очищаться, когда область выходит за пределы... области? - person Zik; 20.06.2012
comment
HandleScope гарантирует, что переменные JavaScript, которые вы создали за время своего существования, будут удалены сборщиком мусора. Он закрывается через деструктор, поэтому, если вы не хотите ничего возвращать, вам не нужно явно вызывать Close(). Если вы хотите вернуть переменную JS, вам нужно вызвать scope.Close(variable), чтобы она не собирала мусор. - person Ivan Vergiliev; 21.06.2012