1 /** 2 * Copyright (c) 2021-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_MONITOR_H_ 16 #define PANDA_RUNTIME_MONITOR_H_ 17 18 #include <atomic> 19 #include <optional> 20 21 #include "libpandabase/os/mutex.h" 22 #include "libpandabase/utils/list.h" 23 #include "libpandabase/utils/logger.h" 24 #include "runtime/include/thread_status.h" 25 26 namespace ark { 27 28 class MTManagedThread; 29 class ObjectHeader; 30 template <class T> 31 class VMHandle; 32 class MarkWord; 33 class MonitorPool; 34 35 /// To avoid inheritance in the `Thread` class we don't use `List` (it forces list element to inherit `ListNode`). 36 template <typename T> 37 class ThreadList { 38 public: Empty()39 bool Empty() const 40 { 41 return head_ == nullptr; 42 } 43 Front()44 T &Front() 45 { 46 return *head_; 47 } 48 49 void PopFront(); 50 51 void PushFront(T &thread); 52 53 void EraseAfter(T *prev, T *current); 54 Swap(ThreadList & other)55 void Swap(ThreadList &other) 56 { 57 std::swap(head_, other.head_); 58 } 59 60 void Splice(ThreadList &other); 61 Clear()62 void Clear() 63 { 64 head_ = nullptr; 65 } 66 67 template <typename Predicate> 68 bool RemoveIf(Predicate pred); 69 70 private: 71 T *head_ {nullptr}; 72 }; 73 74 // NOTE(aWX851037): open questions for implementation: 75 // 1. Should we reset the state to unlocked from heavyweight lock? 76 // Potential benefit: less memory consumption and usage of lightweight locks 77 // Potential drawback: infrustructure to detect, when the monitor is not acquired by any thread and time for repeated 78 // inflation 79 // 2. If the state should be reseted, when it should be done? 80 // Potential targets: after monitor release check the owners of monitors, 81 // special request, for instance, from GC. 82 // 3. Do we really need try locks? 83 // 4. Is it useful to return ObjectHeader from monitorenter/exit? Right now it is enough to return bool value. 84 85 class Monitor { 86 public: 87 using MonitorId = uintptr_t; 88 89 enum State { 90 OK, 91 INTERRUPTED, 92 ILLEGAL, 93 }; 94 GetId()95 MonitorId GetId() const 96 { 97 return id_; 98 } 99 100 PANDA_PUBLIC_API static Monitor::State MonitorEnter(ObjectHeader *obj, bool trylock = false); 101 102 static void InflateThinLock(MTManagedThread *thread, const VMHandle<ObjectHeader> &obj); 103 104 PANDA_PUBLIC_API static Monitor::State MonitorExit(ObjectHeader *obj); 105 106 /** 107 * Static call which attempts to wait until timeout, interrupt, or notification. 108 * 109 * @param obj an object header of corresponding object 110 * @param status status to be set up during wait 111 * @param timeout waiting time in milliseconds 112 * @param nanos additional time in nanoseconds 113 * @param ignore_interruption ignore interruption event or not 114 * @return true if it was interrupted; false otherwise 115 */ 116 PANDA_PUBLIC_API static State Wait(ObjectHeader *obj, ThreadStatus status, uint64_t timeout, uint64_t nanos, 117 bool ignoreInterruption = false); 118 119 static State Notify(ObjectHeader *obj); 120 121 static State NotifyAll(ObjectHeader *obj); 122 123 /** 124 * Static call which attempts to inflate object lock (lightweight/unlocked) and acquires its lock if it's 125 * successful. Provides no guarantees on object having heavy lock unless it returns true. 126 * 127 * @param obj an object header of corresponding object 128 * @param thread pointer to thread which will acquire the monitor. 129 * @tparam for_other_thread include logic for inflation of monitor owned by other thread. Should be used 130 * only in futex build. 131 * @return true if new monitor was successfuly created and object's markword updated with monitor's ID; 132 * false otherwise 133 */ 134 template <bool FOR_OTHER_THREAD = false> 135 static bool Inflate(ObjectHeader *obj, MTManagedThread *thread); 136 137 /** 138 * Static call which attempts to deflate object's heavy lock if it's present and unlocked. 139 * Ignores object if it doesn't have heavy lock. 140 * 141 * @param obj an object header of corresponding object 142 * @return true if object's monitor was found, acquired and freed; false otherwise 143 */ 144 static bool Deflate(ObjectHeader *obj); 145 146 PANDA_PUBLIC_API static uint8_t HoldsLock(ObjectHeader *obj); 147 148 static uint32_t GetLockOwnerOsThreadID(ObjectHeader *obj); 149 150 static Monitor *GetMonitorFromObject(ObjectHeader *obj); 151 152 static void TraceMonitorLock(ObjectHeader *obj, bool isWait); 153 154 static void TraceMonitorUnLock(); 155 156 // NO_THREAD_SAFETY_ANALYSIS for monitor->lock_ 157 // Some more information in the issue #1662 158 bool Release(MTManagedThread *thread) NO_THREAD_SAFETY_ANALYSIS; 159 160 uint32_t GetHashCode(); 161 162 bool HasHashCode() const; 163 164 void SetHashCode(uint32_t hash); 165 SetObject(ObjectHeader * object)166 void SetObject(ObjectHeader *object) 167 { 168 obj_ = object; 169 } 170 GetObject()171 ObjectHeader *GetObject() 172 { 173 return obj_; 174 } 175 176 // Public constructor is needed for allocator Monitor(MonitorId id)177 explicit Monitor(MonitorId id) : id_(id), owner_(), hashCode_(0), waitersCounter_(0) 178 { 179 // Atomic with relaxed order reason: memory access in monitor 180 owner_.store(nullptr, std::memory_order_relaxed); 181 } 182 183 private: 184 MonitorId id_; 185 ObjectHeader *obj_ {nullptr}; // Used for GC deflation 186 std::atomic<MTManagedThread *> owner_; 187 // These are two lists, which are linked with nextThread 188 // Be careful when changing these two lists to other types, or changing List implementation, 189 // current Monitor::Notify implementation relies on the fact that reference to MTManagedThread is still valid 190 // when PopFront is called. 191 ThreadList<MTManagedThread> waiters_; 192 ThreadList<MTManagedThread> toWakeup_; 193 uint64_t recursiveCounter_ {0}; 194 os::memory::Mutex lock_; 195 std::atomic<uint32_t> hashCode_; 196 std::atomic<uint32_t> waitersCounter_; 197 198 // NO_THREAD_SAFETY_ANALYSIS for monitor->lock_ 199 // Some more information in the issue #1662 200 bool Acquire(MTManagedThread *thread, const VMHandle<ObjectHeader> &objHandle, 201 bool trylock) NO_THREAD_SAFETY_ANALYSIS; 202 203 void Acquire(MTManagedThread *thread, const VMHandle<ObjectHeader> &objHandle) NO_THREAD_SAFETY_ANALYSIS; 204 205 void InitWithOwner(MTManagedThread *thread, ObjectHeader *obj) NO_THREAD_SAFETY_ANALYSIS; 206 207 void ReleaseOnFailedInflate(MTManagedThread *thread) NO_THREAD_SAFETY_ANALYSIS; 208 SetOwner(MTManagedThread * expected,MTManagedThread * thread)209 bool SetOwner(MTManagedThread *expected, MTManagedThread *thread) 210 { 211 return owner_.compare_exchange_strong(expected, thread); 212 } 213 214 static std::optional<Monitor::State> HandleLightLockedState(MarkWord &mark, MTManagedThread *thread, 215 VMHandle<ObjectHeader> &objHandle, 216 uint32_t &lightlockRetryCount, 217 [[maybe_unused]] bool &shouldInflate, bool trylock); 218 219 static std::optional<Monitor::State> HandleUnlockedState(MarkWord &mark, MTManagedThread *thread, 220 VMHandle<ObjectHeader> &objHandle, bool &shouldInflate, 221 bool trylock); 222 223 static Monitor::State HandleHeavyLockedState(Monitor *monitor, MTManagedThread *thread, 224 VMHandle<ObjectHeader> &objHandle, bool trylock); 225 GetOwner()226 MTManagedThread *GetOwner() 227 { 228 // Atomic with relaxed order reason: memory access in monitor 229 return owner_.load(std::memory_order_relaxed); 230 } 231 232 bool DeflateInternal(); 233 234 static bool TryAddMonitor(Monitor *monitor, MarkWord &oldMark, MTManagedThread *thread, ObjectHeader *obj, 235 MonitorPool *monitorPool); 236 237 static State WaitWithHeavyLockedState(MTManagedThread *thread, VMHandle<ObjectHeader> &objHandle, MarkWord &mark, 238 ThreadStatus status, uint64_t timeout, uint64_t nanos, 239 bool ignoreInterruption); 240 241 friend class MonitorPool; 242 }; 243 244 } // namespace ark 245 246 #endif // PANDA_RUNTIME_MONITOR_H_ 247