1 /* 2 SPDX-FileCopyrightText: 2007 Kris Wong <kris.p.wong@gmail.com> 3 4 SPDX-License-Identifier: LGPL-2.0-only 5 */ 6 7 #ifndef KDEVPLATFORM_DUCHAINLOCK_H 8 #define KDEVPLATFORM_DUCHAINLOCK_H 9 10 #include <language/languageexport.h> 11 #include <QScopedPointer> 12 13 namespace KDevelop { 14 // #define NO_DUCHAIN_LOCK_TESTING 15 class DUChainLockPrivate; 16 17 /** 18 * Macros for ensuring the DUChain is locked properly. 19 * 20 * These should be used in every method that accesses or modifies a 21 * member on the DUChain or one of its contexts, if ENSURE_CAN_WRITE and ENSURE_CAN_READ do not apply. 22 * From within a Declaration or DUContext, ENSURE_CAN_WRITE and ENSURE_CAN_READ should be used instead of these. 23 */ 24 #if !defined(NDEBUG) && !defined(NO_DUCHAIN_LOCK_TESTING) 25 #define ENSURE_CHAIN_READ_LOCKED Q_ASSERT( \ 26 KDevelop::DUChain::lock()->currentThreadHasReadLock() || \ 27 KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 28 #define ENSURE_CHAIN_WRITE_LOCKED Q_ASSERT(KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 29 #define ENSURE_CHAIN_NOT_LOCKED Q_ASSERT( \ 30 !KDevelop::DUChain::lock()->currentThreadHasReadLock() && \ 31 !KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 32 #else 33 #define ENSURE_CHAIN_READ_LOCKED 34 #define ENSURE_CHAIN_WRITE_LOCKED 35 #define ENSURE_CHAIN_NOT_LOCKED 36 #endif 37 38 /** 39 * Customized read/write locker for the definition-use chain. 40 */ 41 class KDEVPLATFORMLANGUAGE_EXPORT DUChainLock 42 { 43 public: 44 /// Constructor. 45 DUChainLock(); 46 /// Destructor. 47 ~DUChainLock(); 48 49 /** 50 * Acquires a read lock. Will not return until the lock is acquired 51 * or timeout 52 * 53 * Any number of read locks can be acquired at once, but not while 54 * there is a write lock. Read locks are recursive. 55 * That means that a thread can acquire a read-lock when it already 56 * has an arbitrary count of read- and write-locks acquired. 57 * @param timeout A locking timeout in milliseconds. If it is reached, and the lock could not be acquired, false is returned. If null, the default timeout is used. 58 */ 59 bool lockForRead(unsigned int timeout = 0); 60 61 /** 62 * Releases a previously acquired read lock. 63 */ 64 void releaseReadLock(); 65 66 /** 67 * Determines if the current thread has a read lock. 68 */ 69 bool currentThreadHasReadLock(); 70 71 /** 72 * Acquires a write lock. Will not return until the lock is acquired 73 * or timeout is reached (10 seconds). 74 * 75 * Write locks are recursive. That means that they can by acquired by threads 76 * that already have an arbitrary count of write-locks acquired. 77 * 78 * @param timeout A timeout in milliseconds. If zero, the default-timeout is used(Currently 10 seconds). 79 * 80 * \warning Write-locks can NOT be acquired by threads that already have a read-lock. 81 */ 82 bool lockForWrite(unsigned int timeout = 0); 83 84 /** 85 * Releases a previously acquired write lock. 86 */ 87 void releaseWriteLock(); 88 89 /** 90 * Determines if the current thread has a write lock. 91 */ 92 bool currentThreadHasWriteLock() const; 93 94 private: 95 const QScopedPointer<class DUChainLockPrivate> d_ptr; 96 Q_DECLARE_PRIVATE(DUChainLock) 97 }; 98 99 /** 100 * Customized read locker for the definition-use chain. 101 */ 102 class KDEVPLATFORMLANGUAGE_EXPORT DUChainReadLocker 103 { 104 public: 105 /** 106 * Constructor. Attempts to acquire a read lock. 107 * 108 * \param duChainLock lock to read-acquire. If this is left zero, DUChain::lock() is used. 109 * \param timeout Timeout in milliseconds. If this is not zero, you've got to check locked() to see whether the lock succeeded. 110 */ 111 explicit DUChainReadLocker(DUChainLock* duChainLock = nullptr, unsigned int timeout = 0); 112 113 /// Destructor. 114 ~DUChainReadLocker(); 115 116 /// Acquire the read lock (again). Uses the same timeout given to the constructor. 117 bool lock(); 118 /// Unlock the read lock. 119 void unlock(); 120 121 ///Returns true if a lock was requested and the lock succeeded, else false 122 bool locked() const; 123 124 private: 125 Q_DISABLE_COPY(DUChainReadLocker) 126 127 ///This class does not use a d-pointer for performance reasons (allocation+deletion in every high frequency is expensive) 128 DUChainLock* m_lock; 129 bool m_locked; 130 unsigned int m_timeout; 131 }; 132 133 /** 134 * Customized write locker for the definition-use chain. 135 */ 136 class KDEVPLATFORMLANGUAGE_EXPORT DUChainWriteLocker 137 { 138 public: 139 /** 140 * Constructor. Attempts to acquire a write lock. 141 * 142 * \param duChainLock lock to write-acquire. If this is left zero, DUChain::lock() is used. 143 * \param timeout Timeout in milliseconds. If this is not zero, you've got to check locked() to see whether the lock succeeded. 144 */ 145 explicit DUChainWriteLocker(DUChainLock* duChainLock = nullptr, unsigned int timeout = 0); 146 /// Destructor. 147 ~DUChainWriteLocker(); 148 149 /// Acquire the write lock (again). Uses the same timeout given to the constructor. 150 bool lock(); 151 /// Unlock the write lock. 152 void unlock(); 153 154 ///Returns true if a lock was requested and the lock succeeded, else false 155 bool locked() const; 156 157 private: 158 Q_DISABLE_COPY(DUChainWriteLocker) 159 160 ///This class does not use a d-pointer for performance reasons (allocation+deletion in every high frequency is expensive) 161 DUChainLock* m_lock; 162 bool m_locked; 163 unsigned int m_timeout; 164 }; 165 166 /** 167 * Like the ENSURE_CHAIN_WRITE_LOCKED and .._READ_LOCKED, except that this should be used in items that can be detached from the du-chain, like DOContext's and Declarations. 168 * Those items must implement an inDUChain() function that returns whether the item is in the du-chain. 169 * Examples for such detachable items are DUContext's and Declarations, they can be written as long as they are not in the DUChain. 170 * */ 171 #if !defined(NDEBUG) && !defined(NO_DUCHAIN_LOCK_TESTING) 172 #define ENSURE_CAN_WRITE {if (inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }} 173 #define ENSURE_CAN_READ {if (inDUChain()) { ENSURE_CHAIN_READ_LOCKED }} 174 #else 175 #define ENSURE_CAN_WRITE 176 #define ENSURE_CAN_READ 177 #endif 178 } 179 180 #endif // KDEVPLATFORM_DUCHAINLOCK_H 181