• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 #include "native_async_work.h"
17 
18 #ifdef ENABLE_HITRACE
19 #include "hitrace/trace.h"
20 #endif
21 #ifdef ENABLE_CONTAINER_SCOPE
22 #include "core/common/container_scope.h"
23 #endif
24 
25 #include "napi/native_api.h"
26 #include "native_engine.h"
27 #include "utils/log.h"
28 
29 #ifdef ENABLE_CONTAINER_SCOPE
30 using OHOS::Ace::ContainerScope;
31 #endif
32 
NativeAsyncWork(NativeEngine * engine,NativeAsyncExecuteCallback execute,NativeAsyncCompleteCallback complete,void * data)33 NativeAsyncWork::NativeAsyncWork(NativeEngine* engine,
34                                  NativeAsyncExecuteCallback execute,
35                                  NativeAsyncCompleteCallback complete,
36                                  void* data)
37     : work_({ 0 }), engine_(engine), execute_(execute), complete_(complete), data_(data)
38 {
39     work_.data = this;
40 #ifdef ENABLE_HITRACE
41     traceId_ = std::make_unique<OHOS::HiviewDFX::HiTraceId>(OHOS::HiviewDFX::HiTrace::GetId());
42 #endif
43 #ifdef ENABLE_CONTAINER_SCOPE
44     containerScopeId_ = ContainerScope::CurrentId();
45 #endif
46 }
47 
48 NativeAsyncWork::~NativeAsyncWork() = default;
49 
Close()50 void NativeAsyncWork::Close()
51 {
52     if (uv_is_active((uv_handle_t*)&workAsyncHandler_)) {
53         uv_close((uv_handle_t*)&workAsyncHandler_, nullptr);
54     }
55 }
56 
Queue()57 bool NativeAsyncWork::Queue()
58 {
59     uv_loop_t* loop = engine_->GetUVLoop();
60     if (loop == nullptr) {
61         HILOG_ERROR("Get loop failed");
62         return false;
63     }
64 
65     int status = uv_queue_work(loop, &work_, AsyncWorkCallback, AsyncAfterWorkCallback);
66     if (status != 0) {
67         HILOG_ERROR("uv_queue_work failed");
68         return false;
69     }
70     return true;
71 }
72 
Cancel()73 bool NativeAsyncWork::Cancel()
74 {
75     int status = uv_cancel((uv_req_t*)&work_);
76     if (status != 0) {
77         HILOG_ERROR("uv_cancel failed");
78         return false;
79     }
80     return true;
81 }
82 
AsyncWorkRecvCallback(const uv_async_t * req)83 void NativeAsyncWork::AsyncWorkRecvCallback(const uv_async_t* req)
84 {
85     NativeAsyncWork* that = NativeAsyncWork::DereferenceOf(&NativeAsyncWork::workAsyncHandler_, req);
86     if (that == nullptr) {
87         return;
88     }
89 #ifdef ENABLE_CONTAINER_SCOPE
90     ContainerScope containerScope(that->containerScopeId_);
91 #endif
92     NativeAsyncWorkDataPointer res;
93     while (that->PopData(&res)) {
94         if (that->execute_ != nullptr) {
95             that->execute_(that->engine_, res.data_);
96         }
97         if (that->complete_ != nullptr) {
98             that->complete_(that->engine_, -1, res.data_);
99         }
100     }
101 }
102 
Send(void * data)103 void NativeAsyncWork::Send(void* data)
104 {
105     std::lock_guard<std::mutex> lock(workAsyncMutex_);
106     NativeAsyncWorkDataPointer dataPointer(data);
107     asyncWorkRecvData_.push(dataPointer);
108     uv_async_send(&workAsyncHandler_);
109 }
110 
PopData(NativeAsyncWorkDataPointer * data)111 bool NativeAsyncWork::PopData(NativeAsyncWorkDataPointer* data)
112 {
113     std::lock_guard<std::mutex> lock(workAsyncMutex_);
114     if (asyncWorkRecvData_.empty()) {
115         return false;
116     }
117     *data = asyncWorkRecvData_.front();
118     asyncWorkRecvData_.pop();
119     return true;
120 }
121 
Init()122 bool NativeAsyncWork::Init()
123 {
124     uv_loop_t* loop = engine_->GetUVLoop();
125     if (loop == nullptr) {
126         HILOG_ERROR("Get loop failed");
127         return false;
128     }
129     uv_async_init(loop, &workAsyncHandler_, reinterpret_cast<uv_async_cb>(AsyncWorkRecvCallback));
130     return true;
131 }
132 
AsyncWorkCallback(uv_work_t * req)133 void NativeAsyncWork::AsyncWorkCallback(uv_work_t* req)
134 {
135     if (req == nullptr) {
136         HILOG_ERROR("req is nullptr");
137         return;
138     }
139 
140     auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
141 
142 #ifdef ENABLE_CONTAINER_SCOPE
143     ContainerScope containerScope(that->containerScopeId_);
144 #endif
145 #ifdef ENABLE_HITRACE
146     if (that->traceId_ && that->traceId_->IsValid()) {
147         OHOS::HiviewDFX::HiTrace::SetId(*(that->traceId_.get()));
148         that->execute_(that->engine_, that->data_);
149         OHOS::HiviewDFX::HiTrace::ClearId();
150         return;
151     }
152 #endif
153     that->execute_(that->engine_, that->data_);
154 }
155 
AsyncAfterWorkCallback(uv_work_t * req,int status)156 void NativeAsyncWork::AsyncAfterWorkCallback(uv_work_t* req, int status)
157 {
158     if (req == nullptr) {
159         HILOG_ERROR("req is nullptr");
160         return;
161     }
162 
163     auto that = reinterpret_cast<NativeAsyncWork*>(req->data);
164 
165     NativeScopeManager* scopeManager = that->engine_->GetScopeManager();
166     if (scopeManager == nullptr) {
167         HILOG_ERROR("Get scope manager failed");
168         return;
169     }
170 
171     NativeScope* scope = scopeManager->Open();
172     if (scope == nullptr) {
173         HILOG_ERROR("Open scope failed");
174         return;
175     }
176 
177     napi_status nstatus = napi_generic_failure;
178 
179     switch (status) {
180         case 0:
181             nstatus = napi_ok;
182             break;
183         case (int)UV_EINVAL:
184             nstatus = napi_invalid_arg;
185             break;
186         case (int)UV_ECANCELED:
187             nstatus = napi_cancelled;
188             break;
189         default:
190             nstatus = napi_generic_failure;
191     }
192 #ifdef ENABLE_CONTAINER_SCOPE
193     ContainerScope containerScope(that->containerScopeId_);
194 #endif
195 #ifdef ENABLE_HITRACE
196     if (that->traceId_ && that->traceId_->IsValid()) {
197         OHOS::HiviewDFX::HiTrace::SetId(*(that->traceId_.get()));
198         that->complete_(that->engine_, nstatus, that->data_);
199         OHOS::HiviewDFX::HiTrace::ClearId();
200         scopeManager->Close(scope);
201         return;
202     }
203 #endif
204     that->complete_(that->engine_, nstatus, that->data_);
205     scopeManager->Close(scope);
206 }
207