U
U
unclechu2014-07-24 12:35:35
JavaScript
unclechu, 2014-07-24 12:35:35

How to work with asynchronous code in C++ module for Node.JS?

In the JS code, a callback is bound to the global scope, which then needs to be called inside the C ++ code that is not related to Node.JS and works asynchronously through pthread, in a separate thread.
Simplified:

Persistent<Function> processCallback;

Handle<Value> bindProcess(const Arguments &args)
{
    HandleScope scope;

    if ( ! args[0]->IsFunction()) {
        ThrowException(Exception::TypeError(String::New("Callback argument must be a function")));
        return scope.Close(Undefined());
    }

    Local<Function> callback = Local<Function>::Cast( args[0] );
    processCallback = Persistent<Function>::New( callback );

    return scope.Close(Undefined());
}

int process()
{
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(123) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    return 0;
}

The problem is that the code in the process, no matter how you twist it, falls out with a segfault. I clearly misunderstand something and make a mistake in the architecture. Tell me how to implement it correctly? Perhaps you need to do something through uv?
UPD: The problem was solved after smoking libuv manuals:
uv_work_t *baton;

void work(uv_work_t* task) {}

void after(uv_work_t* task, int status) {
    HandleScope scope;

    int n = *((int*)(&task->data));
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(n) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    scope.Close(Undefined());
    delete task;
}

int process()
{
    baton = new uv_work_t();
    baton->data = (void*)123;
    uv_queue_work(uv_default_loop(), baton, work, after);
    return 0;
}

Now the problem is that the call code in the process is asynchronous, I need to wait for the execution of after inside the process and only after that continue. How to do this is perhaps another topic.
UPD2: Synchronization is provided through semaphores: How to synchronize libuv code?

Answer the question

In order to leave comments, you need to log in

1 answer(s)
U
unclechu, 2014-07-25
@unclechu

It worked out, though not exactly the way I wanted it to. Now the callback call is asynchronous, but I need to get the result inside "process", at least just wait for "after" to complete.

uv_work_t *baton;

void work(uv_work_t* task) {}

void after(uv_work_t* task, int status) {
    HandleScope scope;

    int n = *((int*)(&task->data));
    const unsigned argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New( Number::New(n) ) };
    processCallback->Call(Context::GetCurrent()->Global(), argc, argv);

    scope.Close(Undefined());
    delete task;
}

int process()
{
    baton = new uv_work_t();
    baton->data = (void*)123;
    uv_queue_work(uv_default_loop(), baton, work, after);
    return 0;
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question