Skip to content

Commit

Permalink
src: empty data OnProgress in AsyncProgressWorker
Browse files Browse the repository at this point in the history
Fixes: #821
PR-URL: #853
Reviewed-By: Gabriel Schulhof <[email protected]>
Reviewed-By: Michael Dawson <[email protected]>
  • Loading branch information
legendecas authored and Michael Dawson committed Dec 14, 2020
1 parent a7fb5fb commit 86feeeb
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ on: [push, pull_request]

jobs:
test:
timeout-minutes: 30
strategy:
matrix:
node-version:
Expand Down
11 changes: 11 additions & 0 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -5390,6 +5390,17 @@ inline void AsyncProgressWorker<T>::OnWorkProgress(void*) {
this->_asyncsize = 0;
}

/**
* The callback of ThreadSafeFunction is not been invoked immediately on the
* callback of uv_async_t (uv io poll), rather the callback of TSFN is
* invoked on the right next uv idle callback. There are chances that during
* the deferring the signal of uv_async_t is been sent again, i.e. potential
* not coalesced two calls of the TSFN callback.
*/
if (data == nullptr) {
return;
}

this->OnProgress(data, size);
delete[] data;
}
Expand Down
58 changes: 58 additions & 0 deletions test/asyncprogressworker.cc
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,69 @@ class TestWorker : public AsyncProgressWorker<ProgressData> {
FunctionReference _progress;
};

class MalignWorker : public AsyncProgressWorker<ProgressData> {
public:
static void DoWork(const CallbackInfo& info) {
Function cb = info[0].As<Function>();
Function progress = info[1].As<Function>();

MalignWorker* worker =
new MalignWorker(cb, progress, "TestResource", Object::New(info.Env()));
worker->Queue();
}

protected:
void Execute(const ExecutionProgress& progress) override {
std::unique_lock<std::mutex> lock(_cvm);
// Testing a nullptr send is acceptable.
progress.Send(nullptr, 0);
_cv.wait(lock);
// Testing busy looping on send doesn't trigger unexpected empty data
// OnProgress call.
for (size_t i = 0; i < 1000000; i++) {
ProgressData data{0};
progress.Send(&data, 1);
}
}

void OnProgress(const ProgressData* /* data */, size_t count) override {
Napi::Env env = Env();
_test_case_count++;
bool error = false;
Napi::String reason = Napi::String::New(env, "No error");
if (_test_case_count == 1 && count != 0) {
error = true;
reason = Napi::String::New(env, "expect 0 count of data on 1st call");
}
if (_test_case_count > 1 && count != 1) {
error = true;
reason = Napi::String::New(env, "expect 1 count of data on non-1st call");
}
_progress.MakeCallback(Receiver().Value(),
{Napi::Boolean::New(env, error), reason});
_cv.notify_one();
}

private:
MalignWorker(Function cb,
Function progress,
const char* resource_name,
const Object& resource)
: AsyncProgressWorker(cb, resource_name, resource) {
_progress.Reset(progress, 1);
}

size_t _test_case_count = 0;
std::condition_variable _cv;
std::mutex _cvm;
FunctionReference _progress;
};
}

Object InitAsyncProgressWorker(Env env) {
Object exports = Object::New(env);
exports["doWork"] = Function::New(env, TestWorker::DoWork);
exports["doMalignTest"] = Function::New(env, MalignWorker::DoWork);
return exports;
}

Expand Down
17 changes: 17 additions & 0 deletions test/asyncprogressworker.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = test(require(`./build/${buildType}/binding.node`))
async function test({ asyncprogressworker }) {
await success(asyncprogressworker);
await fail(asyncprogressworker);
await malignTest(asyncprogressworker);
}

function success(binding) {
Expand Down Expand Up @@ -43,3 +44,19 @@ function fail(binding) {
);
});
}

function malignTest(binding) {
return new Promise((resolve, reject) => {
binding.doMalignTest(
common.mustCall((err) => {
if (err) {
return reject(err);
}
resolve();
}),
common.mustCallAtLeast((error, reason) => {
assert(!error, reason);
}, 1)
);
});
}
3 changes: 3 additions & 0 deletions test/common/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ function runCallChecks(exitCode) {
exports.mustCall = function(fn, exact) {
return _mustCallInner(fn, exact, 'exact');
};
exports.mustCallAtLeast = function(fn, minimum) {
return _mustCallInner(fn, minimum, 'minimum');
};

function _mustCallInner(fn, criteria, field) {
if (typeof fn === 'number') {
Expand Down

0 comments on commit 86feeeb

Please sign in to comment.