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