133eb0b6dSopenharmony_ci/* 233eb0b6dSopenharmony_ci * Copyright (c) 2021 Huawei Device Co., Ltd. 333eb0b6dSopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 433eb0b6dSopenharmony_ci * you may not use this file except in compliance with the License. 533eb0b6dSopenharmony_ci * You may obtain a copy of the License at 633eb0b6dSopenharmony_ci * 733eb0b6dSopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 833eb0b6dSopenharmony_ci * 933eb0b6dSopenharmony_ci * Unless required by applicable law or agreed to in writing, software 1033eb0b6dSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 1133eb0b6dSopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1233eb0b6dSopenharmony_ci * See the License for the specific language governing permissions and 1333eb0b6dSopenharmony_ci * limitations under the License. 1433eb0b6dSopenharmony_ci */ 1533eb0b6dSopenharmony_ci 1633eb0b6dSopenharmony_ci#include <cinttypes> 1733eb0b6dSopenharmony_ci 1833eb0b6dSopenharmony_ci#include "native_safe_async_work.h" 1933eb0b6dSopenharmony_ci 2033eb0b6dSopenharmony_ci#include "ecmascript/napi/include/jsnapi.h" 2133eb0b6dSopenharmony_ci#include "napi/native_api.h" 2233eb0b6dSopenharmony_ci#include "native_api_internal.h" 2333eb0b6dSopenharmony_ci#include "native_async_work.h" 2433eb0b6dSopenharmony_ci#include "native_engine.h" 2533eb0b6dSopenharmony_ci#include "native_value.h" 2633eb0b6dSopenharmony_ci#include "securec.h" 2733eb0b6dSopenharmony_ci#include "utils/log.h" 2833eb0b6dSopenharmony_ci 2933eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 3033eb0b6dSopenharmony_ci#include "core/common/container_scope.h" 3133eb0b6dSopenharmony_ci#endif 3233eb0b6dSopenharmony_ci 3333eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 3433eb0b6dSopenharmony_ciusing OHOS::Ace::ContainerScope; 3533eb0b6dSopenharmony_ci#endif 3633eb0b6dSopenharmony_ci 3733eb0b6dSopenharmony_ci#if defined(ENABLE_EVENT_HANDLER) 3833eb0b6dSopenharmony_ci#include "event_handler.h" 3933eb0b6dSopenharmony_ciusing namespace OHOS::AppExecFwk; 4033eb0b6dSopenharmony_ci#endif 4133eb0b6dSopenharmony_ci 4233eb0b6dSopenharmony_ci// static methods start 4333eb0b6dSopenharmony_civoid NativeSafeAsyncWork::AsyncCallback(uv_async_t* asyncHandler) 4433eb0b6dSopenharmony_ci{ 4533eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::AsyncCallback called"); 4633eb0b6dSopenharmony_ci NativeSafeAsyncWork* that = NativeAsyncWork::DereferenceOf(&NativeSafeAsyncWork::asyncHandler_, asyncHandler); 4733eb0b6dSopenharmony_ci if (that == nullptr) { 4833eb0b6dSopenharmony_ci HILOG_ERROR("NativeSafeAsyncWork:: DereferenceOf failed!"); 4933eb0b6dSopenharmony_ci return; 5033eb0b6dSopenharmony_ci } 5133eb0b6dSopenharmony_ci that->ProcessAsyncHandle(); 5233eb0b6dSopenharmony_ci} 5333eb0b6dSopenharmony_ci 5433eb0b6dSopenharmony_civoid NativeSafeAsyncWork::CallJs(NativeEngine* engine, napi_value js_call_func, void* context, void* data) 5533eb0b6dSopenharmony_ci{ 5633eb0b6dSopenharmony_ci if (engine == nullptr || js_call_func == nullptr) { 5733eb0b6dSopenharmony_ci HILOG_ERROR("CallJs failed. engine or js_call_func is nullptr!"); 5833eb0b6dSopenharmony_ci return; 5933eb0b6dSopenharmony_ci } 6033eb0b6dSopenharmony_ci napi_value value = nullptr; 6133eb0b6dSopenharmony_ci napi_get_undefined(reinterpret_cast<napi_env>(engine), &value); 6233eb0b6dSopenharmony_ci if (value == nullptr) { 6333eb0b6dSopenharmony_ci HILOG_ERROR("CreateUndefined failed"); 6433eb0b6dSopenharmony_ci return; 6533eb0b6dSopenharmony_ci } 6633eb0b6dSopenharmony_ci 6733eb0b6dSopenharmony_ci auto resultValue = engine->CallFunction(value, js_call_func, nullptr, 0); 6833eb0b6dSopenharmony_ci if (resultValue == nullptr) { 6933eb0b6dSopenharmony_ci HILOG_ERROR("CallFunction failed"); 7033eb0b6dSopenharmony_ci } 7133eb0b6dSopenharmony_ci} 7233eb0b6dSopenharmony_ci 7333eb0b6dSopenharmony_ciNativeSafeAsyncWork::NativeSafeAsyncWork(NativeEngine* engine, 7433eb0b6dSopenharmony_ci napi_value func, 7533eb0b6dSopenharmony_ci napi_value asyncResource, 7633eb0b6dSopenharmony_ci napi_value asyncResourceName, 7733eb0b6dSopenharmony_ci size_t maxQueueSize, 7833eb0b6dSopenharmony_ci size_t threadCount, 7933eb0b6dSopenharmony_ci void* finalizeData, 8033eb0b6dSopenharmony_ci NativeFinalize finalizeCallback, 8133eb0b6dSopenharmony_ci void* context, 8233eb0b6dSopenharmony_ci NativeThreadSafeFunctionCallJs callJsCallback) 8333eb0b6dSopenharmony_ci :engine_(engine), engineId_(engine->GetId()), maxQueueSize_(maxQueueSize), 8433eb0b6dSopenharmony_ci threadCount_(threadCount), finalizeData_(finalizeData), finalizeCallback_(finalizeCallback), 8533eb0b6dSopenharmony_ci context_(context), callJsCallback_(callJsCallback) 8633eb0b6dSopenharmony_ci{ 8733eb0b6dSopenharmony_ci asyncContext_.napiAsyncResource = asyncResource; 8833eb0b6dSopenharmony_ci asyncContext_.napiAsyncResourceName = asyncResourceName; 8933eb0b6dSopenharmony_ci 9033eb0b6dSopenharmony_ci errno_t err = EOK; 9133eb0b6dSopenharmony_ci err = memset_s(&asyncHandler_, sizeof(asyncHandler_), 0, sizeof(asyncHandler_)); 9233eb0b6dSopenharmony_ci if (err != EOK) { 9333eb0b6dSopenharmony_ci HILOG_ERROR("faild to init asyncHandler_"); 9433eb0b6dSopenharmony_ci return; 9533eb0b6dSopenharmony_ci } 9633eb0b6dSopenharmony_ci 9733eb0b6dSopenharmony_ci if (func != nullptr) { 9833eb0b6dSopenharmony_ci uint32_t initialRefcount = 1; 9933eb0b6dSopenharmony_ci ref_ = engine->CreateReference(func, initialRefcount); 10033eb0b6dSopenharmony_ci } 10133eb0b6dSopenharmony_ci 10233eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 10333eb0b6dSopenharmony_ci containerScopeId_ = ContainerScope::CurrentId(); 10433eb0b6dSopenharmony_ci#endif 10533eb0b6dSopenharmony_ci 10633eb0b6dSopenharmony_ci#if defined(ENABLE_EVENT_HANDLER) 10733eb0b6dSopenharmony_ci std::shared_ptr<EventRunner> runner = EventRunner::Current(); 10833eb0b6dSopenharmony_ci if (runner != nullptr) { 10933eb0b6dSopenharmony_ci eventHandler_ = std::make_shared<EventHandler>(runner); 11033eb0b6dSopenharmony_ci } 11133eb0b6dSopenharmony_ci#endif 11233eb0b6dSopenharmony_ci} 11333eb0b6dSopenharmony_ci 11433eb0b6dSopenharmony_ciNativeSafeAsyncWork::~NativeSafeAsyncWork() 11533eb0b6dSopenharmony_ci{ 11633eb0b6dSopenharmony_ci if (ref_ != nullptr) { 11733eb0b6dSopenharmony_ci delete ref_; 11833eb0b6dSopenharmony_ci ref_ = nullptr; 11933eb0b6dSopenharmony_ci } 12033eb0b6dSopenharmony_ci} 12133eb0b6dSopenharmony_ci 12233eb0b6dSopenharmony_cibool NativeSafeAsyncWork::Init() 12333eb0b6dSopenharmony_ci{ 12433eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::Init called"); 12533eb0b6dSopenharmony_ci 12633eb0b6dSopenharmony_ci uv_loop_t* loop = engine_->GetUVLoop(); 12733eb0b6dSopenharmony_ci if (loop == nullptr) { 12833eb0b6dSopenharmony_ci HILOG_ERROR("Get loop failed"); 12933eb0b6dSopenharmony_ci return false; 13033eb0b6dSopenharmony_ci } 13133eb0b6dSopenharmony_ci 13233eb0b6dSopenharmony_ci int ret = uv_async_init(loop, &asyncHandler_, AsyncCallback); 13333eb0b6dSopenharmony_ci if (ret != 0) { 13433eb0b6dSopenharmony_ci HILOG_ERROR("uv async init failed %d", ret); 13533eb0b6dSopenharmony_ci return false; 13633eb0b6dSopenharmony_ci } 13733eb0b6dSopenharmony_ci 13833eb0b6dSopenharmony_ci status_ = SafeAsyncStatus::SAFE_ASYNC_STATUS_INTE; 13933eb0b6dSopenharmony_ci return true; 14033eb0b6dSopenharmony_ci} 14133eb0b6dSopenharmony_ci 14233eb0b6dSopenharmony_cibool NativeSafeAsyncWork::IsMaxQueueSize() 14333eb0b6dSopenharmony_ci{ 14433eb0b6dSopenharmony_ci return (queue_.size() > maxQueueSize_ && 14533eb0b6dSopenharmony_ci maxQueueSize_ > 0 && 14633eb0b6dSopenharmony_ci status_ != SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING && 14733eb0b6dSopenharmony_ci status_ != SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED); 14833eb0b6dSopenharmony_ci} 14933eb0b6dSopenharmony_ci 15033eb0b6dSopenharmony_ciSafeAsyncCode NativeSafeAsyncWork::ValidEngineCheck() 15133eb0b6dSopenharmony_ci{ 15233eb0b6dSopenharmony_ci if (!NativeEngine::IsAlive(engine_)) { 15333eb0b6dSopenharmony_ci HILOG_ERROR("napi_env has been destoryed"); 15433eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_FAILED; 15533eb0b6dSopenharmony_ci } else if (engineId_ != engine_->GetId()) { 15633eb0b6dSopenharmony_ci LOG_IF_SPECIAL(UNLIKELY(engine_->IsCrossThreadCheckEnabled()), 15733eb0b6dSopenharmony_ci "current tsfn was created by dead env, " 15833eb0b6dSopenharmony_ci "owner id: %{public}" PRIu64 ", current id: %{public}" PRIu64, 15933eb0b6dSopenharmony_ci engineId_, engine_->GetId()); 16033eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_CLOSED; 16133eb0b6dSopenharmony_ci } 16233eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_OK; 16333eb0b6dSopenharmony_ci} 16433eb0b6dSopenharmony_ci 16533eb0b6dSopenharmony_ciSafeAsyncCode NativeSafeAsyncWork::Send(void* data, NativeThreadSafeFunctionCallMode mode) 16633eb0b6dSopenharmony_ci{ 16733eb0b6dSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 16833eb0b6dSopenharmony_ci if (IsMaxQueueSize()) { 16933eb0b6dSopenharmony_ci HILOG_INFO("queue size bigger than max queue size"); 17033eb0b6dSopenharmony_ci if (mode == NATIVE_TSFUNC_BLOCKING) { 17133eb0b6dSopenharmony_ci while (IsMaxQueueSize()) { 17233eb0b6dSopenharmony_ci condition_.wait(lock); 17333eb0b6dSopenharmony_ci } 17433eb0b6dSopenharmony_ci } else { 17533eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_QUEUE_FULL; 17633eb0b6dSopenharmony_ci } 17733eb0b6dSopenharmony_ci } 17833eb0b6dSopenharmony_ci 17933eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED || 18033eb0b6dSopenharmony_ci status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING) { 18133eb0b6dSopenharmony_ci if (threadCount_ == 0) { 18233eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_INVALID_ARGS; 18333eb0b6dSopenharmony_ci } else { 18433eb0b6dSopenharmony_ci threadCount_--; 18533eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_CLOSED; 18633eb0b6dSopenharmony_ci } 18733eb0b6dSopenharmony_ci } else { 18833eb0b6dSopenharmony_ci SafeAsyncCode checkRet = ValidEngineCheck(); 18933eb0b6dSopenharmony_ci if (checkRet != SafeAsyncCode::SAFE_ASYNC_OK) { 19033eb0b6dSopenharmony_ci return checkRet; 19133eb0b6dSopenharmony_ci } 19233eb0b6dSopenharmony_ci queue_.emplace(data); 19333eb0b6dSopenharmony_ci auto ret = uv_async_send(&asyncHandler_); 19433eb0b6dSopenharmony_ci if (ret != 0) { 19533eb0b6dSopenharmony_ci HILOG_ERROR("uv async send failed %d", ret); 19633eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_FAILED; 19733eb0b6dSopenharmony_ci } 19833eb0b6dSopenharmony_ci } 19933eb0b6dSopenharmony_ci 20033eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_OK; 20133eb0b6dSopenharmony_ci} 20233eb0b6dSopenharmony_ci 20333eb0b6dSopenharmony_ciSafeAsyncCode NativeSafeAsyncWork::Acquire() 20433eb0b6dSopenharmony_ci{ 20533eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::Acquire called"); 20633eb0b6dSopenharmony_ci 20733eb0b6dSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 20833eb0b6dSopenharmony_ci 20933eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED || 21033eb0b6dSopenharmony_ci status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING) { 21133eb0b6dSopenharmony_ci HILOG_WARN("Do not acquire, thread is closed!"); 21233eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_CLOSED; 21333eb0b6dSopenharmony_ci } 21433eb0b6dSopenharmony_ci 21533eb0b6dSopenharmony_ci // increase thread count 21633eb0b6dSopenharmony_ci threadCount_++; 21733eb0b6dSopenharmony_ci 21833eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_OK; 21933eb0b6dSopenharmony_ci} 22033eb0b6dSopenharmony_ci 22133eb0b6dSopenharmony_ciSafeAsyncCode NativeSafeAsyncWork::Release(NativeThreadSafeFunctionReleaseMode mode) 22233eb0b6dSopenharmony_ci{ 22333eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::Release called"); 22433eb0b6dSopenharmony_ci 22533eb0b6dSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 22633eb0b6dSopenharmony_ci 22733eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED || 22833eb0b6dSopenharmony_ci status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING) { 22933eb0b6dSopenharmony_ci HILOG_WARN("Do not release, thread is closed!"); 23033eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_CLOSED; 23133eb0b6dSopenharmony_ci } 23233eb0b6dSopenharmony_ci 23333eb0b6dSopenharmony_ci if (threadCount_ == 0) { 23433eb0b6dSopenharmony_ci HILOG_ERROR("Do not release, thread count is zero."); 23533eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_INVALID_ARGS; 23633eb0b6dSopenharmony_ci } 23733eb0b6dSopenharmony_ci 23833eb0b6dSopenharmony_ci // decrease thread count 23933eb0b6dSopenharmony_ci threadCount_--; 24033eb0b6dSopenharmony_ci 24133eb0b6dSopenharmony_ci if (mode == NativeThreadSafeFunctionReleaseMode::NATIVE_TSFUNC_ABORT) { 24233eb0b6dSopenharmony_ci status_ = SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING; 24333eb0b6dSopenharmony_ci if (maxQueueSize_ > 0) { 24433eb0b6dSopenharmony_ci condition_.notify_one(); 24533eb0b6dSopenharmony_ci } 24633eb0b6dSopenharmony_ci } 24733eb0b6dSopenharmony_ci 24833eb0b6dSopenharmony_ci if (threadCount_ == 0 || 24933eb0b6dSopenharmony_ci mode == NativeThreadSafeFunctionReleaseMode::NATIVE_TSFUNC_ABORT) { 25033eb0b6dSopenharmony_ci SafeAsyncCode checkRet = ValidEngineCheck(); 25133eb0b6dSopenharmony_ci if (checkRet != SafeAsyncCode::SAFE_ASYNC_OK) { 25233eb0b6dSopenharmony_ci return checkRet; 25333eb0b6dSopenharmony_ci } 25433eb0b6dSopenharmony_ci // trigger async handle 25533eb0b6dSopenharmony_ci auto ret = uv_async_send(&asyncHandler_); 25633eb0b6dSopenharmony_ci if (ret != 0) { 25733eb0b6dSopenharmony_ci HILOG_ERROR("uv async send failed %d", ret); 25833eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_FAILED; 25933eb0b6dSopenharmony_ci } 26033eb0b6dSopenharmony_ci } 26133eb0b6dSopenharmony_ci 26233eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_OK; 26333eb0b6dSopenharmony_ci} 26433eb0b6dSopenharmony_ci 26533eb0b6dSopenharmony_cibool NativeSafeAsyncWork::Ref() 26633eb0b6dSopenharmony_ci{ 26733eb0b6dSopenharmony_ci if (!IsSameTid()) { 26833eb0b6dSopenharmony_ci HILOG_ERROR("tid not same"); 26933eb0b6dSopenharmony_ci return false; 27033eb0b6dSopenharmony_ci } 27133eb0b6dSopenharmony_ci 27233eb0b6dSopenharmony_ci uv_ref(reinterpret_cast<uv_handle_t*>(&asyncHandler_)); 27333eb0b6dSopenharmony_ci 27433eb0b6dSopenharmony_ci return true; 27533eb0b6dSopenharmony_ci} 27633eb0b6dSopenharmony_ci 27733eb0b6dSopenharmony_cibool NativeSafeAsyncWork::Unref() 27833eb0b6dSopenharmony_ci{ 27933eb0b6dSopenharmony_ci if (!IsSameTid()) { 28033eb0b6dSopenharmony_ci HILOG_ERROR("tid not same"); 28133eb0b6dSopenharmony_ci return false; 28233eb0b6dSopenharmony_ci } 28333eb0b6dSopenharmony_ci 28433eb0b6dSopenharmony_ci uv_unref(reinterpret_cast<uv_handle_t*>(&asyncHandler_)); 28533eb0b6dSopenharmony_ci 28633eb0b6dSopenharmony_ci return true; 28733eb0b6dSopenharmony_ci} 28833eb0b6dSopenharmony_ci 28933eb0b6dSopenharmony_civoid* NativeSafeAsyncWork::GetContext() 29033eb0b6dSopenharmony_ci{ 29133eb0b6dSopenharmony_ci return context_; 29233eb0b6dSopenharmony_ci} 29333eb0b6dSopenharmony_ci 29433eb0b6dSopenharmony_civoid NativeSafeAsyncWork::ProcessAsyncHandle() 29533eb0b6dSopenharmony_ci{ 29633eb0b6dSopenharmony_ci std::unique_lock<std::mutex> lock(mutex_); 29733eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED) { 29833eb0b6dSopenharmony_ci HILOG_ERROR("Process failed, thread is closed!"); 29933eb0b6dSopenharmony_ci return; 30033eb0b6dSopenharmony_ci } 30133eb0b6dSopenharmony_ci 30233eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSING) { 30333eb0b6dSopenharmony_ci HILOG_ERROR("thread is closing!"); 30433eb0b6dSopenharmony_ci CloseHandles(); 30533eb0b6dSopenharmony_ci return; 30633eb0b6dSopenharmony_ci } 30733eb0b6dSopenharmony_ci 30833eb0b6dSopenharmony_ci size_t size = queue_.size(); 30933eb0b6dSopenharmony_ci void* data = nullptr; 31033eb0b6dSopenharmony_ci 31133eb0b6dSopenharmony_ci auto vm = engine_->GetEcmaVm(); 31233eb0b6dSopenharmony_ci panda::LocalScope scope(vm); 31333eb0b6dSopenharmony_ci#ifdef ENABLE_CONTAINER_SCOPE 31433eb0b6dSopenharmony_ci ContainerScope containerScope(containerScopeId_); 31533eb0b6dSopenharmony_ci#endif 31633eb0b6dSopenharmony_ci TryCatch tryCatch(reinterpret_cast<napi_env>(engine_)); 31733eb0b6dSopenharmony_ci while (size > 0) { 31833eb0b6dSopenharmony_ci data = queue_.front(); 31933eb0b6dSopenharmony_ci 32033eb0b6dSopenharmony_ci // when queue is full, notify send. 32133eb0b6dSopenharmony_ci if (size == maxQueueSize_ && maxQueueSize_ > 0) { 32233eb0b6dSopenharmony_ci condition_.notify_one(); 32333eb0b6dSopenharmony_ci } 32433eb0b6dSopenharmony_ci 32533eb0b6dSopenharmony_ci napi_value func_ = (ref_ == nullptr) ? nullptr : ref_->Get(engine_); 32633eb0b6dSopenharmony_ci lock.unlock(); 32733eb0b6dSopenharmony_ci if (callJsCallback_ != nullptr) { 32833eb0b6dSopenharmony_ci callJsCallback_(engine_, func_, context_, data); 32933eb0b6dSopenharmony_ci } else { 33033eb0b6dSopenharmony_ci CallJs(engine_, func_, context_, data); 33133eb0b6dSopenharmony_ci } 33233eb0b6dSopenharmony_ci lock.lock(); 33333eb0b6dSopenharmony_ci 33433eb0b6dSopenharmony_ci if (tryCatch.HasCaught()) { 33533eb0b6dSopenharmony_ci engine_->HandleUncaughtException(); 33633eb0b6dSopenharmony_ci } 33733eb0b6dSopenharmony_ci queue_.pop(); 33833eb0b6dSopenharmony_ci size--; 33933eb0b6dSopenharmony_ci } 34033eb0b6dSopenharmony_ci 34133eb0b6dSopenharmony_ci if (size == 0 && threadCount_ == 0) { 34233eb0b6dSopenharmony_ci CloseHandles(); 34333eb0b6dSopenharmony_ci } 34433eb0b6dSopenharmony_ci} 34533eb0b6dSopenharmony_ci 34633eb0b6dSopenharmony_ciSafeAsyncCode NativeSafeAsyncWork::CloseHandles() 34733eb0b6dSopenharmony_ci{ 34833eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::CloseHandles called"); 34933eb0b6dSopenharmony_ci 35033eb0b6dSopenharmony_ci if (status_ == SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED) { 35133eb0b6dSopenharmony_ci HILOG_INFO("Close failed, thread is closed!"); 35233eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_CLOSED; 35333eb0b6dSopenharmony_ci } 35433eb0b6dSopenharmony_ci 35533eb0b6dSopenharmony_ci status_ = SafeAsyncStatus::SAFE_ASYNC_STATUS_CLOSED; 35633eb0b6dSopenharmony_ci 35733eb0b6dSopenharmony_ci // close async handler 35833eb0b6dSopenharmony_ci uv_close(reinterpret_cast<uv_handle_t*>(&asyncHandler_), [](uv_handle_t* handle) { 35933eb0b6dSopenharmony_ci NativeSafeAsyncWork* that = NativeAsyncWork::DereferenceOf(&NativeSafeAsyncWork::asyncHandler_, 36033eb0b6dSopenharmony_ci reinterpret_cast<uv_async_t*>(handle)); 36133eb0b6dSopenharmony_ci that->CleanUp(); 36233eb0b6dSopenharmony_ci }); 36333eb0b6dSopenharmony_ci 36433eb0b6dSopenharmony_ci return SafeAsyncCode::SAFE_ASYNC_OK; 36533eb0b6dSopenharmony_ci} 36633eb0b6dSopenharmony_ci 36733eb0b6dSopenharmony_civoid NativeSafeAsyncWork::CleanUp() 36833eb0b6dSopenharmony_ci{ 36933eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::CleanUp called"); 37033eb0b6dSopenharmony_ci 37133eb0b6dSopenharmony_ci if (finalizeCallback_ != nullptr) { 37233eb0b6dSopenharmony_ci finalizeCallback_(engine_, finalizeData_, context_); 37333eb0b6dSopenharmony_ci } 37433eb0b6dSopenharmony_ci 37533eb0b6dSopenharmony_ci // clean data 37633eb0b6dSopenharmony_ci while (!queue_.empty()) { 37733eb0b6dSopenharmony_ci if (callJsCallback_ != nullptr) { 37833eb0b6dSopenharmony_ci callJsCallback_(nullptr, nullptr, context_, queue_.front()); 37933eb0b6dSopenharmony_ci } else { 38033eb0b6dSopenharmony_ci CallJs(nullptr, nullptr, context_, queue_.front()); 38133eb0b6dSopenharmony_ci } 38233eb0b6dSopenharmony_ci queue_.pop(); 38333eb0b6dSopenharmony_ci } 38433eb0b6dSopenharmony_ci delete this; 38533eb0b6dSopenharmony_ci} 38633eb0b6dSopenharmony_ci 38733eb0b6dSopenharmony_cibool NativeSafeAsyncWork::IsSameTid() 38833eb0b6dSopenharmony_ci{ 38933eb0b6dSopenharmony_ci auto tid = pthread_self(); 39033eb0b6dSopenharmony_ci return (tid == engine_->GetTid()) ? true : false; 39133eb0b6dSopenharmony_ci} 39233eb0b6dSopenharmony_ci 39333eb0b6dSopenharmony_cinapi_status NativeSafeAsyncWork::PostTask(void *data, int32_t priority, bool isTail) 39433eb0b6dSopenharmony_ci{ 39533eb0b6dSopenharmony_ci#if defined(ENABLE_EVENT_HANDLER) 39633eb0b6dSopenharmony_ci HILOG_DEBUG("NativeSafeAsyncWork::PostTask called"); 39733eb0b6dSopenharmony_ci std::unique_lock<std::mutex> lock(eventHandlerMutex_); 39833eb0b6dSopenharmony_ci if (engine_ == nullptr || eventHandler_ == nullptr) { 39933eb0b6dSopenharmony_ci HILOG_ERROR("post task failed due to nullptr engine or eventHandler"); 40033eb0b6dSopenharmony_ci return napi_status::napi_generic_failure; 40133eb0b6dSopenharmony_ci } 40233eb0b6dSopenharmony_ci // the task will be execute at main thread or worker thread 40333eb0b6dSopenharmony_ci auto task = [this, data]() { 40433eb0b6dSopenharmony_ci HILOG_DEBUG("The task is executing in main thread or worker thread"); 40533eb0b6dSopenharmony_ci napi_value func_ = (this->ref_ == nullptr) ? nullptr : this->ref_->Get(engine_); 40633eb0b6dSopenharmony_ci if (this->callJsCallback_ != nullptr) { 40733eb0b6dSopenharmony_ci this->callJsCallback_(engine_, func_, context_, data); 40833eb0b6dSopenharmony_ci } else { 40933eb0b6dSopenharmony_ci CallJs(engine_, func_, context_, data); 41033eb0b6dSopenharmony_ci } 41133eb0b6dSopenharmony_ci }; 41233eb0b6dSopenharmony_ci 41333eb0b6dSopenharmony_ci bool res = false; 41433eb0b6dSopenharmony_ci if (isTail) { 41533eb0b6dSopenharmony_ci HILOG_DEBUG("The task is posted from tail"); 41633eb0b6dSopenharmony_ci res = eventHandler_->PostTask(task, static_cast<EventQueue::Priority>(priority)); 41733eb0b6dSopenharmony_ci } else { 41833eb0b6dSopenharmony_ci HILOG_DEBUG("The task is posted from head"); 41933eb0b6dSopenharmony_ci res = eventHandler_->PostTaskAtFront(task, std::string(), static_cast<EventQueue::Priority>(priority)); 42033eb0b6dSopenharmony_ci } 42133eb0b6dSopenharmony_ci 42233eb0b6dSopenharmony_ci return res ? napi_status::napi_ok : napi_status::napi_generic_failure; 42333eb0b6dSopenharmony_ci#else 42433eb0b6dSopenharmony_ci HILOG_WARN("EventHandler feature is not supported"); 42533eb0b6dSopenharmony_ci return napi_status::napi_generic_failure; 42633eb0b6dSopenharmony_ci#endif 42733eb0b6dSopenharmony_ci} 42833eb0b6dSopenharmony_ci 42933eb0b6dSopenharmony_cinapi_status NativeSafeAsyncWork::SendEvent(const std::function<void()> &cb, napi_event_priority priority) 43033eb0b6dSopenharmony_ci{ 43133eb0b6dSopenharmony_ci#ifdef ENABLE_EVENT_HANDLER 43233eb0b6dSopenharmony_ci if (eventHandler_) { 43333eb0b6dSopenharmony_ci auto task = [eng = engine_, cb]() { 43433eb0b6dSopenharmony_ci auto vm = eng->GetEcmaVm(); 43533eb0b6dSopenharmony_ci panda::LocalScope scope(vm); 43633eb0b6dSopenharmony_ci cb(); 43733eb0b6dSopenharmony_ci }; 43833eb0b6dSopenharmony_ci if (eventHandler_->PostTask(task, static_cast<EventQueue::Priority>(priority))) 43933eb0b6dSopenharmony_ci return napi_status::napi_ok; 44033eb0b6dSopenharmony_ci else 44133eb0b6dSopenharmony_ci return napi_status::napi_generic_failure; 44233eb0b6dSopenharmony_ci } 44333eb0b6dSopenharmony_ci#endif 44433eb0b6dSopenharmony_ci CallbackWrapper *cbw = new (std::nothrow) CallbackWrapper(); 44533eb0b6dSopenharmony_ci if (!cbw) { 44633eb0b6dSopenharmony_ci HILOG_ERROR("malloc failed!"); 44733eb0b6dSopenharmony_ci return napi_status::napi_generic_failure; 44833eb0b6dSopenharmony_ci } 44933eb0b6dSopenharmony_ci cbw->cb = cb; 45033eb0b6dSopenharmony_ci auto code = Send(reinterpret_cast<void *>(cbw), NATIVE_TSFUNC_NONBLOCKING); 45133eb0b6dSopenharmony_ci 45233eb0b6dSopenharmony_ci napi_status status = napi_status::napi_ok; 45333eb0b6dSopenharmony_ci switch (code) { 45433eb0b6dSopenharmony_ci case SafeAsyncCode::SAFE_ASYNC_OK: 45533eb0b6dSopenharmony_ci status = napi_status::napi_ok; 45633eb0b6dSopenharmony_ci break; 45733eb0b6dSopenharmony_ci case SafeAsyncCode::SAFE_ASYNC_QUEUE_FULL: 45833eb0b6dSopenharmony_ci status = napi_status::napi_queue_full; 45933eb0b6dSopenharmony_ci break; 46033eb0b6dSopenharmony_ci case SafeAsyncCode::SAFE_ASYNC_INVALID_ARGS: 46133eb0b6dSopenharmony_ci status = napi_status::napi_invalid_arg; 46233eb0b6dSopenharmony_ci break; 46333eb0b6dSopenharmony_ci case SafeAsyncCode::SAFE_ASYNC_CLOSED: 46433eb0b6dSopenharmony_ci status = napi_status::napi_closing; 46533eb0b6dSopenharmony_ci break; 46633eb0b6dSopenharmony_ci case SafeAsyncCode::SAFE_ASYNC_FAILED: 46733eb0b6dSopenharmony_ci status = napi_status::napi_generic_failure; 46833eb0b6dSopenharmony_ci break; 46933eb0b6dSopenharmony_ci default: 47033eb0b6dSopenharmony_ci HILOG_FATAL("this branch is unreachable, code is %{public}d", code); 47133eb0b6dSopenharmony_ci status = napi_status::napi_generic_failure; 47233eb0b6dSopenharmony_ci break; 47333eb0b6dSopenharmony_ci } 47433eb0b6dSopenharmony_ci if (status != napi_status::napi_ok) { 47533eb0b6dSopenharmony_ci HILOG_ERROR("send event failed(%{public}d)", status); 47633eb0b6dSopenharmony_ci delete cbw; 47733eb0b6dSopenharmony_ci cbw = nullptr; 47833eb0b6dSopenharmony_ci } 47933eb0b6dSopenharmony_ci return status; 48033eb0b6dSopenharmony_ci}