Remove Mutex dependency from MemMap
Use std::mutex to remove the dependency between MemMap and Mutex/Thread,
which depend upon Runtime. Next step towards making dexdump2 build and
run on Windows.
Bug: 22322814
Test: test-art
Change-Id: Ia6f4ef882dcef516ee83a81e965b3d744ce325b0
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index e05a85a..6e102be 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -49,7 +49,6 @@
Mutex* Locks::jni_function_table_lock_ = nullptr;
Mutex* Locks::jni_libraries_lock_ = nullptr;
Mutex* Locks::logging_lock_ = nullptr;
-Mutex* Locks::mem_maps_lock_ = nullptr;
Mutex* Locks::modify_ldt_lock_ = nullptr;
MutatorMutex* Locks::mutator_lock_ = nullptr;
Mutex* Locks::profiler_lock_ = nullptr;
@@ -1116,10 +1115,6 @@
DCHECK(unexpected_signal_lock_ == nullptr);
unexpected_signal_lock_ = new Mutex("unexpected signal lock", current_lock_level, true);
- UPDATE_CURRENT_LOCK_LEVEL(kMemMapsLock);
- DCHECK(mem_maps_lock_ == nullptr);
- mem_maps_lock_ = new Mutex("mem maps lock", current_lock_level);
-
UPDATE_CURRENT_LOCK_LEVEL(kLoggingLock);
DCHECK(logging_lock_ == nullptr);
logging_lock_ = new Mutex("logging lock", current_lock_level, true);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 21dd437..ffe18c6 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -55,7 +55,6 @@
// [1] http://www.drdobbs.com/parallel/use-lock-hierarchies-to-avoid-deadlock/204801163
enum LockLevel {
kLoggingLock = 0,
- kMemMapsLock,
kSwapMutexesLock,
kUnexpectedSignalLock,
kThreadSuspendCountLock,
@@ -712,9 +711,6 @@
// One unexpected signal at a time lock.
static Mutex* unexpected_signal_lock_ ACQUIRED_AFTER(thread_suspend_count_lock_);
- // Guards the maps in mem_map.
- static Mutex* mem_maps_lock_ ACQUIRED_AFTER(unexpected_signal_lock_);
-
// Have an exclusive logging thread.
static Mutex* logging_lock_ ACQUIRED_AFTER(unexpected_signal_lock_);
};
diff --git a/runtime/mem_map.cc b/runtime/mem_map.cc
index 19a65bb..dce56b3 100644
--- a/runtime/mem_map.cc
+++ b/runtime/mem_map.cc
@@ -70,6 +70,7 @@
return os;
}
+std::mutex* MemMap::mem_maps_lock_ = nullptr;
MemMap::Maps* MemMap::maps_ = nullptr;
#if USE_ART_LOW_4G_ALLOCATOR
@@ -139,7 +140,7 @@
// There is a suspicion that BacktraceMap::Create is occasionally missing maps. TODO: Investigate
// further.
{
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
for (auto& pair : *maps_) {
MemMap* const map = pair.second;
if (begin >= reinterpret_cast<uintptr_t>(map->Begin()) &&
@@ -490,7 +491,7 @@
}
// Remove it from maps_.
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
bool found = false;
DCHECK(maps_ != nullptr);
for (auto it = maps_->lower_bound(base_begin_), end = maps_->end();
@@ -518,7 +519,7 @@
CHECK_NE(base_size_, 0U);
// Add it to maps_.
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
DCHECK(maps_ != nullptr);
maps_->insert(std::make_pair(base_begin_, this));
}
@@ -637,7 +638,7 @@
}
bool MemMap::CheckNoGaps(MemMap* begin_map, MemMap* end_map) {
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
CHECK(begin_map != nullptr);
CHECK(end_map != nullptr);
CHECK(HasMemMap(begin_map));
@@ -656,7 +657,7 @@
}
void MemMap::DumpMaps(std::ostream& os, bool terse) {
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
DumpMapsLocked(os, terse);
}
@@ -747,17 +748,31 @@
}
void MemMap::Init() {
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
- if (maps_ == nullptr) {
+ if (mem_maps_lock_ != nullptr) {
// dex2oat calls MemMap::Init twice since its needed before the runtime is created.
- maps_ = new Maps;
+ return;
}
+ mem_maps_lock_ = new std::mutex();
+ // Not for thread safety, but for the annotation that maps_ is GUARDED_BY(mem_maps_lock_).
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
+ DCHECK(maps_ == nullptr);
+ maps_ = new Maps;
}
void MemMap::Shutdown() {
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
- delete maps_;
- maps_ = nullptr;
+ if (mem_maps_lock_ == nullptr) {
+ // If MemMap::Shutdown is called more than once, there is no effect.
+ return;
+ }
+ {
+ // Not for thread safety, but for the annotation that maps_ is GUARDED_BY(mem_maps_lock_).
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
+ DCHECK(maps_ != nullptr);
+ delete maps_;
+ maps_ = nullptr;
+ }
+ delete mem_maps_lock_;
+ mem_maps_lock_ = nullptr;
}
void MemMap::SetSize(size_t new_size) {
@@ -813,7 +828,7 @@
if (low_4gb && addr == nullptr) {
bool first_run = true;
- MutexLock mu(Thread::Current(), *Locks::mem_maps_lock_);
+ std::lock_guard<std::mutex> mu(*mem_maps_lock_);
for (uintptr_t ptr = next_mem_pos_; ptr < 4 * GB; ptr += kPageSize) {
// Use maps_ as an optimization to skip over large maps.
// Find the first map which is address > ptr.
diff --git a/runtime/mem_map.h b/runtime/mem_map.h
index 0fea1a5..71db3f7 100644
--- a/runtime/mem_map.h
+++ b/runtime/mem_map.h
@@ -21,6 +21,7 @@
#include <string>
#include <map>
+#include <mutex>
#include <stddef.h>
#include <sys/mman.h> // For the PROT_* and MAP_* constants.
@@ -120,7 +121,7 @@
std::string* error_msg);
// Releases the memory mapping.
- ~MemMap() REQUIRES(!Locks::mem_maps_lock_);
+ ~MemMap() REQUIRES(!MemMap::mem_maps_lock_);
const std::string& GetName() const {
return name_;
@@ -175,14 +176,17 @@
bool use_ashmem = true);
static bool CheckNoGaps(MemMap* begin_map, MemMap* end_map)
- REQUIRES(!Locks::mem_maps_lock_);
+ REQUIRES(!MemMap::mem_maps_lock_);
static void DumpMaps(std::ostream& os, bool terse = false)
- REQUIRES(!Locks::mem_maps_lock_);
+ REQUIRES(!MemMap::mem_maps_lock_);
typedef AllocationTrackingMultiMap<void*, MemMap*, kAllocatorTagMaps> Maps;
- static void Init() REQUIRES(!Locks::mem_maps_lock_);
- static void Shutdown() REQUIRES(!Locks::mem_maps_lock_);
+ // Init and Shutdown are NOT thread safe.
+ // Both may be called multiple times and MemMap objects may be created any
+ // time after the first call to Init and before the first call to Shutodwn.
+ static void Init() REQUIRES(!MemMap::mem_maps_lock_);
+ static void Shutdown() REQUIRES(!MemMap::mem_maps_lock_);
// If the map is PROT_READ, try to read each page of the map to check it is in fact readable (not
// faulting). This is used to diagnose a bug b/19894268 where mprotect doesn't seem to be working
@@ -197,16 +201,16 @@
size_t base_size,
int prot,
bool reuse,
- size_t redzone_size = 0) REQUIRES(!Locks::mem_maps_lock_);
+ size_t redzone_size = 0) REQUIRES(!MemMap::mem_maps_lock_);
static void DumpMapsLocked(std::ostream& os, bool terse)
- REQUIRES(Locks::mem_maps_lock_);
+ REQUIRES(MemMap::mem_maps_lock_);
static bool HasMemMap(MemMap* map)
- REQUIRES(Locks::mem_maps_lock_);
+ REQUIRES(MemMap::mem_maps_lock_);
static MemMap* GetLargestMemMapAt(void* address)
- REQUIRES(Locks::mem_maps_lock_);
+ REQUIRES(MemMap::mem_maps_lock_);
static bool ContainedWithinExistingMap(uint8_t* ptr, size_t size, std::string* error_msg)
- REQUIRES(!Locks::mem_maps_lock_);
+ REQUIRES(!MemMap::mem_maps_lock_);
// Internal version of mmap that supports low 4gb emulation.
static void* MapInternal(void* addr,
@@ -236,8 +240,10 @@
static uintptr_t next_mem_pos_; // Next memory location to check for low_4g extent.
#endif
+ static std::mutex* mem_maps_lock_;
+
// All the non-empty MemMaps. Use a multimap as we do a reserve-and-divide (eg ElfMap::Load()).
- static Maps* maps_ GUARDED_BY(Locks::mem_maps_lock_);
+ static Maps* maps_ GUARDED_BY(MemMap::mem_maps_lock_);
friend class MemMapTest; // To allow access to base_begin_ and base_size_.
};