• 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 #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