• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "runtime/coroutines/coroutine_context.h"
17 #include "runtime/include/panda_vm.h"
18 #include "runtime/include/thread_scopes.h"
19 #include "runtime/coroutines/coroutine_manager.h"
20 #include "runtime/coroutines/threaded_coroutine.h"
21 
22 namespace ark {
23 
GetCoroutineNativeHandle()24 os::thread::NativeHandleType ThreadedCoroutineContext::GetCoroutineNativeHandle()
25 {
26     return nativeHandle_;
27 }
28 
SetCoroutineNativeHandle(os::thread::NativeHandleType h)29 void ThreadedCoroutineContext::SetCoroutineNativeHandle(os::thread::NativeHandleType h)
30 {
31     nativeHandle_ = h;
32 }
33 
GetStatus() const34 Coroutine::Status ThreadedCoroutineContext::GetStatus() const
35 {
36     return status_;
37 }
38 
SetStatus(Coroutine::Status newStatus)39 void ThreadedCoroutineContext::SetStatus(Coroutine::Status newStatus)
40 {
41 #ifndef NDEBUG
42     PandaString setter = (Thread::GetCurrent() == nullptr) ? "null" : Coroutine::GetCurrent()->GetName();
43     LOG(DEBUG, COROUTINES) << GetCoroutine()->GetName() << ": " << status_ << " -> " << newStatus << " by " << setter;
44 #endif
45     status_ = newStatus;
46 }
47 
AttachToCoroutine(Coroutine * co)48 void ThreadedCoroutineContext::AttachToCoroutine(Coroutine *co)
49 {
50     CoroutineContext::AttachToCoroutine(co);
51 
52     auto *threadManager = static_cast<CoroutineManager *>(co->GetVM()->GetThreadManager());
53     threadManager->RegisterCoroutine(co);
54     if (co->HasManagedEntrypoint()) {
55         std::thread t(ThreadProc, this);
56         SetCoroutineNativeHandle(t.native_handle());
57         t.detach();
58     } else {
59         // coro has no EP, will execute in the current thread context
60         SetCoroutineNativeHandle(os::thread::GetNativeHandle());
61     }
62 }
63 
Destroy()64 void ThreadedCoroutineContext::Destroy()
65 {
66     auto *co = GetCoroutine();
67     if (co->HasManagedEntrypoint()) {
68         // coroutines with an entry point should not be destroyed manually!
69         UNREACHABLE();
70     }
71     ASSERT(co == Coroutine::GetCurrent());
72     ASSERT(co->GetStatus() != ThreadStatus::FINISHED);
73 
74     co->UpdateStatus(ThreadStatus::TERMINATING);
75 
76     auto *threadManager = static_cast<CoroutineManager *>(co->GetVM()->GetThreadManager());
77     if (threadManager->TerminateCoroutine(co)) {
78         // detach
79         Coroutine::SetCurrent(nullptr);
80     }
81 }
82 
RetrieveStackInfo(void * & stackAddr,size_t & stackSize,size_t & guardSize)83 bool ThreadedCoroutineContext::RetrieveStackInfo(void *&stackAddr, size_t &stackSize, size_t &guardSize)
84 {
85     int error = os::thread::ThreadGetStackInfo(GetCoroutineNativeHandle(), &stackAddr, &stackSize, &guardSize);
86     if (error != 0) {
87         LOG(ERROR, RUNTIME) << "ThreadedCoroutineContext::RetrieveStackInfo: fail to get stack info, error = "
88                             << strerror(errno);
89     }
90     return error == 0;
91 }
92 
93 /*static*/
ThreadProc(ThreadedCoroutineContext * ctx)94 void ThreadedCoroutineContext::ThreadProc(ThreadedCoroutineContext *ctx)
95 {
96     auto *co = ctx->GetCoroutine();
97     auto *threadManager = static_cast<CoroutineManager *>(co->GetVM()->GetThreadManager());
98     Coroutine::SetCurrent(co);
99     UpdateId(os::thread::GetCurrentThreadId(), co);
100     os::thread::SetThreadName(os::thread::GetNativeHandle(), co->GetName().c_str());
101     // NOTE(konstanting, #I67QXC): find a workaround to update ThreadId here
102     co->NativeCodeBegin();
103     {
104         ctx->InitializationDone();
105         if (co->IsSuspendOnStartup()) {
106             ctx->WaitUntilResumed();
107         } else {
108             ctx->SetStatus(Coroutine::Status::RUNNING);
109         }
110 
111         ScopedManagedCodeThread s(co);
112         PandaVector<Value> args = std::move(co->GetManagedEntrypointArguments());
113         LOG(DEBUG, COROUTINES) << "ThreadProc: invoking the EP for coro " << co->GetName();
114         Value res = co->GetManagedEntrypoint()->Invoke(co, args.data());
115         LOG(DEBUG, COROUTINES) << "ThreadProc: invoke() finished for the EP of coro " << co->GetName();
116         co->RequestCompletion(res);
117     }
118     ctx->SetStatus(Coroutine::Status::TERMINATING);
119 
120     if (threadManager->TerminateCoroutine(co)) {
121         Coroutine::SetCurrent(nullptr);
122     }
123 }
124 
WaitUntilInitialized()125 void ThreadedCoroutineContext::WaitUntilInitialized()
126 {
127     os::memory::LockHolder l(cvMutex_);
128     while (GetStatus() != Coroutine::Status::RUNNABLE) {
129         cv_.Wait(&cvMutex_);
130     }
131 }
132 
WaitUntilResumed()133 void ThreadedCoroutineContext::WaitUntilResumed()
134 {
135     os::memory::LockHolder l(cvMutex_);
136     while (GetStatus() != Coroutine::Status::RUNNING) {
137         cv_.Wait(&cvMutex_);
138     }
139 }
140 
InitializationDone()141 void ThreadedCoroutineContext::InitializationDone()
142 {
143     if (GetCoroutine()->IsSuspendOnStartup()) {
144         os::memory::LockHolder l(cvMutex_);
145         SetStatus(Coroutine::Status::RUNNABLE);
146         cv_.Signal();
147     } else {
148         SetStatus(Coroutine::Status::RUNNABLE);
149     }
150 }
151 
RequestSuspend(bool getsBlocked)152 void ThreadedCoroutineContext::RequestSuspend(bool getsBlocked)
153 {
154     os::memory::LockHolder l(cvMutex_);
155     SetStatus(getsBlocked ? Coroutine::Status::BLOCKED : Coroutine::Status::RUNNABLE);
156 }
157 
RequestResume()158 void ThreadedCoroutineContext::RequestResume()
159 {
160     os::memory::LockHolder l(cvMutex_);
161     SetStatus(Coroutine::Status::RUNNING);
162     cv_.Signal();
163 }
164 
RequestUnblock()165 void ThreadedCoroutineContext::RequestUnblock()
166 {
167     SetStatus(Coroutine::Status::RUNNABLE);
168 }
169 
MainThreadFinished()170 void ThreadedCoroutineContext::MainThreadFinished()
171 {
172     SetStatus(Coroutine::Status::TERMINATING);
173 }
174 
EnterAwaitLoop()175 void ThreadedCoroutineContext::EnterAwaitLoop()
176 {
177     SetStatus(Coroutine::Status::AWAIT_LOOP);
178 }
179 
180 }  // namespace ark
181