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 "plugins/ets/runtime/interop_js/event_loop_module.h"
17 #include "runtime/coroutines/stackful_coroutine.h"
18 #include "plugins/ets/runtime/interop_js/interop_context.h"
19 #include "plugins/ets/runtime/interop_js/intrinsics_api_impl.h"
20
21 namespace ark::ets::interop::js {
22
23 /*static*/
GetEventLoop()24 uv_loop_t *EventLoopCallbackPoster::GetEventLoop()
25 {
26 uv_loop_t *loop = nullptr;
27 #if defined(PANDA_TARGET_OHOS)
28 [[maybe_unused]] auto nstatus = napi_get_uv_event_loop(InteropCtx::Current()->GetJSEnv(), &loop);
29 ASSERT(nstatus == napi_ok);
30 #else
31 loop = uv_default_loop();
32 #endif
33 return loop;
34 }
35
EventLoopCallbackPoster()36 EventLoopCallbackPoster::EventLoopCallbackPoster()
37 {
38 [[maybe_unused]] auto *coro = EtsCoroutine::GetCurrent();
39 ASSERT(coro == coro->GetPandaVM()->GetCoroutineManager()->GetMainThread());
40 auto loop = GetEventLoop();
41 async_ = Runtime::GetCurrent()->GetInternalAllocator()->New<uv_async_t>();
42 callbackQueue_ = Runtime::GetCurrent()->GetInternalAllocator()->New<ThreadSafeCallbackQueue>();
43 [[maybe_unused]] auto uvstatus = uv_async_init(loop, async_, AsyncEventToExecuteCallbacks);
44 ASSERT(uvstatus == 0);
45 async_->data = callbackQueue_;
46 }
47
~EventLoopCallbackPoster()48 EventLoopCallbackPoster::~EventLoopCallbackPoster()
49 {
50 ASSERT(async_ != nullptr);
51 PostToEventLoop([async = this->async_]() {
52 auto deleter = [](uv_handle_t *handle) {
53 auto *poster = reinterpret_cast<ThreadSafeCallbackQueue *>(handle->data);
54 Runtime::GetCurrent()->GetInternalAllocator()->Delete(poster);
55 Runtime::GetCurrent()->GetInternalAllocator()->Delete(handle);
56 };
57 uv_close(reinterpret_cast<uv_handle_t *>(async), deleter);
58 });
59 }
60
PostImpl(WrappedCallback && callback)61 void EventLoopCallbackPoster::PostImpl(WrappedCallback &&callback)
62 {
63 ASSERT(callback != nullptr);
64 PostToEventLoop(std::move(callback));
65 }
66
PostToEventLoop(WrappedCallback && callback)67 void EventLoopCallbackPoster::PostToEventLoop(WrappedCallback &&callback)
68 {
69 ASSERT(async_ != nullptr);
70 callbackQueue_->PushCallback(std::move(callback), async_);
71 }
72
73 /*static*/
AsyncEventToExecuteCallbacks(uv_async_t * async)74 void EventLoopCallbackPoster::AsyncEventToExecuteCallbacks(uv_async_t *async)
75 {
76 auto *callbackQueue = reinterpret_cast<ThreadSafeCallbackQueue *>(async->data);
77 ASSERT(callbackQueue != nullptr);
78 callbackQueue->ExecuteAllCallbacks();
79 }
80
PushCallback(WrappedCallback && callback,uv_async_t * async)81 void EventLoopCallbackPoster::ThreadSafeCallbackQueue::PushCallback(WrappedCallback &&callback, uv_async_t *async)
82 {
83 os::memory::LockHolder lh(lock_);
84 callbackQueue_.push(std::move(callback));
85 ASSERT(async != nullptr);
86 [[maybe_unused]] auto uvstatus = uv_async_send(async);
87 ASSERT(uvstatus == 0);
88 }
89
ExecuteAllCallbacks()90 void EventLoopCallbackPoster::ThreadSafeCallbackQueue::ExecuteAllCallbacks()
91 {
92 os::memory::LockHolder lh(lock_);
93 while (!callbackQueue_.empty()) {
94 auto callback = callbackQueue_.front();
95 callback();
96 callbackQueue_.pop();
97 }
98 }
99
CreatePoster()100 PandaUniquePtr<CallbackPoster> EventLoopCallbackPosterFactoryImpl::CreatePoster()
101 {
102 auto poster = MakePandaUnique<EventLoopCallbackPoster>();
103 ASSERT(poster != nullptr);
104 return poster;
105 }
106
107 } // namespace ark::ets::interop::js
108