• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2024 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 "ark_interop_internal.h"
17 #include "ark_interop_napi.h"
18 #include "ark_interop_log.h"
19 
20 #include <unordered_map>
21 #include <mutex>
22 
23 using namespace panda::ecmascript;
24 
25 #ifdef __OHOS__
26 using namespace OHOS::AppExecFwk;
27 
28 namespace {
29 std::unordered_map<ARKTS_Env, ARKTS_Loop> g_eventHandlers_;
30 std::mutex g_eventHandlerMutex_;
31 
32 struct ARKTS_Loop_ {
33     enum Status {
34         IDLE,
35         REQUESTING,
36         STOPPING,
37         STOPPED,
38     };
39     uv_loop_t* loop;
40     uv_async_t asyncReq;
41     Status status;
42     std::vector<std::function<void ()>> callbacks;
43     std::mutex mutex;
44     std::condition_variable cv;
45 
46     explicit ARKTS_Loop_(uv_loop_t* loop);
47     ~ARKTS_Loop_();
48 
49     void PostTask(std::function<void ()> task);
50     // only to be call by uv_queue_task
51     void DrainTasks();
52 };
53 
54 std::unordered_map<ARKTS_Env, ARKTS_Loop_*> g_uvLoops_;
55 std::mutex g_uvLoopMutex_;
56 }
57 #endif
58 
ARKTS_GetOrCreateEventHandler(ARKTS_Env env)59 ARKTS_Loop ARKTS_GetOrCreateEventHandler(ARKTS_Env env)
60 {
61     if (!env) {
62         return nullptr;
63     }
64 #ifdef __OHOS__
65     std::lock_guard lock(g_eventHandlerMutex_);
66     auto searchRet = g_eventHandlers_.find(env);
67     if (searchRet != g_eventHandlers_.end()) {
68         return searchRet->second;
69     }
70     auto handler = std::make_shared<EventHandler>(EventRunner::Current());
71     g_eventHandlers_[env] = handler;
72     return handler;
73 #else
74     return nullptr;
75 #endif
76 }
77 
ARKTSInner_GetUvLoop(ARKTS_Env env)78 static ARKTS_Loop_* ARKTSInner_GetUvLoop(ARKTS_Env env)
79 {
80     std::lock_guard lock(g_uvLoopMutex_);
81     auto searchRet = g_uvLoops_.find(env);
82     if (searchRet != g_uvLoops_.end()) {
83         return searchRet->second;
84     } else {
85         return nullptr;
86     }
87 }
88 
89 #ifdef __OHOS__
ARKTS_GetEventHandler(ARKTS_Env env)90 static ARKTS_Loop ARKTS_GetEventHandler(ARKTS_Env env)
91 {
92     if (!env) {
93         return nullptr;
94     }
95     std::lock_guard lock(g_eventHandlerMutex_);
96     auto searchRet = g_eventHandlers_.find(env);
97     if (searchRet != g_eventHandlers_.end()) {
98         return searchRet->second;
99     }
100     return nullptr;
101 }
102 #endif
103 
104 // @deprecated
ARKTS_InitEventHandle(ARKTS_Env env)105 void ARKTS_InitEventHandle(ARKTS_Env env)
106 {
107     ARKTS_ASSERT_V(env, "env is null");
108     void (ARKTS_GetOrCreateEventHandler(env));
109 }
110 
ARKTS_DisposeEventHandler(ARKTS_Env env)111 void ARKTS_DisposeEventHandler(ARKTS_Env env)
112 {
113     if (!env) {
114         return;
115     }
116 #ifdef __OHOS__
117     {
118         std::lock_guard lock(g_eventHandlerMutex_);
119         g_eventHandlers_.erase(env);
120     }
121 #endif
122     {
123         std::lock_guard lock(g_uvLoopMutex_);
124         auto searchRet = g_uvLoops_.find(env);
125         if (searchRet != g_uvLoops_.end()) {
126             auto loop = searchRet->second;
127             g_uvLoops_.erase(searchRet);
128             delete loop;
129         }
130     }
131 }
132 
ARKTSInner_CreateAsyncTask(ARKTS_Env env,ARKTS_AsyncCallback callback,void * data)133 void ARKTSInner_CreateAsyncTask(ARKTS_Env env, ARKTS_AsyncCallback callback, void* data)
134 {
135     // uv_loop first, secondary is for compatible with early version.
136     if (auto loop = ARKTSInner_GetUvLoop(env)) {
137         loop->PostTask([env, callback, data] {
138             callback(env, data);
139         });
140         return;
141     }
142 #ifdef __OHOS__
143     auto handler = ARKTS_GetEventHandler(env);
144     if (!handler) {
145         LOGE("event handler not initialized");
146         return;
147     }
148     handler->PostTask([env, callback, data] {
149         callback(env, data);
150     });
151 #endif
152 }
153 
ARKTS_CreateAsyncTask(ARKTS_Env env,int64_t callbackId)154 void ARKTS_CreateAsyncTask(ARKTS_Env env, int64_t callbackId)
155 {
156     ARKTSInner_CreateAsyncTask(env, ARKTSInner_CJAsyncCallback, reinterpret_cast<void*>(callbackId));
157 }
158 
ARKTS_Loop_(uv_loop_t * loop)159 ARKTS_Loop_::ARKTS_Loop_(uv_loop_t* loop) : loop(loop), asyncReq(), status(IDLE)
160 {
161     uv_async_init(loop, &asyncReq, [](uv_async_t* work) {
162         auto loop = static_cast<ARKTS_Loop_*>(work->data);
163         if (loop) {
164             loop->DrainTasks();
165         }
166     });
167     asyncReq.data = this;
168 }
169 
~ARKTS_Loop_()170 ARKTS_Loop_::~ARKTS_Loop_()
171 {
172     {
173         std::lock_guard lock(mutex);
174         if (status == STOPPED) {
175             return;
176         }
177         if (status == IDLE) {
178             status = STOPPED;
179             return;
180         }
181         status = STOPPING;
182     }
183     // should be STOPPING by now.
184     constexpr auto checkDuration = 10; // ms
185     std::mutex curMutex;
186     std::unique_lock lock(mutex);
187     while (status != STOPPED) {
188         cv.wait_for(lock, std::chrono::milliseconds(checkDuration));
189     }
190 }
191 
PostTask(std::function<void ()> task)192 void ARKTS_Loop_::PostTask(std::function<void()> task)
193 {
194     std::lock_guard lock(mutex);
195     if (status >= STOPPING) {
196         return;
197     }
198     callbacks.push_back(std::move(task));
199     if (status == IDLE) {
200         int tryTimes = 3;
201         while (tryTimes--) {
202             auto ret = uv_async_send(&asyncReq);
203             if (ret == 0) {
204                 status = REQUESTING;
205                 break;
206             }
207         }
208     }
209 }
210 
DrainTasks()211 void ARKTS_Loop_::DrainTasks()
212 {
213     std::vector<std::function<void ()>> pendingTasks;
214     {
215         std::lock_guard lock(mutex);
216         // drop all callbacks
217         if (status >= STOPPING) {
218             if (status == STOPPING) {
219                 status = STOPPED;
220                 cv.notify_all();
221             }
222             return;
223         }
224         // status should be REQUESTING, skipping check.
225         std::swap(callbacks, pendingTasks);
226         status = IDLE;
227     }
228     for (const auto& task : pendingTasks) {
229         task();
230     }
231 }
232 
ARKTSInner_InitLoop(ARKTS_Env env,uv_loop_t * loop)233 bool ARKTSInner_InitLoop(ARKTS_Env env, uv_loop_t* loop)
234 {
235     std::lock_guard lock(g_uvLoopMutex_);
236     if (g_uvLoops_.find(env) != g_uvLoops_.end()) {
237         return true;
238     }
239     auto arktsLoop = new ARKTS_Loop_(loop);
240     if (!arktsLoop) {
241         LOGE("new ARKTS_Loop_ failed.");
242         return false;
243     }
244     g_uvLoops_[env] = arktsLoop;
245     return true;
246 }