|
33 | 33 |
|
34 | 34 | namespace swift {
|
35 | 35 |
|
36 |
| -/// This is a node in a concurrent linked list. |
37 |
| -template <class ElemTy> struct ConcurrentListNode { |
38 |
| - ConcurrentListNode(ElemTy Elem) : Payload(Elem), Next(nullptr) {} |
39 |
| - ConcurrentListNode(const ConcurrentListNode &) = delete; |
40 |
| - ConcurrentListNode &operator=(const ConcurrentListNode &) = delete; |
41 |
| - |
42 |
| - /// The element. |
43 |
| - ElemTy Payload; |
44 |
| - /// Points to the next link in the chain. |
45 |
| - ConcurrentListNode<ElemTy> *Next; |
46 |
| -}; |
47 |
| - |
48 |
| -/// This is a concurrent linked list. It supports insertion at the beginning |
49 |
| -/// of the list and traversal using iterators. |
50 |
| -/// This is a very simple implementation of a concurrent linked list |
51 |
| -/// using atomic operations. The 'push_front' method allocates a new link |
52 |
| -/// and attempts to compare and swap the old head pointer with pointer to |
53 |
| -/// the new link. This operation may fail many times if there are other |
54 |
| -/// contending threads, but eventually the head pointer is set to the new |
55 |
| -/// link that already points to the old head value. Notice that the more |
56 |
| -/// difficult feature of removing links is not supported. |
57 |
| -/// See 'push_front' for more details. |
58 |
| -template <class ElemTy> struct ConcurrentList { |
59 |
| - ConcurrentList() : First(nullptr) {} |
60 |
| - ~ConcurrentList() { |
61 |
| - clear(); |
62 |
| - } |
63 |
| - |
64 |
| - /// Remove all of the links in the chain. This method leaves |
65 |
| - /// the list at a usable state and new links can be added. |
66 |
| - /// Notice that this operation is non-sendable because |
67 |
| - /// we have no way of ensuring that no one is currently |
68 |
| - /// traversing the list. |
69 |
| - void clear() { |
70 |
| - // Iterate over the list and delete all the nodes. |
71 |
| - auto Ptr = First.load(std::memory_order_acquire); |
72 |
| - First.store(nullptr, std:: memory_order_release); |
73 |
| - |
74 |
| - while (Ptr) { |
75 |
| - auto N = Ptr->Next; |
76 |
| - delete Ptr; |
77 |
| - Ptr = N; |
78 |
| - } |
79 |
| - } |
80 |
| - |
81 |
| - ConcurrentList(const ConcurrentList &) = delete; |
82 |
| - ConcurrentList &operator=(const ConcurrentList &) = delete; |
83 |
| - |
84 |
| - /// A list iterator. |
85 |
| - struct ConcurrentListIterator : |
86 |
| - public std::iterator<std::forward_iterator_tag, ElemTy> { |
87 |
| - |
88 |
| - /// Points to the current link. |
89 |
| - ConcurrentListNode<ElemTy> *Ptr; |
90 |
| - /// C'tor. |
91 |
| - ConcurrentListIterator(ConcurrentListNode<ElemTy> *P) : Ptr(P) {} |
92 |
| - /// Move to the next element. |
93 |
| - ConcurrentListIterator &operator++() { |
94 |
| - Ptr = Ptr->Next; |
95 |
| - return *this; |
96 |
| - } |
97 |
| - /// Access the element. |
98 |
| - ElemTy &operator*() { return Ptr->Payload; } |
99 |
| - /// Same? |
100 |
| - bool operator==(const ConcurrentListIterator &o) const { |
101 |
| - return o.Ptr == Ptr; |
102 |
| - } |
103 |
| - /// Not the same? |
104 |
| - bool operator!=(const ConcurrentListIterator &o) const { |
105 |
| - return o.Ptr != Ptr; |
106 |
| - } |
107 |
| - }; |
108 |
| - |
109 |
| - /// Iterator entry point. |
110 |
| - typedef ConcurrentListIterator iterator; |
111 |
| - /// Marks the beginning of the list. |
112 |
| - iterator begin() const { |
113 |
| - return ConcurrentListIterator(First.load(std::memory_order_acquire)); |
114 |
| - } |
115 |
| - /// Marks the end of the list. |
116 |
| - iterator end() const { return ConcurrentListIterator(nullptr); } |
117 |
| - |
118 |
| - /// Add a new item to the list. |
119 |
| - void push_front(ElemTy Elem) { |
120 |
| - /// Allocate a new node. |
121 |
| - ConcurrentListNode<ElemTy> *N = new ConcurrentListNode<ElemTy>(Elem); |
122 |
| - // Point to the first element in the list. |
123 |
| - N->Next = First.load(std::memory_order_acquire); |
124 |
| - auto OldFirst = N->Next; |
125 |
| - // Try to replace the current First with the new node. |
126 |
| - while (!std::atomic_compare_exchange_weak_explicit(&First, &OldFirst, N, |
127 |
| - std::memory_order_release, |
128 |
| - std::memory_order_relaxed)) { |
129 |
| - // If we fail, update the new node to point to the new head and try to |
130 |
| - // insert before the new |
131 |
| - // first element. |
132 |
| - N->Next = OldFirst; |
133 |
| - } |
134 |
| - } |
135 |
| - |
136 |
| - /// Points to the first link in the list. |
137 |
| - std::atomic<ConcurrentListNode<ElemTy> *> First; |
138 |
| -}; |
139 |
| - |
140 | 36 | /// A utility function for ordering two integers, which is useful
|
141 | 37 | /// for implementing compareWithKey.
|
142 | 38 | template <class T>
|
|
0 commit comments