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
16 #ifndef _TASK_BASE_H_
17 #define _TASK_BASE_H_
18 #include <atomic>
19 #include <vector>
20 #include "eu/co_routine.h"
21 #include "internal_inc/types.h"
22 #ifdef USE_OHOS_QOS
23 #include "qos.h"
24 #else
25 #include "staging_qos/sched/qos.h"
26 #endif
27 #include "sched/execute_ctx.h"
28 #include "internal_inc/non_copyable.h"
29 #include "util/time_format.h"
30 #include "internal_inc/types.h"
31 #include "core/task_attr_private.h"
32
33 namespace ffrt {
34 static constexpr uint64_t cacheline_size = 64;
35
36 typedef struct HiTraceIdStruct {
37 #if __BYTE_ORDER == __BIG_ENDIAN
38 uint64_t chainId : 60;
39 uint64_t ver : 3;
40 uint64_t valid : 1;
41
42 uint64_t parentSpanId : 26;
43 uint64_t spanId : 26;
44 uint64_t flags : 12;
45 #elif __BYTE_ORDER == __LITTLE_ENDIAN
46 uint64_t valid : 1;
47 uint64_t ver : 3;
48 uint64_t chainId : 60;
49
50 uint64_t flags : 12;
51 uint64_t spanId : 26;
52 uint64_t parentSpanId : 26;
53 #else
54 #error "ERROR: No BIG_LITTLE_ENDIAN defines."
55 #endif
56 } HiTraceIdStruct;
57 constexpr uint64_t HITRACE_ID_VALID = 1;
58
59 struct TimeoutTask {
60 uint64_t taskGid{0};
61 uint64_t timeoutCnt{0};
62 TaskStatus taskStatus{TaskStatus::PENDING};
63 TimeoutTask() = default;
TimeoutTaskTimeoutTask64 TimeoutTask(uint64_t gid, uint64_t timeoutcnt, TaskStatus status)
65 : taskGid(gid), timeoutCnt(timeoutcnt), taskStatus(status) {}
66 };
67
68 class TaskBase : private NonCopyable {
69 public:
70 TaskBase(ffrt_executor_task_type_t type, const task_attr_private *attr);
71 virtual ~TaskBase() = default;
72
73 // lifecycle actions
74 virtual void Prepare() = 0;
75 virtual void Ready() = 0;
76 virtual void Pop() = 0;
77 // must be called by a sync primitive when blocking this task.
78 // return value indicates this task need to be blocked on thread or yield from it's coroutine.
79 virtual BlockType Block() = 0;
80 virtual void Wake() = 0;
81 virtual void Execute() = 0;
82 virtual void Finish() = 0;
83 virtual void Cancel() = 0;
84 virtual void FreeMem() = 0;
85
86 // must be called by a sync primitive when it wakes a blocking task.
87 // return value indicates this task has been blocked whether on thread or yield from it's coroutine.
88 virtual BlockType GetBlockType() const = 0;
89
90 // getters and setters
91 virtual std::string GetLabel() const = 0;
92 virtual void SetQos(const QoS& newQos) = 0;
93
GetQos()94 inline int GetQos() const
95 {
96 return qos_();
97 }
98
SetStatus(TaskStatus statusIn)99 inline void SetStatus(TaskStatus statusIn)
100 {
101 /* Note this function can be called concurrently.
102 * The following accesses can be interleaved.
103 * We use atomic relaxed accesses in order to
104 * combat data-races without incurring performance
105 * overhead. Currently statusTime & preStatus
106 * are only used in printing debug information
107 * and don't play a role in the logic.
108 */
109 statusTime.store(TimeStampCntvct(), std::memory_order_relaxed);
110 preStatus.store(curStatus, std::memory_order_relaxed);
111 curStatus.store(statusIn, std::memory_order_relaxed);
112 }
113
114 // delete ref setter functions, for memory management
IncDeleteRef()115 inline uint32_t IncDeleteRef()
116 {
117 auto v = rc.fetch_add(1);
118 return v;
119 }
120
DecDeleteRef()121 inline uint32_t DecDeleteRef()
122 {
123 auto v = rc.fetch_sub(1);
124 if (v == 1) {
125 FreeMem();
126 }
127 return v;
128 }
129
130 // returns the current g_taskId value
131 static uint32_t GetLastGid();
132
133 // properties
134 LinkedList node; // used on fifo fast que
135 ffrt_executor_task_type_t type;
136 const uint64_t gid; // global unique id in this process
137 QoS qos_ = qos_default;
138 std::atomic_uint32_t rc = 1; // reference count for delete
139 std::atomic<TaskStatus> preStatus = TaskStatus::PENDING;
140 std::atomic<TaskStatus> curStatus = TaskStatus::PENDING;
141 std::atomic<uint64_t> statusTime = TimeStampCntvct();
142 std::atomic<AliveStatus> aliveStatus {AliveStatus::UNITINITED};
143 bool monitorTimeout_ = true;
144
145 #ifdef FFRT_ASYNC_STACKTRACE
146 uint64_t stackId = 0;
147 #endif
148
149 struct HiTraceIdStruct traceId_ = {};
150 uint64_t createTime {0};
151 uint64_t executeTime {0};
152 int32_t fromTid {0};
153 };
154
155 class CoTask : public TaskBase {
156 public:
CoTask(ffrt_executor_task_type_t type,const task_attr_private * attr)157 CoTask(ffrt_executor_task_type_t type, const task_attr_private *attr)
158 : TaskBase(type, attr)
159 {
160 we.task = this;
161 if (attr) {
162 stack_size = std::max(attr->stackSize_, MIN_STACK_SIZE);
163 }
164 }
165 ~CoTask() override = default;
166
167 uint8_t func_storage[ffrt_auto_managed_function_storage_size]; // 函数闭包、指针或函数对象
168
169 std::string label;
170 CoWakeType coWakeType { CoWakeType::NO_TIMEOUT_WAKE };
171 int cpuBoostCtxId = -1;
172 WaitEntry we; // Used on syncprimitive wait que
173 WaitUntilEntry* wue = nullptr; // used on syncprimitive wait que and delayed wait que
174 // lifecycle connection between task and coroutine is shown as below:
175 // |*task pending*|*task ready*|*task executing*|*task done*|*task release*|
176 // |**********coroutine*********|
177 CoRoutine* coRoutine = nullptr;
178 uint64_t stack_size = STACK_SIZE;
179 std::atomic<pthread_t> runningTid = 0;
180 int legacyCountNum = 0; // dynamic switch controlled by set_legacy_mode api
181 std::mutex mutex_; // used in coroute
182 std::condition_variable waitCond_; // cv for thread wait
183
184 bool pollerEnable = false; // set true if task call ffrt_epoll_ctl
185 bool threadMode_ = false;
GetLabel()186 std::string GetLabel() const override
187 {
188 return label;
189 }
190
UnbindCoRoutione()191 inline void UnbindCoRoutione()
192 {
193 std::lock_guard lck(mutex_);
194 coRoutine = nullptr;
195 }
196
197 protected:
198 BlockType blockType { BlockType::BLOCK_COROUTINE }; // block type for lagacy mode changing
199 };
200
201 void ExecuteTask(TaskBase* task);
202
IsCoTask(TaskBase * task)203 inline bool IsCoTask(TaskBase* task)
204 {
205 return task && (task->type == ffrt_normal_task ||
206 (task->type == ffrt_queue_task && (!reinterpret_cast<ffrt::CoTask*>(task)->threadMode_)));
207 }
208
IncDeleteRefIfPositive(TaskBase * task)209 inline bool IncDeleteRefIfPositive(TaskBase* task)
210 {
211 uint32_t expected = task->rc.load();
212 while (expected > 0) {
213 if (task->rc.compare_exchange_weak(expected, expected + 1)) {
214 return true;
215 }
216 }
217 return false;
218 }
219 } // namespace ffrt
220 #endif
221