• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "worker_new.h"
17 
18 #include "commonlibrary/ets_utils/js_sys_module/timer/timer.h"
19 #include "helper/error_helper.h"
20 #include "helper/hitrace_helper.h"
21 #if defined(OHOS_PLATFORM)
22 #include "parameters.h"
23 #endif
24 
25 namespace Commonlibrary::Concurrent::WorkerModule {
26 using namespace OHOS::JsSysModule;
27 static constexpr int8_t NUM_NEW_WORKER_ARGS = 2;
28 static std::list<NewWorker *> g_newWorkers;
29 static constexpr int MAX_NEW_WORKERS = 8;
30 static std::mutex g_newWorkersMutex;
31 
NewWorker(napi_env env,napi_ref thisVar)32 NewWorker::NewWorker(napi_env env, napi_ref thisVar)
33     : hostEnv_(env), workerRef_(thisVar)
34 {}
35 
InitWorker(napi_env env,napi_value exports)36 napi_value NewWorker::InitWorker(napi_env env, napi_value exports)
37 {
38     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
39     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
40     const char className[] = "ThreadWorker";
41     napi_property_descriptor properties[] = {
42         DECLARE_NAPI_FUNCTION("postMessage", PostMessage),
43         DECLARE_NAPI_FUNCTION("terminate", Terminate),
44         DECLARE_NAPI_FUNCTION("on", On),
45         DECLARE_NAPI_FUNCTION("once", Once),
46         DECLARE_NAPI_FUNCTION("off", Off),
47         DECLARE_NAPI_FUNCTION("addEventListener", AddEventListener),
48         DECLARE_NAPI_FUNCTION("dispatchEvent", DispatchEvent),
49         DECLARE_NAPI_FUNCTION("removeEventListener", RemoveEventListener),
50         DECLARE_NAPI_FUNCTION("removeAllListener", RemoveAllListener),
51         DECLARE_NAPI_FUNCTION("cancelTasks", CancelTask),
52     };
53     napi_value workerClazz = nullptr;
54     napi_define_class(env, className, sizeof(className), NewWorker::WorkerConstructor, nullptr,
55         sizeof(properties) / sizeof(properties[0]), properties, &workerClazz);
56     napi_set_named_property(env, exports, "ThreadWorker", workerClazz);
57 
58     if (engine->IsWorkerThread()) {
59         if (g_newWorkers.size() == 0) {
60             HILOG_DEBUG("worker:: The new worker is not used.");
61             return exports;
62         }
63         NewWorker* worker = nullptr;
64         for (auto item = g_newWorkers.begin(); item != g_newWorkers.end(); item++) {
65             if ((*item)->IsSameWorkerEnv(env)) {
66                 worker = *item;
67             }
68         }
69         if (worker == nullptr) {
70             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null when InitWorker");
71             return exports;
72         }
73 
74         napi_property_descriptor properties[] = {
75             DECLARE_NAPI_FUNCTION_WITH_DATA("postMessage", PostMessageToHost, worker),
76             DECLARE_NAPI_FUNCTION_WITH_DATA("close", CloseWorker, worker),
77             DECLARE_NAPI_FUNCTION_WITH_DATA("cancelTasks", WorkerPortCancelTask, worker),
78             DECLARE_NAPI_FUNCTION_WITH_DATA("addEventListener", WorkerPortAddEventListener, worker),
79             DECLARE_NAPI_FUNCTION_WITH_DATA("dispatchEvent", WorkerPortDispatchEvent, worker),
80             DECLARE_NAPI_FUNCTION_WITH_DATA("removeEventListener", WorkerPortRemoveEventListener, worker),
81             DECLARE_NAPI_FUNCTION_WITH_DATA("removeAllListener", WorkerPortRemoveAllListener, worker),
82         };
83         napi_value workerPortObj = nullptr;
84         napi_create_object(env, &workerPortObj);
85         napi_define_properties(env, workerPortObj, sizeof(properties) / sizeof(properties[0]), properties);
86 
87         // 5. register worker name in DedicatedWorkerGlobalScope
88         std::string workerName = worker->GetName();
89         if (!workerName.empty()) {
90             napi_value nameValue = nullptr;
91             napi_create_string_utf8(env, workerName.c_str(), workerName.length(), &nameValue);
92             napi_set_named_property(env, workerPortObj, "name", nameValue);
93         }
94         napi_set_named_property(env, exports, "workerPort", workerPortObj);
95 
96         // register worker parentPort.
97         napi_create_reference(env, workerPortObj, 1, &worker->workerPort_);
98     }
99     return exports;
100 }
101 
WorkerConstructor(napi_env env,napi_callback_info cbinfo)102 napi_value NewWorker::WorkerConstructor(napi_env env, napi_callback_info cbinfo)
103 {
104     napi_value thisVar = nullptr;
105     void* data = nullptr;
106     size_t argc = 2;  // 2: max args number is 2
107     napi_value args[argc];
108     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
109     // check argv count
110     if (argc < 1) {
111         ErrorHelper::ThrowError(env,
112             ErrorHelper::TYPE_ERROR, "the number of create worker param must be more than 1 with new");
113         return nullptr;
114     }
115     // check 1st param is string
116     if (!NapiHelper::IsString(args[0])) {
117         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of Worker 1st param must be string.");
118         return nullptr;
119     }
120     NewWorker* worker = nullptr;
121     {
122         int maxNewWorkers = MAX_NEW_WORKERS;
123     #if defined(OHOS_PLATFORM)
124         maxNewWorkers = OHOS::system::GetIntParameter<int>("persist.commonlibrary.maxworkers", MAX_NEW_WORKERS);
125     #endif
126         std::lock_guard<std::mutex> lock(g_newWorkersMutex);
127         if (static_cast<int>(g_newWorkers.size()) >= maxNewWorkers) {
128             ErrorHelper::ThrowError(env,
129                 ErrorHelper::ERR_WORKER_INITIALIZATION, "the number of workers exceeds the maximum.");
130             return nullptr;
131         }
132 
133         // 2. new worker instance
134         worker = new NewWorker(env, nullptr);
135         if (worker == nullptr) {
136             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "creat worker error");
137             return nullptr;
138         }
139         g_newWorkers.push_back(worker);
140     }
141 
142     if (argc > 1 && NapiHelper::IsObject(args[1])) {
143         napi_value nameValue = NapiHelper::GetNameProperty(env, args[1], "name");
144         if (NapiHelper::IsNotUndefined(nameValue)) {
145             if (NapiHelper::IsString(nameValue)) {
146                 char* nameStr = NapiHelper::GetString(env, nameValue);
147                 if (nameStr == nullptr) {
148                     ErrorHelper::ThrowError(env,
149                         ErrorHelper::ERR_WORKER_INITIALIZATION, "the name of worker is null.");
150                     return nullptr;
151                 }
152                 worker->name_ = std::string(nameStr);
153                 CloseHelp::DeletePointer(nameStr, true);
154             } else {
155                 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of name in worker must be string.");
156                 return nullptr;
157             }
158         }
159 
160         napi_value typeValue = NapiHelper::GetNameProperty(env, args[1], "type");
161         if (NapiHelper::IsNotUndefined(typeValue)) {
162             if (NapiHelper::IsString(typeValue)) {
163                 char* typeStr = NapiHelper::GetString(env, typeValue);
164                 if (typeStr == nullptr) {
165                     ErrorHelper::ThrowError(env,
166                         ErrorHelper::ERR_WORKER_INITIALIZATION, "the type of worker is null.");
167                     return nullptr;
168                 }
169                 if (strcmp("classic", typeStr) == 0) {
170                     worker->SetScriptMode(CLASSIC);
171                     CloseHelp::DeletePointer(typeStr, true);
172                 } else {
173                     ErrorHelper::ThrowError(env,
174                         ErrorHelper::TYPE_ERROR, "the type must be classic, unsupport others now.");
175                     CloseHelp::DeletePointer(typeStr, true);
176                     CloseHelp::DeletePointer(worker, false);
177                     return nullptr;
178                 }
179             } else {
180                 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of type must be string.");
181                 return nullptr;
182             }
183         }
184     }
185 
186     // 3. execute in thread
187     char* script = NapiHelper::GetString(env, args[0]);
188     if (script == nullptr) {
189         ErrorHelper::ThrowError(env,
190             ErrorHelper::ERR_WORKER_INVALID_FILEPATH, "the file path is invaild, maybe path is null.");
191         return nullptr;
192     }
193     napi_wrap(
194         env, thisVar, worker,
195         [](napi_env env, void* data, void* hint) {
196             NewWorker* worker = reinterpret_cast<NewWorker*>(data);
197             {
198                 std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
199                 if (worker->UpdateHostState(INACTIVE)) {
200                     if (worker->hostOnMessageSignal_ != nullptr &&
201                         !uv_is_closing(reinterpret_cast<uv_handle_t*>(worker->hostOnMessageSignal_))) {
202                         uv_close(reinterpret_cast<uv_handle_t*>(worker->hostOnMessageSignal_), [](uv_handle_t* handle) {
203                             if (handle != nullptr) {
204                                 delete reinterpret_cast<uv_async_t*>(handle);
205                                 handle = nullptr;
206                             }
207                         });
208                     }
209                     if (worker->hostOnErrorSignal_ != nullptr &&
210                         !uv_is_closing(reinterpret_cast<uv_handle_t*>(worker->hostOnErrorSignal_))) {
211                         uv_close(reinterpret_cast<uv_handle_t*>(worker->hostOnErrorSignal_), [](uv_handle_t* handle) {
212                             if (handle != nullptr) {
213                                 delete reinterpret_cast<uv_async_t*>(handle);
214                                 handle = nullptr;
215                             }
216                         });
217                     }
218                     worker->ReleaseHostThreadContent();
219                 }
220                 if (!worker->IsRunning()) {
221                     HILOG_DEBUG("worker:: worker is not in running");
222                     return;
223                 }
224                 worker->TerminateInner();
225             }
226         },
227         nullptr, &worker->workerRef_);
228     worker->StartExecuteInThread(env, script);
229     return thisVar;
230 }
231 
PostMessage(napi_env env,napi_callback_info cbinfo)232 napi_value NewWorker::PostMessage(napi_env env, napi_callback_info cbinfo)
233 {
234     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
235     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
236     if (argc < 1) {
237         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
238             "Worker messageObject must be not null with postMessage");
239         return nullptr;
240     }
241     napi_value* argv = new napi_value[argc];
242     ObjectScope<napi_value> scope(argv, true);
243     napi_value thisVar = nullptr;
244     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
245     NewWorker* worker = nullptr;
246     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
247 
248     if (worker == nullptr || worker->IsTerminated() || worker->IsTerminating()) {
249         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
250             "maybe worker is terminated when PostMessage");
251         return nullptr;
252     }
253 
254     napi_value data = nullptr;
255     napi_status serializeStatus = napi_ok;
256     if (argc >= NUM_NEW_WORKER_ARGS) {
257         if (!NapiHelper::IsArray(argv[1])) {
258             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "transfer list must be an Array");
259             return nullptr;
260         }
261         serializeStatus = napi_serialize(env, argv[0], argv[1], &data);
262     } else {
263         serializeStatus = napi_serialize(env, argv[0], NapiHelper::GetUndefinedValue(env), &data);
264     }
265     if (serializeStatus != napi_ok || data == nullptr) {
266         worker->HostOnMessageErrorInner();
267         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
268         return nullptr;
269     }
270     worker->PostMessageInner(data);
271     return NapiHelper::GetUndefinedValue(env);
272 }
273 
Terminate(napi_env env,napi_callback_info cbinfo)274 napi_value NewWorker::Terminate(napi_env env, napi_callback_info cbinfo)
275 {
276     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
277     napi_value thisVar = nullptr;
278     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
279     NewWorker* worker = nullptr;
280     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
281     if (worker == nullptr) {
282         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when Terminate");
283         return nullptr;
284     }
285     if (worker->IsTerminated() || worker->IsTerminating()) {
286         HILOG_DEBUG("worker:: worker is not in running when Terminate");
287         return nullptr;
288     }
289     worker->TerminateInner();
290     return NapiHelper::GetUndefinedValue(env);
291 }
292 
On(napi_env env,napi_callback_info cbinfo)293 napi_value NewWorker::On(napi_env env, napi_callback_info cbinfo)
294 {
295     return AddListener(env, cbinfo, PERMANENT);
296 }
297 
Once(napi_env env,napi_callback_info cbinfo)298 napi_value NewWorker::Once(napi_env env, napi_callback_info cbinfo)
299 {
300     return AddListener(env, cbinfo, ONCE);
301 }
302 
Off(napi_env env,napi_callback_info cbinfo)303 napi_value NewWorker::Off(napi_env env, napi_callback_info cbinfo)
304 {
305     return RemoveListener(env, cbinfo);
306 }
307 
RemoveEventListener(napi_env env,napi_callback_info cbinfo)308 napi_value NewWorker::RemoveEventListener(napi_env env, napi_callback_info cbinfo)
309 {
310     return RemoveListener(env, cbinfo);
311 }
312 
AddEventListener(napi_env env,napi_callback_info cbinfo)313 napi_value NewWorker::AddEventListener(napi_env env, napi_callback_info cbinfo)
314 {
315     return AddListener(env, cbinfo, PERMANENT);
316 }
317 
AddListener(napi_env env,napi_callback_info cbinfo,ListenerMode mode)318 napi_value NewWorker::AddListener(napi_env env, napi_callback_info cbinfo, ListenerMode mode)
319 {
320     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
321     if (argc < NUM_NEW_WORKER_ARGS) {
322         ErrorHelper::ThrowError(env,
323             ErrorHelper::TYPE_ERROR, "worker add listener param count must be not less than 2.");
324         return nullptr;
325     }
326     // check 1st param is string
327     napi_value thisVar = nullptr;
328     void* data = nullptr;
329     napi_value* args = new napi_value[argc];
330     ObjectScope<napi_value> scope(args, true);
331     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
332     if (!NapiHelper::IsString(args[0])) {
333         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker add listener 1st param must be string");
334         return nullptr;
335     }
336     if (!NapiHelper::IsCallable(env, args[1])) {
337         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker add listener 2st param must be callable");
338         return nullptr;
339     }
340     NewWorker* worker = nullptr;
341     napi_unwrap(env, thisVar, (void**)&worker);
342     if (worker == nullptr) {
343         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
344         return nullptr;
345     }
346 
347     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
348     auto listener = new WorkerListener(env, callback, mode);
349     if (mode == ONCE && argc > NUM_NEW_WORKER_ARGS) {
350         if (NapiHelper::IsObject(args[NUM_NEW_WORKER_ARGS])) {
351             napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_NEW_WORKER_ARGS], "once");
352             bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
353             if (!isOnce) {
354                 listener->SetMode(PERMANENT);
355             }
356         }
357     }
358     char* typeStr = NapiHelper::GetString(env, args[0]);
359     worker->AddListenerInner(env, typeStr, listener);
360     CloseHelp::DeletePointer(typeStr, true);
361     return NapiHelper::GetUndefinedValue(env);
362 }
363 
RemoveListener(napi_env env,napi_callback_info cbinfo)364 napi_value NewWorker::RemoveListener(napi_env env, napi_callback_info cbinfo)
365 {
366     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
367     if (argc < 1) {
368         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the remove listener param must be not less than 1");
369         return nullptr;
370     }
371     // check 1st param is string
372     napi_value thisVar = nullptr;
373     void* data = nullptr;
374     napi_value* args = new napi_value[argc];
375     ObjectScope<napi_value> scope(args, true);
376     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
377     if (!NapiHelper::IsString(args[0])) {
378         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener 1st param must be string");
379         return nullptr;
380     }
381 
382     NewWorker* worker = nullptr;
383     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
384     if (worker == nullptr) {
385         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
386         return nullptr;
387     }
388 
389     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
390         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener 2st param must be callable");
391         return nullptr;
392     }
393 
394     char* typeStr = NapiHelper::GetString(env, args[0]);
395     if (typeStr == nullptr) {
396         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener type must be not null");
397         return nullptr;
398     }
399 
400     napi_ref callback = nullptr;
401     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
402         napi_create_reference(env, args[1], 1, &callback);
403     }
404     worker->RemoveListenerInner(env, typeStr, callback);
405     CloseHelp::DeletePointer(typeStr, true);
406     NapiHelper::DeleteReference(env, callback);
407     return NapiHelper::GetUndefinedValue(env);
408 }
409 
NewCallWorkCallback(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)410 void NewCallWorkCallback(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
411 {
412     napi_value callback = nullptr;
413     napi_get_named_property(env, recv, type, &callback);
414     if (NapiHelper::IsCallable(env, callback)) {
415         napi_value callbackResult = nullptr;
416         napi_call_function(env, recv, callback, argc, argv, &callbackResult);
417     }
418 }
419 
DispatchEvent(napi_env env,napi_callback_info cbinfo)420 napi_value NewWorker::DispatchEvent(napi_env env, napi_callback_info cbinfo)
421 {
422     size_t argc = 1;
423     napi_value args[1];
424     napi_value thisVar = nullptr;
425     void* data = nullptr;
426     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
427     if (argc < 1) {
428         ErrorHelper::ThrowError(env,
429             ErrorHelper::TYPE_ERROR, "the count of event param must be more than 1 in DispatchEvent");
430         return NapiHelper::CreateBooleanValue(env, false);
431     }
432 
433     // check 1st param is event
434     if (!NapiHelper::IsObject(args[0])) {
435         ErrorHelper::ThrowError(env,
436             ErrorHelper::TYPE_ERROR, "the type of event 1st param must be Event in DispatchEvent");
437         return NapiHelper::CreateBooleanValue(env, false);
438     }
439 
440     NewWorker* worker = nullptr;
441     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
442     if (worker == nullptr) {
443         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker has been terminated");
444         return NapiHelper::CreateBooleanValue(env, false);
445     }
446 
447     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
448     if (!NapiHelper::IsString(typeValue)) {
449         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of event type must be string");
450         return NapiHelper::CreateBooleanValue(env, false);
451     }
452 
453     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerRef_);
454 
455     char* typeStr = NapiHelper::GetString(env, typeValue);
456     if (typeStr == nullptr) {
457         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "dispatchEvent event type must be not null");
458         return NapiHelper::CreateBooleanValue(env, false);
459     }
460     if (strcmp(typeStr, "error") == 0) {
461         NewCallWorkCallback(env, obj, 1, args, "onerror");
462     } else if (strcmp(typeStr, "messageerror") == 0) {
463         NewCallWorkCallback(env, obj, 1, args, "onmessageerror");
464     } else if (strcmp(typeStr, "message") == 0) {
465         NewCallWorkCallback(env, obj, 1, args, "onmessage");
466     }
467 
468     worker->HandleEventListeners(env, obj, 1, args, typeStr);
469 
470     CloseHelp::DeletePointer(typeStr, true);
471     return NapiHelper::CreateBooleanValue(env, true);
472 }
473 
RemoveAllListener(napi_env env,napi_callback_info cbinfo)474 napi_value NewWorker::RemoveAllListener(napi_env env, napi_callback_info cbinfo)
475 {
476     napi_value thisVar = nullptr;
477     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
478     NewWorker* worker = nullptr;
479     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
480     if (worker == nullptr) {
481         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
482         return nullptr;
483     }
484 
485     worker->RemoveAllListenerInner();
486     return NapiHelper::GetUndefinedValue(env);
487 }
488 
CancelTask(napi_env env,napi_callback_info cbinfo)489 napi_value NewWorker::CancelTask(napi_env env, napi_callback_info cbinfo)
490 {
491     napi_value thisVar = nullptr;
492     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
493     NewWorker* worker = nullptr;
494     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
495     if (worker == nullptr) {
496         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
497         return nullptr;
498     }
499 
500     if (worker->IsTerminated() || worker->IsTerminating()) {
501         HILOG_INFO("worker:: worker is not in running");
502         return nullptr;
503     }
504 
505     if (!worker->ClearWorkerTasks()) {
506         HILOG_ERROR("worker:: clear worker task error");
507     }
508     return NapiHelper::GetUndefinedValue(env);
509 }
510 
PostMessageToHost(napi_env env,napi_callback_info cbinfo)511 napi_value NewWorker::PostMessageToHost(napi_env env, napi_callback_info cbinfo)
512 {
513     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
514     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
515     if (argc < 1) {
516         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker param count must be more than 1 with new");
517         return nullptr;
518     }
519     napi_value* argv = new napi_value[argc];
520     ObjectScope<napi_value> scope(argv, true);
521     NewWorker* worker = nullptr;
522     napi_get_cb_info(env, cbinfo, &argc, argv, nullptr, reinterpret_cast<void**>(&worker));
523 
524     if (worker == nullptr) {
525         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
526             "worker is nullptr when post message to host");
527         return nullptr;
528     }
529 
530     if (!worker->IsRunning()) {
531         // if worker is not running, don't send any message to host thread
532         HILOG_DEBUG("worker:: when post message to host occur worker is not in running.");
533         return nullptr;
534     }
535 
536     napi_value data = nullptr;
537     napi_status serializeStatus = napi_ok;
538     if (argc >= NUM_NEW_WORKER_ARGS) {
539         if (!NapiHelper::IsArray(argv[1])) {
540             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Transfer list must be an Array");
541             return nullptr;
542         }
543         serializeStatus = napi_serialize(env, argv[0], argv[1], &data);
544     } else {
545         serializeStatus = napi_serialize(env, argv[0], NapiHelper::GetUndefinedValue(env), &data);
546     }
547 
548     if (serializeStatus != napi_ok || data == nullptr) {
549         worker->WorkerOnMessageErrorInner();
550         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
551         return nullptr;
552     }
553     worker->PostMessageToHostInner(data);
554     return NapiHelper::GetUndefinedValue(env);
555 }
556 
CloseWorker(napi_env env,napi_callback_info cbinfo)557 napi_value NewWorker::CloseWorker(napi_env env, napi_callback_info cbinfo)
558 {
559     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
560     NewWorker* worker = nullptr;
561     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, (void**)&worker);
562     if (worker != nullptr) {
563         worker->CloseInner();
564     } else {
565         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null");
566         return nullptr;
567     }
568     return NapiHelper::GetUndefinedValue(env);
569 }
570 
WorkerPortCancelTask(napi_env env,napi_callback_info cbinfo)571 napi_value NewWorker::WorkerPortCancelTask(napi_env env, napi_callback_info cbinfo)
572 {
573     NewWorker* worker = nullptr;
574     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
575     if (worker == nullptr) {
576         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
577         return nullptr;
578     }
579 
580     if (worker->IsTerminated() || worker->IsTerminating()) {
581         HILOG_INFO("worker:: worker is not in running");
582         return nullptr;
583     }
584 
585     if (!worker->ClearWorkerTasks()) {
586         HILOG_ERROR("worker:: clear worker task error");
587     }
588     return NapiHelper::GetUndefinedValue(env);
589 }
590 
WorkerPortAddEventListener(napi_env env,napi_callback_info cbinfo)591 napi_value NewWorker::WorkerPortAddEventListener(napi_env env, napi_callback_info cbinfo)
592 {
593     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
594     if (argc < NUM_NEW_WORKER_ARGS) {
595         ErrorHelper::ThrowError(env,
596             ErrorHelper::TYPE_ERROR, "worker listener param count must be more than WORKPARAMNUM.");
597         return nullptr;
598     }
599 
600     napi_value* args = new napi_value[argc];
601     ObjectScope<napi_value> scope(args, true);
602     NewWorker* worker = nullptr;
603     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
604 
605     if (!NapiHelper::IsString(args[0])) {
606         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker listener 1st param must be string.");
607         return nullptr;
608     }
609 
610     if (!NapiHelper::IsCallable(env, args[1])) {
611         ErrorHelper::ThrowError(env,
612             ErrorHelper::TYPE_ERROR, "the type of worker listener 2st param must be callable.");
613         return nullptr;
614     }
615 
616     if (worker == nullptr || !worker->IsNotTerminate()) {
617         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
618         return nullptr;
619     }
620 
621     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
622     auto listener = new WorkerListener(env, callback, PERMANENT);
623     if (argc > NUM_NEW_WORKER_ARGS && NapiHelper::IsObject(args[NUM_NEW_WORKER_ARGS])) {
624         napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_NEW_WORKER_ARGS], "once");
625         bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
626         if (isOnce) {
627             listener->SetMode(ONCE);
628         }
629     }
630     char* typeStr = NapiHelper::GetString(env, args[0]);
631     worker->ParentPortAddListenerInner(env, typeStr, listener);
632     CloseHelp::DeletePointer(typeStr, true);
633     return NapiHelper::GetUndefinedValue(env);
634 }
635 
WorkerPortDispatchEvent(napi_env env,napi_callback_info cbinfo)636 napi_value NewWorker::WorkerPortDispatchEvent(napi_env env, napi_callback_info cbinfo)
637 {
638     size_t argc = 1;
639     napi_value args[1];
640     NewWorker* worker = nullptr;
641     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
642     if (argc < 1) {
643         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "DispatchEvent param count must be more than 1.");
644         return NapiHelper::CreateBooleanValue(env, false);
645     }
646 
647     if (!NapiHelper::IsObject(args[0])) {
648         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker DispatchEvent 1st param must be Event.");
649         return NapiHelper::CreateBooleanValue(env, false);
650     }
651 
652     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
653     if (!NapiHelper::IsString(typeValue)) {
654         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker event type must be string.");
655         return NapiHelper::CreateBooleanValue(env, false);
656     }
657 
658     if (worker == nullptr || !worker->IsNotTerminate()) {
659         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr.");
660         return NapiHelper::CreateBooleanValue(env, false);
661     }
662 
663     char* typeStr = NapiHelper::GetString(env, typeValue);
664     if (typeStr == nullptr) {
665         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
666         return NapiHelper::CreateBooleanValue(env, false);
667     }
668 
669     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerPort_);
670 
671     if (strcmp(typeStr, "error") == 0) {
672         NewCallWorkCallback(env, obj, 1, args, "onerror");
673     } else if (strcmp(typeStr, "messageerror") == 0) {
674         NewCallWorkCallback(env, obj, 1, args, "onmessageerror");
675     } else if (strcmp(typeStr, "message") == 0) {
676         NewCallWorkCallback(env, obj, 1, args, "onmessage");
677     }
678 
679     worker->ParentPortHandleEventListeners(env, obj, 1, args, typeStr, true);
680 
681     CloseHelp::DeletePointer(typeStr, true);
682     return NapiHelper::CreateBooleanValue(env, true);
683 }
684 
WorkerPortRemoveEventListener(napi_env env,napi_callback_info cbinfo)685 napi_value NewWorker::WorkerPortRemoveEventListener(napi_env env, napi_callback_info cbinfo)
686 {
687     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
688     if (argc < 1) {
689         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener param count must be more than 2.");
690         return nullptr;
691     }
692 
693     napi_value* args = new napi_value[argc];
694     ObjectScope<napi_value> scope(args, true);
695     NewWorker* worker = nullptr;
696     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
697 
698     if (!NapiHelper::IsString(args[0])) {
699         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker listener 1st param must be string.");
700         return nullptr;
701     }
702 
703     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
704         ErrorHelper::ThrowError(env,
705             ErrorHelper::TYPE_ERROR, "the type of worker listener 2st param must be callable with on.");
706         return nullptr;
707     }
708 
709     if (worker == nullptr || !worker->IsNotTerminate()) {
710         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
711         return nullptr;
712     }
713 
714     napi_ref callback = nullptr;
715     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
716         napi_create_reference(env, args[1], 1, &callback);
717     }
718 
719     char* typeStr = NapiHelper::GetString(env, args[0]);
720     if (typeStr == nullptr) {
721         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
722         return nullptr;
723     }
724     worker->ParentPortRemoveListenerInner(env, typeStr, callback);
725     CloseHelp::DeletePointer(typeStr, true);
726     NapiHelper::DeleteReference(env, callback);
727     return NapiHelper::GetUndefinedValue(env);
728 }
729 
WorkerPortRemoveAllListener(napi_env env,napi_callback_info cbinfo)730 napi_value NewWorker::WorkerPortRemoveAllListener(napi_env env, napi_callback_info cbinfo)
731 {
732     NewWorker* worker = nullptr;
733     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
734 
735     if (worker == nullptr || !worker->IsNotTerminate()) {
736         ErrorHelper::ThrowError(env,
737             ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when WorkerPortRemoveAllListener");
738         return nullptr;
739     }
740 
741     worker->ParentPortRemoveAllListenerInner();
742     return NapiHelper::GetUndefinedValue(env);
743 }
744 
GetContainerScopeId(napi_env env)745 void NewWorker::GetContainerScopeId(napi_env env)
746 {
747     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(env);
748     scopeId_ = hostEngine->GetContainerScopeIdFunc();
749 }
750 
StartExecuteInThread(napi_env env,const char * script)751 void NewWorker::StartExecuteInThread(napi_env env, const char* script)
752 {
753     // 1. init hostOnMessageSignal_ in host loop
754     uv_loop_t* loop = NapiHelper::GetLibUV(env);
755     if (loop == nullptr) {
756         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "engine loop is null");
757         CloseHelp::DeletePointer(script, true);
758         return;
759     }
760     GetContainerScopeId(env);
761     hostOnMessageSignal_ = new uv_async_t;
762     uv_async_init(loop, hostOnMessageSignal_, reinterpret_cast<uv_async_cb>(NewWorker::HostOnMessage));
763     hostOnMessageSignal_->data = this;
764     hostOnErrorSignal_ = new uv_async_t;
765     uv_async_init(loop, hostOnErrorSignal_, reinterpret_cast<uv_async_cb>(NewWorker::HostOnError));
766     hostOnErrorSignal_->data = this;
767 
768     // 2. copy the script
769     script_ = std::string(script);
770     CloseHelp::DeletePointer(script, true);
771 
772     // 3. create WorkerRunner to Execute
773     if (!runner_) {
774         runner_ = std::make_unique<WorkerRunner>(WorkerStartCallback(ExecuteInThread, this));
775     }
776     if (runner_) {
777         runner_->Execute(); // start a new thread
778     } else {
779         HILOG_ERROR("runner_ is nullptr");
780     }
781 }
782 
ExecuteInThread(const void * data)783 void NewWorker::ExecuteInThread(const void* data)
784 {
785     HITRACE_HELPER_START_TRACE(__PRETTY_FUNCTION__);
786     auto worker = reinterpret_cast<NewWorker*>(const_cast<void*>(data));
787     // 1. create a runtime, nativeengine
788     napi_env workerEnv = nullptr;
789     {
790         std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
791         if (worker->HostIsStop()) {
792             CloseHelp::DeletePointer(worker, false);
793             return;
794         }
795         napi_env env = worker->GetHostEnv();
796         napi_create_runtime(env, &workerEnv);
797         if (workerEnv == nullptr) {
798             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "Worker create runtime error");
799             return;
800         }
801         // mark worker env is workerThread
802         reinterpret_cast<NativeEngine*>(workerEnv)->MarkWorkerThread();
803         worker->SetWorkerEnv(workerEnv);
804     }
805 
806     uv_loop_t* loop = worker->GetWorkerLoop();
807     if (loop == nullptr) {
808         HILOG_ERROR("worker:: Worker loop is nullptr");
809         return;
810     }
811 
812     // 2. add some preparation for the worker
813     if (worker->PrepareForWorkerInstance()) {
814         worker->workerOnMessageSignal_ = new uv_async_t;
815         uv_async_init(loop, worker->workerOnMessageSignal_, reinterpret_cast<uv_async_cb>(NewWorker::WorkerOnMessage));
816         worker->workerOnMessageSignal_->data = worker;
817 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
818         uv_async_init(loop, &worker->ddebuggerOnPostTaskSignal_, reinterpret_cast<uv_async_cb>(
819             NewWorker::HandleDebuggerTask));
820 #endif
821         worker->UpdateWorkerState(RUNNING);
822         // in order to invoke worker send before subThread start
823         uv_async_send(worker->workerOnMessageSignal_);
824         HITRACE_HELPER_FINISH_TRACE;
825         // 3. start worker loop
826         worker->Loop();
827     } else {
828         HILOG_ERROR("worker:: worker PrepareForWorkerInstance fail");
829         worker->UpdateWorkerState(TERMINATED);
830         HITRACE_HELPER_FINISH_TRACE;
831     }
832     worker->ReleaseWorkerThreadContent();
833     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
834     if (worker->HostIsStop()) {
835         CloseHelp::DeletePointer(worker, false);
836     } else {
837         worker->PublishWorkerOverSignal();
838     }
839 }
840 
PrepareForWorkerInstance()841 bool NewWorker::PrepareForWorkerInstance()
842 {
843     std::vector<uint8_t> scriptContent;
844     std::string workerAmi;
845     {
846         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
847         if (HostIsStop()) {
848             return false;
849         }
850         // 1. init worker async func
851         auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
852 
853         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
854         // 2. init worker environment
855 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
856         workerEngine->SetDebuggerPostTaskFunc(
857             std::bind(&NewWorker::DebuggerOnPostTask, this, std::placeholders::_1));
858 #endif
859         if (!hostEngine->CallInitWorkerFunc(workerEngine)) {
860             HILOG_ERROR("worker:: CallInitWorkerFunc error");
861             return false;
862         }
863         // 3. get uril content
864         if (!hostEngine->CallGetAssetFunc(script_, scriptContent, workerAmi)) {
865             HILOG_ERROR("worker:: CallGetAssetFunc error");
866             return false;
867         }
868     }
869     // add timer interface
870     Timer::RegisterTime(workerEnv_);
871     HILOG_DEBUG("worker:: stringContent size is %{public}zu", scriptContent.size());
872     napi_value execScriptResult = nullptr;
873     napi_run_actor(workerEnv_, scriptContent, workerAmi.c_str(), &execScriptResult);
874     if (execScriptResult == nullptr) {
875         // An exception occurred when running the script.
876         HILOG_ERROR("worker:: run script exception occurs, will handle exception");
877         HandleException();
878         return false;
879     }
880 
881     // 4. register worker name in DedicatedWorkerGlobalScope
882     if (!name_.empty()) {
883         napi_value nameValue = nullptr;
884         napi_create_string_utf8(workerEnv_, name_.c_str(), name_.length(), &nameValue);
885         NapiHelper::SetNamePropertyInGlobal(workerEnv_, "name", nameValue);
886     }
887     return true;
888 }
889 
HostOnMessage(const uv_async_t * req)890 void NewWorker::HostOnMessage(const uv_async_t* req)
891 {
892     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
893     NewWorker* worker = static_cast<NewWorker*>(req->data);
894     if (worker == nullptr) {
895         HILOG_ERROR("worker:: worker is null when host onmessage.");
896         return;
897     }
898     worker->HostOnMessageInner();
899 }
900 
HostOnMessageInner()901 void NewWorker::HostOnMessageInner()
902 {
903     if (hostEnv_ == nullptr || HostIsStop()) {
904         HILOG_ERROR("worker:: host thread maybe is over when host onmessage.");
905         return;
906     }
907 
908     NativeEngine* engine = reinterpret_cast<NativeEngine*>(hostEnv_);
909     if (!engine->InitContainerScopeFunc(scopeId_)) {
910         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnMessageInner begin(only stage model)");
911     }
912 
913     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
914     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onmessage");
915     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
916 
917     MessageDataType data = nullptr;
918     while (hostMessageQueue_.DeQueue(&data)) {
919         // receive close signal.
920         if (data == nullptr) {
921             HILOG_DEBUG("worker:: worker received close signal");
922             uv_close(reinterpret_cast<uv_handle_t*>(hostOnMessageSignal_), [](uv_handle_t* handle) {
923                 if (handle != nullptr) {
924                     delete reinterpret_cast<uv_async_t*>(handle);
925                     handle = nullptr;
926                 }
927             });
928             uv_close(reinterpret_cast<uv_handle_t*>(hostOnErrorSignal_), [](uv_handle_t* handle) {
929                 if (handle != nullptr) {
930                     delete reinterpret_cast<uv_async_t*>(handle);
931                     handle = nullptr;
932                 }
933             });
934             CloseHostCallback();
935             return;
936         }
937         // handle data, call worker onMessage function to handle.
938         napi_status status = napi_ok;
939         HandleScope scope(hostEnv_, status);
940         NAPI_CALL_RETURN_VOID(hostEnv_, status);
941         napi_value result = nullptr;
942         status = napi_deserialize(hostEnv_, data, &result);
943         if (status != napi_ok || result == nullptr) {
944             HostOnMessageErrorInner();
945             continue;
946         }
947         napi_value event = nullptr;
948         napi_create_object(hostEnv_, &event);
949         napi_set_named_property(hostEnv_, event, "data", result);
950         napi_value argv[1] = { event };
951         if (isCallable) {
952             napi_value callbackResult = nullptr;
953             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
954         }
955         // handle listeners.
956         HandleEventListeners(hostEnv_, obj, 1, argv, "message");
957         HandleHostException();
958     }
959     if (!engine->FinishContainerScopeFunc(scopeId_)) {
960         HILOG_WARN("worker:: FinishContainerScopeFunc error when HostOnMessageInner end(only stage model)");
961     }
962 }
963 
CallHostFunction(size_t argc,const napi_value * argv,const char * methodName) const964 void NewWorker::CallHostFunction(size_t argc, const napi_value* argv, const char* methodName) const
965 {
966     if (hostEnv_ == nullptr) {
967         HILOG_ERROR("worker:: host thread maybe is over");
968         return;
969     }
970     if (HostIsStop()) {
971         ErrorHelper::ThrowError(hostEnv_,
972             ErrorHelper::ERR_WORKER_NOT_RUNNING, "host thread maybe is over when CallHostFunction");
973         return;
974     }
975     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
976     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, methodName);
977     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
978     if (!isCallable) {
979         HILOG_DEBUG("worker:: host thread %{public}s is not Callable", methodName);
980         return;
981     }
982     napi_value callbackResult = nullptr;
983     napi_call_function(hostEnv_, obj, callback, argc, argv, &callbackResult);
984     HandleHostException();
985 }
986 
CloseHostCallback()987 void NewWorker::CloseHostCallback()
988 {
989     {
990         napi_status status = napi_ok;
991         HandleScope scope(hostEnv_, status);
992         NAPI_CALL_RETURN_VOID(hostEnv_, status);
993         napi_value exitValue = nullptr;
994         if (isErrorExit_) {
995             napi_create_int32(hostEnv_, 1, &exitValue); // 1 : exit because of error
996         } else {
997             napi_create_int32(hostEnv_, 0, &exitValue); // 0 : exit normally
998         }
999         napi_value argv[1] = { exitValue };
1000         CallHostFunction(1, argv, "onexit");
1001         napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1002         // handle listeners
1003         HandleEventListeners(hostEnv_, obj, 1, argv, "exit");
1004     }
1005     CloseHelp::DeletePointer(this, false);
1006 }
1007 
HostOnError(const uv_async_t * req)1008 void NewWorker::HostOnError(const uv_async_t* req)
1009 {
1010     NewWorker* worker = static_cast<NewWorker*>(req->data);
1011     if (worker == nullptr) {
1012         HILOG_ERROR("worker:: worker is null");
1013         return;
1014     }
1015     worker->HostOnErrorInner();
1016     worker->TerminateInner();
1017 }
1018 
HostOnErrorInner()1019 void NewWorker::HostOnErrorInner()
1020 {
1021     if (hostEnv_ == nullptr || HostIsStop()) {
1022         HILOG_ERROR("worker:: host thread maybe is over when host onerror.");
1023         return;
1024     }
1025     napi_status status = napi_ok;
1026     HandleScope scope(hostEnv_, status);
1027     NAPI_CALL_RETURN_VOID(hostEnv_, status);
1028     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1029     if (!hostEngine->InitContainerScopeFunc(scopeId_)) {
1030         HILOG_WARN("worker:: InitContainerScopeFunc error when onerror begin(only stage model)");
1031     }
1032 
1033     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1034     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onerror");
1035     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1036 
1037     MessageDataType data;
1038     while (errorQueue_.DeQueue(&data)) {
1039         napi_value result = nullptr;
1040         napi_deserialize(hostEnv_, data, &result);
1041 
1042         napi_value argv[1] = { result };
1043         if (isCallable) {
1044             napi_value callbackResult = nullptr;
1045             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
1046         }
1047         // handle listeners
1048         HandleEventListeners(hostEnv_, obj, 1, argv, "error");
1049         HandleHostException();
1050     }
1051     if (!hostEngine->FinishContainerScopeFunc(scopeId_)) {
1052         HILOG_WARN("worker:: FinishContainerScopeFunc error when onerror end(only stage model)");
1053     }
1054 }
1055 
PostMessageInner(MessageDataType data)1056 void NewWorker::PostMessageInner(MessageDataType data)
1057 {
1058     if (IsTerminated()) {
1059         HILOG_DEBUG("worker:: worker has been terminated when PostMessageInner.");
1060         return;
1061     }
1062     workerMessageQueue_.EnQueue(data);
1063     if (workerOnMessageSignal_ != nullptr && uv_is_active((uv_handle_t*)workerOnMessageSignal_)) {
1064         uv_async_send(workerOnMessageSignal_);
1065     }
1066 }
1067 
HostOnMessageErrorInner()1068 void NewWorker::HostOnMessageErrorInner()
1069 {
1070     if (hostEnv_ == nullptr || HostIsStop()) {
1071         HILOG_ERROR("worker:: host thread maybe is over");
1072         return;
1073     }
1074     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1075     CallHostFunction(0, nullptr, "onmessageerror");
1076     // handle listeners
1077     HandleEventListeners(hostEnv_, obj, 0, nullptr, "messageerror");
1078 }
1079 
TerminateInner()1080 void NewWorker::TerminateInner()
1081 {
1082     if (IsTerminated() || IsTerminating()) {
1083         HILOG_INFO("worker:: worker is not in running when TerminateInner");
1084         return;
1085     }
1086     // 1. Update State
1087     UpdateWorkerState(TERMINATEING);
1088     // 2. send null signal
1089     PostMessageInner(NULL);
1090 }
1091 
CloseInner()1092 void NewWorker::CloseInner()
1093 {
1094     UpdateWorkerState(TERMINATEING);
1095     TerminateWorker();
1096 }
1097 
UpdateWorkerState(RunnerState state)1098 bool NewWorker::UpdateWorkerState(RunnerState state)
1099 {
1100     bool done = false;
1101     do {
1102         RunnerState oldState = runnerState_.load(std::memory_order_acquire);
1103         if (oldState >= state) {
1104             // make sure state sequence is start, running, terminating, terminated
1105             return false;
1106         }
1107         done = runnerState_.compare_exchange_strong(oldState, state);
1108     } while (!done);
1109     return true;
1110 }
1111 
UpdateHostState(HostState state)1112 bool NewWorker::UpdateHostState(HostState state)
1113 {
1114     bool done = false;
1115     do {
1116         HostState oldState = hostState_.load(std::memory_order_acquire);
1117         if (oldState >= state) {
1118             // make sure state sequence is ACTIVE, INACTIVE
1119             return false;
1120         }
1121         done = hostState_.compare_exchange_strong(oldState, state);
1122     } while (!done);
1123     return true;
1124 }
1125 
TerminateWorker()1126 void NewWorker::TerminateWorker()
1127 {
1128     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1129     // when there is no active handle, worker loop will stop automatic.
1130     uv_close(reinterpret_cast<uv_handle_t*>(workerOnMessageSignal_), [](uv_handle_t* handle) {
1131         if (handle != nullptr) {
1132             delete reinterpret_cast<uv_async_t*>(handle);
1133             handle = nullptr;
1134         }
1135     });
1136 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1137     uv_close(reinterpret_cast<uv_handle_t*>(&ddebuggerOnPostTaskSignal_), nullptr);
1138 #endif
1139     CloseWorkerCallback();
1140     uv_loop_t* loop = GetWorkerLoop();
1141     if (loop != nullptr) {
1142         if (g_newWorkers.size() <= 1) {
1143             Timer::ClearEnvironmentTimer(workerEnv_);
1144         }
1145         uv_stop(loop);
1146     }
1147     UpdateWorkerState(TERMINATED);
1148 }
1149 
PublishWorkerOverSignal()1150 void NewWorker::PublishWorkerOverSignal()
1151 {
1152     // post NULL tell host worker is not running
1153     if (!HostIsStop()) {
1154         hostMessageQueue_.EnQueue(NULL);
1155         uv_async_send(hostOnMessageSignal_);
1156     }
1157 }
1158 
WorkerOnMessage(const uv_async_t * req)1159 void NewWorker::WorkerOnMessage(const uv_async_t* req)
1160 {
1161     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1162     NewWorker* worker = static_cast<NewWorker*>(req->data);
1163     if (worker == nullptr) {
1164         HILOG_ERROR("worker::worker is null");
1165         return;
1166     }
1167     worker->WorkerOnMessageInner();
1168 }
1169 
WorkerOnMessageInner()1170 void NewWorker::WorkerOnMessageInner()
1171 {
1172     if (IsTerminated()) {
1173         return;
1174     }
1175     napi_status status;
1176     napi_handle_scope scope = nullptr;
1177     status = napi_open_handle_scope(workerEnv_, &scope);
1178     if (status != napi_ok || scope == nullptr) {
1179         HILOG_ERROR("worker:: WorkerOnMessage open handle scope failed.");
1180         return;
1181     }
1182     MessageDataType data = nullptr;
1183     while (!IsTerminated() && workerMessageQueue_.DeQueue(&data)) {
1184         if (data == nullptr) {
1185             HILOG_DEBUG("worker:: worker reveive terminate signal");
1186             // Close handlescope need before TerminateWorker
1187             napi_close_handle_scope(workerEnv_, scope);
1188             TerminateWorker();
1189             return;
1190         }
1191         napi_value result = nullptr;
1192         status = napi_deserialize(workerEnv_, data, &result);
1193         if (status != napi_ok || result == nullptr) {
1194             WorkerOnMessageErrorInner();
1195             continue;
1196         }
1197 
1198         napi_value event = nullptr;
1199         napi_create_object(workerEnv_, &event);
1200         napi_set_named_property(workerEnv_, event, "data", result);
1201         napi_value argv[1] = { event };
1202         CallWorkerFunction(1, argv, "onmessage", true);
1203 
1204         napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
1205         ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "message", true);
1206     }
1207     napi_close_handle_scope(workerEnv_, scope);
1208 }
1209 
HandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)1210 void NewWorker::HandleEventListeners(napi_env env, napi_value recv, size_t argc,
1211                                      const napi_value* argv, const char* type)
1212 {
1213     std::string listener(type);
1214     auto iter = eventListeners_.find(listener);
1215     if (iter == eventListeners_.end()) {
1216         HILOG_DEBUG("worker:: there is no listener for type %{public}s in host thread", type);
1217         return;
1218     }
1219 
1220     std::list<WorkerListener*>& listeners = iter->second;
1221     std::list<WorkerListener*>::iterator it = listeners.begin();
1222     while (it != listeners.end()) {
1223         WorkerListener* data = *it++;
1224         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
1225         if (!NapiHelper::IsCallable(env, callbackObj)) {
1226             HILOG_DEBUG("worker:: host thread listener %{public}s is not callable", type);
1227             return;
1228         }
1229         napi_value callbackResult = nullptr;
1230         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
1231         if (!data->NextIsAvailable()) {
1232             listeners.remove(data);
1233             CloseHelp::DeletePointer(data, false);
1234         }
1235     }
1236 }
1237 
HandleHostException() const1238 void NewWorker::HandleHostException() const
1239 {
1240     if (!NapiHelper::IsExceptionPending(hostEnv_)) {
1241         return;
1242     }
1243     auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1244     hostEngine->HandleUncaughtException();
1245 }
1246 
HandleException()1247 void NewWorker::HandleException()
1248 {
1249     if (!NapiHelper::IsExceptionPending(workerEnv_)) {
1250         return;
1251     }
1252 
1253     napi_status status = napi_ok;
1254     HandleScope scope(workerEnv_, status);
1255     NAPI_CALL_RETURN_VOID(workerEnv_, status);
1256     napi_value exception;
1257     napi_get_and_clear_last_exception(workerEnv_, &exception);
1258     if (exception == nullptr) {
1259         return;
1260     }
1261 
1262     napi_value obj = ErrorHelper::TranslateErrorEvent(workerEnv_, exception);
1263 
1264     // WorkerGlobalScope onerror
1265     WorkerOnErrorInner(obj);
1266 
1267     if (hostEnv_ != nullptr) {
1268         napi_value data = nullptr;
1269         napi_serialize(workerEnv_, obj, NapiHelper::GetUndefinedValue(workerEnv_), &data);
1270         {
1271             std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1272             if (!HostIsStop()) {
1273                 errorQueue_.EnQueue(data);
1274                 uv_async_send(hostOnErrorSignal_);
1275             }
1276         }
1277     } else {
1278         HILOG_ERROR("worker:: host engine is nullptr.");
1279     }
1280 }
1281 
WorkerOnMessageErrorInner()1282 void NewWorker::WorkerOnMessageErrorInner()
1283 {
1284     isErrorExit_ = true;
1285     CallWorkerFunction(0, nullptr, "onmessageerror", true);
1286     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
1287     ParentPortHandleEventListeners(workerEnv_, obj, 0, nullptr, "messageerror", true);
1288 }
1289 
PostMessageToHostInner(MessageDataType data)1290 void NewWorker::PostMessageToHostInner(MessageDataType data)
1291 {
1292     std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1293     if (hostEnv_ != nullptr && !HostIsStop()) {
1294         hostMessageQueue_.EnQueue(data);
1295         uv_async_send(hostOnMessageSignal_);
1296     } else {
1297         HILOG_ERROR("worker:: worker host engine is nullptr when PostMessageToHostInner.");
1298     }
1299 }
1300 
operator ==(const WorkerListener & listener) const1301 bool NewWorker::WorkerListener::operator==(const WorkerListener& listener) const
1302 {
1303     napi_value obj = NapiHelper::GetReferenceValue(listener.env_, listener.callback_);
1304     napi_value compareObj = NapiHelper::GetReferenceValue(env_, callback_);
1305     // the env of listener and cmp listener must be same env because of Synchronization method
1306     return NapiHelper::StrictEqual(env_, compareObj, obj);
1307 }
1308 
AddListenerInner(napi_env env,const char * type,const WorkerListener * listener)1309 void NewWorker::AddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
1310 {
1311     std::string typestr(type);
1312     auto iter = eventListeners_.find(typestr);
1313     if (iter == eventListeners_.end()) {
1314         std::list<WorkerListener*> listeners;
1315         listeners.emplace_back(const_cast<WorkerListener*>(listener));
1316         eventListeners_[typestr] = listeners;
1317     } else {
1318         std::list<WorkerListener*>& listenerList = iter->second;
1319         std::list<WorkerListener*>::iterator it = std::find_if(
1320             listenerList.begin(), listenerList.end(), NewWorker::FindWorkerListener(env, listener->callback_));
1321         if (it != listenerList.end()) {
1322             return;
1323         }
1324         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
1325     }
1326 }
1327 
RemoveListenerInner(napi_env env,const char * type,napi_ref callback)1328 void NewWorker::RemoveListenerInner(napi_env env, const char* type, napi_ref callback)
1329 {
1330     std::string typestr(type);
1331     auto iter = eventListeners_.find(typestr);
1332     if (iter == eventListeners_.end()) {
1333         return;
1334     }
1335     std::list<WorkerListener*>& listenerList = iter->second;
1336     if (callback != nullptr) {
1337         std::list<WorkerListener*>::iterator it =
1338             std::find_if(listenerList.begin(), listenerList.end(), NewWorker::FindWorkerListener(env, callback));
1339         if (it != listenerList.end()) {
1340             CloseHelp::DeletePointer(*it, false);
1341             listenerList.erase(it);
1342         }
1343     } else {
1344         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
1345             CloseHelp::DeletePointer(*it, false);
1346         }
1347         eventListeners_.erase(typestr);
1348     }
1349 }
1350 
~NewWorker()1351 NewWorker::~NewWorker()
1352 {
1353     if (!HostIsStop()) {
1354         ReleaseHostThreadContent();
1355     }
1356     RemoveAllListenerInner();
1357 }
1358 
RemoveAllListenerInner()1359 void NewWorker::RemoveAllListenerInner()
1360 {
1361     for (auto iter = eventListeners_.begin(); iter != eventListeners_.end(); iter++) {
1362         std::list<WorkerListener*>& listeners = iter->second;
1363         for (auto item = listeners.begin(); item != listeners.end(); item++) {
1364             WorkerListener* listener = *item;
1365             CloseHelp::DeletePointer(listener, false);
1366         }
1367     }
1368     eventListeners_.clear();
1369 }
1370 
ReleaseHostThreadContent()1371 void NewWorker::ReleaseHostThreadContent()
1372 {
1373     // 1. clear message send to host thread
1374     hostMessageQueue_.Clear(hostEnv_);
1375     // 2. clear error queue send to host thread
1376     errorQueue_.Clear(hostEnv_);
1377     if (!HostIsStop()) {
1378         napi_status status = napi_ok;
1379         HandleScope scope(hostEnv_, status);
1380         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1381         // 3. set thisVar's nativepointer be null
1382         napi_value thisVar = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1383         NewWorker* worker = nullptr;
1384         napi_remove_wrap(hostEnv_, thisVar, reinterpret_cast<void**>(&worker));
1385         hostEnv_ = nullptr;
1386         // 4. set workerRef_ be null
1387         workerRef_ = nullptr;
1388     }
1389 }
1390 
WorkerOnErrorInner(napi_value error)1391 void NewWorker::WorkerOnErrorInner(napi_value error)
1392 {
1393     isErrorExit_ = true;
1394     napi_value argv[1] = { error };
1395     CallWorkerFunction(1, argv, "onerror", false);
1396     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
1397     ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "error", false);
1398 }
1399 
CallWorkerFunction(size_t argc,const napi_value * argv,const char * methodName,bool tryCatch)1400 bool NewWorker::CallWorkerFunction(size_t argc, const napi_value* argv, const char* methodName, bool tryCatch)
1401 {
1402     if (workerEnv_ == nullptr) {
1403         HILOG_ERROR("Worker:: worker is not running when call workerPort.%{public}s.", methodName);
1404         return false;
1405     }
1406     napi_value callback = NapiHelper::GetNamePropertyInParentPort(workerEnv_, workerPort_, methodName);
1407     bool isCallable = NapiHelper::IsCallable(workerEnv_, callback);
1408     if (!isCallable) {
1409         HILOG_DEBUG("worker:: workerPort.%{public}s is not Callable", methodName);
1410         return false;
1411     }
1412     napi_value undefinedValue = NapiHelper::GetUndefinedValue(workerEnv_);
1413     napi_value callbackResult = nullptr;
1414     napi_call_function(workerEnv_, undefinedValue, callback, argc, argv, &callbackResult);
1415     if (tryCatch && callbackResult == nullptr) {
1416         HILOG_DEBUG("worker:: workerPort.%{public}s handle exception", methodName);
1417         HandleException();
1418         return false;
1419     }
1420     return true;
1421 }
1422 
CloseWorkerCallback()1423 void NewWorker::CloseWorkerCallback()
1424 {
1425     CallWorkerFunction(0, nullptr, "onclose", true);
1426     // off worker inited environment
1427     {
1428         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1429         if (HostIsStop()) {
1430             return;
1431         }
1432         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1433         if (!hostEngine->CallOffWorkerFunc(reinterpret_cast<NativeEngine*>(workerEnv_))) {
1434             HILOG_ERROR("worker:: CallOffWorkerFunc error");
1435         }
1436     }
1437 }
1438 
ReleaseWorkerThreadContent()1439 void NewWorker::ReleaseWorkerThreadContent()
1440 {
1441     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1442     auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1443     auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
1444     if (hostEngine != nullptr && workerEngine != nullptr) {
1445         if (!hostEngine->DeleteWorker(workerEngine)) {
1446             HILOG_ERROR("worker:: DeleteWorker error");
1447         }
1448     }
1449     // 1. remove worker instance count
1450     {
1451         std::lock_guard<std::mutex> lock(g_newWorkersMutex);
1452         std::list<NewWorker*>::iterator it = std::find(g_newWorkers.begin(), g_newWorkers.end(), this);
1453         if (it != g_newWorkers.end()) {
1454             g_newWorkers.erase(it);
1455         }
1456     }
1457 
1458     ParentPortRemoveAllListenerInner();
1459 
1460     // 2. delete worker's parentPort
1461     NapiHelper::DeleteReference(workerEnv_, workerPort_);
1462     workerPort_ = nullptr;
1463 
1464     // 3. clear message send to worker thread
1465     workerMessageQueue_.Clear(workerEnv_);
1466     CloseHelp::DeletePointer(reinterpret_cast<NativeEngine*>(workerEnv_), false);
1467     workerEnv_ = nullptr;
1468 }
1469 
ParentPortAddListenerInner(napi_env env,const char * type,const WorkerListener * listener)1470 void NewWorker::ParentPortAddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
1471 {
1472     std::string typestr(type);
1473     auto iter = parentPortEventListeners_.find(typestr);
1474     if (iter == parentPortEventListeners_.end()) {
1475         std::list<WorkerListener*> listeners;
1476         listeners.emplace_back(const_cast<WorkerListener*>(listener));
1477         parentPortEventListeners_[typestr] = listeners;
1478     } else {
1479         std::list<WorkerListener*>& listenerList = iter->second;
1480         std::list<WorkerListener*>::iterator it = std::find_if(
1481             listenerList.begin(), listenerList.end(), NewWorker::FindWorkerListener(env, listener->callback_));
1482         if (it != listenerList.end()) {
1483             return;
1484         }
1485         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
1486     }
1487 }
1488 
ParentPortRemoveAllListenerInner()1489 void NewWorker::ParentPortRemoveAllListenerInner()
1490 {
1491     for (auto iter = parentPortEventListeners_.begin(); iter != parentPortEventListeners_.end(); iter++) {
1492         std::list<WorkerListener*>& listeners = iter->second;
1493         for (auto item = listeners.begin(); item != listeners.end(); item++) {
1494             WorkerListener* listener = *item;
1495             CloseHelp::DeletePointer(listener, false);
1496         }
1497     }
1498     parentPortEventListeners_.clear();
1499 }
1500 
ParentPortRemoveListenerInner(napi_env env,const char * type,napi_ref callback)1501 void NewWorker::ParentPortRemoveListenerInner(napi_env env, const char* type, napi_ref callback)
1502 {
1503     std::string typestr(type);
1504     auto iter = parentPortEventListeners_.find(typestr);
1505     if (iter == parentPortEventListeners_.end()) {
1506         return;
1507     }
1508     std::list<WorkerListener*>& listenerList = iter->second;
1509     if (callback != nullptr) {
1510         std::list<WorkerListener*>::iterator it =
1511             std::find_if(listenerList.begin(), listenerList.end(), NewWorker::FindWorkerListener(env, callback));
1512         if (it != listenerList.end()) {
1513             CloseHelp::DeletePointer(*it, false);
1514             listenerList.erase(it);
1515         }
1516     } else {
1517         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
1518             CloseHelp::DeletePointer(*it, false);
1519         }
1520         parentPortEventListeners_.erase(typestr);
1521     }
1522 }
1523 
ParentPortHandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type,bool tryCatch)1524 void NewWorker::ParentPortHandleEventListeners(napi_env env, napi_value recv, size_t argc,
1525                                                const napi_value* argv, const char* type, bool tryCatch)
1526 {
1527     std::string listener(type);
1528     auto iter = parentPortEventListeners_.find(listener);
1529     if (iter == parentPortEventListeners_.end()) {
1530         HILOG_DEBUG("worker:: there is no listener for type %{public}s in worker thread", type);
1531         return;
1532     }
1533 
1534     std::list<WorkerListener*>& listeners = iter->second;
1535     std::list<WorkerListener*>::iterator it = listeners.begin();
1536     while (it != listeners.end()) {
1537         WorkerListener* data = *it++;
1538         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
1539         if (!NapiHelper::IsCallable(env, callbackObj)) {
1540             HILOG_DEBUG("worker:: workerPort.addEventListener %{public}s is not callable", type);
1541             return;
1542         }
1543         napi_value callbackResult = nullptr;
1544         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
1545         if (!data->NextIsAvailable()) {
1546             listeners.remove(data);
1547             CloseHelp::DeletePointer(data, false);
1548         }
1549         if (tryCatch && callbackResult == nullptr) {
1550             HandleException();
1551             return;
1552         }
1553     }
1554 }
1555 
1556 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
HandleDebuggerTask(const uv_async_t * req)1557 void NewWorker::HandleDebuggerTask(const uv_async_t* req)
1558 {
1559     NewWorker* worker = DereferenceHelp::DereferenceOf(&NewWorker::ddebuggerOnPostTaskSignal_, req);
1560     if (worker == nullptr) {
1561         HILOG_ERROR("worker::worker is null");
1562         return;
1563     }
1564 
1565     worker->debuggerTask_();
1566 }
1567 
DebuggerOnPostTask(std::function<void ()> && task)1568 void NewWorker::DebuggerOnPostTask(std::function<void()>&& task)
1569 {
1570     if (IsTerminated()) {
1571         HILOG_ERROR("worker:: worker has been terminated.");
1572         return;
1573     }
1574     if (uv_is_active((uv_handle_t*)&ddebuggerOnPostTaskSignal_)) {
1575         debuggerTask_ = std::move(task);
1576         uv_async_send(&ddebuggerOnPostTaskSignal_);
1577     }
1578 }
1579 #endif
1580 
1581 } // namespace Commonlibrary::Concurrent::WorkerModule
1582