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 #ifndef JS_CONCURRENT_MODULE_WORKER_WORKER_NEW_H_ 17 #define JS_CONCURRENT_MODULE_WORKER_WORKER_NEW_H_ 18 19 #include <list> 20 #include <map> 21 #include <mutex> 22 #include "message_queue.h" 23 #include "helper/napi_helper.h" 24 #include "helper/object_helper.h" 25 #include "napi/native_api.h" 26 #include "napi/native_node_api.h" 27 #include "native_engine/native_engine.h" 28 #include "utils/log.h" 29 #include "worker_runner.h" 30 31 namespace Commonlibrary::Concurrent::WorkerModule { 32 using namespace Commonlibrary::Concurrent::Common::Helper; 33 34 class NewWorker { 35 public: 36 static const int8_t WORKERPARAMNUM = 2; 37 static const int32_t TYPE_ERROR = 401; 38 static const int32_t WORKERINITIALIZATION_ERROR = 10200003; 39 static const int32_t WORKENOTRUNNING_ERROR = 10200004; 40 static const int32_t WORKERUNSUPPORTED_ERROR = 10200005; 41 static const int32_t WORKERSERIALIZATION_ERROR = 10200006; 42 static const int32_t WORKERFILEPATH_ERROR = 10200007; 43 44 enum RunnerState { STARTING, RUNNING, TERMINATEING, TERMINATED }; 45 enum HostState { ACTIVE, INACTIVE }; 46 enum ListenerMode { ONCE, PERMANENT }; 47 48 enum ScriptMode { CLASSIC, MODULE }; 49 50 struct WorkerListener { WorkerListenerWorkerListener51 WorkerListener(napi_env env, napi_ref callback, ListenerMode mode) 52 : env_(env), callback_(callback), mode_(mode) 53 {} 54 ~WorkerListenerWorkerListener55 ~WorkerListener() 56 { 57 NapiHelper::DeleteReference(env_, callback_); 58 callback_ = nullptr; 59 } 60 NextIsAvailableWorkerListener61 bool NextIsAvailable() const 62 { 63 return mode_ != ONCE; 64 } 65 SetModeWorkerListener66 void SetMode(ListenerMode mode) 67 { 68 mode_ = mode; 69 } 70 71 bool operator==(const WorkerListener& listener) const; 72 73 napi_env env_ {NULL}; 74 napi_ref callback_ {NULL}; 75 ListenerMode mode_ {PERMANENT}; 76 }; 77 78 struct FindWorkerListener { FindWorkerListenerFindWorkerListener79 FindWorkerListener(napi_env env, napi_ref ref) : env_(env), ref_(ref) {} 80 operatorFindWorkerListener81 bool operator()(const WorkerListener* listener) const 82 { 83 napi_value compareObj = NapiHelper::GetReferenceValue(env_, listener->callback_); 84 napi_value obj = NapiHelper::GetReferenceValue(env_, ref_); 85 // the env of listener and cmp listener must be same env because of Synchronization method 86 return NapiHelper::StrictEqual(env_, compareObj, obj); 87 } 88 89 napi_env env_ {nullptr}; 90 napi_ref ref_ {nullptr}; 91 }; 92 93 /** 94 * Creates a worker instance. 95 * 96 * @param env NAPI environment parameters. 97 * @param thisVar URL of the script to be executed by the worker. 98 */ 99 NewWorker(napi_env env, napi_ref thisVar); 100 101 /** 102 * The destructor of the Worker. 103 */ 104 ~NewWorker(); 105 106 /** 107 * The host thread receives the information. 108 * 109 * @param req The value of the object passed in by the js layer. 110 */ 111 static void HostOnMessage(const uv_async_t* req); 112 113 /** 114 * The host thread receives the information. 115 * 116 * @param req The value of the object passed in by the js layer. 117 */ 118 static void HostOnError(const uv_async_t* req); 119 120 /** 121 * The worker thread receives the information. 122 * 123 * @param req The value of the object passed in by the js layer. 124 */ 125 static void WorkerOnMessage(const uv_async_t* req); 126 127 /** 128 * ExecuteIn in thread. 129 * 130 * @param data The worker pointer. 131 */ 132 static void ExecuteInThread(const void* data); 133 134 /** 135 * Post a message. 136 * 137 * @param env NAPI environment parameters. 138 * @param thisVar The callback information of the js layer. 139 */ 140 static napi_value PostMessage(napi_env env, napi_callback_info cbinfo); 141 142 /** 143 * Add event listeners to host. 144 * 145 * @param env NAPI environment parameters. 146 * @param cbinfo The callback information of the js layer. 147 */ 148 static napi_value PostMessageToHost(napi_env env, napi_callback_info cbinfo); 149 150 /** 151 * Terminates the worker thread to stop the worker from receiving messages. 152 * 153 * @param env NAPI environment parameters. 154 * @param cbinfo The callback information of the js layer. 155 */ 156 static napi_value Terminate(napi_env env, napi_callback_info cbinfo); 157 158 /** 159 * Close the worker. 160 * 161 * @param env NAPI environment parameters. 162 * @param cbinfo The callback information of the js layer. 163 */ 164 static napi_value CloseWorker(napi_env env, napi_callback_info cbinfo); 165 166 /** 167 * Adds an event listener to the worker. 168 * 169 * @param env NAPI environment parameters. 170 * @param cbinfo The callback information of the js layer. 171 */ 172 static napi_value On(napi_env env, napi_callback_info cbinfo); 173 174 /** 175 * Adds an event listener to the worker and removes the event listener automatically after it is invoked once. 176 * 177 * @param env NAPI environment parameters. 178 * @param cbinfo The callback information of the js layer. 179 */ 180 static napi_value Once(napi_env env, napi_callback_info cbinfo); 181 182 /** 183 * Removes an event listener to the worker. 184 * 185 * @param env NAPI environment parameters. 186 * @param cbinfo The callback information of the js layer. 187 */ 188 static napi_value Off(napi_env env, napi_callback_info cbinfo); 189 190 /** 191 * Add event listeners. 192 * 193 * @param env NAPI environment parameters. 194 * @param cbinfo The callback information of the js layer. 195 */ 196 static napi_value AddEventListener(napi_env env, napi_callback_info cbinfo); 197 198 /** 199 * Dispatch the event. 200 * 201 * @param env NAPI environment parameters. 202 * @param cbinfo The callback information of the js layer. 203 */ 204 static napi_value DispatchEvent(napi_env env, napi_callback_info cbinfo); 205 206 /** 207 * Remove the event listener. 208 * 209 * @param env NAPI environment parameters. 210 * @param cbinfo The callback information of the js layer. 211 */ 212 static napi_value RemoveEventListener(napi_env env, napi_callback_info cbinfo); 213 214 /** 215 * Remove all listener. 216 * 217 * @param env NAPI environment parameters. 218 * @param cbinfo The callback information of the js layer. 219 */ 220 static napi_value RemoveAllListener(napi_env env, napi_callback_info cbinfo); 221 222 /** 223 * Add the listener. 224 * 225 * @param env NAPI environment parameters. 226 * @param cbinfo The callback information of the js layer. 227 */ 228 static napi_value AddListener(napi_env env, napi_callback_info cbinfo, ListenerMode mode); 229 230 /** 231 * Remove the listener. 232 * 233 * @param env NAPI environment parameters. 234 * @param cbinfo The callback information of the js layer. 235 */ 236 static napi_value RemoveListener(napi_env env, napi_callback_info cbinfo); 237 238 /** 239 * The constructor of worker. 240 * 241 * @param env NAPI environment parameters. 242 * @param cbinfo The callback information of the js layer. 243 */ 244 static napi_value WorkerConstructor(napi_env env, napi_callback_info cbinfo); 245 246 /** 247 * Initialize the worker. 248 * 249 * @param env NAPI environment parameters. 250 * @param cbinfo The callback information of the js layer. 251 */ 252 static napi_value InitWorker(napi_env env, napi_value exports); 253 254 /** 255 * Cancel the task. 256 * 257 * @param env NAPI environment parameters. 258 * @param cbinfo The callback information of the js layer. 259 */ 260 static napi_value CancelTask(napi_env env, napi_callback_info cbinfo); 261 262 /** 263 * The parent port cancels the task. 264 * 265 * @param env NAPI environment parameters. 266 * @param cbinfo The callback information of the js layer. 267 */ 268 static napi_value WorkerPortCancelTask(napi_env env, napi_callback_info cbinfo); 269 270 /** 271 * The parent port adds an event listener. 272 * 273 * @param env NAPI environment parameters. 274 * @param cbinfo The callback information of the js layer. 275 */ 276 static napi_value WorkerPortAddEventListener(napi_env env, napi_callback_info cbinfo); 277 278 /** 279 * The parent port removes all event listener. 280 * 281 * @param env NAPI environment parameters. 282 * @param cbinfo The callback information of the js layer. 283 */ 284 static napi_value WorkerPortRemoveAllListener(napi_env env, napi_callback_info cbinfo); 285 286 /** 287 * The parent port dispatch the event listener. 288 * 289 * @param env NAPI environment parameters. 290 * @param cbinfo The callback information of the js layer. 291 */ 292 static napi_value WorkerPortDispatchEvent(napi_env env, napi_callback_info cbinfo); 293 294 /** 295 * The parent port removes the event listener. 296 * 297 * @param env NAPI environment parameters. 298 * @param cbinfo The callback information of the js layer. 299 */ 300 static napi_value WorkerPortRemoveEventListener(napi_env env, napi_callback_info cbinfo); 301 302 void StartExecuteInThread(napi_env env, const char* script); 303 304 bool UpdateWorkerState(RunnerState state); 305 bool UpdateHostState(HostState state); 306 IsRunning()307 bool IsRunning() const 308 { 309 return runnerState_.load(std::memory_order_acquire) == RUNNING; 310 } 311 IsTerminated()312 bool IsTerminated() const 313 { 314 return runnerState_.load(std::memory_order_acquire) >= TERMINATED; 315 } 316 IsTerminating()317 bool IsTerminating() const 318 { 319 return runnerState_.load(std::memory_order_acquire) == TERMINATEING; 320 } 321 SetScriptMode(ScriptMode mode)322 void SetScriptMode(ScriptMode mode) 323 { 324 scriptMode_ = mode; 325 } 326 327 void AddListenerInner(napi_env env, const char* type, const WorkerListener* listener); 328 void RemoveListenerInner(napi_env env, const char* type, napi_ref callback); 329 void RemoveAllListenerInner(); 330 GetWorkerLoop()331 uv_loop_t* GetWorkerLoop() const 332 { 333 if (workerEnv_ != nullptr) { 334 return NapiHelper::GetLibUV(workerEnv_); 335 } 336 return nullptr; 337 } 338 SetWorkerEnv(napi_env workerEnv)339 void SetWorkerEnv(napi_env workerEnv) 340 { 341 workerEnv_ = workerEnv; 342 } 343 GetScript()344 std::string GetScript() const 345 { 346 return script_; 347 } 348 GetName()349 std::string GetName() const 350 { 351 return name_; 352 } 353 ClearWorkerTasks()354 bool ClearWorkerTasks() 355 { 356 if (hostEnv_ != nullptr) { 357 workerMessageQueue_.Clear(hostEnv_); 358 return true; 359 } 360 return false; 361 } 362 HostIsStop()363 bool HostIsStop() const 364 { 365 return hostState_.load(std::memory_order_acquire) == INACTIVE; 366 } 367 IsSameWorkerEnv(napi_env env)368 bool IsSameWorkerEnv(napi_env env) const 369 { 370 return workerEnv_ == env; 371 } 372 Loop()373 void Loop() const 374 { 375 uv_loop_t* loop = GetWorkerLoop(); 376 if (loop != nullptr) { 377 uv_run(loop, UV_RUN_DEFAULT); 378 } else { 379 HILOG_ERROR("worker:: Worker loop is nullptr when start worker loop"); 380 return; 381 } 382 } 383 384 static void TranslateErrorEvent(napi_env env, napi_value error, napi_value *obj); 385 386 private: 387 void WorkerOnMessageInner(); 388 void HostOnMessageInner(); 389 void HostOnErrorInner(); 390 void HostOnMessageErrorInner(); 391 void WorkerOnMessageErrorInner(); 392 void WorkerOnErrorInner(napi_value error); 393 394 void HandleException(); 395 bool CallWorkerFunction(size_t argc, const napi_value* argv, const char* methodName, bool tryCatch); 396 void CallHostFunction(size_t argc, const napi_value* argv, const char* methodName) const; 397 398 void HandleEventListeners(napi_env env, napi_value recv, size_t argc, const napi_value* argv, const char* type); 399 void ParentPortHandleEventListeners(napi_env env, napi_value recv, 400 size_t argc, const napi_value* argv, const char* type); 401 void TerminateInner(); 402 403 void PostMessageInner(MessageDataType data); 404 void PostMessageToHostInner(MessageDataType data); 405 406 void TerminateWorker(); 407 void CloseInner(); 408 409 void PublishWorkerOverSignal(); 410 void CloseWorkerCallback(); 411 void CloseHostCallback() const; 412 413 void ReleaseWorkerThreadContent(); 414 void ReleaseHostThreadContent(); 415 bool PrepareForWorkerInstance(); 416 void ParentPortAddListenerInner(napi_env env, const char* type, const WorkerListener* listener); 417 void ParentPortRemoveAllListenerInner(); 418 void ParentPortRemoveListenerInner(napi_env env, const char* type, napi_ref callback); 419 void PreparePandafile(); 420 void GetContainerScopeId(napi_env env); 421 422 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 423 static void HandleDebuggerTask(const uv_async_t* req); 424 void DebuggerOnPostTask(std::function<void()>&& task); 425 #endif 426 GetHostEnv()427 napi_env GetHostEnv() const 428 { 429 return hostEnv_; 430 } 431 GetWorkerEnv()432 napi_env GetWorkerEnv() const 433 { 434 return workerEnv_; 435 } 436 437 std::string script_ {}; 438 std::string name_ {}; 439 ScriptMode scriptMode_ {CLASSIC}; 440 int32_t scopeId_ {-1}; 441 442 MessageQueue workerMessageQueue_ {}; 443 MessageQueue hostMessageQueue_ {}; 444 MessageQueue errorQueue_ {}; 445 446 uv_async_t* workerOnMessageSignal_= nullptr; 447 uv_async_t* hostOnMessageSignal_ = nullptr; 448 uv_async_t* hostOnErrorSignal_ = nullptr; 449 #if !defined(WINDOWS_PLATFORM) && !defined(MAC_PLATFORM) 450 uv_async_t ddebuggerOnPostTaskSignal_ {}; 451 std::function<void()> debuggerTask_; 452 #endif 453 454 std::atomic<RunnerState> runnerState_ {STARTING}; 455 std::atomic<HostState> hostState_ {ACTIVE}; 456 std::unique_ptr<WorkerRunner> runner_ {}; 457 458 napi_env hostEnv_ {nullptr}; 459 napi_env workerEnv_ {nullptr}; 460 461 napi_ref workerRef_ {nullptr}; 462 napi_ref workerPort_ {nullptr}; 463 464 std::map<std::string, std::list<WorkerListener*>> eventListeners_ {}; 465 std::map<std::string, std::list<WorkerListener*>> parentPortEventListeners_ {}; 466 467 std::recursive_mutex liveStatusLock_ {}; 468 }; 469 } // namespace Commonlibrary::Concurrent::WorkerModule 470 #endif // JS_CONCURRENT_MODULE_WORKER_WORKER_NEW_H_ 471