1 /** 2 * Copyright (c) 2022-2024 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_H 16 #define PANDA_RUNTIME_COROUTINES_THREADED_COROUTINE_H 17 18 #include "runtime/coroutines/coroutine_context.h" 19 20 namespace ark { 21 22 /** 23 * @brief Native context of a coroutine. std::thread-based implementation. 24 * 25 * This implementation utilizes std::thread with condition variables and mutexes 26 * to emulate context switch on suspension. 27 * 28 */ 29 class ThreadedCoroutineContext : public CoroutineContext { 30 public: 31 NO_COPY_SEMANTIC(ThreadedCoroutineContext); 32 NO_MOVE_SEMANTIC(ThreadedCoroutineContext); 33 34 explicit ThreadedCoroutineContext() = default; 35 ~ThreadedCoroutineContext() override = default; 36 37 /** 38 * Prepares the context (including the std::thread object creation) for execution, links it to the managed context 39 * part (Coroutine instance) and registers the created coroutine in the CoroutineManager (in the RUNNABLE status) 40 */ 41 void AttachToCoroutine(Coroutine *co) override; 42 /** 43 * Manually destroys the context. Should be called by the Coroutine instance as a part of main coroutine 44 * destruction. All other coroutines and their contexts are destroyed by the CoroutineManager once the coroutine 45 * entrypoint execution finishes 46 */ 47 void Destroy() override; 48 CleanUp()49 void CleanUp() override {} 50 51 bool RetrieveStackInfo(void *&stackAddr, size_t &stackSize, size_t &guardSize) override; 52 53 /** 54 * Intended to be called from the context of a running thread that is going to be suspended. 55 * Changes status to Status::RUNNABLE or Status::BLOCKED, depending on the suspend 56 * reason. The next step for the caller thread is to call WaitUntilResumed() and block on it. 57 */ 58 void RequestSuspend(bool getsBlocked) override; 59 /** 60 * Resume the suspended coroutine by setting status to Status::RUNNING. 61 * Wakes up the thread that is blocked on WaitUntilResumed() 62 */ 63 void RequestResume() override; 64 /// Unblock the coroutine and set its status to Status::RUNNABLE 65 void RequestUnblock() override; 66 67 /** 68 * Intended to be called from the context of a running coroutine that is going to 69 * launch a new one. Blocks until the created coroutine passes the init sequence. 70 */ 71 void WaitUntilInitialized(); 72 /// Blocks until the coroutine becomes running 73 void WaitUntilResumed(); 74 /// Moves the main coroutine to Status::TERMINATING 75 void MainThreadFinished(); 76 /// Moves the main coroutine to Status::AWAIT_LOOP 77 void EnterAwaitLoop(); 78 79 Coroutine::Status GetStatus() const override; 80 81 protected: 82 void SetStatus(Coroutine::Status newStatus) override; 83 os::thread::NativeHandleType GetCoroutineNativeHandle(); 84 void SetCoroutineNativeHandle(os::thread::NativeHandleType h); 85 86 private: 87 /// std::thread's body 88 static void ThreadProc(ThreadedCoroutineContext *ctx); 89 /** 90 * Notify the waiters that the coroutine has finished its initialization sequence. 91 * Unblocks the thread waiting on the WaitUntilInitialized() 92 */ 93 void InitializationDone(); 94 95 os::memory::ConditionVariable cv_; 96 os::memory::Mutex cvMutex_; 97 os::thread::NativeHandleType nativeHandle_ {}; 98 99 std::atomic<Coroutine::Status> status_ {Coroutine::Status::CREATED}; 100 }; 101 102 } // namespace ark 103 104 #endif // PANDA_RUNTIME_COROUTINES_THREADED_COROUTINE_H 105