1 /*
2 * Copyright (c) 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 "datashare_uv_queue.h"
17 #include <thread>
18 #include "datashare_log.h"
19
20 namespace OHOS {
21 namespace DataShare {
22 constexpr int WAIT_TIME = 3;
23 constexpr int SLEEP_TIME = 1;
24 constexpr int TRY_TIMES = 2000;
DataShareUvQueue(napi_env env)25 DataShareUvQueue::DataShareUvQueue(napi_env env)
26 : env_(env)
27 {
28 napi_get_uv_event_loop(env, &loop_);
29 }
30
LambdaForWork(uv_work_t * work,int uvstatus)31 void DataShareUvQueue::LambdaForWork(uv_work_t *work, int uvstatus)
32 {
33 if (work == nullptr || work->data == nullptr) {
34 LOG_ERROR("invalid work or work->data.");
35 return;
36 }
37 auto *entry = static_cast<UvEntry*>(work->data);
38 {
39 std::unique_lock<std::mutex> lock(entry->mutex);
40 if (entry->func) {
41 entry->func();
42 }
43 entry->done = true;
44 if (!entry->purge) {
45 entry->condition.notify_all();
46 return;
47 }
48 }
49 DataShareUvQueue::Purge(work);
50 }
51
SyncCall(NapiVoidFunc func,NapiBoolFunc retFunc)52 void DataShareUvQueue::SyncCall(NapiVoidFunc func, NapiBoolFunc retFunc)
53 {
54 uv_work_t* work = new (std::nothrow) uv_work_t;
55 if (work == nullptr) {
56 LOG_ERROR("invalid work.");
57 return;
58 }
59 work->data = new UvEntry {env_, std::move(func), false, false, {}, {}, std::move(retFunc)};
60 if (work->data == nullptr) {
61 delete work;
62 LOG_ERROR("invalid uvEntry.");
63 return;
64 }
65
66 bool noNeedPurge = false;
67 auto *uvEntry = static_cast<UvEntry*>(work->data);
68 {
69 std::unique_lock<std::mutex> lock(uvEntry->mutex);
70 auto status = uv_queue_work(
71 loop_, work, [](uv_work_t *work) {}, LambdaForWork);
72 if (status != napi_ok) {
73 LOG_ERROR("queue work failed");
74 DataShareUvQueue::Purge(work);
75 return;
76 }
77 if (uvEntry->condition.wait_for(lock, std::chrono::seconds(WAIT_TIME), [uvEntry] { return uvEntry->done; })) {
78 LOG_INFO("function ended successfully");
79 }
80 if (!uvEntry->done && !uv_cancel((uv_req_t*)&work)) {
81 LOG_ERROR("uv_cancel failed.");
82 uvEntry->purge = true;
83 noNeedPurge = true;
84 }
85 }
86
87 CheckFuncAndExec(uvEntry->retFunc);
88 if (!noNeedPurge) {
89 DataShareUvQueue::Purge(work);
90 }
91 }
92
Purge(uv_work_t * work)93 void DataShareUvQueue::Purge(uv_work_t* work)
94 {
95 if (work == nullptr) {
96 LOG_ERROR("invalid work");
97 return;
98 }
99 if (work->data == nullptr) {
100 LOG_ERROR("invalid work->data");
101 delete work;
102 return;
103 }
104
105 auto *entry = static_cast<UvEntry*>(work->data);
106
107 delete entry;
108 entry = nullptr;
109
110 delete work;
111 work = nullptr;
112 }
113
CheckFuncAndExec(NapiBoolFunc retFunc)114 void DataShareUvQueue::CheckFuncAndExec(NapiBoolFunc retFunc)
115 {
116 if (retFunc) {
117 int tryTimes = TRY_TIMES;
118 while (retFunc() != true && tryTimes > 0) {
119 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
120 tryTimes--;
121 }
122 }
123 }
124 } // namespace DataShare
125 } // namespace OHOS