xref: /openbsd-src/gnu/llvm/compiler-rt/lib/tsan/rtl/tsan_ilist.h (revision 810390e339a5425391477d5d41c78d7cab2424ac)
1*810390e3Srobert //===-- tsan_ilist.h --------------------------------------------*- C++ -*-===//
2*810390e3Srobert //
3*810390e3Srobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*810390e3Srobert // See https://llvm.org/LICENSE.txt for license information.
5*810390e3Srobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*810390e3Srobert //
7*810390e3Srobert //===----------------------------------------------------------------------===//
8*810390e3Srobert //
9*810390e3Srobert // This file is a part of ThreadSanitizer (TSan), a race detector.
10*810390e3Srobert //
11*810390e3Srobert //===----------------------------------------------------------------------===//
12*810390e3Srobert #ifndef TSAN_ILIST_H
13*810390e3Srobert #define TSAN_ILIST_H
14*810390e3Srobert 
15*810390e3Srobert #include "sanitizer_common/sanitizer_internal_defs.h"
16*810390e3Srobert 
17*810390e3Srobert namespace __tsan {
18*810390e3Srobert 
19*810390e3Srobert class INode {
20*810390e3Srobert  public:
21*810390e3Srobert   INode() = default;
22*810390e3Srobert 
23*810390e3Srobert  private:
24*810390e3Srobert   INode* next_ = nullptr;
25*810390e3Srobert   INode* prev_ = nullptr;
26*810390e3Srobert 
27*810390e3Srobert   template <typename Base, INode Base::*Node, typename Elem>
28*810390e3Srobert   friend class IList;
29*810390e3Srobert   INode(const INode&) = delete;
30*810390e3Srobert   void operator=(const INode&) = delete;
31*810390e3Srobert };
32*810390e3Srobert 
33*810390e3Srobert // Intrusive doubly-linked list.
34*810390e3Srobert //
35*810390e3Srobert // The node class (MyNode) needs to include "INode foo" field,
36*810390e3Srobert // then the list can be declared as IList<MyNode, &MyNode::foo>.
37*810390e3Srobert // This design allows to link MyNode into multiple lists using
38*810390e3Srobert // different INode fields.
39*810390e3Srobert // The optional Elem template argument allows to specify node MDT
40*810390e3Srobert // (most derived type) if it's different from MyNode.
41*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem = Base>
42*810390e3Srobert class IList {
43*810390e3Srobert  public:
44*810390e3Srobert   IList();
45*810390e3Srobert 
46*810390e3Srobert   void PushFront(Elem* e);
47*810390e3Srobert   void PushBack(Elem* e);
48*810390e3Srobert   void Remove(Elem* e);
49*810390e3Srobert 
50*810390e3Srobert   Elem* PopFront();
51*810390e3Srobert   Elem* PopBack();
52*810390e3Srobert   Elem* Front();
53*810390e3Srobert   Elem* Back();
54*810390e3Srobert 
55*810390e3Srobert   // Prev links point towards front of the queue.
56*810390e3Srobert   Elem* Prev(Elem* e);
57*810390e3Srobert   // Next links point towards back of the queue.
58*810390e3Srobert   Elem* Next(Elem* e);
59*810390e3Srobert 
60*810390e3Srobert   uptr Size() const;
61*810390e3Srobert   bool Empty() const;
62*810390e3Srobert   bool Queued(Elem* e) const;
63*810390e3Srobert 
64*810390e3Srobert  private:
65*810390e3Srobert   INode node_;
66*810390e3Srobert   uptr size_ = 0;
67*810390e3Srobert 
68*810390e3Srobert   void Push(Elem* e, INode* after);
69*810390e3Srobert   static INode* ToNode(Elem* e);
70*810390e3Srobert   static Elem* ToElem(INode* n);
71*810390e3Srobert 
72*810390e3Srobert   IList(const IList&) = delete;
73*810390e3Srobert   void operator=(const IList&) = delete;
74*810390e3Srobert };
75*810390e3Srobert 
76*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
IList()77*810390e3Srobert IList<Base, Node, Elem>::IList() {
78*810390e3Srobert   node_.next_ = node_.prev_ = &node_;
79*810390e3Srobert }
80*810390e3Srobert 
81*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
PushFront(Elem * e)82*810390e3Srobert void IList<Base, Node, Elem>::PushFront(Elem* e) {
83*810390e3Srobert   Push(e, &node_);
84*810390e3Srobert }
85*810390e3Srobert 
86*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
PushBack(Elem * e)87*810390e3Srobert void IList<Base, Node, Elem>::PushBack(Elem* e) {
88*810390e3Srobert   Push(e, node_.prev_);
89*810390e3Srobert }
90*810390e3Srobert 
91*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Push(Elem * e,INode * after)92*810390e3Srobert void IList<Base, Node, Elem>::Push(Elem* e, INode* after) {
93*810390e3Srobert   INode* n = ToNode(e);
94*810390e3Srobert   DCHECK_EQ(n->next_, nullptr);
95*810390e3Srobert   DCHECK_EQ(n->prev_, nullptr);
96*810390e3Srobert   INode* next = after->next_;
97*810390e3Srobert   n->next_ = next;
98*810390e3Srobert   n->prev_ = after;
99*810390e3Srobert   next->prev_ = n;
100*810390e3Srobert   after->next_ = n;
101*810390e3Srobert   size_++;
102*810390e3Srobert }
103*810390e3Srobert 
104*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Remove(Elem * e)105*810390e3Srobert void IList<Base, Node, Elem>::Remove(Elem* e) {
106*810390e3Srobert   INode* n = ToNode(e);
107*810390e3Srobert   INode* next = n->next_;
108*810390e3Srobert   INode* prev = n->prev_;
109*810390e3Srobert   DCHECK(next);
110*810390e3Srobert   DCHECK(prev);
111*810390e3Srobert   DCHECK(size_);
112*810390e3Srobert   next->prev_ = prev;
113*810390e3Srobert   prev->next_ = next;
114*810390e3Srobert   n->prev_ = n->next_ = nullptr;
115*810390e3Srobert   size_--;
116*810390e3Srobert }
117*810390e3Srobert 
118*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
PopFront()119*810390e3Srobert Elem* IList<Base, Node, Elem>::PopFront() {
120*810390e3Srobert   Elem* e = Front();
121*810390e3Srobert   if (e)
122*810390e3Srobert     Remove(e);
123*810390e3Srobert   return e;
124*810390e3Srobert }
125*810390e3Srobert 
126*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
PopBack()127*810390e3Srobert Elem* IList<Base, Node, Elem>::PopBack() {
128*810390e3Srobert   Elem* e = Back();
129*810390e3Srobert   if (e)
130*810390e3Srobert     Remove(e);
131*810390e3Srobert   return e;
132*810390e3Srobert }
133*810390e3Srobert 
134*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Front()135*810390e3Srobert Elem* IList<Base, Node, Elem>::Front() {
136*810390e3Srobert   return size_ ? ToElem(node_.next_) : nullptr;
137*810390e3Srobert }
138*810390e3Srobert 
139*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Back()140*810390e3Srobert Elem* IList<Base, Node, Elem>::Back() {
141*810390e3Srobert   return size_ ? ToElem(node_.prev_) : nullptr;
142*810390e3Srobert }
143*810390e3Srobert 
144*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Prev(Elem * e)145*810390e3Srobert Elem* IList<Base, Node, Elem>::Prev(Elem* e) {
146*810390e3Srobert   INode* n = ToNode(e);
147*810390e3Srobert   DCHECK(n->prev_);
148*810390e3Srobert   return n->prev_ != &node_ ? ToElem(n->prev_) : nullptr;
149*810390e3Srobert }
150*810390e3Srobert 
151*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Next(Elem * e)152*810390e3Srobert Elem* IList<Base, Node, Elem>::Next(Elem* e) {
153*810390e3Srobert   INode* n = ToNode(e);
154*810390e3Srobert   DCHECK(n->next_);
155*810390e3Srobert   return n->next_ != &node_ ? ToElem(n->next_) : nullptr;
156*810390e3Srobert }
157*810390e3Srobert 
158*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Size()159*810390e3Srobert uptr IList<Base, Node, Elem>::Size() const {
160*810390e3Srobert   return size_;
161*810390e3Srobert }
162*810390e3Srobert 
163*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Empty()164*810390e3Srobert bool IList<Base, Node, Elem>::Empty() const {
165*810390e3Srobert   return size_ == 0;
166*810390e3Srobert }
167*810390e3Srobert 
168*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
Queued(Elem * e)169*810390e3Srobert bool IList<Base, Node, Elem>::Queued(Elem* e) const {
170*810390e3Srobert   INode* n = ToNode(e);
171*810390e3Srobert   DCHECK_EQ(!n->next_, !n->prev_);
172*810390e3Srobert   return n->next_;
173*810390e3Srobert }
174*810390e3Srobert 
175*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
ToNode(Elem * e)176*810390e3Srobert INode* IList<Base, Node, Elem>::ToNode(Elem* e) {
177*810390e3Srobert   return &(e->*Node);
178*810390e3Srobert }
179*810390e3Srobert 
180*810390e3Srobert template <typename Base, INode Base::*Node, typename Elem>
ToElem(INode * n)181*810390e3Srobert Elem* IList<Base, Node, Elem>::ToElem(INode* n) {
182*810390e3Srobert   return static_cast<Elem*>(reinterpret_cast<Base*>(
183*810390e3Srobert       reinterpret_cast<uptr>(n) -
184*810390e3Srobert       reinterpret_cast<uptr>(&(reinterpret_cast<Elem*>(0)->*Node))));
185*810390e3Srobert }
186*810390e3Srobert 
187*810390e3Srobert }  // namespace __tsan
188*810390e3Srobert 
189*810390e3Srobert #endif
190