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