mirror of https://github.com/lukechilds/node.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
173 lines
5.1 KiB
173 lines
5.1 KiB
#include <node_api.h>
|
|
#include "../common.h"
|
|
|
|
#if defined _WIN32
|
|
#include <windows.h>
|
|
#else
|
|
#include <unistd.h>
|
|
#endif
|
|
|
|
// this needs to be greater than the thread pool size
|
|
#define MAX_CANCEL_THREADS 6
|
|
|
|
typedef struct {
|
|
int32_t _input;
|
|
int32_t _output;
|
|
napi_ref _callback;
|
|
napi_async_work _request;
|
|
} carrier;
|
|
|
|
carrier the_carrier;
|
|
carrier async_carrier[MAX_CANCEL_THREADS];
|
|
|
|
void Execute(napi_env env, void* data) {
|
|
#if defined _WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
carrier* c = static_cast<carrier*>(data);
|
|
|
|
if (c != &the_carrier) {
|
|
napi_throw_type_error(env, nullptr, "Wrong data parameter to Execute.");
|
|
return;
|
|
}
|
|
|
|
c->_output = c->_input * 2;
|
|
}
|
|
|
|
void Complete(napi_env env, napi_status status, void* data) {
|
|
carrier* c = static_cast<carrier*>(data);
|
|
|
|
if (c != &the_carrier) {
|
|
napi_throw_type_error(env, nullptr, "Wrong data parameter to Complete.");
|
|
return;
|
|
}
|
|
|
|
if (status != napi_ok) {
|
|
napi_throw_type_error(env, nullptr, "Execute callback failed.");
|
|
return;
|
|
}
|
|
|
|
napi_value argv[2];
|
|
|
|
NAPI_CALL_RETURN_VOID(env, napi_get_null(env, &argv[0]));
|
|
NAPI_CALL_RETURN_VOID(env, napi_create_number(env, c->_output, &argv[1]));
|
|
napi_value callback;
|
|
NAPI_CALL_RETURN_VOID(env,
|
|
napi_get_reference_value(env, c->_callback, &callback));
|
|
napi_value global;
|
|
NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global));
|
|
|
|
napi_value result;
|
|
NAPI_CALL_RETURN_VOID(env,
|
|
napi_make_callback(env, global, callback, 2, argv, &result));
|
|
|
|
NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback));
|
|
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
|
|
}
|
|
|
|
napi_value Test(napi_env env, napi_callback_info info) {
|
|
size_t argc = 2;
|
|
napi_value argv[2];
|
|
napi_value _this;
|
|
void* data;
|
|
NAPI_CALL(env,
|
|
napi_get_cb_info(env, info, &argc, argv, &_this, &data));
|
|
NAPI_ASSERT(env, argc >= 2, "Not enough arguments, expected 2.");
|
|
|
|
napi_valuetype t;
|
|
NAPI_CALL(env, napi_typeof(env, argv[0], &t));
|
|
NAPI_ASSERT(env, t == napi_number,
|
|
"Wrong first argument, integer expected.");
|
|
NAPI_CALL(env, napi_typeof(env, argv[1], &t));
|
|
NAPI_ASSERT(env, t == napi_function,
|
|
"Wrong second argument, function expected.");
|
|
|
|
the_carrier._output = 0;
|
|
|
|
NAPI_CALL(env,
|
|
napi_get_value_int32(env, argv[0], &the_carrier._input));
|
|
NAPI_CALL(env,
|
|
napi_create_reference(env, argv[1], 1, &the_carrier._callback));
|
|
NAPI_CALL(env, napi_create_async_work(
|
|
env, Execute, Complete, &the_carrier, &the_carrier._request));
|
|
NAPI_CALL(env,
|
|
napi_queue_async_work(env, the_carrier._request));
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
void BusyCancelComplete(napi_env env, napi_status status, void* data) {
|
|
carrier* c = static_cast<carrier*>(data);
|
|
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
|
|
}
|
|
|
|
void CancelComplete(napi_env env, napi_status status, void* data) {
|
|
carrier* c = static_cast<carrier*>(data);
|
|
|
|
if (status == napi_cancelled) {
|
|
// ok we got the status we expected so make the callback to
|
|
// indicate the cancel succeeded.
|
|
napi_value callback;
|
|
NAPI_CALL_RETURN_VOID(env,
|
|
napi_get_reference_value(env, c->_callback, &callback));
|
|
napi_value global;
|
|
NAPI_CALL_RETURN_VOID(env, napi_get_global(env, &global));
|
|
napi_value result;
|
|
NAPI_CALL_RETURN_VOID(env,
|
|
napi_make_callback(env, global, callback, 0, nullptr, &result));
|
|
}
|
|
|
|
NAPI_CALL_RETURN_VOID(env, napi_delete_async_work(env, c->_request));
|
|
NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, c->_callback));
|
|
}
|
|
|
|
void CancelExecute(napi_env env, void* data) {
|
|
#if defined _WIN32
|
|
Sleep(1000);
|
|
#else
|
|
sleep(1);
|
|
#endif
|
|
}
|
|
|
|
napi_value TestCancel(napi_env env, napi_callback_info info) {
|
|
size_t argc = 1;
|
|
napi_value argv[1];
|
|
napi_value _this;
|
|
void* data;
|
|
|
|
// make sure the work we are going to cancel will not be
|
|
// able to start by using all the threads in the pool
|
|
for (int i = 1; i < MAX_CANCEL_THREADS; i++) {
|
|
NAPI_CALL(env, napi_create_async_work(env, CancelExecute,
|
|
BusyCancelComplete, &async_carrier[i], &async_carrier[i]._request));
|
|
NAPI_CALL(env, napi_queue_async_work(env, async_carrier[i]._request));
|
|
}
|
|
|
|
// now queue the work we are going to cancel and then cancel it.
|
|
// cancel will fail if the work has already started, but
|
|
// we have prevented it from starting by consuming all of the
|
|
// workers above.
|
|
NAPI_CALL(env,
|
|
napi_get_cb_info(env, info, &argc, argv, &_this, &data));
|
|
NAPI_CALL(env, napi_create_async_work(env, CancelExecute,
|
|
CancelComplete, &async_carrier[0], &async_carrier[0]._request));
|
|
NAPI_CALL(env,
|
|
napi_create_reference(env, argv[0], 1, &async_carrier[0]._callback));
|
|
NAPI_CALL(env, napi_queue_async_work(env, async_carrier[0]._request));
|
|
NAPI_CALL(env, napi_cancel_async_work(env, async_carrier[0]._request));
|
|
return nullptr;
|
|
}
|
|
|
|
void Init(napi_env env, napi_value exports, napi_value module, void* priv) {
|
|
napi_property_descriptor properties[] = {
|
|
DECLARE_NAPI_PROPERTY("Test", Test),
|
|
DECLARE_NAPI_PROPERTY("TestCancel", TestCancel),
|
|
};
|
|
|
|
NAPI_CALL_RETURN_VOID(env, napi_define_properties(
|
|
env, exports, sizeof(properties) / sizeof(*properties), properties));
|
|
}
|
|
|
|
NAPI_MODULE(addon, Init)
|
|
|