asan_thread_registry.cc revision cc4e6862c6a8f8f3ead96bd32b815184a36faded
1//===-- asan_thread_registry.cc ---------------------------------*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file is a part of AddressSanitizer, an address sanity checker.
11//
12// AsanThreadRegistry-related code. AsanThreadRegistry is a container
13// for summaries of all created threads.
14//===----------------------------------------------------------------------===//
15
16#include "asan_stack.h"
17#include "asan_thread.h"
18#include "asan_thread_registry.h"
19
20namespace __asan {
21
22static AsanThreadRegistry asan_thread_registry(__asan::LINKER_INITIALIZED);
23
24AsanThreadRegistry &asanThreadRegistry() {
25  return asan_thread_registry;
26}
27
28AsanThreadRegistry::AsanThreadRegistry(LinkerInitialized x)
29    : main_thread_(x),
30      main_thread_summary_(x),
31      accumulated_stats_(x),
32      mu_(x) { }
33
34void AsanThreadRegistry::Init() {
35  AsanTSDInit();
36  main_thread_.set_summary(&main_thread_summary_);
37  main_thread_summary_.set_thread(&main_thread_);
38  SetCurrent(&main_thread_);
39  thread_summaries_[0] = &main_thread_summary_;
40  n_threads_ = 1;
41}
42
43void AsanThreadRegistry::RegisterThread(AsanThread *thread, int parent_tid,
44                                        AsanStackTrace *stack) {
45  ScopedLock lock(&mu_);
46  CHECK(n_threads_ > 0);
47  int tid = n_threads_;
48  n_threads_++;
49  CHECK(n_threads_ < kMaxNumberOfThreads);
50  AsanThreadSummary *summary = new AsanThreadSummary(tid, parent_tid, stack);
51  summary->set_thread(thread);
52  thread_summaries_[tid] = summary;
53  thread->set_summary(summary);
54}
55
56void AsanThreadRegistry::UnregisterThread(AsanThread *thread) {
57  ScopedLock lock(&mu_);
58  FlushToAccumulatedStatsUnlocked(&thread->stats());
59  AsanThreadSummary *summary = thread->summary();
60  CHECK(summary);
61  summary->set_thread(NULL);
62}
63
64AsanThread *AsanThreadRegistry::GetMain() {
65  return &main_thread_;
66}
67
68AsanThread *AsanThreadRegistry::GetCurrent() {
69  AsanThreadSummary *summary = (AsanThreadSummary *)AsanTSDGet();
70  if (!summary) return 0;
71  return summary->thread();
72}
73
74void AsanThreadRegistry::SetCurrent(AsanThread *t) {
75  CHECK(t->summary());
76  if (FLAG_v >= 2) {
77    Report("SetCurrent: %p for thread %p\n", t->summary(), GetThreadSelf());
78  }
79  // Make sure we do not reset the current AsanThread.
80  CHECK(AsanTSDGet() == 0);
81  AsanTSDSet(t->summary());
82  CHECK(AsanTSDGet() == t->summary());
83}
84
85AsanStats &AsanThreadRegistry::GetCurrentThreadStats() {
86  AsanThread *t = GetCurrent();
87  return (t) ? t->stats() : main_thread_.stats();
88}
89
90AsanStats AsanThreadRegistry::GetAccumulatedStats() {
91  ScopedLock lock(&mu_);
92  UpdateAccumulatedStatsUnlocked();
93  return accumulated_stats_;
94}
95
96size_t AsanThreadRegistry::GetCurrentAllocatedBytes() {
97  ScopedLock lock(&mu_);
98  UpdateAccumulatedStatsUnlocked();
99  return accumulated_stats_.malloced - accumulated_stats_.freed;
100}
101
102size_t AsanThreadRegistry::GetHeapSize() {
103  ScopedLock lock(&mu_);
104  UpdateAccumulatedStatsUnlocked();
105  return accumulated_stats_.mmaped;
106}
107
108size_t AsanThreadRegistry::GetFreeBytes() {
109  ScopedLock lock(&mu_);
110  UpdateAccumulatedStatsUnlocked();
111  return accumulated_stats_.mmaped
112         - accumulated_stats_.malloced
113         - accumulated_stats_.malloced_redzones
114         + accumulated_stats_.really_freed
115         + accumulated_stats_.really_freed_redzones;
116}
117
118AsanThreadSummary *AsanThreadRegistry::FindByTid(int tid) {
119  CHECK(tid >= 0);
120  CHECK(tid < n_threads_);
121  CHECK(thread_summaries_[tid]);
122  return thread_summaries_[tid];
123}
124
125AsanThread *AsanThreadRegistry::FindThreadByStackAddress(uintptr_t addr) {
126  ScopedLock lock(&mu_);
127  for (int tid = 0; tid < n_threads_; tid++) {
128    AsanThread *t = thread_summaries_[tid]->thread();
129    if (!t) continue;
130    if (t->fake_stack().AddrIsInFakeStack(addr) || t->AddrIsInStack(addr)) {
131      return t;
132    }
133  }
134  return 0;
135}
136
137void AsanThreadRegistry::UpdateAccumulatedStatsUnlocked() {
138  for (int tid = 0; tid < n_threads_; tid++) {
139    AsanThread *t = thread_summaries_[tid]->thread();
140    if (t != NULL) {
141      FlushToAccumulatedStatsUnlocked(&t->stats());
142    }
143  }
144}
145
146void AsanThreadRegistry::FlushToAccumulatedStatsUnlocked(AsanStats *stats) {
147  // AsanStats consists of variables of type size_t only.
148  size_t *dst = (size_t*)&accumulated_stats_;
149  size_t *src = (size_t*)stats;
150  size_t num_fields = sizeof(AsanStats) / sizeof(size_t);
151  for (size_t i = 0; i < num_fields; i++) {
152    dst[i] += src[i];
153    src[i] = 0;
154  }
155}
156
157}  // namespace __asan
158