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