• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2023-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.h"
17 #include "runtime/coroutines/coroutine_context.h"
18 #include "runtime/coroutines/coroutine_manager.h"
19 #include "runtime/coroutines/coroutine_events.h"
20 #include "runtime/include/panda_vm.h"
21 
22 namespace ark {
23 
Create(Runtime * runtime,PandaVM * vm,PandaString name,CoroutineContext * context,std::optional<EntrypointInfo> && epInfo)24 Coroutine *Coroutine::Create(Runtime *runtime, PandaVM *vm, PandaString name, CoroutineContext *context,
25                              std::optional<EntrypointInfo> &&epInfo)
26 {
27     mem::InternalAllocatorPtr allocator = runtime->GetInternalAllocator();
28     auto *co = allocator->New<Coroutine>(os::thread::GetCurrentThreadId(), allocator, vm,
29                                          ark::panda_file::SourceLang::PANDA_ASSEMBLY, std::move(name), context,
30                                          std::move(epInfo));
31     co->Initialize();
32     return co;
33 }
34 
Coroutine(ThreadId id,mem::InternalAllocatorPtr allocator,PandaVM * vm,ark::panda_file::SourceLang threadLang,PandaString name,CoroutineContext * context,std::optional<EntrypointInfo> && epInfo)35 Coroutine::Coroutine(ThreadId id, mem::InternalAllocatorPtr allocator, PandaVM *vm,
36                      ark::panda_file::SourceLang threadLang, PandaString name, CoroutineContext *context,
37                      std::optional<EntrypointInfo> &&epInfo)
38     : ManagedThread(id, allocator, vm, Thread::ThreadType::THREAD_TYPE_TASK, threadLang),
39       name_(std::move(name)),
40       context_(context),
41       startSuspended_(epInfo.has_value())
42 {
43     ASSERT(vm != nullptr);
44     ASSERT(context != nullptr);
45     SetEntrypointData(std::move(epInfo));
46     coroutineId_ = static_cast<CoroutineManager *>(GetVM()->GetThreadManager())->AllocateCoroutineId();
47 }
48 
~Coroutine()49 Coroutine::~Coroutine()
50 {
51     static_cast<CoroutineManager *>(GetVM()->GetThreadManager())->FreeCoroutineId(coroutineId_);
52 }
53 
ReInitialize(PandaString name,CoroutineContext * context,std::optional<EntrypointInfo> && epInfo)54 void Coroutine::ReInitialize(PandaString name, CoroutineContext *context, std::optional<EntrypointInfo> &&epInfo)
55 {
56     ASSERT(context != nullptr);
57     name_ = std::move(name);
58     startSuspended_ = epInfo.has_value();
59     context_ = context;
60 
61     SetEntrypointData(std::move(epInfo));
62     context_->AttachToCoroutine(this);
63 }
64 
SetEntrypointData(std::optional<EntrypointInfo> && epInfo)65 void Coroutine::SetEntrypointData(std::optional<EntrypointInfo> &&epInfo)
66 {
67     if (epInfo.has_value()) {
68         auto &info = epInfo.value();
69         if (std::holds_alternative<ManagedEntrypointInfo>(info)) {
70             auto &managedEp = std::get<ManagedEntrypointInfo>(info);
71             entrypoint_.emplace<ManagedEntrypointData>(managedEp.completionEvent, managedEp.entrypoint,
72                                                        std::move(managedEp.arguments));
73         } else if (std::holds_alternative<NativeEntrypointInfo>(info)) {
74             auto &nativeEp = std::get<NativeEntrypointInfo>(info);
75             entrypoint_ = NativeEntrypointData(nativeEp.entrypoint, nativeEp.param);
76         }
77     }
78 }
79 
CleanUp()80 void Coroutine::CleanUp()
81 {
82     ManagedThread::CleanUp();
83     name_ = "";
84     entrypoint_ = std::monostate();
85     startSuspended_ = false;
86     context_->CleanUp();
87 }
88 
~ManagedEntrypointData()89 Coroutine::ManagedEntrypointData::~ManagedEntrypointData()
90 {
91     // delete the event as it is owned by the ManagedEntrypointData instance
92     Runtime::GetCurrent()->GetInternalAllocator()->Delete(completionEvent);
93 }
94 
GetName() const95 PandaString Coroutine::GetName() const
96 {
97     return name_;
98 }
99 
GetCoroutineStatus() const100 Coroutine::Status Coroutine::GetCoroutineStatus() const
101 {
102     return context_->GetStatus();
103 }
104 
SetCoroutineStatus(Coroutine::Status newStatus)105 void Coroutine::SetCoroutineStatus(Coroutine::Status newStatus)
106 {
107     context_->SetStatus(newStatus);
108 }
109 
Destroy()110 void Coroutine::Destroy()
111 {
112     context_->Destroy();
113 }
114 
Initialize()115 void Coroutine::Initialize()
116 {
117     context_->AttachToCoroutine(this);
118     InitForStackOverflowCheck(ManagedThread::STACK_OVERFLOW_RESERVED_SIZE,
119                               ManagedThread::STACK_OVERFLOW_PROTECTED_SIZE);
120 }
121 
RetrieveStackInfo(void * & stackAddr,size_t & stackSize,size_t & guardSize)122 bool Coroutine::RetrieveStackInfo(void *&stackAddr, size_t &stackSize, size_t &guardSize)
123 {
124     if (HasManagedEntrypoint() || HasNativeEntrypoint()) {
125         // has EP and separate native context for its execution
126         return context_->RetrieveStackInfo(stackAddr, stackSize, guardSize);
127     }
128     // does not have EP, executes on OS-provided context and stack
129     return ManagedThread::RetrieveStackInfo(stackAddr, stackSize, guardSize);
130 }
131 
RequestSuspend(bool getsBlocked)132 void Coroutine::RequestSuspend(bool getsBlocked)
133 {
134     context_->RequestSuspend(getsBlocked);
135 }
136 
RequestResume()137 void Coroutine::RequestResume()
138 {
139     context_->RequestResume();
140 }
141 
RequestUnblock()142 void Coroutine::RequestUnblock()
143 {
144     context_->RequestUnblock();
145 }
146 
RequestCompletion(Value returnValue)147 void Coroutine::RequestCompletion([[maybe_unused]] Value returnValue)
148 {
149     auto *e = GetCompletionEvent();
150     e->Happen();
151 }
152 
operator <<(std::ostream & os,Coroutine::Status status)153 std::ostream &operator<<(std::ostream &os, Coroutine::Status status)
154 {
155     switch (status) {
156         case Coroutine::Status::CREATED:
157             os << "CREATED";
158             break;
159         case Coroutine::Status::RUNNABLE:
160             os << "RUNNABLE";
161             break;
162         case Coroutine::Status::RUNNING:
163             os << "RUNNING";
164             break;
165         case Coroutine::Status::BLOCKED:
166             os << "BLOCKED";
167             break;
168         case Coroutine::Status::TERMINATING:
169             os << "TERMINATING";
170             break;
171         case Coroutine::Status::AWAIT_LOOP:
172             os << "AWAIT_LOOP";
173             break;
174         default:
175             break;
176     }
177     return os;
178 }
179 
180 }  // namespace ark
181