memprof_thread.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. //===-- memprof_thread.cpp -----------------------------------------------===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // This file is a part of MemProfiler, a memory profiler.
  10. //
  11. // Thread-related code.
  12. //===----------------------------------------------------------------------===//
  13. #include "memprof_thread.h"
  14. #include "memprof_allocator.h"
  15. #include "memprof_interceptors.h"
  16. #include "memprof_mapping.h"
  17. #include "memprof_stack.h"
  18. #include "sanitizer_common/sanitizer_common.h"
  19. #include "sanitizer_common/sanitizer_placement_new.h"
  20. #include "sanitizer_common/sanitizer_stackdepot.h"
  21. #include "sanitizer_common/sanitizer_tls_get_addr.h"
  22. namespace __memprof {
  23. // MemprofThreadContext implementation.
  24. void MemprofThreadContext::OnCreated(void *arg) {
  25. CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs *>(arg);
  26. if (args->stack)
  27. stack_id = StackDepotPut(*args->stack);
  28. thread = args->thread;
  29. thread->set_context(this);
  30. }
  31. void MemprofThreadContext::OnFinished() {
  32. // Drop the link to the MemprofThread object.
  33. thread = nullptr;
  34. }
  35. static ALIGNED(16) char thread_registry_placeholder[sizeof(ThreadRegistry)];
  36. static ThreadRegistry *memprof_thread_registry;
  37. static Mutex mu_for_thread_context;
  38. static LowLevelAllocator allocator_for_thread_context;
  39. static ThreadContextBase *GetMemprofThreadContext(u32 tid) {
  40. Lock lock(&mu_for_thread_context);
  41. return new (allocator_for_thread_context) MemprofThreadContext(tid);
  42. }
  43. ThreadRegistry &memprofThreadRegistry() {
  44. static bool initialized;
  45. // Don't worry about thread_safety - this should be called when there is
  46. // a single thread.
  47. if (!initialized) {
  48. // Never reuse MemProf threads: we store pointer to MemprofThreadContext
  49. // in TSD and can't reliably tell when no more TSD destructors will
  50. // be called. It would be wrong to reuse MemprofThreadContext for another
  51. // thread before all TSD destructors will be called for it.
  52. memprof_thread_registry = new (thread_registry_placeholder)
  53. ThreadRegistry(GetMemprofThreadContext);
  54. initialized = true;
  55. }
  56. return *memprof_thread_registry;
  57. }
  58. MemprofThreadContext *GetThreadContextByTidLocked(u32 tid) {
  59. return static_cast<MemprofThreadContext *>(
  60. memprofThreadRegistry().GetThreadLocked(tid));
  61. }
  62. // MemprofThread implementation.
  63. MemprofThread *MemprofThread::Create(thread_callback_t start_routine, void *arg,
  64. u32 parent_tid, StackTrace *stack,
  65. bool detached) {
  66. uptr PageSize = GetPageSizeCached();
  67. uptr size = RoundUpTo(sizeof(MemprofThread), PageSize);
  68. MemprofThread *thread = (MemprofThread *)MmapOrDie(size, __func__);
  69. thread->start_routine_ = start_routine;
  70. thread->arg_ = arg;
  71. MemprofThreadContext::CreateThreadContextArgs args = {thread, stack};
  72. memprofThreadRegistry().CreateThread(0, detached, parent_tid, &args);
  73. return thread;
  74. }
  75. void MemprofThread::TSDDtor(void *tsd) {
  76. MemprofThreadContext *context = (MemprofThreadContext *)tsd;
  77. VReport(1, "T%d TSDDtor\n", context->tid);
  78. if (context->thread)
  79. context->thread->Destroy();
  80. }
  81. void MemprofThread::Destroy() {
  82. int tid = this->tid();
  83. VReport(1, "T%d exited\n", tid);
  84. malloc_storage().CommitBack();
  85. memprofThreadRegistry().FinishThread(tid);
  86. FlushToDeadThreadStats(&stats_);
  87. uptr size = RoundUpTo(sizeof(MemprofThread), GetPageSizeCached());
  88. UnmapOrDie(this, size);
  89. DTLS_Destroy();
  90. }
  91. inline MemprofThread::StackBounds MemprofThread::GetStackBounds() const {
  92. if (stack_bottom_ >= stack_top_)
  93. return {0, 0};
  94. return {stack_bottom_, stack_top_};
  95. }
  96. uptr MemprofThread::stack_top() { return GetStackBounds().top; }
  97. uptr MemprofThread::stack_bottom() { return GetStackBounds().bottom; }
  98. uptr MemprofThread::stack_size() {
  99. const auto bounds = GetStackBounds();
  100. return bounds.top - bounds.bottom;
  101. }
  102. void MemprofThread::Init(const InitOptions *options) {
  103. CHECK_EQ(this->stack_size(), 0U);
  104. SetThreadStackAndTls(options);
  105. if (stack_top_ != stack_bottom_) {
  106. CHECK_GT(this->stack_size(), 0U);
  107. CHECK(AddrIsInMem(stack_bottom_));
  108. CHECK(AddrIsInMem(stack_top_ - 1));
  109. }
  110. int local = 0;
  111. VReport(1, "T%d: stack [%p,%p) size 0x%zx; local=%p\n", tid(),
  112. (void *)stack_bottom_, (void *)stack_top_, stack_top_ - stack_bottom_,
  113. (void *)&local);
  114. }
  115. thread_return_t
  116. MemprofThread::ThreadStart(tid_t os_id,
  117. atomic_uintptr_t *signal_thread_is_registered) {
  118. Init();
  119. memprofThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular,
  120. nullptr);
  121. if (signal_thread_is_registered)
  122. atomic_store(signal_thread_is_registered, 1, memory_order_release);
  123. if (!start_routine_) {
  124. // start_routine_ == 0 if we're on the main thread or on one of the
  125. // OS X libdispatch worker threads. But nobody is supposed to call
  126. // ThreadStart() for the worker threads.
  127. CHECK_EQ(tid(), 0);
  128. return 0;
  129. }
  130. return start_routine_(arg_);
  131. }
  132. MemprofThread *CreateMainThread() {
  133. MemprofThread *main_thread = MemprofThread::Create(
  134. /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ kMainTid,
  135. /* stack */ nullptr, /* detached */ true);
  136. SetCurrentThread(main_thread);
  137. main_thread->ThreadStart(internal_getpid(),
  138. /* signal_thread_is_registered */ nullptr);
  139. return main_thread;
  140. }
  141. // This implementation doesn't use the argument, which is just passed down
  142. // from the caller of Init (which see, above). It's only there to support
  143. // OS-specific implementations that need more information passed through.
  144. void MemprofThread::SetThreadStackAndTls(const InitOptions *options) {
  145. DCHECK_EQ(options, nullptr);
  146. uptr tls_size = 0;
  147. uptr stack_size = 0;
  148. GetThreadStackAndTls(tid() == kMainTid, &stack_bottom_, &stack_size,
  149. &tls_begin_, &tls_size);
  150. stack_top_ = stack_bottom_ + stack_size;
  151. tls_end_ = tls_begin_ + tls_size;
  152. dtls_ = DTLS_Get();
  153. if (stack_top_ != stack_bottom_) {
  154. int local;
  155. CHECK(AddrIsInStack((uptr)&local));
  156. }
  157. }
  158. bool MemprofThread::AddrIsInStack(uptr addr) {
  159. const auto bounds = GetStackBounds();
  160. return addr >= bounds.bottom && addr < bounds.top;
  161. }
  162. MemprofThread *GetCurrentThread() {
  163. MemprofThreadContext *context =
  164. reinterpret_cast<MemprofThreadContext *>(TSDGet());
  165. if (!context)
  166. return nullptr;
  167. return context->thread;
  168. }
  169. void SetCurrentThread(MemprofThread *t) {
  170. CHECK(t->context());
  171. VReport(2, "SetCurrentThread: %p for thread %p\n", (void *)t->context(),
  172. (void *)GetThreadSelf());
  173. // Make sure we do not reset the current MemprofThread.
  174. CHECK_EQ(0, TSDGet());
  175. TSDSet(t->context());
  176. CHECK_EQ(t->context(), TSDGet());
  177. }
  178. u32 GetCurrentTidOrInvalid() {
  179. MemprofThread *t = GetCurrentThread();
  180. return t ? t->tid() : kInvalidTid;
  181. }
  182. void EnsureMainThreadIDIsCorrect() {
  183. MemprofThreadContext *context =
  184. reinterpret_cast<MemprofThreadContext *>(TSDGet());
  185. if (context && (context->tid == kMainTid))
  186. context->os_id = GetTid();
  187. }
  188. } // namespace __memprof