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