1 /* 2 * Copyright (c) 2021 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 #ifndef PANDA_RUNTIME_MONITOR_H_ 17 #define PANDA_RUNTIME_MONITOR_H_ 18 19 #include <atomic> 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 panda { 27 28 class MTManagedThread; 29 class ObjectHeader; 30 31 /** 32 * To avoid inheritance in the `Thread` class we don't use `List` (it forces list element to inherit `ListNode`). 33 */ 34 template <typename T> 35 class ThreadList { 36 public: Empty()37 bool Empty() const 38 { 39 return head_ == nullptr; 40 } 41 Front()42 T &Front() 43 { 44 return *head_; 45 } 46 47 void PopFront(); 48 49 void PushFront(T &thread); 50 51 void EraseAfter(T *prev, T *current); 52 Swap(ThreadList & other)53 void Swap(ThreadList &other) 54 { 55 std::swap(head_, other.head_); 56 } 57 58 void Splice(ThreadList &other); 59 Clear()60 void Clear() 61 { 62 head_ = nullptr; 63 } 64 65 template <typename Predicate> 66 bool RemoveIf(Predicate pred); 67 68 private: 69 T *head_ {nullptr}; 70 }; 71 72 // 1. Should we reset the state to unlocked from heavyweight lock? 73 // Potential benefit: less memory consumption and usage of lightweight locks 74 // Potential drawback: infrustructure to detect, when the monitor is not acquired by any thread and time for repeated 75 // inflation 76 // 2. If the state should be reseted, when it should be done? 77 // Potential targets: after monitor release check the owners of monitors, 78 // special request, for instance, from GC. 79 // 3. Do we really need try locks? 80 // 4. Is it useful to return ObjectHeader from monitorenter/exit? Right now it is enough to return bool value. 81 82 class Monitor { 83 public: 84 using MonitorId = uintptr_t; 85 86 enum State { 87 OK, 88 INTERRUPTED, 89 ILLEGAL, 90 }; 91 GetId()92 MonitorId GetId() const 93 { 94 return id_; 95 } 96 97 static Monitor::State MonitorEnter(ObjectHeader *obj, bool trylock = false); 98 99 static Monitor::State MonitorExit(ObjectHeader *obj); 100 101 static Monitor::State JniMonitorEnter(ObjectHeader *obj); 102 103 static Monitor::State JniMonitorExit(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 successfully 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 owner_.store(nullptr); 180 } 181 182 ~Monitor() = default; 183 NO_MOVE_SEMANTIC(Monitor); 184 NO_COPY_SEMANTIC(Monitor); 185 186 private: 187 MonitorId id_; 188 ObjectHeader *obj_; // Used for GC deflation 189 std::atomic<MTManagedThread *> owner_; 190 // These are two lists, which are linked with nextThread 191 // Be careful when changind these two lists to other types, or changing List implementation, 192 // current Monitor::Notify implementation relies on the fact that reference to JavaThread is still valid 193 // when PopFront is called. 194 ThreadList<MTManagedThread> waiters_; 195 ThreadList<MTManagedThread> to_wakeup_; 196 uint64_t recursive_counter_; 197 os::memory::Mutex lock_; 198 std::atomic<uint32_t> hash_code_; 199 std::atomic<uint32_t> waiters_counter_; 200 201 // NO_THREAD_SAFETY_ANALYSIS for monitor->lock_ 202 // Some more information in the issue #1662 203 bool Acquire(MTManagedThread *thread, ObjectHeader *obj, bool trylock) 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 GetOwner()214 MTManagedThread *GetOwner() 215 { 216 return owner_.load(std::memory_order_relaxed); 217 } 218 219 bool DeflateInternal(); 220 221 friend class MonitorPool; 222 }; 223 224 } // namespace panda 225 226 #endif // PANDA_RUNTIME_MONITOR_H_ 227