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