tsan_sync.cpp 8.3 KB

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