hanchenye-llvm-project/compiler-rt/lib/asan/asan_thread_registry.cc

169 lines
4.8 KiB
C++
Raw Normal View History

//===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file is a part of AddressSanitizer, an address sanity checker.
//
// AsanThreadRegistry-related code. AsanThreadRegistry is a container
// for summaries of all created threads.
//===----------------------------------------------------------------------===//
#include "asan_stack.h"
#include "asan_thread.h"
#include "asan_thread_registry.h"
#include <limits.h>
#include <pthread.h>
namespace __asan {
static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED);
AsanThreadRegistry &asanThreadRegistry() {
return asan_thread_registry;
}
AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
: main_thread_(x),
main_thread_summary_(x),
accumulated_stats_(x),
mu_(x) { }
void AsanThreadRegistry::Init() {
CHECK(0 == pthread_key_create(&tls_key_, 0));
tls_key_created_ = true;
main_thread_.set_summary(&main_thread_summary_);
main_thread_summary_.set_thread(&main_thread_);
SetCurrent(&main_thread_);
thread_summaries_[0] = &main_thread_summary_;
n_threads_ = 1;
}
void AsanThreadRegistry::RegisterThread(AsanThread *thread, int parent_tid,
AsanStackTrace *stack) {
ScopedLock lock(&mu_);
CHECK(n_threads_ > 0);
int tid = n_threads_;
n_threads_++;
CHECK(n_threads_ < kMaxNumberOfThreads);
AsanThreadSummary *summary = new AsanThreadSummary(tid, parent_tid, stack);
summary->set_thread(thread);
thread_summaries_[tid] = summary;
thread->set_summary(summary);
}
void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
ScopedLock lock(&mu_);
FlushToAccumulatedStatsUnlocked(&thread->stats());
AsanThreadSummary *summary = thread->summary();
CHECK(summary);
summary->set_thread(NULL);
}
AsanThread *AsanThreadRegistry::GetMain() {
return &main_thread_;
}
AsanThread *AsanThreadRegistry::GetCurrent() {
CHECK(tls_key_created_);
AsanThreadSummary *summary =
(AsanThreadSummary *)pthread_getspecific(tls_key_);
if (!summary) return 0;
return summary->thread();
}
void AsanThreadRegistry::SetCurrent(AsanThread *t) {
CHECK(t->summary());
if (FLAG_v >= 2) {
Report("SetCurrent: %p for thread %p\n", t->summary(), pthread_self());
}
// Make sure we do not reset the current AsanThread.
intptr_t old_key = (intptr_t)pthread_getspecific(tls_key_);
CHECK(!old_key);
CHECK(0 == pthread_setspecific(tls_key_, t->summary()));
CHECK(pthread_getspecific(tls_key_) == t->summary());
}
pthread_key_t AsanThreadRegistry::GetTlsKey() {
return tls_key_;
}
AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
AsanThread *t = GetCurrent();
return (t) ? t->stats() : main_thread_.stats();
}
AsanStats AsanThreadRegistry::GetAccumulatedStats() {
ScopedLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats_;
}
size_t AsanThreadRegistry::GetCurrentAllocatedBytes() {
ScopedLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats_.malloced - accumulated_stats_.freed;
}
size_t AsanThreadRegistry::GetHeapSize() {
ScopedLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats_.mmaped;
}
size_t AsanThreadRegistry::GetFreeBytes() {
ScopedLock lock(&mu_);
UpdateAccumulatedStatsUnlocked();
return accumulated_stats_.mmaped
- accumulated_stats_.malloced
- accumulated_stats_.malloced_redzones
+ accumulated_stats_.really_freed
+ accumulated_stats_.really_freed_redzones;
}
AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) {
CHECK(tid >= 0);
CHECK(tid < n_threads_);
CHECK(thread_summaries_[tid]);
return thread_summaries_[tid];
}
AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) {
ScopedLock lock(&mu_);
for (int tid = 0; tid < n_threads_; tid++) {
AsanThread *t = thread_summaries_[tid]->thread();
if (!t) continue;
if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
return t;
}
}
return 0;
}
void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
for (int tid = 0; tid < n_threads_; tid++) {
AsanThread *t = thread_summaries_[tid]->thread();
if (t != NULL) {
FlushToAccumulatedStatsUnlocked(&t->stats());
}
}
}
void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
// AsanStats consists of variables of type size_t only.
size_t *dst = (size_t*)&accumulated_stats_;
size_t *src = (size_t*)stats;
size_t num_fields = sizeof(AsanStats) / sizeof(size_t);
for (size_t i = 0; i < num_fields; i++) {
dst[i] += src[i];
src[i] = 0;
}
}
} // namespace __asan