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 <optional>
17 #include "runtime/coroutines/coroutine_manager.h"
18
19 namespace ark {
20
CoroutineManager(CoroutineFactory factory)21 CoroutineManager::CoroutineManager(CoroutineFactory factory) : coFactory_(factory)
22 {
23 ASSERT(factory != nullptr);
24 }
25
CreateMainCoroutine(Runtime * runtime,PandaVM * vm)26 Coroutine *CoroutineManager::CreateMainCoroutine(Runtime *runtime, PandaVM *vm)
27 {
28 CoroutineContext *ctx = CreateCoroutineContext(false);
29 auto *main = coFactory_(runtime, vm, "_main_", ctx, std::nullopt);
30 ASSERT(main != nullptr);
31
32 Coroutine::SetCurrent(main);
33 main->InitBuffers();
34 main->RequestResume();
35 main->NativeCodeBegin();
36
37 SetMainThread(main);
38 return main;
39 }
40
DestroyMainCoroutine()41 void CoroutineManager::DestroyMainCoroutine()
42 {
43 auto *main = static_cast<Coroutine *>(GetMainThread());
44 auto *context = main->GetContext<CoroutineContext>();
45 main->Destroy();
46 Coroutine::SetCurrent(nullptr);
47 Runtime::GetCurrent()->GetInternalAllocator()->Delete(main);
48 DeleteCoroutineContext(context);
49 }
50
CreateEntrypointlessCoroutine(Runtime * runtime,PandaVM * vm,bool makeCurrent,PandaString name)51 Coroutine *CoroutineManager::CreateEntrypointlessCoroutine(Runtime *runtime, PandaVM *vm, bool makeCurrent,
52 PandaString name)
53 {
54 if (GetCoroutineCount() >= GetCoroutineCountLimit()) {
55 // resource limit reached
56 return nullptr;
57 }
58 CoroutineContext *ctx = CreateCoroutineContext(false);
59 if (ctx == nullptr) {
60 // do not proceed if we cannot create a context for the new coroutine
61 return nullptr;
62 }
63 auto *co = coFactory_(runtime, vm, std::move(name), ctx, std::nullopt);
64 ASSERT(co != nullptr);
65 co->InitBuffers();
66 if (makeCurrent) {
67 Coroutine::SetCurrent(co);
68 co->RequestResume();
69 co->NativeCodeBegin();
70 }
71 return co;
72 }
73
DestroyEntrypointlessCoroutine(Coroutine * co)74 void CoroutineManager::DestroyEntrypointlessCoroutine(Coroutine *co)
75 {
76 ASSERT(co != nullptr);
77 ASSERT(!co->HasManagedEntrypoint() && !co->HasNativeEntrypoint());
78
79 auto *context = co->GetContext<CoroutineContext>();
80 co->Destroy();
81 Runtime::GetCurrent()->GetInternalAllocator()->Delete(co);
82 DeleteCoroutineContext(context);
83 }
84
CreateCoroutineInstance(CompletionEvent * completionEvent,Method * entrypoint,PandaVector<Value> && arguments,PandaString name)85 Coroutine *CoroutineManager::CreateCoroutineInstance(CompletionEvent *completionEvent, Method *entrypoint,
86 PandaVector<Value> &&arguments, PandaString name)
87 {
88 if (GetCoroutineCount() >= GetCoroutineCountLimit()) {
89 // resource limit reached
90 return nullptr;
91 }
92 CoroutineContext *ctx = CreateCoroutineContext(true);
93 if (ctx == nullptr) {
94 // do not proceed if we cannot create a context for the new coroutine
95 return nullptr;
96 }
97 // assuming that the main coro is already created and Coroutine::GetCurrent is not nullptr
98 ASSERT(Coroutine::GetCurrent() != nullptr);
99 auto *coro = coFactory_(Runtime::GetCurrent(), Coroutine::GetCurrent()->GetVM(), std::move(name), ctx,
100 Coroutine::ManagedEntrypointInfo {completionEvent, entrypoint, std::move(arguments)});
101 return coro;
102 }
103
DestroyEntrypointfulCoroutine(Coroutine * co)104 void CoroutineManager::DestroyEntrypointfulCoroutine(Coroutine *co)
105 {
106 DeleteCoroutineContext(co->GetContext<CoroutineContext>());
107 Runtime::GetCurrent()->GetInternalAllocator()->Delete(co);
108 }
109
GetCoroutineFactory()110 CoroutineManager::CoroutineFactory CoroutineManager::GetCoroutineFactory()
111 {
112 return coFactory_;
113 }
114
AllocateCoroutineId()115 uint32_t CoroutineManager::AllocateCoroutineId()
116 {
117 // Taken by copy-paste from MTThreadManager. Need to generalize if possible.
118 // NOTE(konstanting, #I67QXC): try to generalize internal ID allocation
119 os::memory::LockHolder lock(idsLock_);
120 for (size_t i = 0; i < coroutineIds_.size(); i++) {
121 lastCoroutineId_ = (lastCoroutineId_ + 1) % coroutineIds_.size();
122 if (!coroutineIds_[lastCoroutineId_]) {
123 coroutineIds_.set(lastCoroutineId_);
124 return lastCoroutineId_ + 1; // 0 is reserved as uninitialized value.
125 }
126 }
127 LOG(FATAL, COROUTINES) << "Out of coroutine ids";
128 UNREACHABLE();
129 }
130
FreeCoroutineId(uint32_t id)131 void CoroutineManager::FreeCoroutineId(uint32_t id)
132 {
133 // Taken by copy-paste from MTThreadManager. Need to generalize if possible.
134 // NOTE(konstanting, #I67QXC): try to generalize internal ID allocation
135 id--; // 0 is reserved as uninitialized value.
136 os::memory::LockHolder lock(idsLock_);
137 ASSERT(coroutineIds_[id]);
138 coroutineIds_.reset(id);
139 }
140
SetSchedulingPolicy(CoroutineSchedulingPolicy policy)141 void CoroutineManager::SetSchedulingPolicy(CoroutineSchedulingPolicy policy)
142 {
143 schedulingPolicy_ = policy;
144 }
145
GetSchedulingPolicy() const146 CoroutineSchedulingPolicy CoroutineManager::GetSchedulingPolicy() const
147 {
148 return schedulingPolicy_;
149 }
150
151 } // namespace ark
152