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