1 /** 2 * Copyright (c) 2023 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_COROUTINE_EVENTS_H 16 #define PANDA_RUNTIME_COROUTINES_COROUTINE_EVENTS_H 17 18 #include "runtime/include/runtime.h" 19 #include "runtime/mem/refstorage/reference.h" 20 21 namespace panda { 22 23 /** 24 * @brief The base class for coroutine events. Cannot be instantiated directly. 25 * 26 * These events are used to implement blocking and unblocking the coroutines that are waiting for something. 27 * The lifetime of an event is intended to be managed manually or be bound to its owner lifetime (e.g. coroutine). 28 */ 29 class CAPABILITY("mutex") CoroutineEvent { 30 public: 31 NO_COPY_SEMANTIC(CoroutineEvent); 32 NO_MOVE_SEMANTIC(CoroutineEvent); 33 34 enum class Type { NONE, GENERIC, COMPLETION, CHANNEL, IO }; 35 ~CoroutineEvent()36 virtual ~CoroutineEvent() 37 { 38 if (IsLocked()) { 39 Unlock(); 40 } 41 Runtime::GetCurrent()->GetInternalAllocator()->Delete(mutex_); 42 }; 43 GetType()44 Type GetType() 45 { 46 return type_; 47 } 48 Happened()49 bool Happened() REQUIRES(this) 50 { 51 return happened_; 52 } 53 SetHappened()54 void SetHappened() 55 { 56 Lock(); 57 happened_ = true; 58 Unlock(); 59 } 60 SetNotHappened()61 void SetNotHappened() 62 { 63 Lock(); 64 happened_ = false; 65 Unlock(); 66 } 67 Lock()68 void Lock() ACQUIRE() 69 { 70 mutex_->Lock(); 71 locked_ = true; 72 } 73 Unlock()74 void Unlock() RELEASE() 75 { 76 locked_ = false; 77 mutex_->Unlock(); 78 } 79 80 protected: CoroutineEvent(Type t)81 explicit CoroutineEvent(Type t) : type_(t) 82 { 83 mutex_ = Runtime::GetCurrent()->GetInternalAllocator()->New<os::memory::Mutex>(); 84 } 85 IsLocked()86 bool IsLocked() 87 { 88 return locked_; 89 } 90 91 private: 92 Type type_ = Type::NONE; 93 bool happened_ GUARDED_BY(this) = false; 94 bool locked_ = false; 95 96 os::memory::Mutex *mutex_; 97 }; 98 99 /** 100 * @brief The generic event: just some event that can be awaited. 101 * 102 * The only thing that it can do: it can happen. 103 */ 104 class GenericEvent : public CoroutineEvent { 105 public: 106 NO_COPY_SEMANTIC(GenericEvent); 107 NO_MOVE_SEMANTIC(GenericEvent); 108 GenericEvent()109 explicit GenericEvent() : CoroutineEvent(Type::GENERIC) {} 110 ~GenericEvent() override = default; 111 112 private: 113 }; 114 115 /// @brief The coroutine completion event: happens when coroutine is done executing its bytecode. 116 class CompletionEvent : public CoroutineEvent { 117 public: 118 NO_COPY_SEMANTIC(CompletionEvent); 119 NO_MOVE_SEMANTIC(CompletionEvent); 120 121 /** 122 * @param promise A weak reference (from global storage) to the language-dependent promise object that will hold 123 * the coroutine return value. 124 */ CompletionEvent(mem::Reference * promise)125 explicit CompletionEvent(mem::Reference *promise) : CoroutineEvent(Type::COMPLETION), promise_(promise) {} 126 ~CompletionEvent() override = default; 127 GetPromise()128 mem::Reference *GetPromise() 129 { 130 return promise_; 131 } 132 133 private: 134 mem::Reference *promise_ = nullptr; 135 }; 136 137 } // namespace panda 138 139 #endif /* PANDA_RUNTIME_COROUTINES_COROUTINE_EVENTS_H */