1 /*
2 * Copyright (c) 2023 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 "core/task_ctx.h"
16 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
17 #include <dlfcn.h>
18 #include <sstream>
19 #include "libunwind.h"
20 #include "backtrace_local.h"
21 #endif
22 #include "core/dependence_manager.h"
23 #include "util/slab.h"
24 #include "internal_inc/osal.h"
25 #include "internal_inc/types.h"
26
27 namespace ffrt {
DenpenceStr(Denpence d)28 static inline const char* DenpenceStr(Denpence d)
29 {
30 static const char* m[] = {
31 "DEPENCE_INIT",
32 "DATA_DEPENCE",
33 "CALL_DEPENCE",
34 "CONDITION_DEPENCE",
35 };
36 return m[static_cast<uint64_t>(d)];
37 }
38
TaskCtx(const task_attr_private * attr,TaskCtx * parent,const uint64_t & id,const char * identity,const QoS & qos)39 TaskCtx::TaskCtx(const task_attr_private *attr, TaskCtx *parent, const uint64_t &id, const char *identity,
40 const QoS &qos)
41 : parent(parent), rank(id), identity(identity), qos(qos)
42 {
43 wue = nullptr;
44 fq_we.task = this;
45 if (attr && !attr->name_.empty()) {
46 label = attr->name_;
47 } else if (IsRoot()) {
48 label = "root";
49 } else if (parent->parent == nullptr) {
50 label = "t" + std::to_string(rank);
51 } else {
52 label = parent->label + "." + std::to_string(rank);
53 }
54 if (!IsRoot()) {
55 FFRT_SUBMIT_MARKER(label, gid);
56 }
57 FFRT_LOGD("create task name:%s gid=%lu", label.c_str(), gid);
58 }
59
SetQos(QoS & target_qos)60 void TaskCtx::SetQos(QoS& target_qos)
61 {
62 if (target_qos == qos_inherit) {
63 if (!this->IsRoot()) {
64 this->qos = parent->qos;
65 }
66 FFRT_LOGD("Change task %s QoS %d", label.c_str(), this->qos());
67 } else {
68 this->qos = target_qos;
69 }
70 }
71
72 /* For interval based userspace load tracking
73 * Inherit parent's active intervals for a new task
74 */
InitRelatedIntervals(TaskCtx * curr)75 void TaskCtx::InitRelatedIntervals(TaskCtx* curr)
76 {
77 auto& parentIntervals = curr->relatedIntervals;
78 if (parentIntervals.empty()) {
79 return;
80 }
81
82 for (auto it : std::as_const(parentIntervals)) {
83 if (it->Qos() == curr->qos) {
84 curr->relatedIntervals.insert(it);
85 }
86 }
87 }
88
DecDepRef()89 void TaskCtx::DecDepRef()
90 {
91 if (--depRefCnt == 0) {
92 FFRT_LOGI("Undependency completed, enter ready queue, task[%lu], name[%s]", gid, label.c_str());
93 FFRT_WAKE_TRACER(this->gid);
94 this->UpdateState(TaskState::READY);
95 #ifdef FFRT_BBOX_ENABLE
96 TaskEnQueuCounterInc();
97 #endif
98 }
99 }
100
DecChildRef()101 void TaskCtx::DecChildRef()
102 {
103 FFRT_LOGD("DecChildRef parent task:%s, childWaitRefCnt=%u", parent->label.c_str(), parent->childWaitRefCnt.load());
104 FFRT_TRACE_SCOPE(2, taskDecChildRef);
105 std::unique_lock<decltype(parent->lock)> lck(parent->lock);
106 parent->childWaitRefCnt--;
107 if (parent->childWaitRefCnt != 0) {
108 return;
109 }
110 if (FFRT_UNLIKELY(parent->IsRoot())) {
111 RootTaskCtx *root = static_cast<RootTaskCtx *>(parent);
112 if (root->thread_exit == true) {
113 lck.unlock();
114 delete root;
115 return;
116 }
117 }
118
119 if (!parent->IsRoot() && parent->status == TaskStatus::RELEASED && parent->childWaitRefCnt == 0) {
120 FFRT_LOGD("free TaskCtx:%s gid=%lu", parent->label.c_str(), parent->gid);
121 lck.unlock();
122 parent->DecDeleteRef();
123 return;
124 }
125 if (parent->denpenceStatus != Denpence::CALL_DEPENCE) {
126 return;
127 }
128 parent->denpenceStatus = Denpence::DEPENCE_INIT;
129
130 if (!USE_COROUTINE || parent->parent == nullptr) {
131 parent->childWaitCond_.notify_all();
132 } else {
133 FFRT_WAKE_TRACER(parent->gid);
134 parent->UpdateState(TaskState::READY);
135 }
136 }
137
DecWaitDataRef()138 void TaskCtx::DecWaitDataRef()
139 {
140 FFRT_TRACE_SCOPE(2, taskDecWaitData);
141 {
142 std::lock_guard<decltype(lock)> lck(lock);
143 dataWaitRefCnt--;
144 if (dataWaitRefCnt != 0) {
145 return;
146 }
147 if (denpenceStatus != Denpence::DATA_DEPENCE) {
148 return;
149 }
150 denpenceStatus = Denpence::DEPENCE_INIT;
151 }
152
153 if (!USE_COROUTINE || parent == nullptr) {
154 dataWaitCond_.notify_all();
155 } else {
156 FFRT_WAKE_TRACER(this->gid);
157 this->UpdateState(TaskState::READY);
158 #ifdef FFRT_BBOX_ENABLE
159 TaskEnQueuCounterInc();
160 #endif
161 }
162 }
163
IsPrevTask(const TaskCtx * task) const164 bool TaskCtx::IsPrevTask(const TaskCtx* task) const
165 {
166 std::list<uint64_t> ThisTaskIds;
167 std::list<uint64_t> OtherTaskIds;
168 const TaskCtx* now = this;
169 while (now != nullptr && now != DependenceManager::Root()) {
170 ThisTaskIds.push_front(now->rank);
171 now = now->parent;
172 }
173 while (task != nullptr && task != DependenceManager::Root()) {
174 OtherTaskIds.push_front(task->rank);
175 task = task->parent;
176 }
177 return ThisTaskIds < OtherTaskIds;
178 }
179
RecycleTask()180 void TaskCtx::RecycleTask()
181 {
182 std::unique_lock<decltype(lock)> lck(lock);
183 if (childWaitRefCnt == 0) {
184 FFRT_LOGD("free TaskCtx:%s gid=%lu", label.c_str(), gid);
185 lck.unlock();
186 DecDeleteRef();
187 return;
188 } else {
189 status = TaskStatus::RELEASED;
190 }
191 }
192
MultiDepenceAdd(Denpence depType)193 void TaskCtx::MultiDepenceAdd(Denpence depType)
194 {
195 FFRT_LOGD("task(%s) ADD_DENPENCE(%s)", this->label.c_str(), DenpenceStr(depType));
196 denpenceStatus = depType;
197 }
198 #ifdef FFRT_CO_BACKTRACE_OH_ENABLE
DumpTask(TaskCtx * task,std::string & stackInfo,uint8_t flag)199 void TaskCtx::DumpTask(TaskCtx* task, std::string& stackInfo, uint8_t flag)
200 {
201 unw_context_t ctx;
202 unw_cursor_t unw_cur;
203 unw_proc_info_t unw_proc;
204
205 if (ExecuteCtx::Cur()->task == task || task == nullptr) {
206 if (flag == 0) {
207 OHOS::HiviewDFX::PrintTrace(-1);
208 } else {
209 OHOS::HiviewDFX::GetBacktrace(stackInfo, false);
210 }
211 return;
212 } else {
213 memset(&ctx, 0, sizeof(ctx));
214 #if defined(__aarch64__)
215 ctx.uc_mcontext.regs[UNW_AARCH64_X29] = task->coRoutine->ctx.regs[10];
216 ctx.uc_mcontext.sp = task->coRoutine->ctx.regs[13];
217 ctx.uc_mcontext.pc = task->coRoutine->ctx.regs[11];
218 #elif defined(__x86_64__)
219 ctx.uc_mcontext.gregs[REG_RBX] = task->coRoutine->ctx.regs[0];
220 ctx.uc_mcontext.gregs[REG_RBP] = task->coRoutine->ctx.regs[1];
221 ctx.uc_mcontext.gregs[REG_RSP] = task->coRoutine->ctx.regs[6];
222 ctx.uc_mcontext.gregs[REG_RIP] = *(reinterpret_cast<greg_t *>(ctx.uc_mcontext.gregs[REG_RSP] - 8));
223 #elif defined(__arm__)
224 ctx.regs[13] = task->coRoutine->ctx.regs[0]; /* sp */
225 ctx.regs[15] = task->coRoutine->ctx.regs[1]; /* pc */
226 ctx.regs[14] = task->coRoutine->ctx.regs[1]; /* lr */
227 ctx.regs[11] = task->coRoutine->ctx.regs[10]; /* fp */
228 #endif
229 }
230
231 int ret;
232 int frame_id = 0;
233 ret = unw_init_local(&unw_cur, &ctx);
234 if (ret < 0) {
235 return;
236 }
237
238 Dl_info info;
239 unw_word_t prevPc = 0;
240 unw_word_t offset;
241 char symbol[512];
242 std::ostringstream ss;
243 do {
244 ret = unw_get_proc_info(&unw_cur, &unw_proc);
245 if (ret) {
246 break;
247 }
248
249 if (prevPc == unw_proc.start_ip) {
250 break;
251 }
252
253 prevPc = unw_proc.start_ip;
254
255 ret = dladdr(reinterpret_cast<void *>(unw_proc.start_ip), &info);
256 if (!ret) {
257 break;
258 }
259
260 memset(symbol, 0, sizeof(symbol));
261 if (unw_get_proc_name(&unw_cur, symbol, sizeof(symbol), &offset) == 0) {
262 if (flag == 0) {
263 FFRT_LOGE("FFRT | #%d pc: %lx %s(%p) %s", frame_id, unw_proc.start_ip, info.dli_fname,
264 (unw_proc.start_ip - reinterpret_cast<unw_word_t>(info.dli_fbase)), symbol);
265 } else {
266 ss << "FFRT | #" << frame_id << " pc: " << unw_proc.start_ip << " " << info.dli_fname;
267 ss << "(" << (unw_proc.start_ip - reinterpret_cast<unw_word_t>(info.dli_fbase)) << ") ";
268 ss << std::string(symbol, strlen(symbol)) <<std::endl;
269 }
270 } else {
271 if (flag == 0) {
272 FFRT_LOGE("FFRT | #%d pc: %lx %s(%p)", frame_id, unw_proc.start_ip, info.dli_fname,
273 (unw_proc.start_ip - reinterpret_cast<unw_word_t>(info.dli_fbase)));
274 } else {
275 ss << "FFRT | #" << frame_id << " pc: " << unw_proc.start_ip << " " << info.dli_fname;
276 ss << "(" << (unw_proc.start_ip - reinterpret_cast<unw_word_t>(info.dli_fbase)) << ") ";
277 ss << std::endl;
278 }
279 }
280 ++frame_id;
281 } while (unw_step(&unw_cur) > 0);
282
283 if (flag != 0) {
284 stackInfo = ss.str();
285 }
286 return;
287 }
288 #endif
289 } /* namespace ffrt */