• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevplatform/language/duchain

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • language
  • duchain
duchainlock.cpp
Go to the documentation of this file.
1 /* This file is part of KDevelop
2  Copyright 2007 Kris Wong <[email protected]>
3  Copyright 2007 Hamish Rodda <[email protected]>
4  Copyright 2007-2009 David Nolden <[email protected]>
5  Copyright 2013 Milian Wolff <[email protected]>
6 
7  This library is free software; you can redistribute it and/or
8  modify it under the terms of the GNU Library General Public
9  License version 2 as published by the Free Software Foundation.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20  */
21 
22 #include "duchainlock.h"
23 #include "duchain.h"
24 
25 #include <QThread>
26 #include <QThreadStorage>
27 #include <QElapsedTimer>
28 
31 
32 //Microseconds to sleep when waiting for a lock
33 const uint uSleepTime = 500;
34 
35 namespace KDevelop {
36 class DUChainLockPrivate
37 {
38 public:
39  DUChainLockPrivate()
40  : m_writer(nullptr)
41  , m_writerRecursion(0)
42  , m_totalReaderRecursion(0)
43  { }
44 
45  int ownReaderRecursion() const
46  {
47  return m_readerRecursion.localData();
48  }
49 
50  void changeOwnReaderRecursion(int difference)
51  {
52  m_readerRecursion.localData() += difference;
53  Q_ASSERT(m_readerRecursion.localData() >= 0);
54  m_totalReaderRecursion.fetchAndAddOrdered(difference);
55  }
56 
58  QAtomicPointer<QThread> m_writer;
59 
62  QAtomicInt m_writerRecursion;
64  QAtomicInt m_totalReaderRecursion;
65 
66  QThreadStorage<int> m_readerRecursion;
67 };
68 
69 DUChainLock::DUChainLock()
70  : d_ptr(new DUChainLockPrivate)
71 {
72 }
73 
74 DUChainLock::~DUChainLock() = default;
75 
76 bool DUChainLock::lockForRead(unsigned int timeout)
77 {
78  Q_D(DUChainLock);
79 
81  d->changeOwnReaderRecursion(1);
82 
83  QThread* w = d->m_writer.loadAcquire();
84  if (w == nullptr || w == QThread::currentThread()) {
85  //Successful lock: Either there is no writer, or we hold the write-lock by ourselves
86  } else {
88 
89  QElapsedTimer t;
90  if (timeout) {
91  t.start();
92  }
93 
94  while (d->m_writer.loadAcquire()) {
95  if (!timeout || t.elapsed() < timeout) {
96  QThread::usleep(uSleepTime);
97  } else {
98  //Fail!
99  d->changeOwnReaderRecursion(-1);
100  return false;
101  }
102  }
103  }
104 
105  return true;
106 }
107 
108 void DUChainLock::releaseReadLock()
109 {
110  Q_D(DUChainLock);
111 
112  d->changeOwnReaderRecursion(-1);
113 }
114 
115 bool DUChainLock::currentThreadHasReadLock()
116 {
117  Q_D(DUChainLock);
118 
119  return ( bool )d->ownReaderRecursion();
120 }
121 
122 bool DUChainLock::lockForWrite(uint timeout)
123 {
124  Q_D(DUChainLock);
125 
126  //It is not allowed to acquire a write-lock while holding read-lock
127 
128  Q_ASSERT(d->ownReaderRecursion() == 0);
129 
130 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
131  if (d->m_writer.loadRelaxed() == QThread::currentThread()) {
132 #else
133  if (d->m_writer.load() == QThread::currentThread()) {
134 #endif
135  //We already hold the write lock, just increase the recursion count and return
136  d->m_writerRecursion.fetchAndAddRelaxed(1);
137  return true;
138  }
139 
140  QElapsedTimer t;
141  if (timeout) {
142  t.start();
143  }
144 
145  while (1) {
146  //Try acquiring the write-lcok
147 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
148  if (d->m_totalReaderRecursion.loadRelaxed() == 0 &&
149 #else
150  if (d->m_totalReaderRecursion.load() == 0 &&
151 #endif
152  d->m_writerRecursion.testAndSetOrdered(0, 1)) {
153  //Now we can be sure that there is no other writer, as we have increased m_writerRecursion from 0 to 1
154  d->m_writer = QThread::currentThread();
155 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
156  if (d->m_totalReaderRecursion.loadRelaxed() == 0) {
157 #else
158  if (d->m_totalReaderRecursion.load() == 0) {
159 #endif
160  //There is still no readers, we have successfully acquired a write-lock
161  return true;
162  } else {
163  //There may be readers.. we have to continue spinning
164  d->m_writer = nullptr;
165  d->m_writerRecursion = 0;
166  }
167  }
168 
169  if (!timeout || t.elapsed() < timeout) {
170  QThread::usleep(uSleepTime);
171  } else {
172  //Fail!
173  return false;
174  }
175  }
176 
177  return false;
178 }
179 
180 void DUChainLock::releaseWriteLock()
181 {
182  Q_D(DUChainLock);
183 
184  Q_ASSERT(currentThreadHasWriteLock());
185 
186  //The order is important here, m_writerRecursion protects m_writer
187 
188  //TODO: could testAndSet here
189 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
190  if (d->m_writerRecursion.loadRelaxed() == 1) {
191 #else
192  if (d->m_writerRecursion.load() == 1) {
193 #endif
194  d->m_writer = nullptr;
195  d->m_writerRecursion = 0;
196  } else {
197  d->m_writerRecursion.fetchAndAddOrdered(-1);
198  }
199 }
200 
201 bool DUChainLock::currentThreadHasWriteLock() const
202 {
203  Q_D(const DUChainLock);
204 
205 #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
206  return d->m_writer.loadRelaxed() == QThread::currentThread();
207 #else
208  return d->m_writer.load() == QThread::currentThread();
209 #endif
210 }
211 
212 DUChainReadLocker::DUChainReadLocker(DUChainLock* duChainLock, uint timeout)
213  : m_lock(duChainLock ? duChainLock : DUChain::lock())
214  , m_locked(false)
215  , m_timeout(timeout)
216 {
217  lock();
218 }
219 
220 DUChainReadLocker::~DUChainReadLocker()
221 {
222  unlock();
223 }
224 
225 bool DUChainReadLocker::locked() const
226 {
227  return m_locked;
228 }
229 
230 bool DUChainReadLocker::lock()
231 {
232  if (m_locked) {
233  return true;
234  }
235 
236  bool l = false;
237  if (m_lock) {
238  l = m_lock->lockForRead(m_timeout);
239  Q_ASSERT(m_timeout || l);
240  }
241  ;
242 
243  m_locked = l;
244 
245  return l;
246 }
247 
248 void DUChainReadLocker::unlock()
249 {
250  if (m_locked && m_lock) {
251  m_lock->releaseReadLock();
252  m_locked = false;
253  }
254 }
255 
256 DUChainWriteLocker::DUChainWriteLocker(DUChainLock* duChainLock, uint timeout)
257  : m_lock(duChainLock ? duChainLock : DUChain::lock())
258  , m_locked(false)
259  , m_timeout(timeout)
260 {
261  lock();
262 }
263 
264 DUChainWriteLocker::~DUChainWriteLocker()
265 {
266  unlock();
267 }
268 
269 bool DUChainWriteLocker::lock()
270 {
271  if (m_locked) {
272  return true;
273  }
274 
275  bool l = false;
276  if (m_lock) {
277  l = m_lock->lockForWrite(m_timeout);
278  Q_ASSERT(m_timeout || l);
279  }
280  ;
281 
282  m_locked = l;
283 
284  return l;
285 }
286 
287 bool DUChainWriteLocker::locked() const
288 {
289  return m_locked;
290 }
291 
292 void DUChainWriteLocker::unlock()
293 {
294  if (m_locked && m_lock) {
295  m_lock->releaseWriteLock();
296  m_locked = false;
297  }
298 }
299 }
duchainlock.h
KDevelop::DUChainLock::lockForWrite
bool lockForWrite(unsigned int timeout=0)
Acquires a write lock.
Definition: duchainlock.cpp:122
KDevelop::DUChainReadLocker::unlock
void unlock()
Unlock the read lock.
Definition: duchainlock.cpp:248
KDevelop::DUChainReadLocker::lock
bool lock()
Acquire the read lock (again). Uses the same timeout given to the constructor.
Definition: duchainlock.cpp:230
KDevelop::DUChainLock::releaseReadLock
void releaseReadLock()
Releases a previously acquired read lock.
Definition: duchainlock.cpp:108
KDevelop::DUChainLock::lockForRead
bool lockForRead(unsigned int timeout=0)
Acquires a read lock.
Definition: duchainlock.cpp:76
KDevelop::DUChainWriteLocker::DUChainWriteLocker
DUChainWriteLocker(DUChainLock *duChainLock=nullptr, unsigned int timeout=0)
Constructor.
Definition: duchainlock.cpp:256
QThread
KDevelop::DUChainLock::DUChainLock
DUChainLock()
Constructor.
Definition: duchainlock.cpp:69
KDevelop::DUChainReadLocker::locked
bool locked() const
Returns true if a lock was requested and the lock succeeded, else false.
Definition: duchainlock.cpp:225
KDevelop::DUChainReadLocker::~DUChainReadLocker
~DUChainReadLocker()
Destructor.
Definition: duchainlock.cpp:220
KDevelop::DUChainLock
Customized read/write locker for the definition-use chain.
Definition: duchainlock.h:53
KDevelop::DUChainLock::currentThreadHasReadLock
bool currentThreadHasReadLock()
Determines if the current thread has a read lock.
Definition: duchainlock.cpp:115
KDevelop::DUChainLock::currentThreadHasWriteLock
bool currentThreadHasWriteLock() const
Determines if the current thread has a write lock.
Definition: duchainlock.cpp:201
KDevelop::DUChainWriteLocker::locked
bool locked() const
Returns true if a lock was requested and the lock succeeded, else false.
Definition: duchainlock.cpp:287
QThread::currentThread
QThread * currentThread()
QThread::usleep
void usleep(unsigned long usecs)
QElapsedTimer
QElapsedTimer::elapsed
qint64 elapsed() const
KDevelop::DUChainLock::~DUChainLock
~DUChainLock()
Destructor.
KDevelop::DUChainWriteLocker::lock
bool lock()
Acquire the write lock (again). Uses the same timeout given to the constructor.
Definition: duchainlock.cpp:269
QAtomicInt
KDevelop::DUChainWriteLocker::~DUChainWriteLocker
~DUChainWriteLocker()
Destructor.
Definition: duchainlock.cpp:264
KDevelop::DUChainReadLocker::DUChainReadLocker
DUChainReadLocker(DUChainLock *duChainLock=nullptr, unsigned int timeout=0)
Constructor.
Definition: duchainlock.cpp:212
uSleepTime
const uint uSleepTime
Definition: duchainlock.cpp:33
duchain.h
QThreadStorage< int >
KDevelop
Definition: abstractfunctiondeclaration.cpp:27
KDevelop::DUChainWriteLocker::unlock
void unlock()
Unlock the write lock.
Definition: duchainlock.cpp:292
KDevelop::DUChain
Holds references to all top level source file contexts.
Definition: duchain.h:54
KDevelop::DUChainLock::releaseWriteLock
void releaseWriteLock()
Releases a previously acquired write lock.
Definition: duchainlock.cpp:180
QElapsedTimer::start
void start()
QAtomicPointer< QThread >
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Sat Jan 16 2021 23:35:05 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/language/duchain

Skip menu "kdevplatform/language/duchain"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  • kdevplatform
  •   debugger
  •   documentation
  •   interfaces
  •   language
  •     assistant
  •     backgroundparser
  •     checks
  •     classmodel
  •     codecompletion
  •     codegen
  •     duchain
  •     editor
  •     highlighting
  •     interfaces
  •     util
  •   outputview
  •   project
  •   serialization
  •   shell
  •   sublime
  •   tests
  •   util
  •   vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal