sanitizer_deadlock_detector.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  1. //===-- sanitizer_deadlock_detector.h ---------------------------*- C++ -*-===//
  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 Sanitizer runtime.
  10. // The deadlock detector maintains a directed graph of lock acquisitions.
  11. // When a lock event happens, the detector checks if the locks already held by
  12. // the current thread are reachable from the newly acquired lock.
  13. //
  14. // The detector can handle only a fixed amount of simultaneously live locks
  15. // (a lock is alive if it has been locked at least once and has not been
  16. // destroyed). When the maximal number of locks is reached the entire graph
  17. // is flushed and the new lock epoch is started. The node ids from the old
  18. // epochs can not be used with any of the detector methods except for
  19. // nodeBelongsToCurrentEpoch().
  20. //
  21. // FIXME: this is work in progress, nothing really works yet.
  22. //
  23. //===----------------------------------------------------------------------===//
  24. #ifndef SANITIZER_DEADLOCK_DETECTOR_H
  25. #define SANITIZER_DEADLOCK_DETECTOR_H
  26. #include "sanitizer_bvgraph.h"
  27. #include "sanitizer_common.h"
  28. namespace __sanitizer {
  29. // Thread-local state for DeadlockDetector.
  30. // It contains the locks currently held by the owning thread.
  31. template <class BV>
  32. class DeadlockDetectorTLS {
  33. public:
  34. // No CTOR.
  35. void clear() {
  36. bv_.clear();
  37. epoch_ = 0;
  38. n_recursive_locks = 0;
  39. n_all_locks_ = 0;
  40. }
  41. bool empty() const { return bv_.empty(); }
  42. void ensureCurrentEpoch(uptr current_epoch) {
  43. if (epoch_ == current_epoch) return;
  44. bv_.clear();
  45. epoch_ = current_epoch;
  46. n_recursive_locks = 0;
  47. n_all_locks_ = 0;
  48. }
  49. uptr getEpoch() const { return epoch_; }
  50. // Returns true if this is the first (non-recursive) acquisition of this lock.
  51. bool addLock(uptr lock_id, uptr current_epoch, u32 stk) {
  52. CHECK_EQ(epoch_, current_epoch);
  53. if (!bv_.setBit(lock_id)) {
  54. // The lock is already held by this thread, it must be recursive.
  55. CHECK_LT(n_recursive_locks, ARRAY_SIZE(recursive_locks));
  56. recursive_locks[n_recursive_locks++] = lock_id;
  57. return false;
  58. }
  59. CHECK_LT(n_all_locks_, ARRAY_SIZE(all_locks_with_contexts_));
  60. // lock_id < BV::kSize, can cast to a smaller int.
  61. u32 lock_id_short = static_cast<u32>(lock_id);
  62. LockWithContext l = {lock_id_short, stk};
  63. all_locks_with_contexts_[n_all_locks_++] = l;
  64. return true;
  65. }
  66. void removeLock(uptr lock_id) {
  67. if (n_recursive_locks) {
  68. for (sptr i = n_recursive_locks - 1; i >= 0; i--) {
  69. if (recursive_locks[i] == lock_id) {
  70. n_recursive_locks--;
  71. Swap(recursive_locks[i], recursive_locks[n_recursive_locks]);
  72. return;
  73. }
  74. }
  75. }
  76. if (!bv_.clearBit(lock_id))
  77. return; // probably addLock happened before flush
  78. if (n_all_locks_) {
  79. for (sptr i = n_all_locks_ - 1; i >= 0; i--) {
  80. if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id)) {
  81. Swap(all_locks_with_contexts_[i],
  82. all_locks_with_contexts_[n_all_locks_ - 1]);
  83. n_all_locks_--;
  84. break;
  85. }
  86. }
  87. }
  88. }
  89. u32 findLockContext(uptr lock_id) {
  90. for (uptr i = 0; i < n_all_locks_; i++)
  91. if (all_locks_with_contexts_[i].lock == static_cast<u32>(lock_id))
  92. return all_locks_with_contexts_[i].stk;
  93. return 0;
  94. }
  95. const BV &getLocks(uptr current_epoch) const {
  96. CHECK_EQ(epoch_, current_epoch);
  97. return bv_;
  98. }
  99. uptr getNumLocks() const { return n_all_locks_; }
  100. uptr getLock(uptr idx) const { return all_locks_with_contexts_[idx].lock; }
  101. private:
  102. BV bv_;
  103. uptr epoch_;
  104. uptr recursive_locks[64];
  105. uptr n_recursive_locks;
  106. struct LockWithContext {
  107. u32 lock;
  108. u32 stk;
  109. };
  110. LockWithContext all_locks_with_contexts_[64];
  111. uptr n_all_locks_;
  112. };
  113. // DeadlockDetector.
  114. // For deadlock detection to work we need one global DeadlockDetector object
  115. // and one DeadlockDetectorTLS object per evey thread.
  116. // This class is not thread safe, all concurrent accesses should be guarded
  117. // by an external lock.
  118. // Most of the methods of this class are not thread-safe (i.e. should
  119. // be protected by an external lock) unless explicitly told otherwise.
  120. template <class BV>
  121. class DeadlockDetector {
  122. public:
  123. typedef BV BitVector;
  124. uptr size() const { return g_.size(); }
  125. // No CTOR.
  126. void clear() {
  127. current_epoch_ = 0;
  128. available_nodes_.clear();
  129. recycled_nodes_.clear();
  130. g_.clear();
  131. n_edges_ = 0;
  132. }
  133. // Allocate new deadlock detector node.
  134. // If we are out of available nodes first try to recycle some.
  135. // If there is nothing to recycle, flush the graph and increment the epoch.
  136. // Associate 'data' (opaque user's object) with the new node.
  137. uptr newNode(uptr data) {
  138. if (!available_nodes_.empty())
  139. return getAvailableNode(data);
  140. if (!recycled_nodes_.empty()) {
  141. for (sptr i = n_edges_ - 1; i >= 0; i--) {
  142. if (recycled_nodes_.getBit(edges_[i].from) ||
  143. recycled_nodes_.getBit(edges_[i].to)) {
  144. Swap(edges_[i], edges_[n_edges_ - 1]);
  145. n_edges_--;
  146. }
  147. }
  148. CHECK(available_nodes_.empty());
  149. // removeEdgesFrom was called in removeNode.
  150. g_.removeEdgesTo(recycled_nodes_);
  151. available_nodes_.setUnion(recycled_nodes_);
  152. recycled_nodes_.clear();
  153. return getAvailableNode(data);
  154. }
  155. // We are out of vacant nodes. Flush and increment the current_epoch_.
  156. current_epoch_ += size();
  157. recycled_nodes_.clear();
  158. available_nodes_.setAll();
  159. g_.clear();
  160. n_edges_ = 0;
  161. return getAvailableNode(data);
  162. }
  163. // Get data associated with the node created by newNode().
  164. uptr getData(uptr node) const { return data_[nodeToIndex(node)]; }
  165. bool nodeBelongsToCurrentEpoch(uptr node) {
  166. return node && (node / size() * size()) == current_epoch_;
  167. }
  168. void removeNode(uptr node) {
  169. uptr idx = nodeToIndex(node);
  170. CHECK(!available_nodes_.getBit(idx));
  171. CHECK(recycled_nodes_.setBit(idx));
  172. g_.removeEdgesFrom(idx);
  173. }
  174. void ensureCurrentEpoch(DeadlockDetectorTLS<BV> *dtls) {
  175. dtls->ensureCurrentEpoch(current_epoch_);
  176. }
  177. // Returns true if there is a cycle in the graph after this lock event.
  178. // Ideally should be called before the lock is acquired so that we can
  179. // report a deadlock before a real deadlock happens.
  180. bool onLockBefore(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
  181. ensureCurrentEpoch(dtls);
  182. uptr cur_idx = nodeToIndex(cur_node);
  183. return g_.isReachable(cur_idx, dtls->getLocks(current_epoch_));
  184. }
  185. u32 findLockContext(DeadlockDetectorTLS<BV> *dtls, uptr node) {
  186. return dtls->findLockContext(nodeToIndex(node));
  187. }
  188. // Add cur_node to the set of locks held currently by dtls.
  189. void onLockAfter(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
  190. ensureCurrentEpoch(dtls);
  191. uptr cur_idx = nodeToIndex(cur_node);
  192. dtls->addLock(cur_idx, current_epoch_, stk);
  193. }
  194. // Experimental *racy* fast path function.
  195. // Returns true if all edges from the currently held locks to cur_node exist.
  196. bool hasAllEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node) {
  197. uptr local_epoch = dtls->getEpoch();
  198. // Read from current_epoch_ is racy.
  199. if (cur_node && local_epoch == current_epoch_ &&
  200. local_epoch == nodeToEpoch(cur_node)) {
  201. uptr cur_idx = nodeToIndexUnchecked(cur_node);
  202. for (uptr i = 0, n = dtls->getNumLocks(); i < n; i++) {
  203. if (!g_.hasEdge(dtls->getLock(i), cur_idx))
  204. return false;
  205. }
  206. return true;
  207. }
  208. return false;
  209. }
  210. // Adds edges from currently held locks to cur_node,
  211. // returns the number of added edges, and puts the sources of added edges
  212. // into added_edges[].
  213. // Should be called before onLockAfter.
  214. uptr addEdges(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk,
  215. int unique_tid) {
  216. ensureCurrentEpoch(dtls);
  217. uptr cur_idx = nodeToIndex(cur_node);
  218. uptr added_edges[40];
  219. uptr n_added_edges = g_.addEdges(dtls->getLocks(current_epoch_), cur_idx,
  220. added_edges, ARRAY_SIZE(added_edges));
  221. for (uptr i = 0; i < n_added_edges; i++) {
  222. if (n_edges_ < ARRAY_SIZE(edges_)) {
  223. Edge e = {(u16)added_edges[i], (u16)cur_idx,
  224. dtls->findLockContext(added_edges[i]), stk,
  225. unique_tid};
  226. edges_[n_edges_++] = e;
  227. }
  228. }
  229. return n_added_edges;
  230. }
  231. bool findEdge(uptr from_node, uptr to_node, u32 *stk_from, u32 *stk_to,
  232. int *unique_tid) {
  233. uptr from_idx = nodeToIndex(from_node);
  234. uptr to_idx = nodeToIndex(to_node);
  235. for (uptr i = 0; i < n_edges_; i++) {
  236. if (edges_[i].from == from_idx && edges_[i].to == to_idx) {
  237. *stk_from = edges_[i].stk_from;
  238. *stk_to = edges_[i].stk_to;
  239. *unique_tid = edges_[i].unique_tid;
  240. return true;
  241. }
  242. }
  243. return false;
  244. }
  245. // Test-only function. Handles the before/after lock events,
  246. // returns true if there is a cycle.
  247. bool onLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
  248. ensureCurrentEpoch(dtls);
  249. bool is_reachable = !isHeld(dtls, cur_node) && onLockBefore(dtls, cur_node);
  250. addEdges(dtls, cur_node, stk, 0);
  251. onLockAfter(dtls, cur_node, stk);
  252. return is_reachable;
  253. }
  254. // Handles the try_lock event, returns false.
  255. // When a try_lock event happens (i.e. a try_lock call succeeds) we need
  256. // to add this lock to the currently held locks, but we should not try to
  257. // change the lock graph or to detect a cycle. We may want to investigate
  258. // whether a more aggressive strategy is possible for try_lock.
  259. bool onTryLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, u32 stk = 0) {
  260. ensureCurrentEpoch(dtls);
  261. uptr cur_idx = nodeToIndex(cur_node);
  262. dtls->addLock(cur_idx, current_epoch_, stk);
  263. return false;
  264. }
  265. // Returns true iff dtls is empty (no locks are currently held) and we can
  266. // add the node to the currently held locks w/o changing the global state.
  267. // This operation is thread-safe as it only touches the dtls.
  268. bool onFirstLock(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
  269. if (!dtls->empty()) return false;
  270. if (dtls->getEpoch() && dtls->getEpoch() == nodeToEpoch(node)) {
  271. dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
  272. return true;
  273. }
  274. return false;
  275. }
  276. // Finds a path between the lock 'cur_node' (currently not held in dtls)
  277. // and some currently held lock, returns the length of the path
  278. // or 0 on failure.
  279. uptr findPathToLock(DeadlockDetectorTLS<BV> *dtls, uptr cur_node, uptr *path,
  280. uptr path_size) {
  281. tmp_bv_.copyFrom(dtls->getLocks(current_epoch_));
  282. uptr idx = nodeToIndex(cur_node);
  283. CHECK(!tmp_bv_.getBit(idx));
  284. uptr res = g_.findShortestPath(idx, tmp_bv_, path, path_size);
  285. for (uptr i = 0; i < res; i++)
  286. path[i] = indexToNode(path[i]);
  287. if (res)
  288. CHECK_EQ(path[0], cur_node);
  289. return res;
  290. }
  291. // Handle the unlock event.
  292. // This operation is thread-safe as it only touches the dtls.
  293. void onUnlock(DeadlockDetectorTLS<BV> *dtls, uptr node) {
  294. if (dtls->getEpoch() == nodeToEpoch(node))
  295. dtls->removeLock(nodeToIndexUnchecked(node));
  296. }
  297. // Tries to handle the lock event w/o writing to global state.
  298. // Returns true on success.
  299. // This operation is thread-safe as it only touches the dtls
  300. // (modulo racy nature of hasAllEdges).
  301. bool onLockFast(DeadlockDetectorTLS<BV> *dtls, uptr node, u32 stk = 0) {
  302. if (hasAllEdges(dtls, node)) {
  303. dtls->addLock(nodeToIndexUnchecked(node), nodeToEpoch(node), stk);
  304. return true;
  305. }
  306. return false;
  307. }
  308. bool isHeld(DeadlockDetectorTLS<BV> *dtls, uptr node) const {
  309. return dtls->getLocks(current_epoch_).getBit(nodeToIndex(node));
  310. }
  311. uptr testOnlyGetEpoch() const { return current_epoch_; }
  312. bool testOnlyHasEdge(uptr l1, uptr l2) {
  313. return g_.hasEdge(nodeToIndex(l1), nodeToIndex(l2));
  314. }
  315. // idx1 and idx2 are raw indices to g_, not lock IDs.
  316. bool testOnlyHasEdgeRaw(uptr idx1, uptr idx2) {
  317. return g_.hasEdge(idx1, idx2);
  318. }
  319. void Print() {
  320. for (uptr from = 0; from < size(); from++)
  321. for (uptr to = 0; to < size(); to++)
  322. if (g_.hasEdge(from, to))
  323. Printf(" %zx => %zx\n", from, to);
  324. }
  325. private:
  326. void check_idx(uptr idx) const { CHECK_LT(idx, size()); }
  327. void check_node(uptr node) const {
  328. CHECK_GE(node, size());
  329. CHECK_EQ(current_epoch_, nodeToEpoch(node));
  330. }
  331. uptr indexToNode(uptr idx) const {
  332. check_idx(idx);
  333. return idx + current_epoch_;
  334. }
  335. uptr nodeToIndexUnchecked(uptr node) const { return node % size(); }
  336. uptr nodeToIndex(uptr node) const {
  337. check_node(node);
  338. return nodeToIndexUnchecked(node);
  339. }
  340. uptr nodeToEpoch(uptr node) const { return node / size() * size(); }
  341. uptr getAvailableNode(uptr data) {
  342. uptr idx = available_nodes_.getAndClearFirstOne();
  343. data_[idx] = data;
  344. return indexToNode(idx);
  345. }
  346. struct Edge {
  347. u16 from;
  348. u16 to;
  349. u32 stk_from;
  350. u32 stk_to;
  351. int unique_tid;
  352. };
  353. uptr current_epoch_;
  354. BV available_nodes_;
  355. BV recycled_nodes_;
  356. BV tmp_bv_;
  357. BVGraph<BV> g_;
  358. uptr data_[BV::kSize];
  359. Edge edges_[BV::kSize * 32];
  360. uptr n_edges_;
  361. };
  362. } // namespace __sanitizer
  363. #endif // SANITIZER_DEADLOCK_DETECTOR_H