1 //===-- tsan_ilist.h --------------------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file is a part of ThreadSanitizer (TSan), a race detector.
11 //===----------------------------------------------------------------------===//
15 #include "sanitizer_common/sanitizer_internal_defs.h"
24 INode
* next_
= nullptr;
25 INode
* prev_
= nullptr;
27 template <typename Base
, INode
Base::*Node
, typename Elem
>
29 INode(const INode
&) = delete;
30 void operator=(const INode
&) = delete;
33 // Intrusive doubly-linked list.
35 // The node class (MyNode) needs to include "INode foo" field,
36 // then the list can be declared as IList<MyNode, &MyNode::foo>.
37 // This design allows to link MyNode into multiple lists using
38 // different INode fields.
39 // The optional Elem template argument allows to specify node MDT
40 // (most derived type) if it's different from MyNode.
41 template <typename Base
, INode
Base::*Node
, typename Elem
= Base
>
46 void PushFront(Elem
* e
);
47 void PushBack(Elem
* e
);
55 // Prev links point towards front of the queue.
57 // Next links point towards back of the queue.
62 bool Queued(Elem
* e
) const;
68 void Push(Elem
* e
, INode
* after
);
69 static INode
* ToNode(Elem
* e
);
70 static Elem
* ToElem(INode
* n
);
72 IList(const IList
&) = delete;
73 void operator=(const IList
&) = delete;
76 template <typename Base
, INode
Base::*Node
, typename Elem
>
77 IList
<Base
, Node
, Elem
>::IList() {
78 node_
.next_
= node_
.prev_
= &node_
;
81 template <typename Base
, INode
Base::*Node
, typename Elem
>
82 void IList
<Base
, Node
, Elem
>::PushFront(Elem
* e
) {
86 template <typename Base
, INode
Base::*Node
, typename Elem
>
87 void IList
<Base
, Node
, Elem
>::PushBack(Elem
* e
) {
91 template <typename Base
, INode
Base::*Node
, typename Elem
>
92 void IList
<Base
, Node
, Elem
>::Push(Elem
* e
, INode
* after
) {
94 DCHECK_EQ(n
->next_
, nullptr);
95 DCHECK_EQ(n
->prev_
, nullptr);
96 INode
* next
= after
->next_
;
104 template <typename Base
, INode
Base::*Node
, typename Elem
>
105 void IList
<Base
, Node
, Elem
>::Remove(Elem
* e
) {
106 INode
* n
= ToNode(e
);
107 INode
* next
= n
->next_
;
108 INode
* prev
= n
->prev_
;
114 n
->prev_
= n
->next_
= nullptr;
118 template <typename Base
, INode
Base::*Node
, typename Elem
>
119 Elem
* IList
<Base
, Node
, Elem
>::PopFront() {
126 template <typename Base
, INode
Base::*Node
, typename Elem
>
127 Elem
* IList
<Base
, Node
, Elem
>::PopBack() {
134 template <typename Base
, INode
Base::*Node
, typename Elem
>
135 Elem
* IList
<Base
, Node
, Elem
>::Front() {
136 return size_
? ToElem(node_
.next_
) : nullptr;
139 template <typename Base
, INode
Base::*Node
, typename Elem
>
140 Elem
* IList
<Base
, Node
, Elem
>::Back() {
141 return size_
? ToElem(node_
.prev_
) : nullptr;
144 template <typename Base
, INode
Base::*Node
, typename Elem
>
145 Elem
* IList
<Base
, Node
, Elem
>::Prev(Elem
* e
) {
146 INode
* n
= ToNode(e
);
148 return n
->prev_
!= &node_
? ToElem(n
->prev_
) : nullptr;
151 template <typename Base
, INode
Base::*Node
, typename Elem
>
152 Elem
* IList
<Base
, Node
, Elem
>::Next(Elem
* e
) {
153 INode
* n
= ToNode(e
);
155 return n
->next_
!= &node_
? ToElem(n
->next_
) : nullptr;
158 template <typename Base
, INode
Base::*Node
, typename Elem
>
159 uptr IList
<Base
, Node
, Elem
>::Size() const {
163 template <typename Base
, INode
Base::*Node
, typename Elem
>
164 bool IList
<Base
, Node
, Elem
>::Empty() const {
168 template <typename Base
, INode
Base::*Node
, typename Elem
>
169 bool IList
<Base
, Node
, Elem
>::Queued(Elem
* e
) const {
170 INode
* n
= ToNode(e
);
171 DCHECK_EQ(!n
->next_
, !n
->prev_
);
175 template <typename Base
, INode
Base::*Node
, typename Elem
>
176 INode
* IList
<Base
, Node
, Elem
>::ToNode(Elem
* e
) {
180 template <typename Base
, INode
Base::*Node
, typename Elem
>
181 Elem
* IList
<Base
, Node
, Elem
>::ToElem(INode
* n
) {
182 return static_cast<Elem
*>(reinterpret_cast<Base
*>(
183 reinterpret_cast<uptr
>(n
) -
184 reinterpret_cast<uptr
>(&(reinterpret_cast<Elem
*>(0)->*Node
))));
187 } // namespace __tsan