tsan_sync.cpp 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. //===-- tsan_sync.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 ThreadSanitizer (TSan), a race detector.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #include "sanitizer_common/sanitizer_placement_new.h"
  13. #include "tsan_sync.h"
  14. #include "tsan_rtl.h"
  15. #include "tsan_mman.h"
  16. namespace __tsan {
  17. void DDMutexInit(ThreadState *thr, uptr pc, SyncVar *s);
  18. SyncVar::SyncVar() : mtx(MutexTypeSyncVar) { Reset(); }
  19. void SyncVar::Init(ThreadState *thr, uptr pc, uptr addr, bool save_stack) {
  20. Reset();
  21. this->addr = addr;
  22. next = 0;
  23. if (save_stack && !SANITIZER_GO) // Go does not use them
  24. creation_stack_id = CurrentStackId(thr, pc);
  25. if (common_flags()->detect_deadlocks)
  26. DDMutexInit(thr, pc, this);
  27. }
  28. void SyncVar::Reset() {
  29. CHECK(!ctx->resetting);
  30. creation_stack_id = kInvalidStackID;
  31. owner_tid = kInvalidTid;
  32. last_lock.Reset();
  33. recursion = 0;
  34. atomic_store_relaxed(&flags, 0);
  35. Free(clock);
  36. Free(read_clock);
  37. }
  38. MetaMap::MetaMap()
  39. : block_alloc_("heap block allocator"), sync_alloc_("sync allocator") {}
  40. void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
  41. u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache);
  42. MBlock *b = block_alloc_.Map(idx);
  43. b->siz = sz;
  44. b->tag = 0;
  45. b->tid = thr->tid;
  46. b->stk = CurrentStackId(thr, pc);
  47. u32 *meta = MemToMeta(p);
  48. DCHECK_EQ(*meta, 0);
  49. *meta = idx | kFlagBlock;
  50. }
  51. uptr MetaMap::FreeBlock(Processor *proc, uptr p, bool reset) {
  52. MBlock* b = GetBlock(p);
  53. if (b == 0)
  54. return 0;
  55. uptr sz = RoundUpTo(b->siz, kMetaShadowCell);
  56. FreeRange(proc, p, sz, reset);
  57. return sz;
  58. }
  59. bool MetaMap::FreeRange(Processor *proc, uptr p, uptr sz, bool reset) {
  60. bool has_something = false;
  61. u32 *meta = MemToMeta(p);
  62. u32 *end = MemToMeta(p + sz);
  63. if (end == meta)
  64. end++;
  65. for (; meta < end; meta++) {
  66. u32 idx = *meta;
  67. if (idx == 0) {
  68. // Note: don't write to meta in this case -- the block can be huge.
  69. continue;
  70. }
  71. *meta = 0;
  72. has_something = true;
  73. while (idx != 0) {
  74. if (idx & kFlagBlock) {
  75. block_alloc_.Free(&proc->block_cache, idx & ~kFlagMask);
  76. break;
  77. } else if (idx & kFlagSync) {
  78. DCHECK(idx & kFlagSync);
  79. SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
  80. u32 next = s->next;
  81. if (reset)
  82. s->Reset();
  83. sync_alloc_.Free(&proc->sync_cache, idx & ~kFlagMask);
  84. idx = next;
  85. } else {
  86. CHECK(0);
  87. }
  88. }
  89. }
  90. return has_something;
  91. }
  92. // ResetRange removes all meta objects from the range.
  93. // It is called for large mmap-ed regions. The function is best-effort wrt
  94. // freeing of meta objects, because we don't want to page in the whole range
  95. // which can be huge. The function probes pages one-by-one until it finds a page
  96. // without meta objects, at this point it stops freeing meta objects. Because
  97. // thread stacks grow top-down, we do the same starting from end as well.
  98. void MetaMap::ResetRange(Processor *proc, uptr p, uptr sz, bool reset) {
  99. if (SANITIZER_GO) {
  100. // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
  101. // so we do the optimization only for C/C++.
  102. FreeRange(proc, p, sz, reset);
  103. return;
  104. }
  105. const uptr kMetaRatio = kMetaShadowCell / kMetaShadowSize;
  106. const uptr kPageSize = GetPageSizeCached() * kMetaRatio;
  107. if (sz <= 4 * kPageSize) {
  108. // If the range is small, just do the normal free procedure.
  109. FreeRange(proc, p, sz, reset);
  110. return;
  111. }
  112. // First, round both ends of the range to page size.
  113. uptr diff = RoundUp(p, kPageSize) - p;
  114. if (diff != 0) {
  115. FreeRange(proc, p, diff, reset);
  116. p += diff;
  117. sz -= diff;
  118. }
  119. diff = p + sz - RoundDown(p + sz, kPageSize);
  120. if (diff != 0) {
  121. FreeRange(proc, p + sz - diff, diff, reset);
  122. sz -= diff;
  123. }
  124. // Now we must have a non-empty page-aligned range.
  125. CHECK_GT(sz, 0);
  126. CHECK_EQ(p, RoundUp(p, kPageSize));
  127. CHECK_EQ(sz, RoundUp(sz, kPageSize));
  128. const uptr p0 = p;
  129. const uptr sz0 = sz;
  130. // Probe start of the range.
  131. for (uptr checked = 0; sz > 0; checked += kPageSize) {
  132. bool has_something = FreeRange(proc, p, kPageSize, reset);
  133. p += kPageSize;
  134. sz -= kPageSize;
  135. if (!has_something && checked > (128 << 10))
  136. break;
  137. }
  138. // Probe end of the range.
  139. for (uptr checked = 0; sz > 0; checked += kPageSize) {
  140. bool has_something = FreeRange(proc, p + sz - kPageSize, kPageSize, reset);
  141. sz -= kPageSize;
  142. // Stacks grow down, so sync object are most likely at the end of the region
  143. // (if it is a stack). The very end of the stack is TLS and tsan increases
  144. // TLS by at least 256K, so check at least 512K.
  145. if (!has_something && checked > (512 << 10))
  146. break;
  147. }
  148. // Finally, page out the whole range (including the parts that we've just
  149. // freed). Note: we can't simply madvise, because we need to leave a zeroed
  150. // range (otherwise __tsan_java_move can crash if it encounters a left-over
  151. // meta objects in java heap).
  152. uptr metap = (uptr)MemToMeta(p0);
  153. uptr metasz = sz0 / kMetaRatio;
  154. UnmapOrDie((void*)metap, metasz);
  155. if (!MmapFixedSuperNoReserve(metap, metasz))
  156. Die();
  157. }
  158. void MetaMap::ResetClocks() {
  159. // This can be called from the background thread
  160. // which does not have proc/cache.
  161. // The cache is too large for stack.
  162. static InternalAllocatorCache cache;
  163. internal_memset(&cache, 0, sizeof(cache));
  164. internal_allocator()->InitCache(&cache);
  165. sync_alloc_.ForEach([&](SyncVar *s) {
  166. if (s->clock) {
  167. InternalFree(s->clock, &cache);
  168. s->clock = nullptr;
  169. }
  170. if (s->read_clock) {
  171. InternalFree(s->read_clock, &cache);
  172. s->read_clock = nullptr;
  173. }
  174. s->last_lock.Reset();
  175. });
  176. internal_allocator()->DestroyCache(&cache);
  177. }
  178. MBlock* MetaMap::GetBlock(uptr p) {
  179. u32 *meta = MemToMeta(p);
  180. u32 idx = *meta;
  181. for (;;) {
  182. if (idx == 0)
  183. return 0;
  184. if (idx & kFlagBlock)
  185. return block_alloc_.Map(idx & ~kFlagMask);
  186. DCHECK(idx & kFlagSync);
  187. SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
  188. idx = s->next;
  189. }
  190. }
  191. SyncVar *MetaMap::GetSync(ThreadState *thr, uptr pc, uptr addr, bool create,
  192. bool save_stack) {
  193. DCHECK(!create || thr->slot_locked);
  194. u32 *meta = MemToMeta(addr);
  195. u32 idx0 = *meta;
  196. u32 myidx = 0;
  197. SyncVar *mys = nullptr;
  198. for (;;) {
  199. for (u32 idx = idx0; idx && !(idx & kFlagBlock);) {
  200. DCHECK(idx & kFlagSync);
  201. SyncVar * s = sync_alloc_.Map(idx & ~kFlagMask);
  202. if (LIKELY(s->addr == addr)) {
  203. if (UNLIKELY(myidx != 0)) {
  204. mys->Reset();
  205. sync_alloc_.Free(&thr->proc()->sync_cache, myidx);
  206. }
  207. return s;
  208. }
  209. idx = s->next;
  210. }
  211. if (!create)
  212. return nullptr;
  213. if (UNLIKELY(*meta != idx0)) {
  214. idx0 = *meta;
  215. continue;
  216. }
  217. if (LIKELY(myidx == 0)) {
  218. myidx = sync_alloc_.Alloc(&thr->proc()->sync_cache);
  219. mys = sync_alloc_.Map(myidx);
  220. mys->Init(thr, pc, addr, save_stack);
  221. }
  222. mys->next = idx0;
  223. if (atomic_compare_exchange_strong((atomic_uint32_t*)meta, &idx0,
  224. myidx | kFlagSync, memory_order_release)) {
  225. return mys;
  226. }
  227. }
  228. }
  229. void MetaMap::MoveMemory(uptr src, uptr dst, uptr sz) {
  230. // src and dst can overlap,
  231. // there are no concurrent accesses to the regions (e.g. stop-the-world).
  232. CHECK_NE(src, dst);
  233. CHECK_NE(sz, 0);
  234. uptr diff = dst - src;
  235. u32 *src_meta = MemToMeta(src);
  236. u32 *dst_meta = MemToMeta(dst);
  237. u32 *src_meta_end = MemToMeta(src + sz);
  238. uptr inc = 1;
  239. if (dst > src) {
  240. src_meta = MemToMeta(src + sz) - 1;
  241. dst_meta = MemToMeta(dst + sz) - 1;
  242. src_meta_end = MemToMeta(src) - 1;
  243. inc = -1;
  244. }
  245. for (; src_meta != src_meta_end; src_meta += inc, dst_meta += inc) {
  246. CHECK_EQ(*dst_meta, 0);
  247. u32 idx = *src_meta;
  248. *src_meta = 0;
  249. *dst_meta = idx;
  250. // Patch the addresses in sync objects.
  251. while (idx != 0) {
  252. if (idx & kFlagBlock)
  253. break;
  254. CHECK(idx & kFlagSync);
  255. SyncVar *s = sync_alloc_.Map(idx & ~kFlagMask);
  256. s->addr += diff;
  257. idx = s->next;
  258. }
  259. }
  260. }
  261. void MetaMap::OnProcIdle(Processor *proc) {
  262. block_alloc_.FlushCache(&proc->block_cache);
  263. sync_alloc_.FlushCache(&proc->sync_cache);
  264. }
  265. MetaMap::MemoryStats MetaMap::GetMemoryStats() const {
  266. MemoryStats stats;
  267. stats.mem_block = block_alloc_.AllocatedMemory();
  268. stats.sync_obj = sync_alloc_.AllocatedMemory();
  269. return stats;
  270. }
  271. } // namespace __tsan