Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_lockless_stack.h
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2010 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * References:
5 * * Maged M. Michael, Safe memory reclamation for dynamic
6 * lock-free objects using atomic reads and writes,
7 * Proceedings of the twenty-first annual symposium on
8 * Principles of distributed computing, July 21-24, 2002,
9 * Monterey, California
10 *
11 * * Idea of m_deleteBlockers is taken from Andrey Gulin's blog
12 * https://users.livejournal.com/-foreseer/34284.html
13 *
14 * SPDX-License-Identifier: GPL-2.0-or-later
15 */
16
17#ifndef __KIS_LOCKLESS_STACK_H
18#define __KIS_LOCKLESS_STACK_H
19
20#include <QAtomicPointer>
21
22template<class T>
24{
25private:
26 struct Node {
29 };
30
31public:
34
35 freeList(m_top.fetchAndStoreOrdered(0));
36 freeList(m_freeNodes.fetchAndStoreOrdered(0));
37 }
38
39 void push(T data) {
40 Node *newNode = new Node();
41 newNode->data = data;
42
43 Node *top;
44
45 do {
46 top = m_top;
47 newNode->next = top;
48 } while (!m_top.testAndSetOrdered(top, newNode));
49
50 m_numNodes.ref();
51 }
52
53 bool pop(T &value) {
54 bool result = false;
55
56 m_deleteBlockers.ref();
57
58 while(1) {
59 Node *top = (Node*) m_top;
60 if(!top) break;
61
62 // This is safe as we ref'ed m_deleteBlockers
63 Node *next = top->next;
64
65 if(m_top.testAndSetOrdered(top, next)) {
66 m_numNodes.deref();
67 result = true;
68
69 value = top->data;
70
77 if (m_deleteBlockers == 1) {
79 delete top;
80 }
81 else {
82 releaseNode(top);
83 }
84
85 break;
86 }
87 }
88
89 m_deleteBlockers.deref();
90
91 return result;
92 }
93
94 void clear() {
95 // a fast-path without write ops
96 if(!m_top) return;
97
98 m_deleteBlockers.ref();
99
100 Node *top = m_top.fetchAndStoreOrdered(0);
101
102 int removedChunkSize = 0;
103 Node *tmp = top;
104 while(tmp) {
105 removedChunkSize++;
106 tmp = tmp->next;
107 }
108 m_numNodes.fetchAndAddOrdered(-removedChunkSize);
109
110 while(top) {
111 Node *next = top->next;
112
113 if (m_deleteBlockers == 1) {
118 cleanUpNodes();
119 freeList(top);
120 next = 0;
121 }
122 else {
123 releaseNode(top);
124 }
125
126 top = next;
127 }
128
129 m_deleteBlockers.deref();
130 }
131
133 Node *otherTop = other.m_top.fetchAndStoreOrdered(0);
134 if (!otherTop) return;
135
136 int removedChunkSize = 1;
137 Node *last = otherTop;
138 while(last->next) {
139 removedChunkSize++;
140 last = last->next;
141 }
142 other.m_numNodes.fetchAndAddOrdered(-removedChunkSize);
143
144 Node *top;
145
146 do {
147 top = m_top;
148 last->next = top;
149 } while (!m_top.testAndSetOrdered(top, otherTop));
150
151 m_numNodes.fetchAndAddOrdered(removedChunkSize);
152 }
153
159 qint32 size() const {
160 return m_numNodes;
161 }
162
163 bool isEmpty() const {
164 return !m_numNodes;
165 }
166
167private:
168
169 inline void releaseNode(Node *node) {
170 Node *top;
171 do {
172 top = m_freeNodes;
173 node->next = top;
174 } while (!m_freeNodes.testAndSetOrdered(top, node));
175 }
176
177 inline void cleanUpNodes() {
178 Node *cleanChain = m_freeNodes.fetchAndStoreOrdered(0);
179 if (!cleanChain) return;
180
187 if (m_deleteBlockers == 1) {
188 freeList(cleanChain);
189 } else {
190 Node *last = cleanChain;
191 while (last->next) last = last->next;
192
193 Node *freeTop;
194
195 do {
196 freeTop = m_freeNodes;
197 last->next = freeTop;
198 } while (!m_freeNodes.testAndSetOrdered(freeTop, cleanChain));
199 }
200 }
201
202 inline void freeList(Node *first) {
203 Node *next;
204 while (first) {
205 next = first->next;
206 delete first;
207 first = next;
208 }
209 }
210
211
212private:
213 Q_DISABLE_COPY(KisLocklessStack)
214
215 QAtomicPointer<Node> m_top;
216 QAtomicPointer<Node> m_freeNodes;
217
219 QAtomicInt m_numNodes;
220};
221
222#endif /* __KIS_LOCKLESS_STACK_H */
223
float value(const T *src, size_t ch)
QAtomicPointer< Node > m_freeNodes
void releaseNode(Node *node)
QAtomicPointer< Node > m_top
void mergeFrom(KisLocklessStack< T > &other)
void freeList(Node *first)