I have a struct that looks like this:
struct Work {
uv_work_t requst;
Local<Promise::Resolver> resolver;
};
I then have this method which crops an image with imagemagick:
void MagickNode::Crop(const FunctionCallbackInfo<Value> &args) {
// Create a promise
Local<Promise::Resolver> resolver = v8::Promise::Resolver::New(i.isolate);
args.GetReturnValue().Set(resolver->GetPromise());
// Create a worker
Work *work = new Work();
work->requst.data = work;
work->resolver = resolver;
// Do work
uv_queue_work(uv_default_loop(), &work->requst, [](uv_work_t *req) {
// Do the heavy lifting
}, WorkVoidComplete);
}
When the process is complete, I want to resolve the promise. Which I do here:
void MagickNode::WorkVoidComplete(uv_work_t *req, int status) {
// Setup the required items
Isolate *isolate = Isolate::GetCurrent();
v8::HandleScope handleScope(isolate);
Work *work = static_cast<Work *>(req->data);
// Resolve the promise
work->resolver->Resolve(Undefined(isolate));
delete work;
}
The problem, is that when work->resolver->Resolve
runs it gives Segmentation fault. I think that this is because it is executed from a thread when it was created on the parent thread giving me no access.
How can I get access and run that line?
If I move that line to the end of the method MagickNode::Crop
, it runs without error and the promise gets called.
Your WorkVoidComplete
will actually be called in the loop thread. The problem here is that you're using a Local<T>
handle instead of a Persistent<T>
handle.
When the scope of MagickNode::Crop
closes the local handle is released.
Changing your struct to use v8::Persistent<Promise::Resolver>
will fix the problem. Note that when you're done with a persistent reference handle it must be manually released by calling Reset()
.
class Work {
public:
Work(Isolate* i, Local<Promise::Resolver> r)
: isolate_(i) {
resolver_.Reset(i, r);
}
~Work() {
resolver_.Reset();
}
inline uv_work_t* request() { return &request_; }
inline Isolate* isolate() { return isolate_; }
inline Local<Promise::Resolver> resolver() {
return resolver_.Get(isolate_);
}
private:
Isolate* isolate_;
Persistent<Promise::Resolver> resolver_;
uv_work_t request_;
};
void Something(const FunctionCallbackInfo<Value>& args) {
Isolate* isolate = args.GetIsolate();
Local<Context> context = isolate->GetCurrentContext();
Local<Promise::Resolver> resolver =
v8::Promise::Resolver::New(context).ToLocalChecked();
Work* work = new Work(isolate, resolver);
work->request()->data = work;
uv_queue_work(uv_default_loop(), work->request(), DoWork, WorkComplete);
args.GetReturnValue().Set(resolver->GetPromise());
}