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 #include "barrier_handler.h"
16 #include "hilog_wrapper.h"
17
18 namespace OHOS {
19 namespace AppExecFwk {
BarrierHandler(const std::shared_ptr<TaskExecutor> & executor)20 BarrierHandler::BarrierHandler(const std::shared_ptr<TaskExecutor> &executor)
21 {
22 executor_ = executor;
23 };
24
AddBarrier(std::shared_ptr<Task> & barrierTask)25 ErrCode BarrierHandler::AddBarrier(std::shared_ptr<Task> &barrierTask)
26 {
27 HILOG_INFO("BarrierHandler::AddBarrier start");
28 if (ListenToTask(barrierTask) != ERR_OK) {
29 HILOG_ERROR("BarrierHandler::AddBarrier listenToTask failed");
30 return ERR_APPEXECFWK_CHECK_FAILED;
31 };
32
33 bool execNow = false;
34 {
35 std::unique_lock<std::mutex> lock(barrierLock_);
36 std::shared_ptr<BarrierPair> pair = barrierQueue_.size() == 0 ? nullptr : barrierQueue_.back();
37 if ((pair == nullptr) || ((!HasTask(pair->tasks_)) && (pair->barrier_ == nullptr))) {
38 execNow = true;
39 HILOG_INFO("BarrierHandler::AddBarrier need execute now");
40 }
41 if ((pair == nullptr) || (pair->barrier_ != nullptr)) {
42 std::set<std::shared_ptr<Task>> tmp;
43 std::shared_ptr<BarrierPair> barrierPair = std::make_shared<BarrierPair>(tmp, barrierTask);
44 if (barrierPair == nullptr) {
45 HILOG_ERROR("BarrierHandler::AddBarrier barrierPair is nullptr");
46 return ERR_APPEXECFWK_CHECK_FAILED;
47 }
48 barrierQueue_.push_back(barrierPair);
49 HILOG_INFO("BarrierHandler::AddBarrier barrierQueue push barrierPair");
50 } else {
51 pair->barrier_ = barrierTask;
52 }
53 }
54
55 if (execNow) {
56 HILOG_INFO("BarrierHandler::AddBarrier execute task");
57 executor_->Execute(barrierTask);
58 }
59 HILOG_INFO("BarrierHandler::AddBarrier end");
60 return ERR_OK;
61 }
62
Intercept(std::shared_ptr<Task> & task)63 ErrCode BarrierHandler::Intercept(std::shared_ptr<Task> &task)
64 {
65 HILOG_INFO("BarrierHandler::Intercept start");
66 if (ListenToTask(task) != ERR_OK) {
67 HILOG_ERROR("BarrierHandler::Intercept listenToTask failed");
68 return ERR_APPEXECFWK_CHECK_FAILED;
69 };
70
71 // afterBarrier means is intercepted.
72 bool intercepted = AddTaskAfterBarrier(task);
73 if (intercepted) {
74 HILOG_INFO("BarrierHandler::Intercept intercepted a task.");
75 }
76 ErrCode result = intercepted ? ERR_APPEXECFWK_INTERCEPT_TASK_EXECUTE_SUCCESS : ERR_APPEXECFWK_CHECK_FAILED;
77 HILOG_INFO("BarrierHandler::Intercept end, result:%{public}d", result);
78 return result;
79 }
80
ListenToTask(std::shared_ptr<Task> & task)81 ErrCode BarrierHandler::ListenToTask(std::shared_ptr<Task> &task)
82 {
83 HILOG_INFO("BarrierHandler::ListenToTask start");
84 std::shared_ptr<MyTaskListener> ptrlistener = std::make_shared<MyTaskListener>();
85 if (ptrlistener == nullptr) {
86 HILOG_ERROR("BarrierHandler::listenToTask make shared MyTaskListener is nullptr");
87 return ERR_APPEXECFWK_CHECK_FAILED;
88 }
89 const std::function<void()> onTaskDone = std::bind(&BarrierHandler::OnTaskDone, this, task);
90 ptrlistener->Callback(onTaskDone);
91 task->AddTaskListener(ptrlistener);
92 HILOG_INFO("BarrierHandler::ListenToTask end");
93 return ERR_OK;
94 }
95
OnTaskDone(std::shared_ptr<Task> & task)96 void BarrierHandler::OnTaskDone(std::shared_ptr<Task> &task)
97 {
98 HILOG_INFO("BarrierHandler::OnTaskDone start");
99 // remove from head of queue.
100 // Under the premise that task cannot be reused.
101 bool removed = false;
102 {
103 std::unique_lock<std::mutex> lock(barrierLock_);
104 std::shared_ptr<BarrierPair> barrierPair = barrierQueue_.size() == 0 ? nullptr : barrierQueue_.front();
105 if (barrierPair != nullptr) {
106 if (HasTask(barrierPair->tasks_)) {
107 removed = barrierPair->tasks_.erase(task) == 0 ? false : true;
108 if (barrierPair->tasks_.empty() && (barrierPair->barrier_ != nullptr)) {
109 HILOG_INFO("Barrier.onTaskDone execute barrier task after task done.");
110 executor_->Execute(barrierPair->barrier_);
111 }
112 } else if (task == (barrierPair->barrier_)) {
113 HILOG_INFO("Barrier.onTaskDone remove a barrier.");
114 barrierPair->barrier_ = nullptr;
115 removed = true;
116 // Driven to next barrier.
117 // In one case (barrierQueue.size() == 1): call barrier, and no more task incoming.
118 if (barrierQueue_.size() > 1) {
119 barrierQueue_.pop_front();
120 std::shared_ptr<BarrierPair> nextPair = barrierQueue_.front();
121 if (HasTask(nextPair->tasks_)) {
122 for (std::set<std::shared_ptr<Task>>::iterator it = nextPair->tasks_.begin();
123 it != nextPair->tasks_.end();
124 it++) {
125 executor_->Execute(*it);
126 }
127 } else if (nextPair->barrier_ != nullptr) {
128 HILOG_INFO("Barrier.onTaskDone execute barrier task after barrier done.");
129 executor_->Execute(nextPair->barrier_);
130 } else {
131 HILOG_WARN("Barrier.onTaskDone: Detected an empty node.");
132 }
133 }
134 }
135 }
136 }
137
138 if (!removed) {
139 HILOG_INFO("Barrier.onTaskDone: Task remove failed.");
140 }
141 HILOG_INFO("BarrierHandler::OnTaskDone end");
142 }
143
AddTaskAfterBarrier(std::shared_ptr<Task> & task)144 bool BarrierHandler::AddTaskAfterBarrier(std::shared_ptr<Task> &task)
145 {
146 HILOG_INFO("BarrierHandler::AddTaskAfterBarrier start");
147 std::unique_lock<std::mutex> lock(barrierLock_);
148 std::shared_ptr<BarrierPair> pair = barrierQueue_.size() == 0 ? nullptr : barrierQueue_.back();
149 if ((pair == nullptr) || (pair->barrier_ != nullptr)) {
150 std::shared_ptr<BarrierPair> tmp = std::make_shared<BarrierPair>(CreateTaskSet(task), nullptr);
151 if (tmp == nullptr) {
152 HILOG_ERROR("BarrierHandler::addTaskAfterBarrier make shared BarrierPair is nullptr");
153 return false;
154 }
155
156 barrierQueue_.push_back(tmp);
157 } else if (pair->tasks_.empty()) {
158 pair->tasks_ = CreateTaskSet(task);
159 } else {
160 pair->tasks_.insert(task);
161 }
162 HILOG_INFO("BarrierHandler::AddTaskAfterBarrier end");
163 return (barrierQueue_.size() > 1);
164 }
165
HasTask(const std::set<std::shared_ptr<Task>> & tasks)166 bool BarrierHandler::HasTask(const std::set<std::shared_ptr<Task>> &tasks)
167 {
168 return ((tasks.size() != 0) && !tasks.empty());
169 }
170
CreateTaskSet(std::shared_ptr<Task> & firstTask)171 std::set<std::shared_ptr<Task>> BarrierHandler::CreateTaskSet(std::shared_ptr<Task> &firstTask)
172 {
173 std::set<std::shared_ptr<Task>> taskSet;
174 taskSet.insert(firstTask);
175 return taskSet;
176 }
177 } // namespace AppExecFwk
178 } // namespace OHOS