• 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 #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