1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <thread>
17
18 #include "napi/native_api.h"
19 #include "napi/native_node_api.h"
20
21 #include "uv.h"
22
23 struct CallbackContext {
24 napi_env env = nullptr;
25 napi_ref callbackRef = nullptr;
26 int retData = 0;
27 };
28
callbackTest(CallbackContext * context)29 void callbackTest(CallbackContext* context)
30 {
31 uv_loop_s* loop = nullptr;
32 napi_get_uv_event_loop(context->env, &loop);
33
34 uv_work_t* work = new uv_work_t;
35 context->retData = 1;
36 work->data = (void*)context;
37
38 uv_queue_work(
39 loop, work, [](uv_work_t* work) {},
40 // using callback function back to JS thread
41 [](uv_work_t* work, int status) {
42 CallbackContext* context = (CallbackContext*)work->data;
43 napi_handle_scope scope = nullptr;
44 napi_open_handle_scope(context->env, &scope);
45 if (scope == nullptr) {
46 return;
47 }
48
49 napi_value callback = nullptr;
50 napi_get_reference_value(context->env, context->callbackRef, &callback);
51 napi_value retArg;
52 napi_create_int32(context->env, context->retData, &retArg);
53 napi_value ret;
54 napi_call_function(context->env, nullptr, callback, 1, &retArg, &ret);
55 napi_delete_reference(context->env, context->callbackRef);
56
57 napi_close_handle_scope(context->env, scope);
58
59 if (work != nullptr) {
60 delete work;
61 }
62
63 delete context;
64 }
65 );
66 }
67
JSTest(napi_env env,napi_callback_info info)68 static napi_value JSTest(napi_env env, napi_callback_info info)
69 {
70 size_t argc = 1;
71 napi_value argv[1] = { 0 };
72 napi_value thisVar = nullptr;
73 void* data = nullptr;
74 napi_get_cb_info(env, info, &argc, argv, &thisVar, &data);
75
76 napi_valuetype valueType = napi_undefined;
77 napi_typeof(env, argv[0], &valueType);
78 if (valueType != napi_function) {
79 return nullptr;
80 }
81 auto asyncContext = new CallbackContext();
82 asyncContext->env = env;
83 napi_create_reference(env, argv[0], 1, &asyncContext->callbackRef);
84 // using callback function on other thread
85 std::thread testThread(callbackTest, asyncContext);
86 testThread.detach();
87
88 return nullptr;
89 }
90
91 /***********************************************
92 * Module export and register
93 ***********************************************/
CallbackExport(napi_env env,napi_value exports)94 static napi_value CallbackExport(napi_env env, napi_value exports)
95 {
96 static napi_property_descriptor desc[] = {
97 DECLARE_NAPI_FUNCTION("test", JSTest)
98 };
99 NAPI_CALL(env, napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc));
100 return exports;
101 }
102
103 // callback module define
104 static napi_module callbackModule = {
105 .nm_version = 1,
106 .nm_flags = 0,
107 .nm_filename = nullptr,
108 .nm_register_func = CallbackExport,
109 .nm_modname = "callback",
110 .nm_priv = ((void*)0),
111 .reserved = { 0 },
112 };
113
114 // callback module register
CallbackTestRegister()115 extern "C" __attribute__((constructor)) void CallbackTestRegister()
116 {
117 napi_module_register(&callbackModule);
118 }