| /* |
| * Copyright (C) 2011 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #ifndef ART_RUNTIME_BASE_LOCKS_H_ |
| #define ART_RUNTIME_BASE_LOCKS_H_ |
| |
| #include <stdint.h> |
| |
| #include <iosfwd> |
| #include <vector> |
| |
| #include "base/atomic.h" |
| #include "base/macros.h" |
| |
| namespace art { |
| |
| class BaseMutex; |
| class ConditionVariable; |
| class SHARED_LOCKABLE ReaderWriterMutex; |
| class SHARED_LOCKABLE MutatorMutex; |
| class LOCKABLE Mutex; |
| class Thread; |
| |
| // LockLevel is used to impose a lock hierarchy [1] where acquisition of a Mutex at a higher or |
| // equal level to a lock a thread holds is invalid. The lock hierarchy achieves a cycle free |
| // partial ordering and thereby cause deadlock situations to fail checks. |
| // |
| // [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163 |
| enum LockLevel : uint8_t { |
| kLoggingLock = 0, |
| kSwapMutexesLock, |
| kUnexpectedSignalLock, |
| kThreadSuspendCountLock, |
| kAbortLock, |
| kJniIdLock, |
| kNativeDebugInterfaceLock, |
| kSignalHandlingLock, |
| // A generic lock level for mutexes that should not allow any additional mutexes to be gained |
| // after acquiring it. |
| kGenericBottomLock, |
| // Tracks the second acquisition at the same lock level for kThreadWaitLock. This is an exception |
| // to the normal lock ordering, used to implement Monitor::Wait - while holding one kThreadWait |
| // level lock, it is permitted to acquire a second one - with internal safeguards to ensure that |
| // the second lock acquisition does not result in deadlock. This is implemented in the lock |
| // order by treating the second acquisition of a kThreadWaitLock as a kThreadWaitWakeLock |
| // acquisition. Thus, acquiring kThreadWaitWakeLock requires holding kThreadWaitLock. This entry |
| // is here near the bottom of the hierarchy because other locks should not be |
| // acquired while it is held. kThreadWaitLock cannot be moved here because GC |
| // activity acquires locks while holding the wait lock. |
| kThreadWaitWakeLock, |
| kJdwpAdbStateLock, |
| kJdwpSocketLock, |
| kRegionSpaceRegionLock, |
| kMarkSweepMarkStackLock, |
| // Can be held while GC related work is done, and thus must be above kMarkSweepMarkStackLock |
| kThreadWaitLock, |
| kCHALock, |
| kJitCodeCacheLock, |
| kRosAllocGlobalLock, |
| kRosAllocBracketLock, |
| kRosAllocBulkFreeLock, |
| kAllocSpaceLock, |
| kTaggingLockLevel, |
| kTransactionLogLock, |
| kCustomTlsLock, |
| kJniFunctionTableLock, |
| kJniWeakGlobalsLock, |
| kJniGlobalsLock, |
| kReferenceQueueSoftReferencesLock, |
| kReferenceQueuePhantomReferencesLock, |
| kReferenceQueueFinalizerReferencesLock, |
| kReferenceQueueWeakReferencesLock, |
| kReferenceQueueClearedReferencesLock, |
| kReferenceProcessorLock, |
| kJitDebugInterfaceLock, |
| kBumpPointerSpaceBlockLock, |
| kArenaPoolLock, |
| kInternTableLock, |
| kOatFileSecondaryLookupLock, |
| kHostDlOpenHandlesLock, |
| kVerifierDepsLock, |
| kOatFileManagerLock, |
| kTracingUniqueMethodsLock, |
| kTracingStreamingLock, |
| kJniLoadLibraryLock, |
| kClassLoaderClassesLock, |
| kDefaultMutexLevel, |
| kDexCacheLock, |
| kDexLock, |
| kMarkSweepLargeObjectLock, |
| kJdwpObjectRegistryLock, |
| kModifyLdtLock, |
| kAllocatedThreadIdsLock, |
| kMonitorPoolLock, |
| kClassLinkerClassesLock, // TODO rename. |
| kSubtypeCheckLock, |
| kBreakpointLock, |
| // This is a generic lock level for a lock meant to be gained after having a |
| // monitor lock. |
| kPostMonitorLock, |
| kMonitorLock, |
| kMonitorListLock, |
| kThreadListLock, |
| kAllocTrackerLock, |
| kDeoptimizationLock, |
| kProfilerLock, |
| kJdwpShutdownLock, |
| kJdwpEventListLock, |
| kJdwpAttachLock, |
| kJdwpStartLock, |
| kRuntimeThreadPoolLock, |
| kRuntimeShutdownLock, |
| kTraceLock, |
| kHeapBitmapLock, |
| |
| // This is a generic lock level for a top-level lock meant to be gained after having the |
| // mutator_lock_. |
| kPostMutatorTopLockLevel, |
| |
| kMutatorLock, |
| kInstrumentEntrypointsLock, |
| // This is a generic lock level for a top-level lock meant to be gained after having the |
| // UserCodeSuspensionLock. |
| kPostUserCodeSuspensionTopLevelLock, |
| kUserCodeSuspensionLock, |
| kZygoteCreationLock, |
| |
| // The highest valid lock level. Use this if there is code that should only be called with no |
| // other locks held. Since this is the highest lock level we also allow it to be held even if the |
| // runtime or current thread is not fully set-up yet (for example during thread attach). Note that |
| // this lock also has special behavior around the mutator_lock_. Since the mutator_lock_ is not |
| // really a 'real' lock we allow this to be locked when the mutator_lock_ is held exclusive. |
| // Furthermore, the mutator_lock_ may not be acquired in any form when a lock of this level is |
| // held. Since the mutator_lock_ being held strong means that all other threads are suspended this |
| // will prevent deadlocks while still allowing this lock level to function as a "highest" level. |
| kTopLockLevel, |
| |
| kLockLevelCount // Must come last. |
| }; |
| std::ostream& operator<<(std::ostream& os, LockLevel rhs); |
| |
| // For StartNoThreadSuspension and EndNoThreadSuspension. |
| class CAPABILITY("role") Role { |
| public: |
| void Acquire() ACQUIRE() {} |
| void Release() RELEASE() {} |
| const Role& operator!() const { return *this; } |
| }; |
| |
| class Uninterruptible : public Role { |
| }; |
| |
| // Global mutexes corresponding to the levels above. |
| class Locks { |
| public: |
| static void Init(); |
| static void InitConditions() NO_THREAD_SAFETY_ANALYSIS; // Condition variables. |
| |
| // Destroying various lock types can emit errors that vary depending upon |
| // whether the client (art::Runtime) is currently active. Allow the client |
| // to set a callback that is used to check when it is acceptable to call |
| // Abort. The default behavior is that the client *is not* able to call |
| // Abort if no callback is established. |
| using ClientCallback = bool(); |
| static void SetClientCallback(ClientCallback* is_safe_to_call_abort_cb) NO_THREAD_SAFETY_ANALYSIS; |
| // Checks for whether it is safe to call Abort() without using locks. |
| static bool IsSafeToCallAbortRacy() NO_THREAD_SAFETY_ANALYSIS; |
| |
| // Add a mutex to expected_mutexes_on_weak_ref_access_. |
| static void AddToExpectedMutexesOnWeakRefAccess(BaseMutex* mutex, bool need_lock = true); |
| // Remove a mutex from expected_mutexes_on_weak_ref_access_. |
| static void RemoveFromExpectedMutexesOnWeakRefAccess(BaseMutex* mutex, bool need_lock = true); |
| // Check if the given mutex is in expected_mutexes_on_weak_ref_access_. |
| static bool IsExpectedOnWeakRefAccess(BaseMutex* mutex); |
| |
| // Guards code that deals with user-code suspension. This mutex must be held when suspending or |
| // resuming threads with SuspendReason::kForUserCode. It may be held by a suspended thread, but |
| // only if the suspension is not due to SuspendReason::kForUserCode. |
| static Mutex* user_code_suspension_lock_; |
| |
| // Guards allocation entrypoint instrumenting. |
| static Mutex* instrument_entrypoints_lock_ ACQUIRED_AFTER(user_code_suspension_lock_); |
| |
| // A barrier is used to synchronize the GC/Debugger thread with mutator threads. When GC/Debugger |
| // thread wants to suspend all mutator threads, it needs to wait for all mutator threads to pass |
| // a barrier. Threads that are already suspended will get their barrier passed by the GC/Debugger |
| // thread; threads in the runnable state will pass the barrier when they transit to the suspended |
| // state. GC/Debugger thread will be woken up when all mutator threads are suspended. |
| // |
| // Thread suspension: |
| // mutator thread | GC/Debugger |
| // .. running .. | .. running .. |
| // .. running .. | Request thread suspension by: |
| // .. running .. | - acquiring thread_suspend_count_lock_ |
| // .. running .. | - incrementing Thread::suspend_count_ on |
| // .. running .. | all mutator threads |
| // .. running .. | - releasing thread_suspend_count_lock_ |
| // .. running .. | Block wait for all threads to pass a barrier |
| // Poll Thread::suspend_count_ and enter full | .. blocked .. |
| // suspend code. | .. blocked .. |
| // Change state to kSuspended (pass the barrier) | Wake up when all threads pass the barrier |
| // x: Acquire thread_suspend_count_lock_ | .. running .. |
| // while Thread::suspend_count_ > 0 | .. running .. |
| // - wait on Thread::resume_cond_ | .. running .. |
| // (releases thread_suspend_count_lock_) | .. running .. |
| // .. waiting .. | Request thread resumption by: |
| // .. waiting .. | - acquiring thread_suspend_count_lock_ |
| // .. waiting .. | - decrementing Thread::suspend_count_ on |
| // .. waiting .. | all mutator threads |
| // .. waiting .. | - notifying on Thread::resume_cond_ |
| // - re-acquire thread_suspend_count_lock_ | - releasing thread_suspend_count_lock_ |
| // Release thread_suspend_count_lock_ | .. running .. |
| // Change to kRunnable | .. running .. |
| // - this uses a CAS operation to ensure the | .. running .. |
| // suspend request flag isn't raised as the | .. running .. |
| // state is changed | .. running .. |
| // - if the CAS operation fails then goto x | .. running .. |
| // .. running .. | .. running .. |
| static MutatorMutex* mutator_lock_ ACQUIRED_AFTER(instrument_entrypoints_lock_); |
| |
| // Allow reader-writer mutual exclusion on the mark and live bitmaps of the heap. |
| static ReaderWriterMutex* heap_bitmap_lock_ ACQUIRED_AFTER(mutator_lock_); |
| |
| // Guards shutdown of the runtime. |
| static Mutex* runtime_shutdown_lock_ ACQUIRED_AFTER(heap_bitmap_lock_); |
| |
| // Runtime thread pool lock. |
| static Mutex* runtime_thread_pool_lock_ ACQUIRED_AFTER(runtime_shutdown_lock_); |
| |
| // Guards background profiler global state. |
| static Mutex* profiler_lock_ ACQUIRED_AFTER(runtime_thread_pool_lock_); |
| |
| // Guards trace (ie traceview) requests. |
| static Mutex* trace_lock_ ACQUIRED_AFTER(profiler_lock_); |
| |
| // Guards debugger recent allocation records. |
| static Mutex* alloc_tracker_lock_ ACQUIRED_AFTER(trace_lock_); |
| |
| // Guards updates to instrumentation to ensure mutual exclusion of |
| // events like deoptimization requests. |
| // TODO: improve name, perhaps instrumentation_update_lock_. |
| static Mutex* deoptimization_lock_ ACQUIRED_AFTER(alloc_tracker_lock_); |
| |
| // Guard the update of the SubtypeCheck data stores in each Class::status_ field. |
| // This lock is used in SubtypeCheck methods which are the interface for |
| // any SubtypeCheck-mutating methods. |
| // In Class::IsSubClass, the lock is not required since it does not update the SubtypeCheck data. |
| static Mutex* subtype_check_lock_ ACQUIRED_AFTER(deoptimization_lock_); |
| |
| // The thread_list_lock_ guards ThreadList::list_. It is also commonly held to stop threads |
| // attaching and detaching. |
| static Mutex* thread_list_lock_ ACQUIRED_AFTER(subtype_check_lock_); |
| |
| // Signaled when threads terminate. Used to determine when all non-daemons have terminated. |
| static ConditionVariable* thread_exit_cond_ GUARDED_BY(Locks::thread_list_lock_); |
| |
| // Guards maintaining loading library data structures. |
| static Mutex* jni_libraries_lock_ ACQUIRED_AFTER(thread_list_lock_); |
| |
| // Guards breakpoints. |
| static ReaderWriterMutex* breakpoint_lock_ ACQUIRED_AFTER(jni_libraries_lock_); |
| |
| // Guards lists of classes within the class linker. |
| static ReaderWriterMutex* classlinker_classes_lock_ ACQUIRED_AFTER(breakpoint_lock_); |
| |
| // When declaring any Mutex add DEFAULT_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code |
| // doesn't try to hold a higher level Mutex. |
| #define DEFAULT_MUTEX_ACQUIRED_AFTER ACQUIRED_AFTER(art::Locks::classlinker_classes_lock_) |
| |
| static Mutex* allocated_monitor_ids_lock_ ACQUIRED_AFTER(classlinker_classes_lock_); |
| |
| // Guard the allocation/deallocation of thread ids. |
| static Mutex* allocated_thread_ids_lock_ ACQUIRED_AFTER(allocated_monitor_ids_lock_); |
| |
| // Guards modification of the LDT on x86. |
| static Mutex* modify_ldt_lock_ ACQUIRED_AFTER(allocated_thread_ids_lock_); |
| |
| static ReaderWriterMutex* dex_lock_ ACQUIRED_AFTER(modify_ldt_lock_); |
| |
| static Mutex* dex_cache_lock_ ACQUIRED_AFTER(dex_lock_); |
| |
| // Guards opened oat files in OatFileManager. |
| static ReaderWriterMutex* oat_file_manager_lock_ ACQUIRED_AFTER(dex_lock_); |
| |
| // Guards extra string entries for VerifierDeps. |
| static ReaderWriterMutex* verifier_deps_lock_ ACQUIRED_AFTER(oat_file_manager_lock_); |
| |
| // Guards dlopen_handles_ in DlOpenOatFile. |
| static Mutex* host_dlopen_handles_lock_ ACQUIRED_AFTER(verifier_deps_lock_); |
| |
| // Guards intern table. |
| static Mutex* intern_table_lock_ ACQUIRED_AFTER(host_dlopen_handles_lock_); |
| |
| // Guards reference processor. |
| static Mutex* reference_processor_lock_ ACQUIRED_AFTER(intern_table_lock_); |
| |
| // Guards cleared references queue. |
| static Mutex* reference_queue_cleared_references_lock_ ACQUIRED_AFTER(reference_processor_lock_); |
| |
| // Guards weak references queue. |
| static Mutex* reference_queue_weak_references_lock_ ACQUIRED_AFTER(reference_queue_cleared_references_lock_); |
| |
| // Guards finalizer references queue. |
| static Mutex* reference_queue_finalizer_references_lock_ ACQUIRED_AFTER(reference_queue_weak_references_lock_); |
| |
| // Guards phantom references queue. |
| static Mutex* reference_queue_phantom_references_lock_ ACQUIRED_AFTER(reference_queue_finalizer_references_lock_); |
| |
| // Guards soft references queue. |
| static Mutex* reference_queue_soft_references_lock_ ACQUIRED_AFTER(reference_queue_phantom_references_lock_); |
| |
| // Guard accesses to the JNI Global Reference table. |
| static ReaderWriterMutex* jni_globals_lock_ ACQUIRED_AFTER(reference_queue_soft_references_lock_); |
| |
| // Guard accesses to the JNI Weak Global Reference table. |
| static Mutex* jni_weak_globals_lock_ ACQUIRED_AFTER(jni_globals_lock_); |
| |
| // Guard accesses to the JNI function table override. |
| static Mutex* jni_function_table_lock_ ACQUIRED_AFTER(jni_weak_globals_lock_); |
| |
| // Guard accesses to the Thread::custom_tls_. We use this to allow the TLS of other threads to be |
| // read (the reader must hold the ThreadListLock or have some other way of ensuring the thread |
| // will not die in that case though). This is useful for (eg) the implementation of |
| // GetThreadLocalStorage. |
| static Mutex* custom_tls_lock_ ACQUIRED_AFTER(jni_function_table_lock_); |
| |
| // Guard access to any JIT data structure. |
| static Mutex* jit_lock_ ACQUIRED_AFTER(custom_tls_lock_); |
| |
| // Guards Class Hierarchy Analysis (CHA). |
| static Mutex* cha_lock_ ACQUIRED_AFTER(jit_lock_); |
| |
| // When declaring any Mutex add BOTTOM_MUTEX_ACQUIRED_AFTER to use annotalysis to check the code |
| // doesn't try to acquire a higher level Mutex. NB Due to the way the annotalysis works this |
| // actually only encodes the mutex being below jni_function_table_lock_ although having |
| // kGenericBottomLock level is lower than this. |
| #define BOTTOM_MUTEX_ACQUIRED_AFTER ACQUIRED_AFTER(art::Locks::cha_lock_) |
| |
| // Have an exclusive aborting thread. |
| static Mutex* abort_lock_ ACQUIRED_AFTER(custom_tls_lock_); |
| |
| // Allow mutual exclusion when manipulating Thread::suspend_count_. |
| // TODO: Does the trade-off of a per-thread lock make sense? |
| static Mutex* thread_suspend_count_lock_ ACQUIRED_AFTER(abort_lock_); |
| |
| // One unexpected signal at a time lock. |
| static Mutex* unexpected_signal_lock_ ACQUIRED_AFTER(thread_suspend_count_lock_); |
| |
| // Guards the magic global variables used by native tools (e.g. libunwind). |
| static Mutex* native_debug_interface_lock_ ACQUIRED_AFTER(unexpected_signal_lock_); |
| |
| // Guards the data structures responsible for keeping track of the JNI |
| // jmethodID/jfieldID <-> ArtMethod/ArtField mapping when using index-ids. |
| static ReaderWriterMutex* jni_id_lock_ ACQUIRED_AFTER(native_debug_interface_lock_); |
| |
| // Have an exclusive logging thread. |
| static Mutex* logging_lock_ ACQUIRED_AFTER(jni_id_lock_); |
| |
| // List of mutexes that we expect a thread may hold when accessing weak refs. This is used to |
| // avoid a deadlock in the empty checkpoint while weak ref access is disabled (b/34964016). If we |
| // encounter an unexpected mutex on accessing weak refs, |
| // Thread::CheckEmptyCheckpointFromWeakRefAccess will detect it. |
| static std::vector<BaseMutex*> expected_mutexes_on_weak_ref_access_; |
| static Atomic<const BaseMutex*> expected_mutexes_on_weak_ref_access_guard_; |
| class ScopedExpectedMutexesOnWeakRefAccessLock; |
| }; |
| |
| class Roles { |
| public: |
| // Uninterruptible means that the thread may not become suspended. |
| static Uninterruptible uninterruptible_; |
| }; |
| |
| } // namespace art |
| |
| #endif // ART_RUNTIME_BASE_LOCKS_H_ |