tsan_mutexset.cpp 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. //===-- tsan_mutexset.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 "tsan_mutexset.h"
  13. #include "sanitizer_common/sanitizer_placement_new.h"
  14. #include "tsan_rtl.h"
  15. namespace __tsan {
  16. MutexSet::MutexSet() {
  17. }
  18. void MutexSet::Add(u64 id, bool write, u64 epoch) {
  19. // Look up existing mutex with the same id.
  20. for (uptr i = 0; i < size_; i++) {
  21. if (descs_[i].id == id) {
  22. descs_[i].count++;
  23. descs_[i].epoch = epoch;
  24. return;
  25. }
  26. }
  27. // On overflow, find the oldest mutex and drop it.
  28. if (size_ == kMaxSize) {
  29. u64 minepoch = (u64)-1;
  30. u64 mini = (u64)-1;
  31. for (uptr i = 0; i < size_; i++) {
  32. if (descs_[i].epoch < minepoch) {
  33. minepoch = descs_[i].epoch;
  34. mini = i;
  35. }
  36. }
  37. RemovePos(mini);
  38. CHECK_EQ(size_, kMaxSize - 1);
  39. }
  40. // Add new mutex descriptor.
  41. descs_[size_].addr = 0;
  42. descs_[size_].stack_id = kInvalidStackID;
  43. descs_[size_].id = id;
  44. descs_[size_].write = write;
  45. descs_[size_].epoch = epoch;
  46. descs_[size_].seq = seq_++;
  47. descs_[size_].count = 1;
  48. size_++;
  49. }
  50. void MutexSet::Del(u64 id, bool write) {
  51. for (uptr i = 0; i < size_; i++) {
  52. if (descs_[i].id == id) {
  53. if (--descs_[i].count == 0)
  54. RemovePos(i);
  55. return;
  56. }
  57. }
  58. }
  59. void MutexSet::Remove(u64 id) {
  60. for (uptr i = 0; i < size_; i++) {
  61. if (descs_[i].id == id) {
  62. RemovePos(i);
  63. return;
  64. }
  65. }
  66. }
  67. void MutexSet::AddAddr(uptr addr, StackID stack_id, bool write) {
  68. // Look up existing mutex with the same id.
  69. for (uptr i = 0; i < size_; i++) {
  70. if (descs_[i].addr == addr) {
  71. descs_[i].count++;
  72. descs_[i].seq = seq_++;
  73. return;
  74. }
  75. }
  76. // On overflow, find the oldest mutex and drop it.
  77. if (size_ == kMaxSize) {
  78. uptr min = 0;
  79. for (uptr i = 0; i < size_; i++) {
  80. if (descs_[i].seq < descs_[min].seq)
  81. min = i;
  82. }
  83. RemovePos(min);
  84. CHECK_EQ(size_, kMaxSize - 1);
  85. }
  86. // Add new mutex descriptor.
  87. descs_[size_].addr = addr;
  88. descs_[size_].stack_id = stack_id;
  89. descs_[size_].id = 0;
  90. descs_[size_].write = write;
  91. descs_[size_].epoch = 0;
  92. descs_[size_].seq = seq_++;
  93. descs_[size_].count = 1;
  94. size_++;
  95. }
  96. void MutexSet::DelAddr(uptr addr, bool destroy) {
  97. for (uptr i = 0; i < size_; i++) {
  98. if (descs_[i].addr == addr) {
  99. if (destroy || --descs_[i].count == 0)
  100. RemovePos(i);
  101. return;
  102. }
  103. }
  104. }
  105. void MutexSet::RemovePos(uptr i) {
  106. CHECK_LT(i, size_);
  107. descs_[i] = descs_[size_ - 1];
  108. size_--;
  109. }
  110. uptr MutexSet::Size() const {
  111. return size_;
  112. }
  113. MutexSet::Desc MutexSet::Get(uptr i) const {
  114. CHECK_LT(i, size_);
  115. return descs_[i];
  116. }
  117. DynamicMutexSet::DynamicMutexSet() : ptr_(New<MutexSet>()) {}
  118. DynamicMutexSet::~DynamicMutexSet() { DestroyAndFree(ptr_); }
  119. } // namespace __tsan