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 FFRT_CO_ROUTINE_HPP
17 #define FFRT_CO_ROUTINE_HPP
18 #include <atomic>
19 #include <functional>
20 #include <thread>
21 #include <pthread.h>
22 #include "co2_context.h"
23
24 #if defined(__aarch64__)
25 constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD;
26 #elif defined(__arm__)
27 constexpr size_t STACK_MAGIC = 0x7BCDABCD;
28 #elif defined(__x86_64__)
29 constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD;
30 #endif
31
32 #ifndef FFRT_STACK_SIZE
33 #define FFRT_STACK_SIZE (1 << 20)
34 #endif
35
36 #ifdef ASAN_MODE
37 extern "C" void __sanitizer_start_switch_fiber(void **fake_stack_save, const void *bottom, size_t size);
38 extern "C" void __sanitizer_finish_switch_fiber(void *fake_stack_save, const void **bottom_old, size_t *size_old);
39 extern "C" void __asan_handle_no_return();
40 #endif
41
42 namespace ffrt {
43 class CoTask;
44 class CPUEUTask;
45 struct WaitEntry;
46 } // namespace ffrt
47 struct CoRoutine;
48
49 enum class CoStatus {
50 CO_UNINITIALIZED,
51 CO_NOT_FINISH,
52 CO_RUNNING,
53 };
54
55 enum class CoStackProtectType {
56 CO_STACK_WEAK_PROTECT,
57 CO_STACK_STRONG_PROTECT
58 };
59
60 enum class CoWakeType {
61 TIMEOUT_WAKE,
62 NO_TIMEOUT_WAKE
63 };
64
65 constexpr uint64_t STACK_SIZE = FFRT_STACK_SIZE;
66 constexpr uint64_t MIN_STACK_SIZE = 32 * 1024;
67 constexpr uint64_t STACK_MEM_SIZE = 8;
68
69 using CoCtx = ffrt_fiber_t;
70
71 struct CoRoutineEnv {
72 // when task is running, runningCo same with task->co
73 // if task switch out, set to null. if task complete, be used as co cache for next task.
74 CoRoutine* runningCo = nullptr;
75 CoCtx schCtx;
76 const std::function<bool(ffrt::CoTask*)>* pending = nullptr;
77 };
78
79 struct StackMem {
80 uint64_t size;
81 size_t magic;
82 uint8_t stk[STACK_MEM_SIZE];
83 };
84
85 struct CoRoutine {
86 std::atomic_int status {static_cast<int>(CoStatus::CO_UNINITIALIZED)};
87 CoRoutineEnv* thEnv;
88 ffrt::CoTask* task;
89 #ifdef ASAN_MODE
90 void *asanFakeStack = nullptr; // not finished, need further verification
91 const void *asanFiberAddr = nullptr;
92 size_t asanFiberSize = 0;
93 #endif
94 CoCtx ctx;
95 uint64_t allocatedSize; // CoRoutine allocated size
96 bool isTaskDone = false;
97 /* do not add item after stkMem */
98 StackMem stkMem;
99 };
100
101 struct CoStackAttr {
102 public:
103 explicit CoStackAttr(uint64_t coSize = STACK_SIZE, CoStackProtectType coType =
104 CoStackProtectType::CO_STACK_WEAK_PROTECT)
105 {
106 size = coSize;
107 type = coType;
108 }
~CoStackAttrCoStackAttr109 ~CoStackAttr() {}
110 uint64_t size;
111 CoStackProtectType type;
112
113 static inline CoStackAttr* Instance(uint64_t coSize = STACK_SIZE,
114 CoStackProtectType coType = CoStackProtectType::CO_STACK_WEAK_PROTECT)
115 {
116 static CoStackAttr inst(coSize, coType);
117 return &inst;
118 }
119 };
120
121 class CoRoutineFactory {
122 public:
123 using CowakeCB = std::function<void (ffrt::CoTask*, CoWakeType)>;
124
125 static CoRoutineFactory &Instance();
126
CoWakeFunc(ffrt::CoTask * task,CoWakeType type)127 static void CoWakeFunc(ffrt::CoTask* task, CoWakeType type)
128 {
129 return Instance().cowake_(task, type);
130 }
131
RegistCb(const CowakeCB & cowake)132 static void RegistCb(const CowakeCB &cowake)
133 {
134 Instance().cowake_ = cowake;
135 }
136 private:
137 CowakeCB cowake_;
138 };
139
140 void CoStackFree(void);
141 void CoWorkerExit(void);
142
143 int CoStart(ffrt::CoTask* task, CoRoutineEnv* coRoutineEnv);
144 void CoYield(void);
145
146 void CoWait(const std::function<bool(ffrt::CoTask*)>& pred);
147 void CoWake(ffrt::CoTask* task, CoWakeType type);
148
149 CoRoutineEnv* GetCoRoutineEnv(void);
150
GetCoStackAddr(CoRoutine * co)151 inline void* GetCoStackAddr(CoRoutine* co)
152 {
153 return static_cast<void*>(reinterpret_cast<char*>(co) + sizeof(CoRoutine) - STACK_MEM_SIZE);
154 }
155
156 #ifdef FFRT_TASK_LOCAL_ENABLE
157 void TaskTsdDeconstruct(ffrt::CPUEUTask* task);
158 #endif
159
160 #endif
161