File indexing completed on 2024-05-12 04:37:59
0001 /* 0002 SPDX-FileCopyrightText: 2007 Kris Wong <kris.p.wong@gmail.com> 0003 0004 SPDX-License-Identifier: LGPL-2.0-only 0005 */ 0006 0007 #ifndef KDEVPLATFORM_DUCHAINLOCK_H 0008 #define KDEVPLATFORM_DUCHAINLOCK_H 0009 0010 #include <language/languageexport.h> 0011 #include <QScopedPointer> 0012 0013 namespace KDevelop { 0014 // #define NO_DUCHAIN_LOCK_TESTING 0015 class DUChainLockPrivate; 0016 0017 /** 0018 * Macros for ensuring the DUChain is locked properly. 0019 * 0020 * These should be used in every method that accesses or modifies a 0021 * member on the DUChain or one of its contexts, if ENSURE_CAN_WRITE and ENSURE_CAN_READ do not apply. 0022 * From within a Declaration or DUContext, ENSURE_CAN_WRITE and ENSURE_CAN_READ should be used instead of these. 0023 */ 0024 #if !defined(NDEBUG) && !defined(NO_DUCHAIN_LOCK_TESTING) 0025 #define ENSURE_CHAIN_READ_LOCKED Q_ASSERT( \ 0026 KDevelop::DUChain::lock()->currentThreadHasReadLock() || \ 0027 KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 0028 #define ENSURE_CHAIN_WRITE_LOCKED Q_ASSERT(KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 0029 #define ENSURE_CHAIN_NOT_LOCKED Q_ASSERT( \ 0030 !KDevelop::DUChain::lock()->currentThreadHasReadLock() && \ 0031 !KDevelop::DUChain::lock()->currentThreadHasWriteLock()); 0032 #else 0033 #define ENSURE_CHAIN_READ_LOCKED 0034 #define ENSURE_CHAIN_WRITE_LOCKED 0035 #define ENSURE_CHAIN_NOT_LOCKED 0036 #endif 0037 0038 /** 0039 * Customized read/write locker for the definition-use chain. 0040 */ 0041 class KDEVPLATFORMLANGUAGE_EXPORT DUChainLock 0042 { 0043 public: 0044 /// Constructor. 0045 DUChainLock(); 0046 /// Destructor. 0047 ~DUChainLock(); 0048 0049 /** 0050 * Acquires a read lock. Will not return until the lock is acquired 0051 * or timeout 0052 * 0053 * Any number of read locks can be acquired at once, but not while 0054 * there is a write lock. Read locks are recursive. 0055 * That means that a thread can acquire a read-lock when it already 0056 * has an arbitrary count of read- and write-locks acquired. 0057 * @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. 0058 */ 0059 bool lockForRead(unsigned int timeout = 0); 0060 0061 /** 0062 * Releases a previously acquired read lock. 0063 */ 0064 void releaseReadLock(); 0065 0066 /** 0067 * Determines if the current thread has a read lock. 0068 */ 0069 bool currentThreadHasReadLock(); 0070 0071 /** 0072 * Acquires a write lock. Will not return until the lock is acquired 0073 * or timeout is reached (10 seconds). 0074 * 0075 * Write locks are recursive. That means that they can by acquired by threads 0076 * that already have an arbitrary count of write-locks acquired. 0077 * 0078 * @param timeout A timeout in milliseconds. If zero, the default-timeout is used(Currently 10 seconds). 0079 * 0080 * \warning Write-locks can NOT be acquired by threads that already have a read-lock. 0081 */ 0082 bool lockForWrite(unsigned int timeout = 0); 0083 0084 /** 0085 * Releases a previously acquired write lock. 0086 */ 0087 void releaseWriteLock(); 0088 0089 /** 0090 * Determines if the current thread has a write lock. 0091 */ 0092 bool currentThreadHasWriteLock() const; 0093 0094 private: 0095 const QScopedPointer<class DUChainLockPrivate> d_ptr; 0096 Q_DECLARE_PRIVATE(DUChainLock) 0097 }; 0098 0099 /** 0100 * Customized read locker for the definition-use chain. 0101 */ 0102 class KDEVPLATFORMLANGUAGE_EXPORT DUChainReadLocker 0103 { 0104 public: 0105 /** 0106 * Constructor. Attempts to acquire a read lock. 0107 * 0108 * \param duChainLock lock to read-acquire. If this is left zero, DUChain::lock() is used. 0109 * \param timeout Timeout in milliseconds. If this is not zero, you've got to check locked() to see whether the lock succeeded. 0110 */ 0111 explicit DUChainReadLocker(DUChainLock* duChainLock = nullptr, unsigned int timeout = 0); 0112 0113 /// Destructor. 0114 ~DUChainReadLocker(); 0115 0116 /// Acquire the read lock (again). Uses the same timeout given to the constructor. 0117 bool lock(); 0118 /// Unlock the read lock. 0119 void unlock(); 0120 0121 ///Returns true if a lock was requested and the lock succeeded, else false 0122 bool locked() const; 0123 0124 private: 0125 Q_DISABLE_COPY(DUChainReadLocker) 0126 0127 ///This class does not use a d-pointer for performance reasons (allocation+deletion in every high frequency is expensive) 0128 DUChainLock* m_lock; 0129 bool m_locked; 0130 unsigned int m_timeout; 0131 }; 0132 0133 /** 0134 * Customized write locker for the definition-use chain. 0135 */ 0136 class KDEVPLATFORMLANGUAGE_EXPORT DUChainWriteLocker 0137 { 0138 public: 0139 /** 0140 * Constructor. Attempts to acquire a write lock. 0141 * 0142 * \param duChainLock lock to write-acquire. If this is left zero, DUChain::lock() is used. 0143 * \param timeout Timeout in milliseconds. If this is not zero, you've got to check locked() to see whether the lock succeeded. 0144 */ 0145 explicit DUChainWriteLocker(DUChainLock* duChainLock = nullptr, unsigned int timeout = 0); 0146 /// Destructor. 0147 ~DUChainWriteLocker(); 0148 0149 /// Acquire the write lock (again). Uses the same timeout given to the constructor. 0150 bool lock(); 0151 /// Unlock the write lock. 0152 void unlock(); 0153 0154 ///Returns true if a lock was requested and the lock succeeded, else false 0155 bool locked() const; 0156 0157 private: 0158 Q_DISABLE_COPY(DUChainWriteLocker) 0159 0160 ///This class does not use a d-pointer for performance reasons (allocation+deletion in every high frequency is expensive) 0161 DUChainLock* m_lock; 0162 bool m_locked; 0163 unsigned int m_timeout; 0164 }; 0165 0166 /** 0167 * 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. 0168 * Those items must implement an inDUChain() function that returns whether the item is in the du-chain. 0169 * Examples for such detachable items are DUContext's and Declarations, they can be written as long as they are not in the DUChain. 0170 * */ 0171 #if !defined(NDEBUG) && !defined(NO_DUCHAIN_LOCK_TESTING) 0172 #define ENSURE_CAN_WRITE {if (inDUChain()) { ENSURE_CHAIN_WRITE_LOCKED }} 0173 #define ENSURE_CAN_READ {if (inDUChain()) { ENSURE_CHAIN_READ_LOCKED }} 0174 #else 0175 #define ENSURE_CAN_WRITE 0176 #define ENSURE_CAN_READ 0177 #endif 0178 } 0179 0180 #endif // KDEVPLATFORM_DUCHAINLOCK_H