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