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 "co2_context.h"
22 
23 #if defined(__aarch64__)
24 constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD;
25 #elif defined(__arm__)
26 constexpr size_t STACK_MAGIC = 0x7BCDABCD;
27 #elif defined(__x86_64__)
28 constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD;
29 #elif defined(__riscv) && __riscv_xlen == 64
30 constexpr size_t STACK_MAGIC = 0x7BCDABCDABCDABCD;
31 #endif
32 
33 #ifndef FFRT_STACK_SIZE
34 #define FFRT_STACK_SIZE (1 << 20)
35 #endif
36 
37 namespace ffrt {
38 class CPUEUTask;
39 struct WaitEntry;
40 } // namespace ffrt
41 struct CoRoutine;
42 
43 enum class CoStatus {
44     CO_UNINITIALIZED,
45     CO_NOT_FINISH,
46     CO_RUNNING,
47 };
48 
49 enum class CoStackProtectType {
50     CO_STACK_WEAK_PROTECT,
51     CO_STACK_STRONG_PROTECT
52 };
53 
54 enum class BlockType {
55     BLOCK_COROUTINE,
56     BLOCK_THREAD
57 };
58 
59 constexpr uint64_t STACK_SIZE = FFRT_STACK_SIZE;
60 constexpr uint64_t MIN_STACK_SIZE = 32 * 1024;
61 
62 using CoCtx = struct co2_context;
63 
64 struct CoRoutineEnv {
65     CoRoutine* runningCo = nullptr;
66     CoCtx schCtx;
67     const std::function<bool(ffrt::CPUEUTask*)>* pending = nullptr;
68 };
69 
70 struct StackMem {
71     uint64_t size;
72     size_t magic;
73     uint8_t stk[8];
74 };
75 
76 struct CoRoutine {
77     std::atomic_int status;
78     CoRoutineEnv* thEnv;
79     ffrt::CPUEUTask* task;
80     CoCtx ctx;
81     uint64_t allocatedSize; // CoRoutine allocated size
82     bool isTaskDone = false;
83     StackMem stkMem;
84 };
85 
86 struct CoStackAttr {
87 public:
CoStackAttrCoStackAttr88     explicit CoStackAttr(uint64_t coSize = STACK_SIZE, CoStackProtectType coType =
89         CoStackProtectType::CO_STACK_WEAK_PROTECT)
90     {
91         size = coSize;
92         type = coType;
93     }
~CoStackAttrCoStackAttr94     ~CoStackAttr() {}
95     uint64_t size;
96     CoStackProtectType type;
97 
InstanceCoStackAttr98     static inline CoStackAttr* Instance(uint64_t coSize = STACK_SIZE,
99         CoStackProtectType coType = CoStackProtectType::CO_STACK_WEAK_PROTECT)
100     {
101         static CoStackAttr inst(coSize, coType);
102         return &inst;
103     }
104 };
105 
106 class CoRoutineFactory {
107 public:
108     using CowakeCB = std::function<void (ffrt::CPUEUTask*, bool)>;
109 
110     static CoRoutineFactory &Instance();
111 
CoWakeFunc(ffrt::CPUEUTask* task, bool timeOut)112     static void CoWakeFunc(ffrt::CPUEUTask* task, bool timeOut)
113     {
114         return Instance().cowake_(task, timeOut);
115     }
116 
RegistCb(const CowakeCB &cowake)117     static void RegistCb(const CowakeCB &cowake)
118     {
119         Instance().cowake_ = cowake;
120     }
121 private:
122     CowakeCB cowake_;
123 };
124 
125 void CoStackFree(void);
126 void CoWorkerExit(void);
127 
128 int CoStart(ffrt::CPUEUTask* task);
129 void CoYield(void);
130 
131 void CoWait(const std::function<bool(ffrt::CPUEUTask*)>& pred);
132 void CoWake(ffrt::CPUEUTask* task, bool timeOut);
133 
134 #ifdef FFRT_TASK_LOCAL_ENABLE
135 void TaskTsdDeconstruct(ffrt::CPUEUTask* task);
136 #endif
137 
138 #endif
139