|
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