1 /** 2 * Copyright (c) 2022-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 #ifndef PANDA_RUNTIME_COROUTINES_THREADED_COROUTINE_MANAGER_H 16 #define PANDA_RUNTIME_COROUTINES_THREADED_COROUTINE_MANAGER_H 17 18 #include "libpandabase/os/mutex.h" 19 #include "runtime/coroutines/coroutine_manager.h" 20 #include "runtime/coroutines/coroutine.h" 21 #include "runtime/coroutines/priority_queue.h" 22 #include "runtime/include/value.h" 23 24 namespace ark { 25 26 /** 27 * @brief Thread-based coroutine manager implementation. 28 * 29 * In this implementation coroutines are OS threads. The invariants (only N coroutines are running simultaniously, etc.) 30 * are kept with the help of mutexes and condition variables. 31 * 32 * For interface function descriptions see CoroutineManager class declaration. 33 */ 34 class ThreadedCoroutineManager : public CoroutineManager { 35 public: 36 NO_COPY_SEMANTIC(ThreadedCoroutineManager); 37 NO_MOVE_SEMANTIC(ThreadedCoroutineManager); 38 ThreadedCoroutineManager(CoroutineFactory factory)39 explicit ThreadedCoroutineManager(CoroutineFactory factory) : CoroutineManager(factory) {} 40 ~ThreadedCoroutineManager() override = default; 41 42 /* CoroutineManager interfaces, see CoroutineManager class for the details */ 43 void Initialize(CoroutineManagerConfig config, Runtime *runtime, PandaVM *vm) override; 44 void Finalize() override; 45 void RegisterCoroutine(Coroutine *co) override; 46 bool TerminateCoroutine(Coroutine *co) override; 47 bool Launch(CompletionEvent *completionEvent, Method *entrypoint, PandaVector<Value> &&arguments, 48 CoroutineLaunchMode mode, CoroutinePriority priority, bool abortFlag) override; 49 bool LaunchImmediately(CompletionEvent *completionEvent, Method *entrypoint, PandaVector<Value> &&arguments, 50 CoroutineLaunchMode mode, CoroutinePriority priority, bool abortFlag) override; 51 bool LaunchNative(NativeEntrypointFunc epFunc, void *param, PandaString coroName, CoroutineLaunchMode mode, 52 CoroutinePriority priority, bool abortFlag) override; 53 void Schedule() override; 54 void Await(CoroutineEvent *awaitee) RELEASE(awaitee) override; 55 void UnblockWaiters(CoroutineEvent *blocker) override; PreZygoteFork()56 void PreZygoteFork() override {}; PostZygoteFork()57 void PostZygoteFork() override {}; 58 59 /* ThreadManager interfaces, see ThreadManager class for the details */ 60 void WaitForDeregistration() override; 61 void SuspendAllThreads() override; 62 void ResumeAllThreads() override; 63 bool IsRunningThreadExist() override; 64 65 /* debugging tools */ 66 /** 67 * For ThreadedCoroutineManager implementation: no action performed if an attempt to switch coroutines on current 68 * worker is detected when coroutine switch is disabled. 69 */ DisableCoroutineSwitch()70 void DisableCoroutineSwitch() override {}; EnableCoroutineSwitch()71 void EnableCoroutineSwitch() override {}; IsCoroutineSwitchDisabled()72 bool IsCoroutineSwitchDisabled() override 73 { 74 return false; 75 }; 76 77 bool IsMainWorker(Coroutine *co) const override; 78 79 protected: 80 bool EnumerateThreadsImpl(const ThreadManager::Callback &cb, unsigned int incMask, 81 unsigned int xorMask) const override; 82 CoroutineContext *CreateCoroutineContext(bool coroHasEntrypoint) override; 83 void DeleteCoroutineContext(CoroutineContext *ctx) override; 84 85 size_t GetCoroutineCount() override; 86 size_t GetCoroutineCountLimit() override; 87 88 /// @return number of coroutines that can execute simultaniously 89 uint32_t GetActiveWorkersCount() const; 90 /** 91 * Create the required number of worker instances. They are required only for the interface 92 * level compatibility with other parts of the runtime. 93 */ 94 void CreateWorkers(size_t howMany, Runtime *runtime, PandaVM *vm) REQUIRES(workersLock_) override; 95 CoroutineWorker *ChooseWorkerForCoroutine([[maybe_unused]] Coroutine *co); 96 97 private: 98 bool LaunchImpl(EntrypointInfo &&epInfo, PandaString &&coroName, CoroutinePriority priority, 99 bool startSuspended = true); 100 void ScheduleImpl(); 101 void UnblockWaitersImpl(CoroutineEvent *blocker) REQUIRES(coroSwitchLock_); 102 103 /* runnables queue management */ 104 void PushToRunnableQueue(Coroutine *co, CoroutinePriority priority); 105 Coroutine *PopFromRunnableQueue(); 106 #ifndef NDEBUG 107 void PrintRunnableQueue(const PandaString &requester); 108 #endif 109 bool RunnableCoroutinesExist(); 110 111 /* coroutine registry management */ 112 void AddToRegistry(Coroutine *co) REQUIRES(coroListLock_); 113 void RemoveFromRegistry(Coroutine *co) REQUIRES(coroListLock_); 114 115 void DeleteCoroutineInstance(Coroutine *co); 116 bool RegisterWaiter(Coroutine *waiter, CoroutineEvent *awaitee) RELEASE(awaitee); 117 void ScheduleNextCoroutine(); 118 void MainCoroutineCompleted(); 119 120 os::memory::Mutex coroSwitchLock_; 121 os::memory::Mutex waitersLock_; 122 mutable os::memory::Mutex coroListLock_; 123 // all registered coros 124 PandaSet<Coroutine *> coroutines_ GUARDED_BY(coroListLock_); 125 // ready coros 126 PriorityQueue runnablesQueue_; 127 // blocked coros: Coroutine AWAITS CoroutineEvent 128 PandaMap<CoroutineEvent *, Coroutine *> waiters_; 129 130 os::memory::ConditionVariable cvAwaitAll_; 131 os::memory::Mutex cvAwaitAllMutex_; 132 133 // worker related members 134 PandaVector<CoroutineWorker *> workers_ GUARDED_BY(workersLock_); 135 size_t activeWorkersCount_ GUARDED_BY(workersLock_) = 0; 136 mutable os::memory::RecursiveMutex workersLock_; 137 mutable os::memory::ConditionVariable workersCv_; 138 139 // main is running from the very beginning 140 std::atomic_uint32_t runningCorosCount_ = 1; 141 std::atomic_uint32_t coroutineCount_ = 0; 142 }; 143 144 } // namespace ark 145 146 #endif /* PANDA_RUNTIME_COROUTINES_THREADED_COROUTINE_MANAGER_H */ 147