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