3

I'm building a native extension for node which includes a long-running operation with a callback on completion.

I am passing a node buffer to the call. It contains the payload of what is to be processed by the extension.

I should be able to store my buffer in persistent storage in the constructor of my AsyncWorker, and retrieve it later when I need it.

This example (from the nan test suite) is what I'm generally basing my code on: https://github.com/nodejs/nan/blob/master/test/cpp/bufferworkerpersistent.cpp

This test works, but it doesn't do anything with the buffer until the HandleOKCallback method, which isn't super interesting to me. I need to access the buffer during the Execute method.

If I simply add a line to the test's Execute() method to try to access the buffer, like this:

void Execute () {
    printf("before GetFromPersistent\n");
    v8::Local<v8::Value> handle = GetFromPersistent("buffer");
    printf("after GetFromPersistent\n");
    printf("buffer @%llux len %ld\n", (uint64_t)node::Buffer::Data(handle), node::Buffer::Length(handle));
    Sleep(milliseconds);
}

I get a seg fault on the GetFromPersistent call.

My question is: what am I missing? Should I be not be able to pull a persistent object into the Execute method? If so, why not?

ZachB
  • 13,051
  • 4
  • 61
  • 89
Jim B.
  • 4,512
  • 3
  • 25
  • 53

1 Answers1

4

OK, I think the answer is "duh", but for others just getting started with Node native extensions, here's what I now understand is going on:

Since node is a single thread, long-running tasks must run in a different thread if they are to not block node.

Nan uses libuv to manage a thread pool to do the asynchronous work that you write in the "Execute" method.

However, the Constructor of your AsyncWorker actually gets run on node's thread, and the HandleOKCallback is also scheduled to run there once Execute has finished.

So it's OK to access node resources while in the constructor and in the callback setup, but since Execute is running on a different thread it's not OK, so it seg faults.

So for my problem (I'm running a JPEG decode in an AsyncWorker), I am instead pulling the pointer and length out of the buffer in the constructor, but still calling SaveToPersistent on the buffer so it doesn't get GCed while I'm decoding the bits.

Jim B.
  • 4,512
  • 3
  • 25
  • 53