Merge "Fix race condition updating local map data."
This commit is contained in:
commit
863d8e11b9
6 changed files with 45 additions and 5 deletions
|
|
@ -368,6 +368,7 @@ static void dump_all_maps(Backtrace* backtrace, BacktraceMap* map, log_t* log, p
|
||||||
ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
ALOGE("Cannot get siginfo for %d: %s\n", tid, strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScopedBacktraceMapIteratorLock lock(map);
|
||||||
_LOG(log, logtype::MAPS, "\n");
|
_LOG(log, logtype::MAPS, "\n");
|
||||||
if (!print_fault_address_marker) {
|
if (!print_fault_address_marker) {
|
||||||
_LOG(log, logtype::MAPS, "memory map:\n");
|
_LOG(log, logtype::MAPS, "memory map:\n");
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,12 @@ public:
|
||||||
bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
|
bool IsWritable(uintptr_t pc) { return GetFlags(pc) & PROT_WRITE; }
|
||||||
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
|
bool IsExecutable(uintptr_t pc) { return GetFlags(pc) & PROT_EXEC; }
|
||||||
|
|
||||||
|
// In order to use the iterators on this object, a caller must
|
||||||
|
// call the LockIterator and UnlockIterator function to guarantee
|
||||||
|
// that the data does not change while it's being used.
|
||||||
|
virtual void LockIterator() {}
|
||||||
|
virtual void UnlockIterator() {}
|
||||||
|
|
||||||
typedef std::deque<backtrace_map_t>::iterator iterator;
|
typedef std::deque<backtrace_map_t>::iterator iterator;
|
||||||
iterator begin() { return maps_.begin(); }
|
iterator begin() { return maps_.begin(); }
|
||||||
iterator end() { return maps_.end(); }
|
iterator end() { return maps_.end(); }
|
||||||
|
|
@ -102,4 +108,18 @@ protected:
|
||||||
pid_t pid_;
|
pid_t pid_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ScopedBacktraceMapIteratorLock {
|
||||||
|
public:
|
||||||
|
explicit ScopedBacktraceMapIteratorLock(BacktraceMap* map) : map_(map) {
|
||||||
|
map->LockIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
~ScopedBacktraceMapIteratorLock() {
|
||||||
|
map_->UnlockIterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
BacktraceMap* map_;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // _BACKTRACE_BACKTRACE_MAP_H
|
#endif // _BACKTRACE_BACKTRACE_MAP_H
|
||||||
|
|
|
||||||
|
|
@ -36,8 +36,8 @@ BacktraceMap::~BacktraceMap() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
|
void BacktraceMap::FillIn(uintptr_t addr, backtrace_map_t* map) {
|
||||||
for (BacktraceMap::const_iterator it = begin();
|
ScopedBacktraceMapIteratorLock lock(this);
|
||||||
it != end(); ++it) {
|
for (BacktraceMap::const_iterator it = begin(); it != end(); ++it) {
|
||||||
if (addr >= it->start && addr < it->end) {
|
if (addr >= it->start && addr < it->end) {
|
||||||
*map = *it;
|
*map = *it;
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
@ -72,6 +73,7 @@ bool UnwindMapRemote::Build() {
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
|
UnwindMapLocal::UnwindMapLocal() : UnwindMap(getpid()), map_created_(false) {
|
||||||
|
pthread_rwlock_init(&map_lock_, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
UnwindMapLocal::~UnwindMapLocal() {
|
UnwindMapLocal::~UnwindMapLocal() {
|
||||||
|
|
@ -82,9 +84,14 @@ UnwindMapLocal::~UnwindMapLocal() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwindMapLocal::GenerateMap() {
|
bool UnwindMapLocal::GenerateMap() {
|
||||||
|
// Lock so that multiple threads cannot modify the maps data at the
|
||||||
|
// same time.
|
||||||
|
pthread_rwlock_wrlock(&map_lock_);
|
||||||
|
|
||||||
// It's possible for the map to be regenerated while this loop is occurring.
|
// It's possible for the map to be regenerated while this loop is occurring.
|
||||||
// If that happens, get the map again, but only try at most three times
|
// If that happens, get the map again, but only try at most three times
|
||||||
// before giving up.
|
// before giving up.
|
||||||
|
bool generated = false;
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
maps_.clear();
|
maps_.clear();
|
||||||
|
|
||||||
|
|
@ -110,12 +117,17 @@ bool UnwindMapLocal::GenerateMap() {
|
||||||
}
|
}
|
||||||
// Check to see if the map changed while getting the data.
|
// Check to see if the map changed while getting the data.
|
||||||
if (ret != -UNW_EINVAL) {
|
if (ret != -UNW_EINVAL) {
|
||||||
return true;
|
generated = true;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BACK_LOGW("Unable to generate the map.");
|
pthread_rwlock_unlock(&map_lock_);
|
||||||
return false;
|
|
||||||
|
if (!generated) {
|
||||||
|
BACK_LOGW("Unable to generate the map.");
|
||||||
|
}
|
||||||
|
return generated;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UnwindMapLocal::Build() {
|
bool UnwindMapLocal::Build() {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#ifndef _LIBBACKTRACE_UNWIND_MAP_H
|
#ifndef _LIBBACKTRACE_UNWIND_MAP_H
|
||||||
#define _LIBBACKTRACE_UNWIND_MAP_H
|
#define _LIBBACKTRACE_UNWIND_MAP_H
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
|
@ -56,10 +57,15 @@ public:
|
||||||
|
|
||||||
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
|
void FillIn(uintptr_t addr, backtrace_map_t* map) override;
|
||||||
|
|
||||||
|
void LockIterator() override { pthread_rwlock_rdlock(&map_lock_); }
|
||||||
|
void UnlockIterator() override { pthread_rwlock_unlock(&map_lock_); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool GenerateMap();
|
bool GenerateMap();
|
||||||
|
|
||||||
bool map_created_;
|
bool map_created_;
|
||||||
|
|
||||||
|
pthread_rwlock_t map_lock_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // _LIBBACKTRACE_UNWIND_MAP_H
|
#endif // _LIBBACKTRACE_UNWIND_MAP_H
|
||||||
|
|
|
||||||
|
|
@ -895,6 +895,7 @@ void VerifyMap(pid_t pid) {
|
||||||
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
|
std::unique_ptr<BacktraceMap> map(BacktraceMap::Create(pid));
|
||||||
|
|
||||||
// Basic test that verifies that the map is in the expected order.
|
// Basic test that verifies that the map is in the expected order.
|
||||||
|
ScopedBacktraceMapIteratorLock lock(map.get());
|
||||||
std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
|
std::vector<map_test_t>::const_iterator test_it = test_maps.begin();
|
||||||
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
|
for (BacktraceMap::const_iterator it = map->begin(); it != map->end(); ++it) {
|
||||||
ASSERT_TRUE(test_it != test_maps.end());
|
ASSERT_TRUE(test_it != test_maps.end());
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue