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
26 namespace {
27 const int TSD_SIZE = 128;
28 }
29
30 namespace ffrt {
SetQos(const QoS & newQos)31 void CPUEUTask::SetQos(const QoS& newQos)
32 {
33 if (newQos == qos_inherit) {
34 if (!this->IsRoot()) {
35 this->qos_ = parent->qos_;
36 } else {
37 this->qos_ = QoS();
38 }
39 FFRT_LOGD("Change task %s QoS %d", label.c_str(), this->qos_());
40 } else {
41 this->qos_ = newQos;
42 }
43 }
44
FreeMem()45 void CPUEUTask::FreeMem()
46 {
47 BboxCheckAndFreeze();
48 // only tasks which called ffrt_poll_ctl may have cached events
49 if (pollerEnable) {
50 FFRTFacade::GetPPInstance().GetPoller(qos_).ClearCachedEvents(this);
51 }
52 #ifdef FFRT_TASK_LOCAL_ENABLE
53 TaskTsdDeconstruct(this);
54 #endif
55 TaskFactory<CPUEUTask>::Free(this);
56 }
57
Execute()58 void CPUEUTask::Execute()
59 {
60 FFRT_LOGD("Execute task[%lu], name[%s]", gid, label.c_str());
61 FFRTTraceRecord::TaskExecute(&(this->executeTime));
62 UpdateState(TaskState::RUNNING);
63 auto f = reinterpret_cast<ffrt_function_header_t*>(func_storage);
64 auto exp = ffrt::SkipStatus::SUBMITTED;
65 if (likely(__atomic_compare_exchange_n(&skipped, &exp, ffrt::SkipStatus::EXECUTED, 0,
66 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))) {
67 f->exec(f);
68 }
69 f->destroy(f);
70 FFRT_TASKDONE_MARKER(gid);
71 if (!USE_COROUTINE) {
72 this->UpdateState(ffrt::TaskState::EXITED);
73 } else {
74 this->coRoutine->isTaskDone = true;
75 }
76 }
77
CPUEUTask(const task_attr_private * attr,CPUEUTask * parent,const uint64_t & id,const QoS & qos)78 CPUEUTask::CPUEUTask(const task_attr_private *attr, CPUEUTask *parent, const uint64_t &id,
79 const QoS &qos)
80 : parent(parent), rank(id)
81 {
82 this->qos_ = qos;
83 fq_we.task = this;
84 if (attr && !attr->name_.empty()) {
85 label = attr->name_;
86 } else if (IsRoot()) {
87 label = "root";
88 } else if ((parent != nullptr) && parent->IsRoot()) {
89 label = "t" + std::to_string(rank);
90 } else {
91 label = parent->label + "." + std::to_string(rank);
92 }
93
94 taskLocal = false;
95 tsd = nullptr;
96 if (attr && attr->taskLocal_) {
97 tsd = (void **)malloc(TSD_SIZE * sizeof(void *));
98 if (unlikely(tsd == nullptr)) {
99 FFRT_LOGE("task local malloc tsd failed");
100 return;
101 }
102 memset_s(tsd, TSD_SIZE * sizeof(void *), 0, TSD_SIZE * sizeof(void *));
103 taskLocal = attr->taskLocal_;
104 }
105 if (attr) {
106 stack_size = std::max(attr->stackSize_, MIN_STACK_SIZE);
107 }
108 }
109
ExecuteUVTask(TaskBase * task,QoS qos)110 void ExecuteUVTask(TaskBase* task, QoS qos)
111 {
112 ffrt_executor_task_func func = FuncManager::Instance()->getFunc(ffrt_uv_task);
113 if (func == nullptr) {
114 FFRT_LOGE("Static func is nullptr");
115 return;
116 }
117 ffrt_executor_task_t* uv_work = reinterpret_cast<ffrt_executor_task_t *>(task);
118 FFRTTraceRecord::TaskExecute<ffrt_uv_task>(qos);
119 FFRT_EXECUTOR_TASK_BEGIN(uv_work);
120 func(uv_work, qos);
121 FFRT_EXECUTOR_TASK_END();
122 FFRT_EXECUTOR_TASK_FINISH_MARKER(uv_work); // task finish marker for uv task
123 FFRTTraceRecord::TaskDone<ffrt_uv_task>(qos);
124 }
125
ExecuteTask(TaskBase * task,QoS qos)126 void ExecuteTask(TaskBase* task, QoS qos)
127 {
128 bool isCoTask = IsCoTask(task);
129
130 // set current task info to context
131 ExecuteCtx* ctx = ExecuteCtx::Cur();
132 if (isCoTask) {
133 ctx->task = reinterpret_cast<CPUEUTask *>(task);
134 ctx->lastGid_ = task->gid;
135 } else {
136 ctx->exec_task = task; // for ffrt_wake_coroutine
137 }
138
139 // run Task with coroutine
140 if (USE_COROUTINE && isCoTask) {
141 while (CoStart(static_cast<CPUEUTask*>(task), GetCoEnv()) != 0) {
142 usleep(CO_CREATE_RETRY_INTERVAL);
143 }
144 } else {
145 // run task on thread
146 #ifdef FFRT_ASYNC_STACKTRACE
147 if (isCoTask) {
148 FFRTSetStackId(task->stackId);
149 }
150 #endif
151 if (task->type < ffrt_invalid_task && task->type != ffrt_uv_task) {
152 task->Execute();
153 } else {
154 ExecuteUVTask(task, qos);
155 }
156 }
157
158 // reset task info in context
159 ctx->task = nullptr;
160 ctx->exec_task = nullptr;
161 }
162 } /* namespace ffrt */