• 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.h"
17 
18 #include "commonlibrary/ets_utils/js_sys_module/timer/timer.h"
19 #include "helper/concurrent_helper.h"
20 #include "helper/error_helper.h"
21 #include "helper/hitrace_helper.h"
22 #include "helper/path_helper.h"
23 #if defined(OHOS_PLATFORM)
24 #include "parameters.h"
25 #endif
26 
27 namespace Commonlibrary::Concurrent::WorkerModule {
28 using namespace OHOS::JsSysModule;
29 static constexpr int8_t NUM_WORKER_ARGS = 2;
30 static constexpr uint8_t NUM_GLOBAL_CALL_ARGS = 3;
31 static std::list<Worker *> g_workers;
32 static constexpr int MAX_WORKERS = 8;
33 static std::mutex g_workersMutex;
34 static std::list<Worker *> g_limitedworkers;
35 static constexpr int MAX_LIMITEDWORKERS = 16;
36 static std::mutex g_limitedworkersMutex;
37 static constexpr uint8_t BEGIN_INDEX_OF_ARGUMENTS = 2;
38 static constexpr uint32_t DEFAULT_TIMEOUT = 5000;
39 static constexpr uint32_t GLOBAL_CALL_ID_MAX = 4294967295;
40 
Worker(napi_env env,napi_ref thisVar)41 Worker::Worker(napi_env env, napi_ref thisVar)
42     : hostEnv_(env), workerRef_(thisVar)
43 {}
44 
InitWorker(napi_env env,napi_value exports)45 napi_value Worker::InitWorker(napi_env env, napi_value exports)
46 {
47     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
48     napi_property_descriptor properties[] = {
49         DECLARE_NAPI_FUNCTION("postMessage", PostMessage),
50         DECLARE_NAPI_FUNCTION("postSendableMessage", PostSendableMessage),
51         DECLARE_NAPI_FUNCTION("terminate", Terminate),
52         DECLARE_NAPI_FUNCTION("on", On),
53         DECLARE_NAPI_FUNCTION("registerGlobalCallObject", RegisterGlobalCallObject),
54         DECLARE_NAPI_FUNCTION("unregisterGlobalCallObject", UnregisterGlobalCallObject),
55         DECLARE_NAPI_FUNCTION("once", Once),
56         DECLARE_NAPI_FUNCTION("off", Off),
57         DECLARE_NAPI_FUNCTION("addEventListener", AddEventListener),
58         DECLARE_NAPI_FUNCTION("dispatchEvent", DispatchEvent),
59         DECLARE_NAPI_FUNCTION("removeEventListener", RemoveEventListener),
60         DECLARE_NAPI_FUNCTION("removeAllListener", RemoveAllListener),
61         DECLARE_NAPI_FUNCTION("cancelTasks", CancelTask),
62     };
63     // for worker.ThreadWorker
64     const char threadWorkerName[] = "ThreadWorker";
65     napi_value threadWorkerClazz = nullptr;
66     napi_define_class(env, threadWorkerName, sizeof(threadWorkerName), Worker::ThreadWorkerConstructor, nullptr,
67         sizeof(properties) / sizeof(properties[0]), properties, &threadWorkerClazz);
68     napi_set_named_property(env, exports, "ThreadWorker", threadWorkerClazz);
69 
70     // for worker.Worker
71     const char workerName[] = "Worker";
72     napi_value workerClazz = nullptr;
73     napi_define_class(env, workerName, sizeof(workerName), Worker::WorkerConstructor, nullptr,
74         sizeof(properties) / sizeof(properties[0]), properties, &workerClazz);
75     napi_set_named_property(env, exports, "Worker", workerClazz);
76 
77     // for worker.LimitedWorker
78     const char limitedWorkerName[] = "RestrictedWorker";
79     napi_value limitedWorkerClazz = nullptr;
80     napi_define_class(env, limitedWorkerName, sizeof(limitedWorkerName), Worker::LimitedWorkerConstructor, nullptr,
81         sizeof(properties) / sizeof(properties[0]), properties, &limitedWorkerClazz);
82     napi_set_named_property(env, exports, "RestrictedWorker", limitedWorkerClazz);
83     return InitPort(env, exports);
84 }
85 
InitPort(napi_env env,napi_value exports)86 napi_value Worker::InitPort(napi_env env, napi_value exports)
87 {
88     NativeEngine* engine = reinterpret_cast<NativeEngine*>(env);
89     Worker* worker = nullptr;
90     if (engine->IsRestrictedWorkerThread()) {
91         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
92         for (auto item = g_limitedworkers.begin(); item != g_limitedworkers.end(); item++) {
93             if ((*item)->IsSameWorkerEnv(env)) {
94                 worker = *item;
95             }
96         }
97     } else if (engine->IsWorkerThread()) {
98         std::lock_guard<std::mutex> lock(g_workersMutex);
99         for (auto item = g_workers.begin(); item != g_workers.end(); item++) {
100             if ((*item)->IsSameWorkerEnv(env)) {
101                 worker = *item;
102             }
103         }
104     } else {
105         return exports;
106     }
107 
108     if (worker == nullptr) {
109         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null when InitWorker");
110         return exports;
111     }
112 
113     napi_property_descriptor properties[] = {
114         DECLARE_NAPI_FUNCTION_WITH_DATA("postMessage", PostMessageToHost, worker),
115         DECLARE_NAPI_FUNCTION_WITH_DATA("postSendableMessage", PostSendableMessageToHost, worker),
116         DECLARE_NAPI_FUNCTION_WITH_DATA("callGlobalCallObjectMethod", GlobalCall, worker),
117         DECLARE_NAPI_FUNCTION_WITH_DATA("close", CloseWorker, worker),
118         DECLARE_NAPI_FUNCTION_WITH_DATA("cancelTasks", ParentPortCancelTask, worker),
119         DECLARE_NAPI_FUNCTION_WITH_DATA("addEventListener", ParentPortAddEventListener, worker),
120         DECLARE_NAPI_FUNCTION_WITH_DATA("dispatchEvent", ParentPortDispatchEvent, worker),
121         DECLARE_NAPI_FUNCTION_WITH_DATA("removeEventListener", ParentPortRemoveEventListener, worker),
122         DECLARE_NAPI_FUNCTION_WITH_DATA("removeAllListener", ParentPortRemoveAllListener, worker),
123     };
124     napi_value workerPortObj = nullptr;
125     napi_create_object(env, &workerPortObj);
126     napi_define_properties(env, workerPortObj, sizeof(properties) / sizeof(properties[0]), properties);
127 
128     // 5. register worker name in DedicatedWorkerGlobalScope
129     std::string name = worker->GetName();
130     if (!name.empty()) {
131         napi_value nameValue = nullptr;
132         napi_create_string_utf8(env, name.c_str(), name.length(), &nameValue);
133         napi_set_named_property(env, workerPortObj, "name", nameValue);
134     }
135 
136     napi_set_named_property(env, workerPortObj, "self", workerPortObj);
137 
138     while (!engine->IsMainThread()) {
139         engine = engine->GetHostEngine();
140     }
141     if (engine->IsTargetWorkerVersion(WorkerVersion::NEW)) {
142         napi_set_named_property(env, exports, "workerPort", workerPortObj);
143     } else {
144         napi_set_named_property(env, exports, "parentPort", workerPortObj);
145     }
146     // register worker Port.
147     napi_create_reference(env, workerPortObj, 1, &worker->workerPort_);
148     return exports;
149 }
150 
LimitedWorkerConstructor(napi_env env,napi_callback_info cbinfo)151 napi_value Worker::LimitedWorkerConstructor(napi_env env, napi_callback_info cbinfo)
152 {
153     if (CanCreateWorker(env, WorkerVersion::NEW)) {
154         return Constructor(env, cbinfo, true);
155     }
156     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
157         "Using both Worker and LimitedWorker is not supported.");
158     return nullptr;
159 }
160 
ThreadWorkerConstructor(napi_env env,napi_callback_info cbinfo)161 napi_value Worker::ThreadWorkerConstructor(napi_env env, napi_callback_info cbinfo)
162 {
163     HITRACE_HELPER_METER_NAME("ThreadWorkerConstructor: [Add Thread]");
164     if (CanCreateWorker(env, WorkerVersion::NEW)) {
165         return Constructor(env, cbinfo);
166     }
167     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
168         "Using both Worker and ThreadWorker is not supported.");
169     return nullptr;
170 }
171 
WorkerConstructor(napi_env env,napi_callback_info cbinfo)172 napi_value Worker::WorkerConstructor(napi_env env, napi_callback_info cbinfo)
173 {
174     HITRACE_HELPER_METER_NAME("WorkerConstructor: [Add Thread]");
175     if (CanCreateWorker(env, WorkerVersion::OLD)) {
176         return Constructor(env, cbinfo);
177     }
178     ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION,
179         "Using both Worker and other Workers is not supported.");
180     return nullptr;
181 }
182 
Constructor(napi_env env,napi_callback_info cbinfo,bool limitSign)183 napi_value Worker::Constructor(napi_env env, napi_callback_info cbinfo, bool limitSign)
184 {
185     napi_value thisVar = nullptr;
186     void* data = nullptr;
187     size_t argc = 2;  // 2: max args number is 2
188     napi_value args[argc];
189     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
190     // check argv count
191     if (argc < 1) {
192         ErrorHelper::ThrowError(env,
193             ErrorHelper::TYPE_ERROR, "the number of create worker param must be more than 1 with new");
194         return nullptr;
195     }
196     // check 1st param is string
197     if (!NapiHelper::IsString(env, args[0])) {
198         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of Worker 1st param must be string.");
199         return nullptr;
200     }
201     WorkerParams* workerParams = nullptr;
202     if (argc == 2) {  // 2: max args number is 2
203         workerParams = CheckWorkerArgs(env, args[1]);
204         if (workerParams == nullptr) {
205             HILOG_ERROR("Worker:: arguments check failed.");
206             return nullptr;
207         }
208     }
209 
210     Worker* worker = nullptr;
211     if (limitSign) {
212         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
213         if (static_cast<int>(g_limitedworkers.size()) >= MAX_LIMITEDWORKERS) {
214             ErrorHelper::ThrowError(env,
215                 ErrorHelper::ERR_WORKER_INITIALIZATION, "the number of limiteworkers exceeds the maximum.");
216             return nullptr;
217         }
218 
219         // 2. new worker instance
220         worker = new Worker(env, nullptr);
221         if (worker == nullptr) {
222             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "creat worker error");
223             return nullptr;
224         }
225         g_limitedworkers.push_back(worker);
226     } else {
227         int maxWorkers = MAX_WORKERS;
228     #if defined(OHOS_PLATFORM)
229         maxWorkers = OHOS::system::GetIntParameter<int>("persist.commonlibrary.maxworkers", MAX_WORKERS);
230     #endif
231         std::lock_guard<std::mutex> lock(g_workersMutex);
232         if (static_cast<int>(g_workers.size()) >= maxWorkers) {
233             ErrorHelper::ThrowError(env,
234                 ErrorHelper::ERR_WORKER_INITIALIZATION, "the number of workers exceeds the maximum.");
235             return nullptr;
236         }
237 
238         // 2. new worker instance
239         worker = new Worker(env, nullptr);
240         if (worker == nullptr) {
241             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "creat worker error");
242             return nullptr;
243         }
244         g_workers.push_back(worker);
245     }
246 
247     if (workerParams != nullptr) {
248         if (!workerParams->name_.empty()) {
249             worker->name_ = workerParams->name_;
250         }
251         // default classic
252         worker->SetScriptMode(workerParams->type_);
253         CloseHelp::DeletePointer(workerParams, false);
254         workerParams = nullptr;
255     }
256     worker->isLimitedWorker_ = limitSign;
257 
258     // 3. execute in thread
259     char* script = NapiHelper::GetString(env, args[0]);
260     if (script == nullptr) {
261         ErrorHelper::ThrowError(env,
262             ErrorHelper::ERR_WORKER_INVALID_FILEPATH, "the file path is invaild, maybe path is null.");
263         return nullptr;
264     }
265     napi_wrap(
266         env, thisVar, worker,
267         [](napi_env env, void* data, void* hint) {
268             Worker* worker = reinterpret_cast<Worker*>(data);
269             {
270                 std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
271                 if (worker->UpdateHostState(INACTIVE)) {
272                     if (worker->hostOnMessageSignal_ != nullptr &&
273                         !uv_is_closing(reinterpret_cast<uv_handle_t*>(worker->hostOnMessageSignal_))) {
274                         uv_close(reinterpret_cast<uv_handle_t*>(worker->hostOnMessageSignal_), [](uv_handle_t* handle) {
275                             if (handle != nullptr) {
276                                 delete reinterpret_cast<uv_async_t*>(handle);
277                                 handle = nullptr;
278                             }
279                         });
280                     }
281                     if (worker->hostOnErrorSignal_ != nullptr &&
282                         !uv_is_closing(reinterpret_cast<uv_handle_t*>(worker->hostOnErrorSignal_))) {
283                         uv_close(reinterpret_cast<uv_handle_t*>(worker->hostOnErrorSignal_), [](uv_handle_t* handle) {
284                             if (handle != nullptr) {
285                                 delete reinterpret_cast<uv_async_t*>(handle);
286                                 handle = nullptr;
287                             }
288                         });
289                     }
290                     if (worker->hostOnGlobalCallSignal_ != nullptr &&
291                         !uv_is_closing(reinterpret_cast<uv_handle_t*>(worker->hostOnGlobalCallSignal_))) {
292                         uv_close(reinterpret_cast<uv_handle_t*>(worker->hostOnGlobalCallSignal_),
293                             [](uv_handle_t* handle) {
294                             if (handle != nullptr) {
295                                 delete reinterpret_cast<uv_async_t*>(handle);
296                                 handle = nullptr;
297                             }
298                         });
299                     }
300                     worker->ReleaseHostThreadContent();
301                 }
302                 if (!worker->IsRunning()) {
303                     HILOG_DEBUG("worker:: worker is not in running");
304                     return;
305                 }
306                 worker->TerminateInner();
307             }
308         },
309         nullptr, &worker->workerRef_);
310     worker->StartExecuteInThread(env, script);
311     return thisVar;
312 }
313 
CheckWorkerArgs(napi_env env,napi_value argsValue)314 Worker::WorkerParams* Worker::CheckWorkerArgs(napi_env env, napi_value argsValue)
315 {
316     WorkerParams* workerParams = nullptr;
317     if (NapiHelper::IsObject(env, argsValue)) {
318         workerParams = new WorkerParams();
319         napi_value nameValue = NapiHelper::GetNameProperty(env, argsValue, "name");
320         if (NapiHelper::IsNotUndefined(env, nameValue)) {
321             if (!NapiHelper::IsString(env, nameValue)) {
322                 CloseHelp::DeletePointer(workerParams, false);
323                 WorkerThrowError(env, ErrorHelper::TYPE_ERROR, "the type of name in worker must be string.");
324                 return nullptr;
325             }
326             char* nameStr = NapiHelper::GetString(env, nameValue);
327             if (nameStr == nullptr) {
328                 CloseHelp::DeletePointer(workerParams, false);
329                 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "the name of worker is null.");
330                 return nullptr;
331             }
332             workerParams->name_ = std::string(nameStr);
333             CloseHelp::DeletePointer(nameStr, true);
334         }
335         napi_value typeValue = NapiHelper::GetNameProperty(env, argsValue, "type");
336         if (NapiHelper::IsNotUndefined(env, typeValue)) {
337             if (!NapiHelper::IsString(env, typeValue)) {
338                 CloseHelp::DeletePointer(workerParams, false);
339                 WorkerThrowError(env, ErrorHelper::TYPE_ERROR, "the type of type must be string.");
340                 return nullptr;
341             }
342             char* typeStr = NapiHelper::GetString(env, typeValue);
343             if (typeStr == nullptr) {
344                 CloseHelp::DeletePointer(workerParams, false);
345                 ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_INITIALIZATION, "the type of worker is null.");
346                 return nullptr;
347             }
348             if (strcmp("classic", typeStr) == 0) {
349                 workerParams->type_ = CLASSIC;
350                 CloseHelp::DeletePointer(typeStr, true);
351             } else {
352                 CloseHelp::DeletePointer(workerParams, false);
353                 CloseHelp::DeletePointer(typeStr, true);
354                 ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
355                                         "the type must be classic, unsupport others now.");
356                 return nullptr;
357             }
358         }
359     }
360     return workerParams;
361 }
362 
PostMessage(napi_env env,napi_callback_info cbinfo)363 napi_value Worker::PostMessage(napi_env env, napi_callback_info cbinfo)
364 {
365     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
366     return CommonPostMessage(env, cbinfo, true);
367 }
368 
PostSendableMessage(napi_env env,napi_callback_info cbinfo)369 napi_value Worker::PostSendableMessage(napi_env env, napi_callback_info cbinfo)
370 {
371     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
372     return CommonPostMessage(env, cbinfo, false);
373 }
374 
CommonPostMessage(napi_env env,napi_callback_info cbinfo,bool cloneSendable)375 napi_value Worker::CommonPostMessage(napi_env env, napi_callback_info cbinfo, bool cloneSendable)
376 {
377     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
378     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
379     if (argc < 1) {
380         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
381             "Worker messageObject must be not null with postMessage");
382         return nullptr;
383     }
384     napi_value* argv = new napi_value[argc];
385     ObjectScope<napi_value> scope(argv, true);
386     napi_value thisVar = nullptr;
387     napi_get_cb_info(env, cbinfo, &argc, argv, &thisVar, nullptr);
388     Worker* worker = nullptr;
389     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
390 
391     if (worker == nullptr || worker->IsTerminated() || worker->IsTerminating()) {
392         HILOG_ERROR("worker:: worker is nullptr when PostMessage, maybe worker is terminated");
393         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated when PostMessage");
394         return nullptr;
395     }
396 
397     napi_value data = nullptr;
398     napi_status serializeStatus = napi_ok;
399     bool defaultClone = cloneSendable ? true : false;
400     napi_value undefined = NapiHelper::GetUndefinedValue(env);
401     if (argc >= NUM_WORKER_ARGS) {
402         if (!NapiHelper::IsArray(env, argv[1])) {
403             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "transfer list must be an Array");
404             return nullptr;
405         }
406         serializeStatus = napi_serialize(env, argv[0], argv[1], undefined, false, defaultClone, &data);
407     } else {
408         serializeStatus = napi_serialize(env, argv[0], undefined, undefined, false, defaultClone, &data);
409     }
410     if (serializeStatus != napi_ok || data == nullptr) {
411         worker->HostOnMessageErrorInner();
412         WorkerThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
413         return nullptr;
414     }
415     worker->PostMessageInner(data);
416     return NapiHelper::GetUndefinedValue(env);
417 }
418 
Terminate(napi_env env,napi_callback_info cbinfo)419 napi_value Worker::Terminate(napi_env env, napi_callback_info cbinfo)
420 {
421     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
422     napi_value thisVar = nullptr;
423     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
424     Worker* worker = nullptr;
425     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
426     if (worker == nullptr) {
427         HILOG_ERROR("worker:: worker is nullptr when Terminate, maybe worker is terminated");
428         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when Terminate");
429         return nullptr;
430     }
431     if (worker->IsTerminated() || worker->IsTerminating()) {
432         HILOG_DEBUG("worker:: worker is not in running when Terminate");
433         return nullptr;
434     }
435     worker->TerminateInner();
436     return NapiHelper::GetUndefinedValue(env);
437 }
438 
On(napi_env env,napi_callback_info cbinfo)439 napi_value Worker::On(napi_env env, napi_callback_info cbinfo)
440 {
441     return AddListener(env, cbinfo, PERMANENT);
442 }
443 
Once(napi_env env,napi_callback_info cbinfo)444 napi_value Worker::Once(napi_env env, napi_callback_info cbinfo)
445 {
446     return AddListener(env, cbinfo, ONCE);
447 }
448 
RegisterGlobalCallObject(napi_env env,napi_callback_info cbinfo)449 napi_value Worker::RegisterGlobalCallObject(napi_env env, napi_callback_info cbinfo)
450 {
451     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
452     if (argc != NUM_WORKER_ARGS) {
453         ErrorHelper::ThrowError(env,
454             ErrorHelper::TYPE_ERROR, "worker registerGlobalCallObject param count must be 2");
455         return nullptr;
456     }
457     // check 1st param is string
458     napi_value thisVar = nullptr;
459     void* data = nullptr;
460     napi_value* args = new napi_value[argc];
461     ObjectScope<napi_value> scope(args, true);
462     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
463     if (!NapiHelper::IsString(env, args[0])) {
464         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
465             "BusinessError 401:: Parameter error. The type of 'instanceName' must be string");
466         return nullptr;
467     }
468     std::string instanceName = NapiHelper::GetString(env, args[0]);
469 
470     Worker* worker = nullptr;
471     napi_unwrap(env, thisVar, (void**)&worker);
472     if (worker == nullptr) {
473         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
474         return nullptr;
475     }
476     napi_ref obj = NapiHelper::CreateReference(env, args[1], 1);
477     worker->AddGlobalCallObject(instanceName, obj);
478     return nullptr;
479 }
480 
UnregisterGlobalCallObject(napi_env env,napi_callback_info cbinfo)481 napi_value Worker::UnregisterGlobalCallObject(napi_env env, napi_callback_info cbinfo)
482 {
483     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
484     if (argc > 1) {
485         ErrorHelper::ThrowError(env,
486             ErrorHelper::TYPE_ERROR, "worker unregisterGlobalCallObject param count shall be 1 or 0");
487         return nullptr;
488     }
489     napi_value thisVar = nullptr;
490     void* data = nullptr;
491     napi_value* args = new napi_value[argc];
492     ObjectScope<napi_value> scope(args, true);
493     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
494     Worker* worker = nullptr;
495     napi_unwrap(env, thisVar, (void**)&worker);
496     if (worker == nullptr) {
497         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
498         return nullptr;
499     }
500     if (argc == 0) {
501         worker->ClearGlobalCallObject();
502         HILOG_DEBUG("worker:: clear all registered globalCallObject");
503         return nullptr;
504     }
505     // check 1st param is string
506     if (!NapiHelper::IsString(env, args[0])) {
507         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
508             "BusinessError 401:: Parameter error. The type of 'instanceName' must be string");
509         return nullptr;
510     }
511     std::string instanceName = NapiHelper::GetString(env, args[0]);
512     if (!worker->RemoveGlobalCallObject(instanceName)) {
513         HILOG_ERROR("worker:: unregister unexist globalCallObject");
514     }
515     return nullptr;
516 }
517 
Off(napi_env env,napi_callback_info cbinfo)518 napi_value Worker::Off(napi_env env, napi_callback_info cbinfo)
519 {
520     return RemoveListener(env, cbinfo);
521 }
522 
RemoveEventListener(napi_env env,napi_callback_info cbinfo)523 napi_value Worker::RemoveEventListener(napi_env env, napi_callback_info cbinfo)
524 {
525     return RemoveListener(env, cbinfo);
526 }
527 
AddEventListener(napi_env env,napi_callback_info cbinfo)528 napi_value Worker::AddEventListener(napi_env env, napi_callback_info cbinfo)
529 {
530     return AddListener(env, cbinfo, PERMANENT);
531 }
532 
AddListener(napi_env env,napi_callback_info cbinfo,ListenerMode mode)533 napi_value Worker::AddListener(napi_env env, napi_callback_info cbinfo, ListenerMode mode)
534 {
535     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
536     if (argc < NUM_WORKER_ARGS) {
537         ErrorHelper::ThrowError(env,
538             ErrorHelper::TYPE_ERROR, "worker add listener param count must be not less than 2.");
539         return nullptr;
540     }
541     // check 1st param is string
542     napi_value thisVar = nullptr;
543     void* data = nullptr;
544     napi_value* args = new napi_value[argc];
545     ObjectScope<napi_value> scope(args, true);
546     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
547     if (!NapiHelper::IsString(env, args[0])) {
548         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker add listener 1st param must be string");
549         return nullptr;
550     }
551     if (!NapiHelper::IsCallable(env, args[1])) {
552         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker add listener 2st param must be callable");
553         return nullptr;
554     }
555     Worker* worker = nullptr;
556     napi_unwrap(env, thisVar, (void**)&worker);
557     if (worker == nullptr) {
558         HILOG_ERROR("worker:: worker is nullptr when addListener, maybe worker is terminated");
559         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
560         return nullptr;
561     }
562 
563     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
564     auto listener = new WorkerListener(env, callback, mode);
565     if (mode == ONCE && argc > NUM_WORKER_ARGS) {
566         if (NapiHelper::IsObject(env, args[NUM_WORKER_ARGS])) {
567             napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_WORKER_ARGS], "once");
568             bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
569             if (!isOnce) {
570                 listener->SetMode(PERMANENT);
571             }
572         }
573     }
574     char* typeStr = NapiHelper::GetString(env, args[0]);
575     worker->AddListenerInner(env, typeStr, listener);
576     CloseHelp::DeletePointer(typeStr, true);
577     return NapiHelper::GetUndefinedValue(env);
578 }
579 
RemoveListener(napi_env env,napi_callback_info cbinfo)580 napi_value Worker::RemoveListener(napi_env env, napi_callback_info cbinfo)
581 {
582     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
583     if (argc < 1) {
584         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the remove listener param must be not less than 1");
585         return nullptr;
586     }
587     // check 1st param is string
588     napi_value thisVar = nullptr;
589     void* data = nullptr;
590     napi_value* args = new napi_value[argc];
591     ObjectScope<napi_value> scope(args, true);
592     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
593     if (!NapiHelper::IsString(env, args[0])) {
594         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener 1st param must be string");
595         return nullptr;
596     }
597 
598     Worker* worker = nullptr;
599     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
600     if (worker == nullptr) {
601         HILOG_ERROR("worker:: worker is nullptr when RemoveListener, maybe worker is terminated");
602         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
603         return nullptr;
604     }
605 
606     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
607         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener 2st param must be callable");
608         return nullptr;
609     }
610 
611     char* typeStr = NapiHelper::GetString(env, args[0]);
612     if (typeStr == nullptr) {
613         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of remove listener type must be not null");
614         return nullptr;
615     }
616 
617     napi_ref callback = nullptr;
618     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
619         napi_create_reference(env, args[1], 1, &callback);
620     }
621     worker->RemoveListenerInner(env, typeStr, callback);
622     CloseHelp::DeletePointer(typeStr, true);
623     NapiHelper::DeleteReference(env, callback);
624     return NapiHelper::GetUndefinedValue(env);
625 }
626 
CallWorkCallback(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)627 void CallWorkCallback(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
628 {
629     napi_value callback = nullptr;
630     napi_get_named_property(env, recv, type, &callback);
631     if (NapiHelper::IsCallable(env, callback)) {
632         napi_value callbackResult = nullptr;
633         napi_call_function(env, recv, callback, argc, argv, &callbackResult);
634     }
635 }
636 
DispatchEvent(napi_env env,napi_callback_info cbinfo)637 napi_value Worker::DispatchEvent(napi_env env, napi_callback_info cbinfo)
638 {
639     size_t argc = 1;
640     napi_value args[1];
641     napi_value thisVar = nullptr;
642     void* data = nullptr;
643     napi_get_cb_info(env, cbinfo, &argc, args, &thisVar, &data);
644     if (argc < 1) {
645         ErrorHelper::ThrowError(env,
646             ErrorHelper::TYPE_ERROR, "the count of event param must be more than 1 in DispatchEvent");
647         return NapiHelper::CreateBooleanValue(env, false);
648     }
649 
650     // check 1st param is event
651     if (!NapiHelper::IsObject(env, args[0])) {
652         ErrorHelper::ThrowError(env,
653             ErrorHelper::TYPE_ERROR, "the type of event 1st param must be Event in DispatchEvent");
654         return NapiHelper::CreateBooleanValue(env, false);
655     }
656 
657     Worker* worker = nullptr;
658     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
659     if (worker == nullptr) {
660         HILOG_ERROR("worker:: worker is nullptr when DispatchEvent, maybe worker is terminated");
661         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker has been terminated");
662         return NapiHelper::CreateBooleanValue(env, false);
663     }
664 
665     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
666     if (!NapiHelper::IsString(env, typeValue)) {
667         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of event type must be string");
668         return NapiHelper::CreateBooleanValue(env, false);
669     }
670 
671     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerRef_);
672 
673     char* typeStr = NapiHelper::GetString(env, typeValue);
674     if (typeStr == nullptr) {
675         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "dispatchEvent event type must be not null");
676         return NapiHelper::CreateBooleanValue(env, false);
677     }
678     if (strcmp(typeStr, "error") == 0) {
679         CallWorkCallback(env, obj, 1, args, "onerror");
680     } else if (strcmp(typeStr, "messageerror") == 0) {
681         CallWorkCallback(env, obj, 1, args, "onmessageerror");
682     } else if (strcmp(typeStr, "message") == 0) {
683         CallWorkCallback(env, obj, 1, args, "onmessage");
684     }
685 
686     worker->HandleEventListeners(env, obj, 1, args, typeStr);
687 
688     CloseHelp::DeletePointer(typeStr, true);
689     return NapiHelper::CreateBooleanValue(env, true);
690 }
691 
RemoveAllListener(napi_env env,napi_callback_info cbinfo)692 napi_value Worker::RemoveAllListener(napi_env env, napi_callback_info cbinfo)
693 {
694     napi_value thisVar = nullptr;
695     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
696     Worker* worker = nullptr;
697     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
698     if (worker == nullptr) {
699         HILOG_ERROR("worker:: worker is nullptr when RemoveAllListener, maybe worker is terminated");
700         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "maybe worker is terminated");
701         return nullptr;
702     }
703 
704     worker->RemoveAllListenerInner();
705     return NapiHelper::GetUndefinedValue(env);
706 }
707 
CancelTask(napi_env env,napi_callback_info cbinfo)708 napi_value Worker::CancelTask(napi_env env, napi_callback_info cbinfo)
709 {
710     napi_value thisVar = nullptr;
711     napi_get_cb_info(env, cbinfo, nullptr, nullptr, &thisVar, nullptr);
712     Worker* worker = nullptr;
713     napi_unwrap(env, thisVar, reinterpret_cast<void**>(&worker));
714     if (worker == nullptr) {
715         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
716         return nullptr;
717     }
718 
719     if (worker->IsTerminated() || worker->IsTerminating()) {
720         HILOG_INFO("worker:: worker is not in running");
721         return nullptr;
722     }
723 
724     if (!worker->ClearWorkerTasks()) {
725         HILOG_ERROR("worker:: clear worker task error");
726     }
727     return NapiHelper::GetUndefinedValue(env);
728 }
729 
PostMessageToHost(napi_env env,napi_callback_info cbinfo)730 napi_value Worker::PostMessageToHost(napi_env env, napi_callback_info cbinfo)
731 {
732     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
733     return CommonPostMessageToHost(env, cbinfo, true);
734 }
735 
PostSendableMessageToHost(napi_env env,napi_callback_info cbinfo)736 napi_value Worker::PostSendableMessageToHost(napi_env env, napi_callback_info cbinfo)
737 {
738     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
739     return CommonPostMessageToHost(env, cbinfo, false);
740 }
741 
CommonPostMessageToHost(napi_env env,napi_callback_info cbinfo,bool cloneSendable)742 napi_value Worker::CommonPostMessageToHost(napi_env env, napi_callback_info cbinfo, bool cloneSendable)
743 {
744     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
745     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
746     if (argc < 1) {
747         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Worker param count must be more than 1 with new");
748         return nullptr;
749     }
750     napi_value* argv = new napi_value[argc];
751     ObjectScope<napi_value> scope(argv, true);
752     Worker* worker = nullptr;
753     napi_get_cb_info(env, cbinfo, &argc, argv, nullptr, reinterpret_cast<void**>(&worker));
754 
755     if (worker == nullptr) {
756         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
757         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr when post message to host");
758         return nullptr;
759     }
760 
761     if (!worker->IsRunning()) {
762         // if worker is not running, don't send any message to host thread
763         HILOG_DEBUG("worker:: when post message to host occur worker is not in running.");
764         return nullptr;
765     }
766 
767     napi_value data = nullptr;
768     napi_status serializeStatus = napi_ok;
769     bool defaultClone = cloneSendable ? true : false;
770     napi_value undefined = NapiHelper::GetUndefinedValue(env);
771     if (argc >= NUM_WORKER_ARGS) {
772         if (!NapiHelper::IsArray(env, argv[1])) {
773             ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "Transfer list must be an Array");
774             return nullptr;
775         }
776         serializeStatus = napi_serialize(env, argv[0], argv[1], undefined, false, defaultClone, &data);
777     } else {
778         napi_value undefined = NapiHelper::GetUndefinedValue(env);
779         serializeStatus = napi_serialize(env, argv[0], undefined, undefined, false, defaultClone, &data);
780     }
781 
782     if (serializeStatus != napi_ok || data == nullptr) {
783         worker->WorkerOnMessageErrorInner();
784         WorkerThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
785         return nullptr;
786     }
787     worker->PostMessageToHostInner(data);
788     return NapiHelper::GetUndefinedValue(env);
789 }
790 
GlobalCall(napi_env env,napi_callback_info cbinfo)791 napi_value Worker::GlobalCall(napi_env env, napi_callback_info cbinfo)
792 {
793     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
794     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
795     if (argc < NUM_GLOBAL_CALL_ARGS) {
796         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
797             "callGloballCallObjectMethod param must be equal or more than 3");
798         return nullptr;
799     }
800     napi_value* args = new napi_value[argc];
801     ObjectScope<napi_value> scope(args, true);
802     Worker* worker = nullptr;
803     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
804     if (worker == nullptr) {
805         HILOG_ERROR("worker:: worker is null when callGlobalCallObjectMethod to host");
806         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
807             "worker is null when callGlobalCallObjectMethod to host");
808         return nullptr;
809     }
810 
811     if (!worker->IsRunning()) {
812         // if worker is not running, don't send any message to host thread
813         HILOG_DEBUG("worker:: when post message to host occur worker is not in running.");
814         return nullptr;
815     }
816 
817     if (!NapiHelper::IsString(env, args[0])) {
818         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
819             "Parameter error. The type of 'instanceName' must be string");
820         return nullptr;
821     }
822     if (!NapiHelper::IsString(env, args[1])) {
823         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
824             "Parameter error. The type of 'methodName' must be string");
825         return nullptr;
826     }
827     if (!NapiHelper::IsNumber(env, args[2])) { // 2: the index of argument "timeout"
828         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR,
829             "Parameter error. The type of 'timeout' must be number");
830         return nullptr;
831     }
832 
833     napi_status serializeStatus = napi_ok;
834     napi_value data = nullptr;
835     napi_value argsArray;
836     napi_create_array_with_length(env, argc - 1, &argsArray);
837     size_t index = 0;
838     uint32_t timeout = 0;
839     for (size_t i = 0; i < argc; i++) {
840         if (i == 2) { // 2: index of time limitation arg
841             timeout = NapiHelper::GetUint32Value(env, args[i]);
842             continue;
843         }
844         napi_set_element(env, argsArray, index, args[i]);
845         index++;
846     }
847     if (timeout <= 0 || timeout > DEFAULT_TIMEOUT) {
848         timeout = DEFAULT_TIMEOUT;
849     }
850 
851     // defautly not transfer
852     napi_value undefined = NapiHelper::GetUndefinedValue(env);
853     // meaningless to copy sendable object when call globalObject
854     bool defaultClone = true;
855     bool defaultTransfer = false;
856     serializeStatus = napi_serialize(env, argsArray, undefined, undefined, defaultTransfer, defaultClone, &data);
857     if (serializeStatus != napi_ok || data == nullptr) {
858         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
859         return nullptr;
860     }
861     worker->hostGlobalCallQueue_.Push(worker->globalCallId_, data);
862 
863     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
864     if (env != nullptr && !worker->HostIsStop()) {
865         worker->InitGlobalCallStatus(env);
866         uv_async_send(worker->hostOnGlobalCallSignal_);
867     } else {
868         HILOG_ERROR("worker:: worker host engine is nullptr when callGloballCallObjectMethod.");
869         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null");
870         return nullptr;
871     }
872 
873     {
874         std::unique_lock lock(worker->globalCallMutex_);
875         if (!worker->cv_.wait_for(lock, std::chrono::milliseconds(timeout), [worker]() {
876             return !worker->workerGlobalCallQueue_.IsEmpty() || !worker->globalCallSuccess_;
877         })) {
878             worker->IncreaseGlobalCallId();
879             HILOG_ERROR("worker:: callGlobalCallObjectMethod has exceeded the waiting time limitation, skip this turn");
880             ErrorHelper::ThrowError(env, ErrorHelper::ERR_GLOBAL_CALL_TIMEOUT);
881             return nullptr;
882         }
883     }
884     worker->IncreaseGlobalCallId();
885     if (!worker->globalCallSuccess_) {
886         worker->HandleGlobalCallError(env);
887         return nullptr;
888     }
889     if (!worker->workerGlobalCallQueue_.DeQueue(&data)) {
890         HILOG_ERROR("worker:: message returned from host is empty when callGloballCallObjectMethod");
891         return nullptr;
892     }
893     napi_value res = nullptr;
894     serializeStatus = napi_deserialize(env, data, &res);
895     napi_delete_serialization_data(env, data);
896     if (serializeStatus != napi_ok || res == nullptr) {
897         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_SERIALIZATION, "failed to serialize message.");
898         return nullptr;
899     }
900     return res;
901 }
902 
InitGlobalCallStatus(napi_env env)903 void Worker::InitGlobalCallStatus(napi_env env)
904 {
905     // worker side event data queue shall be empty before uv_async_send
906     workerGlobalCallQueue_.Clear(env);
907     ClearGlobalCallError(env);
908     globalCallSuccess_ = true;
909 }
910 
IncreaseGlobalCallId()911 void Worker::IncreaseGlobalCallId()
912 {
913     if (UNLIKELY(globalCallId_ == GLOBAL_CALL_ID_MAX)) {
914         globalCallId_ = 1;
915     } else {
916         globalCallId_++;
917     }
918 }
919 
CloseWorker(napi_env env,napi_callback_info cbinfo)920 napi_value Worker::CloseWorker(napi_env env, napi_callback_info cbinfo)
921 {
922     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
923     Worker* worker = nullptr;
924     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, (void**)&worker);
925     if (worker != nullptr) {
926         worker->CloseInner();
927     } else {
928         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is null");
929         return nullptr;
930     }
931     return NapiHelper::GetUndefinedValue(env);
932 }
933 
ParentPortCancelTask(napi_env env,napi_callback_info cbinfo)934 napi_value Worker::ParentPortCancelTask(napi_env env, napi_callback_info cbinfo)
935 {
936     Worker* worker = nullptr;
937     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
938     if (worker == nullptr) {
939         HILOG_ERROR("worker:: worker is nullptr when CancelTask, maybe worker is terminated");
940         return nullptr;
941     }
942 
943     if (worker->IsTerminated() || worker->IsTerminating()) {
944         HILOG_INFO("worker:: worker is not in running");
945         return nullptr;
946     }
947 
948     if (!worker->ClearWorkerTasks()) {
949         HILOG_ERROR("worker:: clear worker task error");
950     }
951     return NapiHelper::GetUndefinedValue(env);
952 }
953 
ParentPortAddEventListener(napi_env env,napi_callback_info cbinfo)954 napi_value Worker::ParentPortAddEventListener(napi_env env, napi_callback_info cbinfo)
955 {
956     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
957     if (argc < NUM_WORKER_ARGS) {
958         ErrorHelper::ThrowError(env,
959             ErrorHelper::TYPE_ERROR, "worker listener param count must be more than WORKPARAMNUM.");
960         return nullptr;
961     }
962 
963     napi_value* args = new napi_value[argc];
964     ObjectScope<napi_value> scope(args, true);
965     Worker* worker = nullptr;
966     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
967 
968     if (!NapiHelper::IsString(env, args[0])) {
969         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker listener 1st param must be string.");
970         return nullptr;
971     }
972 
973     if (!NapiHelper::IsCallable(env, args[1])) {
974         ErrorHelper::ThrowError(env,
975             ErrorHelper::TYPE_ERROR, "the type of worker listener 2st param must be callable.");
976         return nullptr;
977     }
978 
979     if (worker == nullptr || !worker->IsNotTerminate()) {
980         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
981         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
982         return nullptr;
983     }
984 
985     napi_ref callback = NapiHelper::CreateReference(env, args[1], 1);
986     auto listener = new WorkerListener(env, callback, PERMANENT);
987     if (argc > NUM_WORKER_ARGS && NapiHelper::IsObject(env, args[NUM_WORKER_ARGS])) {
988         napi_value onceValue = NapiHelper::GetNameProperty(env, args[NUM_WORKER_ARGS], "once");
989         bool isOnce = NapiHelper::GetBooleanValue(env, onceValue);
990         if (isOnce) {
991             listener->SetMode(ONCE);
992         }
993     }
994     char* typeStr = NapiHelper::GetString(env, args[0]);
995     worker->ParentPortAddListenerInner(env, typeStr, listener);
996     CloseHelp::DeletePointer(typeStr, true);
997     return NapiHelper::GetUndefinedValue(env);
998 }
999 
ParentPortDispatchEvent(napi_env env,napi_callback_info cbinfo)1000 napi_value Worker::ParentPortDispatchEvent(napi_env env, napi_callback_info cbinfo)
1001 {
1002     size_t argc = 1;
1003     napi_value args[1];
1004     Worker* worker = nullptr;
1005     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
1006     if (argc < 1) {
1007         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "DispatchEvent param count must be more than 1.");
1008         return NapiHelper::CreateBooleanValue(env, false);
1009     }
1010 
1011     if (!NapiHelper::IsObject(env, args[0])) {
1012         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker DispatchEvent 1st param must be Event.");
1013         return NapiHelper::CreateBooleanValue(env, false);
1014     }
1015 
1016     napi_value typeValue = NapiHelper::GetNameProperty(env, args[0], "type");
1017     if (!NapiHelper::IsString(env, typeValue)) {
1018         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker event type must be string.");
1019         return NapiHelper::CreateBooleanValue(env, false);
1020     }
1021 
1022     if (worker == nullptr || !worker->IsNotTerminate()) {
1023         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1024         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is nullptr.");
1025         return NapiHelper::CreateBooleanValue(env, false);
1026     }
1027 
1028     char* typeStr = NapiHelper::GetString(env, typeValue);
1029     if (typeStr == nullptr) {
1030         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
1031         return NapiHelper::CreateBooleanValue(env, false);
1032     }
1033 
1034     napi_value obj = NapiHelper::GetReferenceValue(env, worker->workerPort_);
1035 
1036     if (strcmp(typeStr, "error") == 0) {
1037         CallWorkCallback(env, obj, 1, args, "onerror");
1038     } else if (strcmp(typeStr, "messageerror") == 0) {
1039         CallWorkCallback(env, obj, 1, args, "onmessageerror");
1040     } else if (strcmp(typeStr, "message") == 0) {
1041         CallWorkCallback(env, obj, 1, args, "onmessage");
1042     }
1043 
1044     worker->ParentPortHandleEventListeners(env, obj, 1, args, typeStr, true);
1045 
1046     CloseHelp::DeletePointer(typeStr, true);
1047     return NapiHelper::CreateBooleanValue(env, true);
1048 }
1049 
ParentPortRemoveEventListener(napi_env env,napi_callback_info cbinfo)1050 napi_value Worker::ParentPortRemoveEventListener(napi_env env, napi_callback_info cbinfo)
1051 {
1052     size_t argc = NapiHelper::GetCallbackInfoArgc(env, cbinfo);
1053     if (argc < 1) {
1054         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener param count must be more than 2.");
1055         return nullptr;
1056     }
1057 
1058     napi_value* args = new napi_value[argc];
1059     ObjectScope<napi_value> scope(args, true);
1060     Worker* worker = nullptr;
1061     napi_get_cb_info(env, cbinfo, &argc, args, nullptr, reinterpret_cast<void**>(&worker));
1062 
1063     if (!NapiHelper::IsString(env, args[0])) {
1064         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "the type of worker listener 1st param must be string.");
1065         return nullptr;
1066     }
1067 
1068     if (argc > 1 && !NapiHelper::IsCallable(env, args[1])) {
1069         ErrorHelper::ThrowError(env,
1070             ErrorHelper::TYPE_ERROR, "the type of worker listener 2st param must be callable with on.");
1071         return nullptr;
1072     }
1073 
1074     if (worker == nullptr || !worker->IsNotTerminate()) {
1075         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1076         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "worker is not running.");
1077         return nullptr;
1078     }
1079 
1080     napi_ref callback = nullptr;
1081     if (argc > 1 && NapiHelper::IsCallable(env, args[1])) {
1082         napi_create_reference(env, args[1], 1, &callback);
1083     }
1084 
1085     char* typeStr = NapiHelper::GetString(env, args[0]);
1086     if (typeStr == nullptr) {
1087         ErrorHelper::ThrowError(env, ErrorHelper::TYPE_ERROR, "worker listener type must be not null.");
1088         return nullptr;
1089     }
1090     worker->ParentPortRemoveListenerInner(env, typeStr, callback);
1091     CloseHelp::DeletePointer(typeStr, true);
1092     NapiHelper::DeleteReference(env, callback);
1093     return NapiHelper::GetUndefinedValue(env);
1094 }
1095 
ParentPortRemoveAllListener(napi_env env,napi_callback_info cbinfo)1096 napi_value Worker::ParentPortRemoveAllListener(napi_env env, napi_callback_info cbinfo)
1097 {
1098     Worker* worker = nullptr;
1099     napi_get_cb_info(env, cbinfo, nullptr, nullptr, nullptr, reinterpret_cast<void**>(&worker));
1100 
1101     if (worker == nullptr || !worker->IsNotTerminate()) {
1102         HILOG_ERROR("worker:: when post message to host occur worker is nullptr");
1103         WorkerThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING,
1104             "worker is nullptr when ParentPortRemoveAllListener");
1105         return nullptr;
1106     }
1107 
1108     worker->ParentPortRemoveAllListenerInner();
1109     return NapiHelper::GetUndefinedValue(env);
1110 }
1111 
GetContainerScopeId(napi_env env)1112 void Worker::GetContainerScopeId(napi_env env)
1113 {
1114     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(env);
1115     scopeId_ = hostEngine->GetContainerScopeIdFunc();
1116 }
1117 
AddGlobalCallObject(const std::string & instanceName,napi_ref obj)1118 void Worker::AddGlobalCallObject(const std::string &instanceName, napi_ref obj)
1119 {
1120     globalCallObjects_.insert_or_assign(instanceName, obj);
1121 }
1122 
RemoveGlobalCallObject(const std::string & instanceName)1123 bool Worker::RemoveGlobalCallObject(const std::string &instanceName)
1124 {
1125     for (auto iter = globalCallObjects_.begin(); iter != globalCallObjects_.end(); iter++) {
1126         if (iter->first == instanceName) {
1127             NapiHelper::DeleteReference(hostEnv_, iter->second);
1128             globalCallObjects_.erase(iter);
1129             return true;
1130         }
1131     }
1132     return false;
1133 }
1134 
ClearGlobalCallObject()1135 void Worker::ClearGlobalCallObject()
1136 {
1137     for (auto iter = globalCallObjects_.begin(); iter != globalCallObjects_.end(); iter++) {
1138         napi_ref objRef = iter->second;
1139         NapiHelper::DeleteReference(hostEnv_, objRef);
1140     }
1141     globalCallObjects_.clear();
1142 }
1143 
StartExecuteInThread(napi_env env,const char * script)1144 void Worker::StartExecuteInThread(napi_env env, const char* script)
1145 {
1146     // 1. init hostOnMessageSignal_ in host loop
1147     uv_loop_t* loop = NapiHelper::GetLibUV(env);
1148     if (loop == nullptr) {
1149         ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "engine loop is null");
1150         CloseHelp::DeletePointer(script, true);
1151         return;
1152     }
1153     GetContainerScopeId(env);
1154     hostOnMessageSignal_ = new uv_async_t;
1155     uv_async_init(loop, hostOnMessageSignal_, reinterpret_cast<uv_async_cb>(Worker::HostOnMessage));
1156     hostOnMessageSignal_->data = this;
1157     hostOnErrorSignal_ = new uv_async_t;
1158     uv_async_init(loop, hostOnErrorSignal_, reinterpret_cast<uv_async_cb>(Worker::HostOnError));
1159     hostOnErrorSignal_->data = this;
1160     hostOnGlobalCallSignal_ = new uv_async_t;
1161     uv_async_init(loop, hostOnGlobalCallSignal_, reinterpret_cast<uv_async_cb>(Worker::HostOnGlobalCall));
1162     hostOnGlobalCallSignal_->data = this;
1163 
1164     // 2. copy the script
1165     script_ = std::string(script);
1166     CloseHelp::DeletePointer(script, true);
1167     // isBundle : FA mode and BundlePack.
1168     bool isBundle = reinterpret_cast<NativeEngine*>(env)->GetIsBundle();
1169     // if worker file is packed in har, need find moduleName in hostVM, and concat new recordName.
1170     if ((script_.find_first_of(PathHelper::NAME_SPACE_TAG) == 0 &&
1171         script_.find(PathHelper::PREFIX_BUNDLE) == std::string::npos) ||
1172         (!isBundle && script_.find_first_of(PathHelper::POINT_TAG) == 0)) {
1173         PathHelper::ConcatFileNameForWorker(env, script_, fileName_, isRelativePath_);
1174         HILOG_INFO("worker:: Concated worker recordName: %{public}s, fileName: %{public}s",
1175                    script_.c_str(), fileName_.c_str());
1176     }
1177 
1178     // 3. create WorkerRunner to Execute
1179     if (!runner_) {
1180         runner_ = std::make_unique<WorkerRunner>(WorkerStartCallback(ExecuteInThread, this));
1181     }
1182     if (runner_) {
1183         runner_->Execute(); // start a new thread
1184     } else {
1185         HILOG_ERROR("runner_ is nullptr");
1186     }
1187 }
1188 
ExecuteInThread(const void * data)1189 void Worker::ExecuteInThread(const void* data)
1190 {
1191     HITRACE_HELPER_START_TRACE(__PRETTY_FUNCTION__);
1192     auto worker = reinterpret_cast<Worker*>(const_cast<void*>(data));
1193     // 1. create a runtime, nativeengine
1194     napi_env workerEnv = nullptr;
1195     {
1196         std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
1197         if (worker->HostIsStop()) {
1198             CloseHelp::DeletePointer(worker, false);
1199             return;
1200         }
1201         napi_env env = worker->GetHostEnv();
1202         if (worker->isLimitedWorker_) {
1203             napi_create_limit_runtime(env, &workerEnv);
1204         } else {
1205             napi_create_runtime(env, &workerEnv);
1206         }
1207         if (workerEnv == nullptr) {
1208             ErrorHelper::ThrowError(env, ErrorHelper::ERR_WORKER_NOT_RUNNING, "Worker create runtime error");
1209             return;
1210         }
1211         if (worker->isLimitedWorker_) {
1212             reinterpret_cast<NativeEngine*>(workerEnv)->MarkRestrictedWorkerThread();
1213         } else {
1214             // mark worker env is workerThread
1215             reinterpret_cast<NativeEngine*>(workerEnv)->MarkWorkerThread();
1216         }
1217         // for load balance in taskpool
1218         reinterpret_cast<NativeEngine*>(env)->IncreaseSubEnvCounter();
1219 
1220         worker->SetWorkerEnv(workerEnv);
1221     }
1222 
1223     uv_loop_t* loop = worker->GetWorkerLoop();
1224     if (loop == nullptr) {
1225         HILOG_ERROR("worker:: Worker loop is nullptr");
1226         return;
1227     }
1228 
1229     // 2. add some preparation for the worker
1230     if (worker->PrepareForWorkerInstance()) {
1231         worker->workerOnMessageSignal_ = new uv_async_t;
1232         uv_async_init(loop, worker->workerOnMessageSignal_, reinterpret_cast<uv_async_cb>(Worker::WorkerOnMessage));
1233         worker->workerOnMessageSignal_->data = worker;
1234 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1235         uv_async_init(loop, &worker->debuggerOnPostTaskSignal_, reinterpret_cast<uv_async_cb>(
1236             Worker::HandleDebuggerTask));
1237 #endif
1238         worker->UpdateWorkerState(RUNNING);
1239         // in order to invoke worker send before subThread start
1240         uv_async_send(worker->workerOnMessageSignal_);
1241         HITRACE_HELPER_FINISH_TRACE;
1242         // 3. start worker loop
1243         worker->Loop();
1244     } else {
1245         HILOG_ERROR("worker:: worker PrepareForWorkerInstance fail");
1246         worker->UpdateWorkerState(TERMINATED);
1247         HITRACE_HELPER_FINISH_TRACE;
1248     }
1249     worker->ReleaseWorkerThreadContent();
1250     std::lock_guard<std::recursive_mutex> lock(worker->liveStatusLock_);
1251     if (worker->HostIsStop()) {
1252         CloseHelp::DeletePointer(worker, false);
1253     } else {
1254         worker->PublishWorkerOverSignal();
1255     }
1256 }
1257 
PrepareForWorkerInstance()1258 bool Worker::PrepareForWorkerInstance()
1259 {
1260     std::string rawFileName = script_;
1261     std::vector<uint8_t> scriptContent;
1262     std::string workerAmi;
1263     {
1264         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1265         if (HostIsStop()) {
1266             return false;
1267         }
1268         // 1. init worker async func
1269         auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
1270 
1271         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1272         // 2. init worker environment
1273 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1274         workerEngine->SetDebuggerPostTaskFunc(
1275             std::bind(&Worker::DebuggerOnPostTask, this, std::placeholders::_1));
1276 #endif
1277         if (!hostEngine->CallInitWorkerFunc(workerEngine)) {
1278             HILOG_ERROR("worker:: CallInitWorkerFunc error");
1279             return false;
1280         }
1281         // 3. get uril content
1282         if (isRelativePath_) {
1283             rawFileName = fileName_;
1284         }
1285         if (!hostEngine->CallGetAssetFunc(rawFileName, scriptContent, workerAmi)) {
1286             HILOG_ERROR("worker:: CallGetAssetFunc error");
1287             return false;
1288         }
1289     }
1290     // add timer interface
1291     Timer::RegisterTime(workerEnv_);
1292     HILOG_DEBUG("worker:: stringContent size is %{public}zu", scriptContent.size());
1293     napi_value execScriptResult = nullptr;
1294     napi_run_actor(workerEnv_, scriptContent, workerAmi.c_str(), &execScriptResult, const_cast<char*>(script_.c_str()));
1295     if (execScriptResult == nullptr) {
1296         // An exception occurred when running the script.
1297         HILOG_ERROR("worker:: run script exception occurs, will handle exception");
1298         HandleException();
1299         return false;
1300     }
1301 
1302     // 4. register worker name in DedicatedWorkerGlobalScope
1303     if (!name_.empty()) {
1304         napi_value nameValue = nullptr;
1305         napi_create_string_utf8(workerEnv_, name_.c_str(), name_.length(), &nameValue);
1306         NapiHelper::SetNamePropertyInGlobal(workerEnv_, "name", nameValue);
1307     }
1308     return true;
1309 }
1310 
HostOnMessage(const uv_async_t * req)1311 void Worker::HostOnMessage(const uv_async_t* req)
1312 {
1313     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1314     Worker* worker = static_cast<Worker*>(req->data);
1315     if (worker == nullptr) {
1316         HILOG_ERROR("worker:: worker is null when host onmessage.");
1317         return;
1318     }
1319     worker->HostOnMessageInner();
1320 }
1321 
HostOnMessageInner()1322 void Worker::HostOnMessageInner()
1323 {
1324     if (hostEnv_ == nullptr || HostIsStop()) {
1325         HILOG_ERROR("worker:: host thread maybe is over when host onmessage.");
1326         return;
1327     }
1328 
1329     NativeEngine* engine = reinterpret_cast<NativeEngine*>(hostEnv_);
1330     if (!engine->InitContainerScopeFunc(scopeId_)) {
1331         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnMessageInner begin(only stage model)");
1332     }
1333 
1334     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1335     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onmessage");
1336     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1337 
1338     MessageDataType data = nullptr;
1339     while (hostMessageQueue_.DeQueue(&data)) {
1340         // receive close signal.
1341         if (data == nullptr) {
1342             HILOG_DEBUG("worker:: worker received close signal");
1343             uv_close(reinterpret_cast<uv_handle_t*>(hostOnMessageSignal_), [](uv_handle_t* handle) {
1344                 if (handle != nullptr) {
1345                     delete reinterpret_cast<uv_async_t*>(handle);
1346                     handle = nullptr;
1347                 }
1348             });
1349             uv_close(reinterpret_cast<uv_handle_t*>(hostOnErrorSignal_), [](uv_handle_t* handle) {
1350                 if (handle != nullptr) {
1351                     delete reinterpret_cast<uv_async_t*>(handle);
1352                     handle = nullptr;
1353                 }
1354             });
1355             CloseHostCallback();
1356             return;
1357         }
1358         // handle data, call worker onMessage function to handle.
1359         napi_status status = napi_ok;
1360         HandleScope scope(hostEnv_, status);
1361         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1362         napi_value result = nullptr;
1363         status = napi_deserialize(hostEnv_, data, &result);
1364         napi_delete_serialization_data(hostEnv_, data);
1365         if (status != napi_ok || result == nullptr) {
1366             HostOnMessageErrorInner();
1367             continue;
1368         }
1369         napi_value event = nullptr;
1370         napi_create_object(hostEnv_, &event);
1371         napi_set_named_property(hostEnv_, event, "data", result);
1372         napi_value argv[1] = { event };
1373         if (isCallable) {
1374             napi_value callbackResult = nullptr;
1375             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
1376         }
1377         // handle listeners.
1378         HandleEventListeners(hostEnv_, obj, 1, argv, "message");
1379         HandleHostException();
1380     }
1381     if (!engine->FinishContainerScopeFunc(scopeId_)) {
1382         HILOG_WARN("worker:: FinishContainerScopeFunc error when HostOnMessageInner end(only stage model)");
1383     }
1384 }
1385 
HostOnGlobalCall(const uv_async_t * req)1386 void Worker::HostOnGlobalCall(const uv_async_t* req)
1387 {
1388     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1389     Worker* worker = static_cast<Worker*>(req->data);
1390     if (worker == nullptr) {
1391         HILOG_ERROR("worker:: worker is null");
1392         return;
1393     }
1394     worker->HostOnGlobalCallInner();
1395 }
1396 
HostOnGlobalCallInner()1397 void Worker::HostOnGlobalCallInner()
1398 {
1399     if (hostEnv_ == nullptr || HostIsStop()) {
1400         HILOG_ERROR("worker:: host thread maybe is over when host onmessage.");
1401         globalCallSuccess_ = false;
1402         cv_.notify_one();
1403         return;
1404     }
1405 
1406     NativeEngine* engine = reinterpret_cast<NativeEngine*>(hostEnv_);
1407     if (!engine->InitContainerScopeFunc(scopeId_)) {
1408         HILOG_WARN("worker:: InitContainerScopeFunc error when HostOnMessageInner begin(only stage model)");
1409     }
1410 
1411     if (hostGlobalCallQueue_.IsEmpty()) {
1412         HILOG_ERROR("worker:: message queue is empty when HostOnGlobalCallInner");
1413         globalCallSuccess_ = false;
1414         cv_.notify_one();
1415         return;
1416     }
1417     MessageDataType data = nullptr;
1418     uint32_t currentCallId = 0;
1419     size_t size = hostGlobalCallQueue_.GetSize();
1420     for (size_t i = 0; i < size; i++) {
1421         std::pair<uint32_t, MessageDataType> pair = hostGlobalCallQueue_.Front();
1422         hostGlobalCallQueue_.Pop();
1423         if (pair.first == globalCallId_) {
1424             currentCallId = pair.first;
1425             data = pair.second;
1426             break;
1427         }
1428         napi_delete_serialization_data(hostEnv_, pair.second);
1429     }
1430     napi_value argsArray = nullptr;
1431     napi_status status = napi_ok;
1432     status = napi_deserialize(hostEnv_, data, &argsArray);
1433     napi_delete_serialization_data(hostEnv_, data);
1434     if (status != napi_ok || argsArray == nullptr) {
1435         AddGlobalCallError(ErrorHelper::ERR_WORKER_SERIALIZATION);
1436         globalCallSuccess_ = false;
1437         cv_.notify_one();
1438         return;
1439     }
1440     napi_value instanceName = nullptr;
1441     napi_get_element(hostEnv_, argsArray, 0, &instanceName);
1442     napi_value methodName = nullptr;
1443     napi_get_element(hostEnv_, argsArray, 1, &methodName);
1444 
1445     std::string instanceNameStr = NapiHelper::GetString(hostEnv_, instanceName);
1446     auto iter = globalCallObjects_.find(instanceNameStr);
1447     if (iter == globalCallObjects_.end()) {
1448         HILOG_ERROR("worker:: there is no instance: %{public}s registered for global call", instanceNameStr.c_str());
1449         AddGlobalCallError(ErrorHelper::ERR_TRIGGER_NONEXIST_EVENT);
1450         globalCallSuccess_ = false;
1451         cv_.notify_one();
1452         return;
1453     }
1454     napi_ref objRef = iter->second;
1455     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, objRef);
1456     bool hasProperty = false;
1457     napi_has_property(hostEnv_, obj, methodName, &hasProperty);
1458     if (!hasProperty) {
1459         const char* methodNameStr = NapiHelper::GetString(hostEnv_, methodName);
1460         HILOG_ERROR("worker:: registered obj for global call has no method: %{public}s", methodNameStr);
1461         AddGlobalCallError(ErrorHelper::ERR_CALL_METHOD_ON_BINDING_OBJ);
1462         globalCallSuccess_ = false;
1463         cv_.notify_one();
1464         return;
1465     }
1466     napi_value method = nullptr;
1467     napi_get_property(hostEnv_, obj, methodName, &method);
1468     // call method must not be generator function or async function
1469     bool validMethod = NapiHelper::IsCallable(hostEnv_, method) && !NapiHelper::IsAsyncFunction(hostEnv_, method) &&
1470         !NapiHelper::IsGeneratorFunction(hostEnv_, method);
1471     if (!validMethod) {
1472         const char* methodNameStr = NapiHelper::GetString(hostEnv_, methodName);
1473         HILOG_ERROR("worker:: method %{public}s shall be callable and not async or generator method", methodNameStr);
1474         AddGlobalCallError(ErrorHelper::ERR_CALL_METHOD_ON_BINDING_OBJ);
1475         globalCallSuccess_ = false;
1476         cv_.notify_one();
1477         return;
1478     }
1479     uint32_t argc = 0;
1480     napi_get_array_length(hostEnv_, argsArray, &argc);
1481     napi_value* args = nullptr;
1482     ObjectScope<napi_value> scope(args, true);
1483     if (argc > BEGIN_INDEX_OF_ARGUMENTS) {
1484         args = new napi_value[argc - BEGIN_INDEX_OF_ARGUMENTS];
1485         for (uint32_t index = 0; index < argc - BEGIN_INDEX_OF_ARGUMENTS; index++) {
1486             napi_get_element(hostEnv_, argsArray, index + BEGIN_INDEX_OF_ARGUMENTS, &args[index]);
1487         }
1488     }
1489 
1490     napi_value res = nullptr;
1491     napi_call_function(hostEnv_, obj, method, argc - BEGIN_INDEX_OF_ARGUMENTS, args, &res);
1492     bool hasPendingException = NapiHelper::IsExceptionPending(hostEnv_);
1493     if (hasPendingException) {
1494         napi_value exception = nullptr;
1495         napi_get_and_clear_last_exception(hostEnv_, &exception);
1496         napi_throw(hostEnv_, exception);
1497         globalCallSuccess_ = false;
1498         cv_.notify_one();
1499         return;
1500     }
1501     // defautly not transfer
1502     napi_value undefined = NapiHelper::GetUndefinedValue(hostEnv_);
1503     // meaningless to copy sendable object when call globalObject
1504     bool defaultClone = true;
1505     bool defaultTransfer = false;
1506     status = napi_serialize(hostEnv_, res, undefined, undefined, defaultTransfer, defaultClone, &data);
1507     if (status != napi_ok || data == nullptr) {
1508         AddGlobalCallError(ErrorHelper::ERR_WORKER_SERIALIZATION);
1509         globalCallSuccess_ = false;
1510         cv_.notify_one();
1511         return;
1512     }
1513     // drop and destruct result if timeout
1514     if (currentCallId != globalCallId_ || currentCallId == 0) {
1515         napi_delete_serialization_data(hostEnv_, data);
1516         cv_.notify_one();
1517         return;
1518     }
1519     workerGlobalCallQueue_.EnQueue(data);
1520     globalCallSuccess_ = true;
1521     cv_.notify_one();
1522 }
1523 
AddGlobalCallError(int32_t errCode,napi_value errData)1524 void Worker::AddGlobalCallError(int32_t errCode, napi_value errData)
1525 {
1526     globalCallErrors_.push({errCode, errData});
1527 }
1528 
HandleGlobalCallError(napi_env env)1529 void Worker::HandleGlobalCallError(napi_env env)
1530 {
1531     while (!globalCallErrors_.empty()) {
1532         std::pair<int32_t, napi_value> pair = globalCallErrors_.front();
1533         globalCallErrors_.pop();
1534         int32_t errCode = pair.first;
1535         ErrorHelper::ThrowError(env, errCode);
1536     }
1537 }
1538 
ClearGlobalCallError(napi_env env)1539 void Worker::ClearGlobalCallError(napi_env env)
1540 {
1541     while (!globalCallErrors_.empty()) {
1542         std::pair<int32_t, napi_value> pair = globalCallErrors_.front();
1543         globalCallErrors_.pop();
1544         if (pair.second != nullptr) {
1545             napi_delete_serialization_data(env, pair.second);
1546         }
1547     }
1548 }
1549 
CallHostFunction(size_t argc,const napi_value * argv,const char * methodName) const1550 void Worker::CallHostFunction(size_t argc, const napi_value* argv, const char* methodName) const
1551 {
1552     if (hostEnv_ == nullptr) {
1553         HILOG_ERROR("worker:: host thread maybe is over");
1554         return;
1555     }
1556     if (HostIsStop()) {
1557         HILOG_ERROR("worker:: host thread maybe is over");
1558         WorkerThrowError(hostEnv_, ErrorHelper::ERR_WORKER_NOT_RUNNING,
1559             "host thread maybe is over when CallHostFunction");
1560         return;
1561     }
1562     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1563     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, methodName);
1564     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1565     if (!isCallable) {
1566         HILOG_DEBUG("worker:: host thread %{public}s is not Callable", methodName);
1567         return;
1568     }
1569     napi_value callbackResult = nullptr;
1570     napi_call_function(hostEnv_, obj, callback, argc, argv, &callbackResult);
1571     HandleHostException();
1572 }
1573 
CloseHostCallback()1574 void Worker::CloseHostCallback()
1575 {
1576     {
1577         napi_status status = napi_ok;
1578         HandleScope scope(hostEnv_, status);
1579         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1580         napi_value exitValue = nullptr;
1581         if (isErrorExit_) {
1582             napi_create_int32(hostEnv_, 1, &exitValue); // 1 : exit because of error
1583         } else {
1584             napi_create_int32(hostEnv_, 0, &exitValue); // 0 : exit normally
1585         }
1586         napi_value argv[1] = { exitValue };
1587         CallHostFunction(1, argv, "onexit");
1588         napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1589         // handle listeners
1590         HandleEventListeners(hostEnv_, obj, 1, argv, "exit");
1591     }
1592     CloseHelp::DeletePointer(this, false);
1593 }
1594 
HostOnError(const uv_async_t * req)1595 void Worker::HostOnError(const uv_async_t* req)
1596 {
1597     Worker* worker = static_cast<Worker*>(req->data);
1598     if (worker == nullptr) {
1599         HILOG_ERROR("worker:: worker is null");
1600         return;
1601     }
1602     worker->HostOnErrorInner();
1603     worker->TerminateInner();
1604 }
1605 
HostOnErrorInner()1606 void Worker::HostOnErrorInner()
1607 {
1608     if (hostEnv_ == nullptr || HostIsStop()) {
1609         HILOG_ERROR("worker:: host thread maybe is over when host onerror.");
1610         return;
1611     }
1612     napi_status status = napi_ok;
1613     HandleScope scope(hostEnv_, status);
1614     NAPI_CALL_RETURN_VOID(hostEnv_, status);
1615     NativeEngine* hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1616     if (!hostEngine->InitContainerScopeFunc(scopeId_)) {
1617         HILOG_WARN("worker:: InitContainerScopeFunc error when onerror begin(only stage model)");
1618     }
1619 
1620     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1621     napi_value callback = NapiHelper::GetNameProperty(hostEnv_, obj, "onerror");
1622     bool isCallable = NapiHelper::IsCallable(hostEnv_, callback);
1623 
1624     MessageDataType data;
1625     while (errorQueue_.DeQueue(&data)) {
1626         napi_value result = nullptr;
1627         napi_deserialize(hostEnv_, data, &result);
1628         napi_delete_serialization_data(hostEnv_, data);
1629 
1630         napi_value argv[1] = { result };
1631         if (isCallable) {
1632             napi_value callbackResult = nullptr;
1633             napi_call_function(hostEnv_, obj, callback, 1, argv, &callbackResult);
1634         }
1635         // handle listeners
1636         bool isHandle = HandleEventListeners(hostEnv_, obj, 1, argv, "error");
1637         if (!isCallable && !isHandle) {
1638             napi_value businessError = ErrorHelper::ObjectToError(hostEnv_, result);
1639             napi_throw(hostEnv_, businessError);
1640             HandleHostException();
1641             return;
1642         }
1643         HandleHostException();
1644     }
1645     if (!hostEngine->FinishContainerScopeFunc(scopeId_)) {
1646         HILOG_WARN("worker:: FinishContainerScopeFunc error when onerror end(only stage model)");
1647     }
1648 }
1649 
PostMessageInner(MessageDataType data)1650 void Worker::PostMessageInner(MessageDataType data)
1651 {
1652     if (IsTerminated()) {
1653         HILOG_DEBUG("worker:: worker has been terminated when PostMessageInner.");
1654         return;
1655     }
1656     workerMessageQueue_.EnQueue(data);
1657     std::lock_guard<std::mutex> lock(workerOnmessageMutex_);
1658     if (workerOnMessageSignal_ != nullptr && uv_is_active((uv_handle_t*)workerOnMessageSignal_)) {
1659         uv_async_send(workerOnMessageSignal_);
1660     }
1661 }
1662 
HostOnMessageErrorInner()1663 void Worker::HostOnMessageErrorInner()
1664 {
1665     if (hostEnv_ == nullptr || HostIsStop()) {
1666         HILOG_ERROR("worker:: host thread maybe is over");
1667         return;
1668     }
1669     napi_value obj = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1670     CallHostFunction(0, nullptr, "onmessageerror");
1671     // handle listeners
1672     HandleEventListeners(hostEnv_, obj, 0, nullptr, "messageerror");
1673 }
1674 
TerminateInner()1675 void Worker::TerminateInner()
1676 {
1677     if (IsTerminated() || IsTerminating()) {
1678         HILOG_INFO("worker:: worker is not in running when TerminateInner");
1679         return;
1680     }
1681     // 1. Update State
1682     UpdateWorkerState(TERMINATEING);
1683     // 2. send null signal
1684     PostMessageInner(NULL);
1685 }
1686 
CloseInner()1687 void Worker::CloseInner()
1688 {
1689     UpdateWorkerState(TERMINATEING);
1690     TerminateWorker();
1691 }
1692 
UpdateWorkerState(RunnerState state)1693 bool Worker::UpdateWorkerState(RunnerState state)
1694 {
1695     bool done = false;
1696     do {
1697         RunnerState oldState = runnerState_.load(std::memory_order_acquire);
1698         if (oldState >= state) {
1699             // make sure state sequence is start, running, terminating, terminated
1700             return false;
1701         }
1702         done = runnerState_.compare_exchange_strong(oldState, state);
1703     } while (!done);
1704     return true;
1705 }
1706 
UpdateHostState(HostState state)1707 bool Worker::UpdateHostState(HostState state)
1708 {
1709     bool done = false;
1710     do {
1711         HostState oldState = hostState_.load(std::memory_order_acquire);
1712         if (oldState >= state) {
1713             // make sure state sequence is ACTIVE, INACTIVE
1714             return false;
1715         }
1716         done = hostState_.compare_exchange_strong(oldState, state);
1717     } while (!done);
1718     return true;
1719 }
1720 
TerminateWorker()1721 void Worker::TerminateWorker()
1722 {
1723     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1724     // when there is no active handle, worker loop will stop automatic.
1725     {
1726         std::lock_guard<std::mutex> lock(workerOnmessageMutex_);
1727         uv_close(reinterpret_cast<uv_handle_t*>(workerOnMessageSignal_), [](uv_handle_t* handle) {
1728             if (handle != nullptr) {
1729                 delete reinterpret_cast<uv_async_t*>(handle);
1730                 handle = nullptr;
1731             }
1732         });
1733     }
1734 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
1735     uv_close(reinterpret_cast<uv_handle_t*>(&debuggerOnPostTaskSignal_), nullptr);
1736 #endif
1737     CloseWorkerCallback();
1738     uv_loop_t* loop = GetWorkerLoop();
1739     if (loop != nullptr) {
1740         Timer::ClearEnvironmentTimer(workerEnv_);
1741         uv_stop(loop);
1742     }
1743     UpdateWorkerState(TERMINATED);
1744 }
1745 
PublishWorkerOverSignal()1746 void Worker::PublishWorkerOverSignal()
1747 {
1748     // post NULL tell host worker is not running
1749     if (!HostIsStop()) {
1750         hostMessageQueue_.EnQueue(NULL);
1751         uv_async_send(hostOnMessageSignal_);
1752     }
1753 }
1754 
WorkerOnMessage(const uv_async_t * req)1755 void Worker::WorkerOnMessage(const uv_async_t* req)
1756 {
1757     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
1758     Worker* worker = static_cast<Worker*>(req->data);
1759     if (worker == nullptr) {
1760         HILOG_ERROR("worker::worker is null");
1761         return;
1762     }
1763     worker->WorkerOnMessageInner();
1764 }
1765 
WorkerOnMessageInner()1766 void Worker::WorkerOnMessageInner()
1767 {
1768     if (IsTerminated()) {
1769         return;
1770     }
1771     napi_status status;
1772     napi_handle_scope scope = nullptr;
1773     status = napi_open_handle_scope(workerEnv_, &scope);
1774     if (status != napi_ok || scope == nullptr) {
1775         HILOG_ERROR("worker:: WorkerOnMessage open handle scope failed.");
1776         return;
1777     }
1778     MessageDataType data = nullptr;
1779     while (!IsTerminated() && workerMessageQueue_.DeQueue(&data)) {
1780         if (data == nullptr) {
1781             HILOG_DEBUG("worker:: worker reveive terminate signal");
1782             // Close handlescope need before TerminateWorker
1783             napi_close_handle_scope(workerEnv_, scope);
1784             TerminateWorker();
1785             return;
1786         }
1787         napi_value result = nullptr;
1788         status = napi_deserialize(workerEnv_, data, &result);
1789         napi_delete_serialization_data(workerEnv_, data);
1790         if (status != napi_ok || result == nullptr) {
1791             WorkerOnMessageErrorInner();
1792             continue;
1793         }
1794 
1795         napi_value event = nullptr;
1796         napi_create_object(workerEnv_, &event);
1797         napi_set_named_property(workerEnv_, event, "data", result);
1798         napi_value argv[1] = { event };
1799         CallWorkerFunction(1, argv, "onmessage", true);
1800 
1801         napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
1802         ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "message", true);
1803     }
1804     napi_close_handle_scope(workerEnv_, scope);
1805 }
1806 
HandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type)1807 bool Worker::HandleEventListeners(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type)
1808 {
1809     std::string listener(type);
1810     auto iter = eventListeners_.find(listener);
1811     if (iter == eventListeners_.end()) {
1812         HILOG_DEBUG("worker:: there is no listener for type %{public}s in host thread", type);
1813         return false;
1814     }
1815 
1816     std::list<WorkerListener*>& listeners = iter->second;
1817     std::list<WorkerListener*>::iterator it = listeners.begin();
1818     while (it != listeners.end()) {
1819         WorkerListener* data = *it++;
1820         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
1821         if (!NapiHelper::IsCallable(env, callbackObj)) {
1822             HILOG_DEBUG("worker:: host thread listener %{public}s is not callable", type);
1823             return false;
1824         }
1825         napi_value callbackResult = nullptr;
1826         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
1827         if (!data->NextIsAvailable()) {
1828             listeners.remove(data);
1829             CloseHelp::DeletePointer(data, false);
1830         }
1831     }
1832     return true;
1833 }
1834 
HandleHostException() const1835 void Worker::HandleHostException() const
1836 {
1837     if (!NapiHelper::IsExceptionPending(hostEnv_)) {
1838         return;
1839     }
1840     auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
1841     hostEngine->HandleUncaughtException();
1842 }
1843 
HandleException()1844 void Worker::HandleException()
1845 {
1846     if (!NapiHelper::IsExceptionPending(workerEnv_)) {
1847         return;
1848     }
1849 
1850     napi_status status = napi_ok;
1851     HandleScope scope(workerEnv_, status);
1852     NAPI_CALL_RETURN_VOID(workerEnv_, status);
1853     napi_value exception;
1854     napi_get_and_clear_last_exception(workerEnv_, &exception);
1855     if (exception == nullptr) {
1856         return;
1857     }
1858 
1859     HandleUncaughtException(exception);
1860 }
1861 
HandleUncaughtException(napi_value exception)1862 void Worker::HandleUncaughtException(napi_value exception)
1863 {
1864     napi_value obj = ErrorHelper::TranslateErrorEvent(workerEnv_, exception);
1865 
1866     // WorkerGlobalScope onerror
1867     WorkerOnErrorInner(obj);
1868 
1869     if (hostEnv_ != nullptr) {
1870         napi_value data = nullptr;
1871         napi_value undefined = NapiHelper::GetUndefinedValue(workerEnv_);
1872         napi_serialize(workerEnv_, obj, undefined, undefined, false, true, &data);
1873         {
1874             std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1875             if (!HostIsStop()) {
1876                 errorQueue_.EnQueue(data);
1877                 uv_async_send(hostOnErrorSignal_);
1878             }
1879         }
1880     } else {
1881         HILOG_ERROR("worker:: host engine is nullptr.");
1882     }
1883 }
1884 
WorkerOnMessageErrorInner()1885 void Worker::WorkerOnMessageErrorInner()
1886 {
1887     isErrorExit_ = true;
1888     CallWorkerFunction(0, nullptr, "onmessageerror", true);
1889     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
1890     ParentPortHandleEventListeners(workerEnv_, obj, 0, nullptr, "messageerror", true);
1891 }
1892 
PostMessageToHostInner(MessageDataType data)1893 void Worker::PostMessageToHostInner(MessageDataType data)
1894 {
1895     std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
1896     if (hostEnv_ != nullptr && !HostIsStop()) {
1897         hostMessageQueue_.EnQueue(data);
1898         uv_async_send(hostOnMessageSignal_);
1899     } else {
1900         HILOG_ERROR("worker:: worker host engine is nullptr when PostMessageToHostInner.");
1901     }
1902 }
1903 
operator ==(const WorkerListener & listener) const1904 bool Worker::WorkerListener::operator==(const WorkerListener& listener) const
1905 {
1906     napi_value obj = NapiHelper::GetReferenceValue(listener.env_, listener.callback_);
1907     napi_value compareObj = NapiHelper::GetReferenceValue(env_, callback_);
1908     // the env of listener and cmp listener must be same env because of Synchronization method
1909     return NapiHelper::StrictEqual(env_, compareObj, obj);
1910 }
1911 
AddListenerInner(napi_env env,const char * type,const WorkerListener * listener)1912 void Worker::AddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
1913 {
1914     std::string typestr(type);
1915     auto iter = eventListeners_.find(typestr);
1916     if (iter == eventListeners_.end()) {
1917         std::list<WorkerListener*> listeners;
1918         listeners.emplace_back(const_cast<WorkerListener*>(listener));
1919         eventListeners_[typestr] = listeners;
1920     } else {
1921         std::list<WorkerListener*>& listenerList = iter->second;
1922         std::list<WorkerListener*>::iterator it = std::find_if(
1923             listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, listener->callback_));
1924         if (it != listenerList.end()) {
1925             return;
1926         }
1927         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
1928     }
1929 }
1930 
RemoveListenerInner(napi_env env,const char * type,napi_ref callback)1931 void Worker::RemoveListenerInner(napi_env env, const char* type, napi_ref callback)
1932 {
1933     std::string typestr(type);
1934     auto iter = eventListeners_.find(typestr);
1935     if (iter == eventListeners_.end()) {
1936         return;
1937     }
1938     std::list<WorkerListener*>& listenerList = iter->second;
1939     if (callback != nullptr) {
1940         std::list<WorkerListener*>::iterator it =
1941             std::find_if(listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, callback));
1942         if (it != listenerList.end()) {
1943             CloseHelp::DeletePointer(*it, false);
1944             listenerList.erase(it);
1945         }
1946     } else {
1947         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
1948             CloseHelp::DeletePointer(*it, false);
1949         }
1950         eventListeners_.erase(typestr);
1951     }
1952 }
1953 
~Worker()1954 Worker::~Worker()
1955 {
1956     if (!HostIsStop()) {
1957         ReleaseHostThreadContent();
1958     }
1959     RemoveAllListenerInner();
1960     ClearGlobalCallObject();
1961 }
1962 
RemoveAllListenerInner()1963 void Worker::RemoveAllListenerInner()
1964 {
1965     for (auto iter = eventListeners_.begin(); iter != eventListeners_.end(); iter++) {
1966         std::list<WorkerListener*>& listeners = iter->second;
1967         for (auto item = listeners.begin(); item != listeners.end(); item++) {
1968             WorkerListener* listener = *item;
1969             CloseHelp::DeletePointer(listener, false);
1970         }
1971     }
1972     eventListeners_.clear();
1973 }
1974 
ReleaseHostThreadContent()1975 void Worker::ReleaseHostThreadContent()
1976 {
1977     // 1. clear message send to host thread
1978     hostMessageQueue_.Clear(hostEnv_);
1979     hostGlobalCallQueue_.Clear(hostEnv_);
1980     // 2. clear error queue send to host thread
1981     errorQueue_.Clear(hostEnv_);
1982     if (!HostIsStop()) {
1983         napi_status status = napi_ok;
1984         HandleScope scope(hostEnv_, status);
1985         NAPI_CALL_RETURN_VOID(hostEnv_, status);
1986         // 3. set thisVar's nativepointer be null
1987         napi_value thisVar = NapiHelper::GetReferenceValue(hostEnv_, workerRef_);
1988         Worker* worker = nullptr;
1989         napi_remove_wrap(hostEnv_, thisVar, reinterpret_cast<void**>(&worker));
1990         hostEnv_ = nullptr;
1991         // 4. set workerRef_ be null
1992         workerRef_ = nullptr;
1993     }
1994 }
1995 
WorkerOnErrorInner(napi_value error)1996 void Worker::WorkerOnErrorInner(napi_value error)
1997 {
1998     isErrorExit_ = true;
1999     napi_value argv[1] = { error };
2000     CallWorkerFunction(1, argv, "onerror", false);
2001     napi_value obj = NapiHelper::GetReferenceValue(workerEnv_, this->workerPort_);
2002     ParentPortHandleEventListeners(workerEnv_, obj, 1, argv, "error", false);
2003 }
2004 
CallWorkerFunction(size_t argc,const napi_value * argv,const char * methodName,bool tryCatch)2005 bool Worker::CallWorkerFunction(size_t argc, const napi_value* argv, const char* methodName, bool tryCatch)
2006 {
2007     if (workerEnv_ == nullptr) {
2008         HILOG_ERROR("Worker:: worker is not running when call workerPort.%{public}s.", methodName);
2009         return false;
2010     }
2011     napi_value callback = NapiHelper::GetNamePropertyInParentPort(workerEnv_, workerPort_, methodName);
2012     bool isCallable = NapiHelper::IsCallable(workerEnv_, callback);
2013     if (!isCallable) {
2014         HILOG_DEBUG("worker:: workerPort.%{public}s is not Callable", methodName);
2015         return false;
2016     }
2017     napi_value workerPortObj = NapiHelper::GetReferenceValue(workerEnv_, workerPort_);
2018     napi_value callbackResult = nullptr;
2019     napi_call_function(workerEnv_, workerPortObj, callback, argc, argv, &callbackResult);
2020     if (tryCatch && callbackResult == nullptr) {
2021         HILOG_DEBUG("worker:: workerPort.%{public}s handle exception", methodName);
2022         HandleException();
2023         return false;
2024     }
2025     return true;
2026 }
2027 
CloseWorkerCallback()2028 void Worker::CloseWorkerCallback()
2029 {
2030     CallWorkerFunction(0, nullptr, "onclose", true);
2031     // off worker inited environment
2032     {
2033         std::lock_guard<std::recursive_mutex> lock(liveStatusLock_);
2034         if (HostIsStop()) {
2035             return;
2036         }
2037         auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2038         if (!hostEngine->CallOffWorkerFunc(reinterpret_cast<NativeEngine*>(workerEnv_))) {
2039             HILOG_ERROR("worker:: CallOffWorkerFunc error");
2040         }
2041     }
2042 }
2043 
ReleaseWorkerThreadContent()2044 void Worker::ReleaseWorkerThreadContent()
2045 {
2046     HITRACE_HELPER_METER_NAME(__PRETTY_FUNCTION__);
2047     auto hostEngine = reinterpret_cast<NativeEngine*>(hostEnv_);
2048     auto workerEngine = reinterpret_cast<NativeEngine*>(workerEnv_);
2049     if (hostEngine != nullptr && workerEngine != nullptr) {
2050         if (!hostEngine->DeleteWorker(workerEngine)) {
2051             HILOG_ERROR("worker:: DeleteWorker error");
2052         }
2053         hostEngine->DecreaseSubEnvCounter();
2054     }
2055     // 1. remove worker instance count
2056     if (!workerEngine->IsRestrictedWorkerThread()) {
2057         std::lock_guard<std::mutex> lock(g_workersMutex);
2058         std::list<Worker*>::iterator it = std::find(g_workers.begin(), g_workers.end(), this);
2059         if (it != g_workers.end()) {
2060             g_workers.erase(it);
2061         }
2062     } else {
2063         std::lock_guard<std::mutex> lock(g_limitedworkersMutex);
2064         std::list<Worker*>::iterator it = std::find(g_limitedworkers.begin(), g_limitedworkers.end(), this);
2065         if (it != g_limitedworkers.end()) {
2066             g_limitedworkers.erase(it);
2067         }
2068     }
2069 
2070     ParentPortRemoveAllListenerInner();
2071 
2072     // 2. delete worker's parentPort
2073     NapiHelper::DeleteReference(workerEnv_, workerPort_);
2074     workerPort_ = nullptr;
2075 
2076     // 3. clear message send to worker thread
2077     workerMessageQueue_.Clear(workerEnv_);
2078     workerGlobalCallQueue_.Clear(workerEnv_);
2079     CloseHelp::DeletePointer(reinterpret_cast<NativeEngine*>(workerEnv_), false);
2080     workerEnv_ = nullptr;
2081 }
2082 
ParentPortAddListenerInner(napi_env env,const char * type,const WorkerListener * listener)2083 void Worker::ParentPortAddListenerInner(napi_env env, const char* type, const WorkerListener* listener)
2084 {
2085     std::string typestr(type);
2086     auto iter = parentPortEventListeners_.find(typestr);
2087     if (iter == parentPortEventListeners_.end()) {
2088         std::list<WorkerListener*> listeners;
2089         listeners.emplace_back(const_cast<WorkerListener*>(listener));
2090         parentPortEventListeners_[typestr] = listeners;
2091     } else {
2092         std::list<WorkerListener*>& listenerList = iter->second;
2093         std::list<WorkerListener*>::iterator it = std::find_if(
2094             listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, listener->callback_));
2095         if (it != listenerList.end()) {
2096             return;
2097         }
2098         listenerList.emplace_back(const_cast<WorkerListener*>(listener));
2099     }
2100 }
2101 
ParentPortRemoveAllListenerInner()2102 void Worker::ParentPortRemoveAllListenerInner()
2103 {
2104     for (auto iter = parentPortEventListeners_.begin(); iter != parentPortEventListeners_.end(); iter++) {
2105         std::list<WorkerListener*>& listeners = iter->second;
2106         for (auto item = listeners.begin(); item != listeners.end(); item++) {
2107             WorkerListener* listener = *item;
2108             CloseHelp::DeletePointer(listener, false);
2109         }
2110     }
2111     parentPortEventListeners_.clear();
2112 }
2113 
ParentPortRemoveListenerInner(napi_env env,const char * type,napi_ref callback)2114 void Worker::ParentPortRemoveListenerInner(napi_env env, const char* type, napi_ref callback)
2115 {
2116     std::string typestr(type);
2117     auto iter = parentPortEventListeners_.find(typestr);
2118     if (iter == parentPortEventListeners_.end()) {
2119         return;
2120     }
2121     std::list<WorkerListener*>& listenerList = iter->second;
2122     if (callback != nullptr) {
2123         std::list<WorkerListener*>::iterator it =
2124             std::find_if(listenerList.begin(), listenerList.end(), Worker::FindWorkerListener(env, callback));
2125         if (it != listenerList.end()) {
2126             CloseHelp::DeletePointer(*it, false);
2127             listenerList.erase(it);
2128         }
2129     } else {
2130         for (auto it = listenerList.begin(); it != listenerList.end(); it++) {
2131             CloseHelp::DeletePointer(*it, false);
2132         }
2133         parentPortEventListeners_.erase(typestr);
2134     }
2135 }
2136 
ParentPortHandleEventListeners(napi_env env,napi_value recv,size_t argc,const napi_value * argv,const char * type,bool tryCatch)2137 void Worker::ParentPortHandleEventListeners(napi_env env, napi_value recv, size_t argc,
2138                                             const napi_value* argv, const char* type, bool tryCatch)
2139 {
2140     std::string listener(type);
2141     auto iter = parentPortEventListeners_.find(listener);
2142     if (iter == parentPortEventListeners_.end()) {
2143         HILOG_DEBUG("worker:: there is no listener for type %{public}s in worker thread", type);
2144         return;
2145     }
2146 
2147     std::list<WorkerListener*>& listeners = iter->second;
2148     std::list<WorkerListener*>::iterator it = listeners.begin();
2149     while (it != listeners.end()) {
2150         WorkerListener* data = *it++;
2151         napi_value callbackObj = NapiHelper::GetReferenceValue(env, data->callback_);
2152         if (!NapiHelper::IsCallable(env, callbackObj)) {
2153             HILOG_DEBUG("worker:: workerPort.addEventListener %{public}s is not callable", type);
2154             return;
2155         }
2156         napi_value callbackResult = nullptr;
2157         napi_call_function(env, recv, callbackObj, argc, argv, &callbackResult);
2158         if (!data->NextIsAvailable()) {
2159             listeners.remove(data);
2160             CloseHelp::DeletePointer(data, false);
2161         }
2162         if (tryCatch && callbackResult == nullptr) {
2163             HandleException();
2164             return;
2165         }
2166     }
2167 }
2168 
WorkerThrowError(napi_env env,int32_t errCode,const char * errMessage)2169 void Worker::WorkerThrowError(napi_env env, int32_t errCode, const char* errMessage)
2170 {
2171     auto engine = reinterpret_cast<NativeEngine*>(env);
2172     while (!engine->IsMainThread()) {
2173         engine = engine->GetHostEngine();
2174     }
2175     if (engine->IsTargetWorkerVersion(WorkerVersion::NEW)) {
2176         ErrorHelper::ThrowError(env, errCode, errMessage);
2177     }
2178 }
2179 
CanCreateWorker(napi_env env,WorkerVersion target)2180 bool Worker::CanCreateWorker(napi_env env, WorkerVersion target)
2181 {
2182     auto engine = reinterpret_cast<NativeEngine*>(env);
2183     while (!engine->IsMainThread()) {
2184         engine = engine->GetHostEngine();
2185     }
2186     if (engine->CheckAndSetWorkerVersion(WorkerVersion::NONE, target) || engine->IsTargetWorkerVersion(target)) {
2187         return true;
2188     }
2189     return false;
2190 }
2191 
2192 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM)
HandleDebuggerTask(const uv_async_t * req)2193 void Worker::HandleDebuggerTask(const uv_async_t* req)
2194 {
2195     Worker* worker = DereferenceHelp::DereferenceOf(&Worker::debuggerOnPostTaskSignal_, req);
2196     if (worker == nullptr) {
2197         HILOG_ERROR("worker::worker is null");
2198         return;
2199     }
2200 
2201     worker->debuggerMutex_.lock();
2202     auto task = std::move(worker->debuggerQueue_.front());
2203     worker->debuggerQueue_.pop();
2204     worker->debuggerMutex_.unlock();
2205     task();
2206 }
2207 
DebuggerOnPostTask(std::function<void ()> && task)2208 void Worker::DebuggerOnPostTask(std::function<void()>&& task)
2209 {
2210     if (IsTerminated()) {
2211         HILOG_ERROR("worker:: worker has been terminated.");
2212         return;
2213     }
2214     if (uv_is_active((uv_handle_t*)&debuggerOnPostTaskSignal_)) {
2215         std::lock_guard<std::mutex> lock(debuggerMutex_);
2216         debuggerQueue_.push(std::move(task));
2217         uv_async_send(&debuggerOnPostTaskSignal_);
2218     }
2219 }
2220 #endif
2221 
2222 } // namespace Commonlibrary::Concurrent::WorkerModule
2223