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}