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 "tm/cpu_task.h"
16 #include <securec.h>
17 #include "dfx/trace_record/ffrt_trace_record.h"
18 #include "dm/dependence_manager.h"
19
20 #include "internal_inc/osal.h"
21 #include "tm/task_factory.h"
22 #include "util/ffrt_facade.h"
23 #include "util/slab.h"
24 #include "eu/func_manager.h"
25 #include "cpp/task_ext.h"
26 #include "util/ref_function_header.h"
27
28 namespace {
29 const int TSD_SIZE = 128;
30 }
31
32 namespace ffrt {
SetQos(const QoS & newQos)33 void CPUEUTask::SetQos(const QoS& newQos)
34 {
35 if (newQos == qos_inherit) {
36 if (!IsRoot()) {
37 qos_ = parent->qos_;
38 } else {
39 qos_ = QoS();
40 }
41 } else {
42 qos_ = newQos;
43 }
44 FFRT_LOGD("Change task %s QoS %d", label.c_str(), qos_());
45 }
46
Prepare()47 void CPUEUTask::Prepare()
48 {
49 this->SetStatus(TaskStatus::SUBMITTED);
50 FFRTTraceRecord::TaskSubmit<ffrt_normal_task>(qos_, &createTime, &fromTid);
51 }
52
Ready()53 void CPUEUTask::Ready()
54 {
55 int qos = qos_();
56 bool notifyWorker = notifyWorker_;
57 this->SetStatus(TaskStatus::READY);
58 bool isRisingEdge = FFRTFacade::GetSchedInstance()->GetScheduler(qos_).PushTaskGlobal(this, false);
59 FFRTTraceRecord::TaskEnqueue<ffrt_normal_task>(qos);
60 if (notifyWorker) {
61 FFRTFacade::GetEUInstance().NotifyTask<TaskNotifyType::TASK_ADDED_RTQ>(qos, false, isRisingEdge);
62 }
63 }
64
FreeMem()65 void CPUEUTask::FreeMem()
66 {
67 BboxCheckAndFreeze();
68 // only tasks which called ffrt_poll_ctl may have cached events
69 if (pollerEnable) {
70 FFRTFacade::GetPPInstance().ClearCachedEvents(this);
71 }
72 #ifdef FFRT_TASK_LOCAL_ENABLE
73 TaskTsdDeconstruct(this);
74 #endif
75 auto f = reinterpret_cast<ffrt_function_header_t*>(func_storage);
76 if ((f->reserve[0] & MASK_FOR_HCS_TASK) != MASK_FOR_HCS_TASK) {
77 TaskFactory<CPUEUTask>::Free(this);
78 return;
79 }
80 FFRT_LOGD("hcs task deconstruct dec ref gid:%llu, create time:%llu", gid, createTime);
81 this->~CPUEUTask();
82 // hcs task dec ref
83 reinterpret_cast<RefFunctionHeader*>(f->reserve[0] & (~MASK_FOR_HCS_TASK))->DecDeleteRef();
84 }
85
Execute()86 void CPUEUTask::Execute()
87 {
88 FFRT_LOGD("Execute task[%lu], name[%s]", gid, label.c_str());
89 FFRTTraceRecord::TaskExecute(&executeTime);
90 auto f = reinterpret_cast<ffrt_function_header_t*>(func_storage);
91 auto exp = ffrt::SkipStatus::SUBMITTED;
92 if (likely(__atomic_compare_exchange_n(&skipped, &exp, ffrt::SkipStatus::EXECUTED, 0,
93 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))) {
94 SetStatus(TaskStatus::EXECUTING);
95 f->exec(f);
96 }
97 if ((f->reserve[0] & MASK_FOR_HCS_TASK) != MASK_FOR_HCS_TASK) {
98 if (f->destroy) {
99 f->destroy(f);
100 }
101 }
102 FFRT_TASKDONE_MARKER(gid);
103 // skipped task can not be marked as finish
104 if (curStatus == TaskStatus::EXECUTING) {
105 SetStatus(TaskStatus::FINISH);
106 }
107 if (!USE_COROUTINE) {
108 FFRTFacade::GetDMInstance().onTaskDone(this);
109 } else {
110 /*
111 if we call onTaskDone inside coroutine, the memory of task may be recycled.
112 1. recycled memory of task can be used by another submit
113 2. task->coRoutine will be recycled and can be used by another task
114 In this scenario, CoStart will crash.
115 Because it needs to use this task and it's coRoutine to perform some action after it finished.
116 */
117 coRoutine->isTaskDone = true;
118 UnbindCoRoutione();
119 }
120 }
121
CPUEUTask(const task_attr_private * attr,CPUEUTask * parent,const uint64_t & id)122 CPUEUTask::CPUEUTask(const task_attr_private *attr, CPUEUTask *parent, const uint64_t &id)
123 : CoTask(ffrt_normal_task, attr), parent(parent)
124 {
125 if (attr && !attr->name_.empty()) {
126 label = attr->name_;
127 } else if (IsRoot()) {
128 label = "root";
129 } else if ((parent != nullptr) && parent->IsRoot()) {
130 label = "t" + std::to_string(id);
131 } else if (parent != nullptr) {
132 label = parent->label + "." + std::to_string(id);
133 } else {
134 label = "t" + std::to_string(id);
135 }
136
137 if (attr) {
138 notifyWorker_ = attr->notifyWorker_;
139
140 if (attr->qos_ == qos_inherit && !IsRoot()) {
141 qos_ = parent->qos_;
142 }
143 #ifdef FFRT_TASK_LOCAL_ENABLE
144 if (attr->taskLocal_) {
145 tlsAttr = new TaskLocalAttr;
146 tlsAttr->tsd = static_cast<void**>(malloc(TSD_SIZE * sizeof(void*)));
147 if (unlikely(tlsAttr->tsd == nullptr)) {
148 FFRT_SYSEVENT_LOGE("task local malloc tsd failed");
149 return;
150 }
151 memset_s(tlsAttr->tsd, TSD_SIZE * sizeof(void *), 0, TSD_SIZE * sizeof(void *));
152 tlsAttr->taskLocal = true;
153 }
154 #endif
155 }
156
157 aliveStatus.store(AliveStatus::INITED, std::memory_order_relaxed);
158 }
~CPUEUTask()159 CPUEUTask::~CPUEUTask()
160 {
161 #ifdef FFRT_TASK_LOCAL_ENABLE
162 if (tlsAttr != nullptr) {
163 delete tlsAttr;
164 tlsAttr = nullptr;
165 }
166 #endif
167 if (in_handles_ != nullptr) {
168 delete in_handles_;
169 in_handles_ = nullptr;
170 }
171 aliveStatus.store(AliveStatus::RELEASED, std::memory_order_relaxed);
172 }
173 } /* namespace ffrt */
174