-
-
Notifications
You must be signed in to change notification settings - Fork 488
Description
One n-api addon accepting two JavaScript parameters, A and B, should internally call two AsyncWorker methods, one after the other and return the 2nd method result by callback call.
The 1st AsyncWorker method shall be invoked with JS parameter A.
The 2nd method shall be invoked with 1st method result and JS parameter B.
I tried to pass both A and B parameters (and callback arg) to 1st AsyncWorker method, keep B as 1st AsyncWorker private variable and use it in OnOK
, to invoke the 2nd AsyncWorker method.
The B parameter seem to be corrupted in Execute
and in OnOK
methods of the 1st AccessWorker. Access causes the segfault.
I tested by modifying async_pi_estimate
original example.
Uncommenting the printf
statement in Execute
leads to segfault.
async.cc
#include <napi.h>
#include "pi_est.h" // NOLINT(build/include)
#include "async.h" // NOLINT(build/include)
class PiWorker : public Napi::AsyncWorker {
public:
PiWorker(Napi::Function& callback, int points, Napi::String str1)
: Napi::AsyncWorker(callback), points(points), str1(str1), estimate(0) {
printf ("\nconstructor:: %d\n", str1.IsString());
}
~PiWorker() {}
// Executed inside the worker-thread.
// It is not safe to access JS engine data structure
// here, so everything we need for input and output
// should go on `this`.
void Execute () {
estimate = Estimate(points);
//printf ("\nexecute:: %d\n", str1.IsString());
}
// Executed when the async work is complete
// this function will be run inside the main event loop
// so it is safe to use JS engine data again
void OnOK() {
//if (!str1.IsString()) printf ("\nok:: %d\n", str1.IsString());
Napi::HandleScope scope(Env());
Callback().Call({Env().Global(), Napi::Number::New(Env(), estimate)});
}
private:
int points;
Napi::String str1;
double estimate;
};
// Asynchronous access to the `Estimate()` function
Napi::Value CalculateAsync(const Napi::CallbackInfo& info) {
int points = info[0].As<Napi::Number>().Uint32Value();
Napi::Function callback = info[1].As<Napi::Function>();
Napi::String str1 = info[2].As<Napi::String>(); // segfault in Execute
//Napi::String str1 = Napi::String::New(info.Env(), "Test"); // no segfault
PiWorker* piWorker = new PiWorker(callback, points, str1);
piWorker->Queue();
return info.Env().Undefined();
}
addon.js
var addon = require('bindings')('addon');
var calculations = process.argv[3] || 100000000;
function printResult(type, pi, ms) {
console.log(type, 'method:');
console.log('\tπ ≈ ' + pi + ' (' + Math.abs(pi - Math.PI) + ' away from actual)');
console.log('\tTook ' + ms + 'ms');
console.log();
}
function runSync(str) {
var start = Date.now();
// Estimate() will execute in the current thread,
// the next line won't return until it is finished
var result = addon.calculateSync(calculations, str);
printResult('Sync', result, Date.now() - start);
}
function runAsync(str) {
// how many batches should we split the work in to?
var batches = process.argv[4] || 16;
var ended = 0;
var total = 0;
var start = Date.now();
function done(err, result) {
total += result;
// have all the batches finished executing?
if (++ended === batches) {
printResult('Async', total / batches, Date.now() - start);
}
}
// for each batch of work, request an async Estimate() for
// a portion of the total number of calculations
for (var i = 0; i < batches; i++) {
addon.calculateAsync(calculations / batches, done, str);
}
}
//runSync(process.argv[2]);
runAsync(process.argv[2]);
Is it how chained AsyncWorker calls could/should work or what would be the correct approach? Any working example available?
The issue happens only with parameters from command line (eg. node addon test
), see 4th and 5th line from the bottom.