• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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_JOB_UTILS_H
17 #define FFRT_JOB_UTILS_H
18 
19 #include <cstdint>
20 #include <functional>
21 #include <atomic>
22 #include "ffrt/fiber.h"
23 
24 namespace ffrt {
25 
26 namespace detail {
27     struct NonCopyable {
28     protected:
29         NonCopyable() = default;
30         ~NonCopyable() = default;
31         NonCopyable(const NonCopyable&) = delete;
32         NonCopyable& operator=(const NonCopyable&) = delete;
33     };
34 }
35 
36 template <int UsageId = 0, class FiberLocal = char, class ThreadLocal = char>
37 struct Fiber : detail::NonCopyable {
38     struct ThreadEnv :  detail::NonCopyable {
39         Fiber* cur = nullptr;
40         bool (*cond)(void*) = nullptr;
41         ThreadLocal tl;
42     };
43 
EnvFiber44     static __attribute__((noinline)) ThreadEnv& Env()
45     {
46         static thread_local ThreadEnv ctx;
47         return ctx;
48     }
49 
InitFiber50     static Fiber* Init(std::function<void()>&& f, void* stack, size_t stack_size)
51     {
52         if (stack == nullptr || stack_size < sizeof(Fiber) + minStackSize) {
53             return nullptr;
54         }
55         auto c = new (stack) Fiber(std::forward<std::function<void()>>(f));
56         if (ffrt_fiber_init(&c->fb, reinterpret_cast<void(*)(void*)>(FiberEntry), c,
57             static_cast<char*>(stack) + sizeof(Fiber), stack_size - sizeof(Fiber))) {
58             c->~Fiber<UsageId, FiberLocal, ThreadLocal>();
59             return nullptr;
60         }
61         return c;
62     }
63 
DestroyFiber64     inline void Destroy()
65     {
66         this->~Fiber<UsageId, FiberLocal, ThreadLocal>();
67     }
68 
StartFiber69     bool Start()
70     {
71         bool currentDone;
72         auto& e = Fiber::Env();
73 
74         do {
75             e.cond = nullptr;
76             e.cur = this;
77             ffrt_fiber_switch(&link, &fb);
78             currentDone = this->done;
79         } while (e.cond && !(e.cond)(this));
80         e.cond = nullptr;
81         return currentDone;
82     }
83 
84     template<bool is_final = false>
85     static inline void Suspend(ThreadEnv& e, bool (*cond)(void*) = nullptr)
86     {
87         auto j = e.cur;
88         if constexpr(is_final) {
89             j->done = true;
90         } else {
91             e.cond = cond;
92         }
93         e.cur = nullptr;
94 
95         ffrt_fiber_switch(&j->fb, &j->link);
96     }
97 
98     template<bool is_final = false>
99     static inline void Suspend(bool (*cond)(void*) = nullptr)
100     {
101         Suspend<is_final>(Fiber::Env(), cond);
102     }
103 
LocalFiber104     FiberLocal& Local()
105     {
106         return local_;
107     }
108 
109     uint64_t id;
110 
111     static constexpr uint64_t minStackSize = 32;
112 
FiberFiber113     Fiber(std::function<void()>&& f)
114     {
115         fn = std::forward<std::function<void()>>(f);
116         id = idx.fetch_add(1, std::memory_order_relaxed);
117     }
118 
FiberEntryFiber119     static void FiberEntry(Fiber* c)
120     {
121         c->fn();
122         c->fn = nullptr;
123         Suspend<true>();
124     }
125 
126     ffrt_fiber_t fb;
127     ffrt_fiber_t link;
128     std::function<void()> fn;
129     bool done = false;
130     FiberLocal local_;
131     static inline std::atomic_uint64_t idx{0};
132 };
133 }
134 #endif