tsan_ilist.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. //===-- tsan_ilist.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 ThreadSanitizer (TSan), a race detector.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #ifndef TSAN_ILIST_H
  13. #define TSAN_ILIST_H
  14. #include "sanitizer_common/sanitizer_internal_defs.h"
  15. namespace __tsan {
  16. class INode {
  17. public:
  18. INode() = default;
  19. private:
  20. INode* next_ = nullptr;
  21. INode* prev_ = nullptr;
  22. template <typename Base, INode Base::*Node, typename Elem>
  23. friend class IList;
  24. INode(const INode&) = delete;
  25. void operator=(const INode&) = delete;
  26. };
  27. // Intrusive doubly-linked list.
  28. //
  29. // The node class (MyNode) needs to include "INode foo" field,
  30. // then the list can be declared as IList<MyNode, &MyNode::foo>.
  31. // This design allows to link MyNode into multiple lists using
  32. // different INode fields.
  33. // The optional Elem template argument allows to specify node MDT
  34. // (most derived type) if it's different from MyNode.
  35. template <typename Base, INode Base::*Node, typename Elem = Base>
  36. class IList {
  37. public:
  38. IList();
  39. void PushFront(Elem* e);
  40. void PushBack(Elem* e);
  41. void Remove(Elem* e);
  42. Elem* PopFront();
  43. Elem* PopBack();
  44. Elem* Front();
  45. Elem* Back();
  46. // Prev links point towards front of the queue.
  47. Elem* Prev(Elem* e);
  48. // Next links point towards back of the queue.
  49. Elem* Next(Elem* e);
  50. uptr Size() const;
  51. bool Empty() const;
  52. bool Queued(Elem* e) const;
  53. private:
  54. INode node_;
  55. uptr size_ = 0;
  56. void Push(Elem* e, INode* after);
  57. static INode* ToNode(Elem* e);
  58. static Elem* ToElem(INode* n);
  59. IList(const IList&) = delete;
  60. void operator=(const IList&) = delete;
  61. };
  62. template <typename Base, INode Base::*Node, typename Elem>
  63. IList<Base, Node, Elem>::IList() {
  64. node_.next_ = node_.prev_ = &node_;
  65. }
  66. template <typename Base, INode Base::*Node, typename Elem>
  67. void IList<Base, Node, Elem>::PushFront(Elem* e) {
  68. Push(e, &node_);
  69. }
  70. template <typename Base, INode Base::*Node, typename Elem>
  71. void IList<Base, Node, Elem>::PushBack(Elem* e) {
  72. Push(e, node_.prev_);
  73. }
  74. template <typename Base, INode Base::*Node, typename Elem>
  75. void IList<Base, Node, Elem>::Push(Elem* e, INode* after) {
  76. INode* n = ToNode(e);
  77. DCHECK_EQ(n->next_, nullptr);
  78. DCHECK_EQ(n->prev_, nullptr);
  79. INode* next = after->next_;
  80. n->next_ = next;
  81. n->prev_ = after;
  82. next->prev_ = n;
  83. after->next_ = n;
  84. size_++;
  85. }
  86. template <typename Base, INode Base::*Node, typename Elem>
  87. void IList<Base, Node, Elem>::Remove(Elem* e) {
  88. INode* n = ToNode(e);
  89. INode* next = n->next_;
  90. INode* prev = n->prev_;
  91. DCHECK(next);
  92. DCHECK(prev);
  93. DCHECK(size_);
  94. next->prev_ = prev;
  95. prev->next_ = next;
  96. n->prev_ = n->next_ = nullptr;
  97. size_--;
  98. }
  99. template <typename Base, INode Base::*Node, typename Elem>
  100. Elem* IList<Base, Node, Elem>::PopFront() {
  101. Elem* e = Front();
  102. if (e)
  103. Remove(e);
  104. return e;
  105. }
  106. template <typename Base, INode Base::*Node, typename Elem>
  107. Elem* IList<Base, Node, Elem>::PopBack() {
  108. Elem* e = Back();
  109. if (e)
  110. Remove(e);
  111. return e;
  112. }
  113. template <typename Base, INode Base::*Node, typename Elem>
  114. Elem* IList<Base, Node, Elem>::Front() {
  115. return size_ ? ToElem(node_.next_) : nullptr;
  116. }
  117. template <typename Base, INode Base::*Node, typename Elem>
  118. Elem* IList<Base, Node, Elem>::Back() {
  119. return size_ ? ToElem(node_.prev_) : nullptr;
  120. }
  121. template <typename Base, INode Base::*Node, typename Elem>
  122. Elem* IList<Base, Node, Elem>::Prev(Elem* e) {
  123. INode* n = ToNode(e);
  124. DCHECK(n->prev_);
  125. return n->prev_ != &node_ ? ToElem(n->prev_) : nullptr;
  126. }
  127. template <typename Base, INode Base::*Node, typename Elem>
  128. Elem* IList<Base, Node, Elem>::Next(Elem* e) {
  129. INode* n = ToNode(e);
  130. DCHECK(n->next_);
  131. return n->next_ != &node_ ? ToElem(n->next_) : nullptr;
  132. }
  133. template <typename Base, INode Base::*Node, typename Elem>
  134. uptr IList<Base, Node, Elem>::Size() const {
  135. return size_;
  136. }
  137. template <typename Base, INode Base::*Node, typename Elem>
  138. bool IList<Base, Node, Elem>::Empty() const {
  139. return size_ == 0;
  140. }
  141. template <typename Base, INode Base::*Node, typename Elem>
  142. bool IList<Base, Node, Elem>::Queued(Elem* e) const {
  143. INode* n = ToNode(e);
  144. DCHECK_EQ(!n->next_, !n->prev_);
  145. return n->next_;
  146. }
  147. template <typename Base, INode Base::*Node, typename Elem>
  148. INode* IList<Base, Node, Elem>::ToNode(Elem* e) {
  149. return &(e->*Node);
  150. }
  151. template <typename Base, INode Base::*Node, typename Elem>
  152. Elem* IList<Base, Node, Elem>::ToElem(INode* n) {
  153. return static_cast<Elem*>(reinterpret_cast<Base*>(
  154. reinterpret_cast<uptr>(n) -
  155. reinterpret_cast<uptr>(&(reinterpret_cast<Elem*>(0)->*Node))));
  156. }
  157. } // namespace __tsan
  158. #endif