19
19
#include < stdio.h>
20
20
#endif
21
21
22
+ namespace swift {
23
+
22
24
// / This is a node in a concurrent linked list.
23
25
template <class ElemTy > struct ConcurrentListNode {
24
26
ConcurrentListNode (ElemTy Elem) : Payload(Elem), Next(nullptr ) {}
@@ -123,6 +125,29 @@ template <class ElemTy> struct ConcurrentList {
123
125
std::atomic<ConcurrentListNode<ElemTy> *> First;
124
126
};
125
127
128
+ template <class T , bool Delete> class AtomicMaybeOwningPointer ;
129
+
130
+ template <class T >
131
+ class AtomicMaybeOwningPointer <T, false > {
132
+ public:
133
+ std::atomic<T*> Value;
134
+ constexpr AtomicMaybeOwningPointer (T *value) : Value(value) {}
135
+ };
136
+
137
+ template <class T >
138
+ class AtomicMaybeOwningPointer <T, true > {
139
+ public:
140
+ std::atomic<T*> Value;
141
+ constexpr AtomicMaybeOwningPointer (T *value) : Value(value) {}
142
+
143
+ ~AtomicMaybeOwningPointer () {
144
+ // This can use relaxed memory order because the client has to ensure
145
+ // that all accesses are safely completed and their effects fully
146
+ // visible before destruction occurs anyway.
147
+ ::delete Value.load (std::memory_order_relaxed);
148
+ }
149
+ };
150
+
126
151
// / A concurrent map that is implemented using a binary tree. It supports
127
152
// / concurrent insertions but does not support removals or rebalancing of
128
153
// / the tree.
@@ -140,7 +165,8 @@ template <class ElemTy> struct ConcurrentList {
140
165
// / /// where KeyTy is the type of the first argument to getOrInsert and
141
166
// / /// ArgTys is the type of the remaining arguments.
142
167
// / static size_t getExtraAllocationSize(KeyTy key, ArgTys...)
143
- template <class EntryTy > class ConcurrentMap {
168
+ template <class EntryTy , bool ProvideDestructor = true >
169
+ class ConcurrentMap {
144
170
struct Node {
145
171
std::atomic<Node*> Left;
146
172
std::atomic<Node*> Right;
@@ -182,7 +208,7 @@ template <class EntryTy> class ConcurrentMap {
182
208
};
183
209
184
210
// / The root of the tree.
185
- std::atomic <Node* > Root;
211
+ AtomicMaybeOwningPointer <Node, ProvideDestructor > Root;
186
212
187
213
// / This member stores the address of the last node that was found by the
188
214
// / search procedure. We cache the last search to accelerate code that
@@ -195,13 +221,14 @@ template <class EntryTy> class ConcurrentMap {
195
221
ConcurrentMap (const ConcurrentMap &) = delete ;
196
222
ConcurrentMap &operator =(const ConcurrentMap &) = delete ;
197
223
198
- ~ConcurrentMap () {
199
- ::delete Root.load (std::memory_order_relaxed);
200
- }
224
+ // ConcurrentMap<T, false> must have a trivial destructor.
225
+ ~ConcurrentMap () = default ;
226
+
227
+ public:
201
228
202
229
#ifndef NDEBUG
203
230
void dump () const {
204
- auto R = Root.load (std::memory_order_acquire);
231
+ auto R = Root.Value . load (std::memory_order_acquire);
205
232
printf (" digraph g {\n "
206
233
" graph [ rankdir = \" TB\" ];\n "
207
234
" node [ fontsize = \" 16\" ];\n "
@@ -225,7 +252,7 @@ template <class EntryTy> class ConcurrentMap {
225
252
}
226
253
227
254
// Search the tree, starting from the root.
228
- Node *node = Root.load (std::memory_order_acquire);
255
+ Node *node = Root.Value . load (std::memory_order_acquire);
229
256
while (node) {
230
257
int comparisonResult = node->Payload .compareWithKey (key);
231
258
if (comparisonResult == 0 ) {
@@ -258,7 +285,7 @@ template <class EntryTy> class ConcurrentMap {
258
285
Node *newNode = nullptr ;
259
286
260
287
// Start from the root.
261
- auto edge = &Root;
288
+ auto edge = &Root. Value ;
262
289
263
290
while (true ) {
264
291
// Load the edge.
@@ -313,4 +340,6 @@ template <class EntryTy> class ConcurrentMap {
313
340
}
314
341
};
315
342
343
+ } // end namespace swift
344
+
316
345
#endif // SWIFT_RUNTIME_CONCURRENTUTILS_H
0 commit comments