File indexing completed on 2024-05-26 04:28:04
0001 /* 0002 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org> 0003 * (c) 2009 Dmitry Kazakov <dimula73@gmail.com> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 0008 0009 #include "kis_tile_data.h" 0010 #include "kis_tile_data_store.h" 0011 #include "kis_tile.h" 0012 #include "kis_memento_manager.h" 0013 #include "kis_debug.h" 0014 0015 0016 void KisTile::init(qint32 col, qint32 row, 0017 KisTileData *defaultTileData, KisMementoManager* mm) 0018 { 0019 m_col = col; 0020 m_row = row; 0021 m_lockCounter = 0; 0022 0023 m_extent = QRect(m_col * KisTileData::WIDTH, m_row * KisTileData::HEIGHT, 0024 KisTileData::WIDTH, KisTileData::HEIGHT); 0025 0026 m_tileData = defaultTileData; 0027 m_tileData->acquire(); 0028 0029 if (mm) { 0030 mm->registerTileChange(this); 0031 } 0032 m_mementoManager.storeRelease(mm); 0033 } 0034 0035 KisTile::KisTile(qint32 col, qint32 row, 0036 KisTileData *defaultTileData, KisMementoManager* mm) 0037 { 0038 init(col, row, defaultTileData, mm); 0039 } 0040 0041 KisTile::KisTile(const KisTile& rhs, qint32 col, qint32 row, KisMementoManager* mm) 0042 : KisShared() 0043 { 0044 init(col, row, rhs.tileData(), mm); 0045 } 0046 0047 KisTile::KisTile(const KisTile& rhs, KisMementoManager* mm) 0048 : KisShared() 0049 { 0050 init(rhs.col(), rhs.row(), rhs.tileData(), mm); 0051 } 0052 0053 KisTile::KisTile(const KisTile& rhs) 0054 : KisShared() 0055 { 0056 init(rhs.col(), rhs.row(), rhs.tileData(), rhs.m_mementoManager); 0057 } 0058 0059 KisTile::~KisTile() 0060 { 0061 #ifdef DEAD_TILES_SANITY_CHECK 0062 KIS_ASSERT(!m_lockCounter); 0063 0064 /** 0065 * We should have been disconnected from the memento manager in 0066 * notifyDetachedFromDataManager() or notifyDeadWithoutDetaching(), 0067 * otherwise there is a bug 0068 */ 0069 0070 if (m_mementoManager) { 0071 qDebug() << this << ppVar(m_sanityNumCOWHappened); 0072 qDebug() << this << ppVar(m_sanityHasBeenDetached); 0073 qDebug() << this << ppVar(m_sanityMMHasBeenInitializedManually); 0074 qDebug() << this << ppVar(m_sanityIsDead); 0075 KIS_ASSERT(0 && "m_mementoManager is still initialized during destruction"); 0076 } 0077 #endif 0078 0079 m_tileData->release(); 0080 } 0081 0082 void KisTile::notifyDetachedFromDataManager() 0083 { 0084 #ifdef DEAD_TILES_SANITY_CHECK 0085 sanityCheckIsNotLockedForWrite(); 0086 #endif 0087 0088 if (m_mementoManager.loadAcquire()) { 0089 KisMementoManager *manager = m_mementoManager; 0090 m_mementoManager.storeRelease(0); 0091 manager->registerTileDeleted(this); 0092 } 0093 0094 #ifdef DEAD_TILES_SANITY_CHECK 0095 m_sanityHasBeenDetached.ref(); 0096 #endif 0097 } 0098 0099 void KisTile::notifyDeadWithoutDetaching() 0100 { 0101 #ifdef DEAD_TILES_SANITY_CHECK 0102 sanityCheckIsNotLockedForWrite(); 0103 #endif 0104 0105 m_mementoManager.storeRelease(0); 0106 0107 #ifdef DEAD_TILES_SANITY_CHECK 0108 m_sanityIsDead.ref(); 0109 #endif 0110 } 0111 0112 void KisTile::notifyAttachedToDataManager(KisMementoManager *mm) 0113 { 0114 #ifdef DEAD_TILES_SANITY_CHECK 0115 sanityCheckIsNotDestroyedYet(); 0116 #endif 0117 0118 // TODO: check if we really need locking here 0119 if (!m_mementoManager.loadAcquire()) { 0120 QMutexLocker locker(&m_COWMutex); 0121 0122 if (!m_mementoManager.loadAcquire()) { 0123 0124 if (mm) { 0125 mm->registerTileChange(this); 0126 } 0127 m_mementoManager.storeRelease(mm); 0128 0129 #ifdef DEAD_TILES_SANITY_CHECK 0130 m_sanityMMHasBeenInitializedManually.ref(); 0131 #endif 0132 } 0133 } 0134 0135 #ifdef DEAD_TILES_SANITY_CHECK 0136 sanityCheckIsNotDestroyedYet(); 0137 #endif 0138 } 0139 0140 //#define DEBUG_TILE_LOCKING 0141 //#define DEBUG_TILE_COWING 0142 0143 #ifdef DEBUG_TILE_LOCKING 0144 #define DEBUG_LOG_ACTION(action) \ 0145 printf("### %s \ttile:\t0x%llX (%d, %d) (0x%llX) ###\n", action, (quintptr)this, m_col, m_row, (quintptr)m_tileData) 0146 #else 0147 #define DEBUG_LOG_ACTION(action) 0148 #endif 0149 0150 #ifdef DEBUG_TILE_COWING 0151 #define DEBUG_COWING(newTD) \ 0152 printf("### COW done \ttile:\t0x%X (%d, %d) (0x%X -> 0x%X) [mm: 0x%X] ###\n", (quintptr)this, m_col, m_row, (quintptr)m_tileData, (quintptr)newTD, m_mementoManager); 0153 #else 0154 #define DEBUG_COWING(newTD) 0155 #endif 0156 0157 inline void KisTile::blockSwapping() const 0158 { 0159 /** 0160 * We need to hold a special barrier lock here to ensure 0161 * m_tileData->blockSwapping() has finished executing 0162 * before anyone started reading the tile data. That is 0163 * why we can not use atomic operations here. 0164 */ 0165 0166 QMutexLocker locker(&m_swapBarrierLock); 0167 Q_ASSERT(m_lockCounter >= 0); 0168 0169 if(!m_lockCounter++) 0170 m_tileData->blockSwapping(); 0171 0172 Q_ASSERT(data()); 0173 } 0174 0175 inline void KisTile::unblockSwapping() const 0176 { 0177 QMutexLocker locker(&m_swapBarrierLock); 0178 Q_ASSERT(m_lockCounter > 0); 0179 0180 if(--m_lockCounter == 0) { 0181 m_tileData->unblockSwapping(); 0182 0183 if(!m_oldTileData.isEmpty()) { 0184 Q_FOREACH (KisTileData *td, m_oldTileData) { 0185 td->unblockSwapping(); 0186 td->release(); 0187 } 0188 m_oldTileData.clear(); 0189 } 0190 } 0191 } 0192 0193 inline void KisTile::safeReleaseOldTileData(KisTileData *td) 0194 { 0195 QMutexLocker locker(&m_swapBarrierLock); 0196 Q_ASSERT(m_lockCounter >= 0); 0197 0198 if(m_lockCounter > 0) { 0199 m_oldTileData.push(td); 0200 } 0201 else { 0202 td->unblockSwapping(); 0203 td->release(); 0204 } 0205 } 0206 0207 void KisTile::lockForRead() const 0208 { 0209 #ifdef DEAD_TILES_SANITY_CHECK 0210 m_sanityLockedForRead.ref(); 0211 #endif 0212 0213 DEBUG_LOG_ACTION("lock [R]"); 0214 blockSwapping(); 0215 } 0216 0217 0218 #define lazyCopying() (m_tileData->m_usersCount>1) 0219 0220 void KisTile::lockForWrite() 0221 { 0222 #ifdef DEAD_TILES_SANITY_CHECK 0223 m_sanityLockedForWrite.ref(); 0224 #endif 0225 0226 blockSwapping(); 0227 0228 /* We are doing COW here */ 0229 if (lazyCopying()) { 0230 m_COWMutex.lock(); 0231 0232 /** 0233 * Everything could have happened before we took 0234 * the mutex, so let's check again... 0235 */ 0236 0237 if (lazyCopying()) { 0238 0239 KisTileData *tileData = m_tileData->clone(); 0240 tileData->acquire(); 0241 tileData->blockSwapping(); 0242 KisTileData *oldTileData = m_tileData; 0243 m_tileData = tileData; 0244 safeReleaseOldTileData(oldTileData); 0245 0246 DEBUG_COWING(tileData); 0247 0248 KisMementoManager *mm = m_mementoManager.load(); 0249 if (mm) { 0250 mm->registerTileChange(this); 0251 } 0252 } 0253 m_COWMutex.unlock(); 0254 0255 #ifdef DEAD_TILES_SANITY_CHECK 0256 m_sanityNumCOWHappened.ref(); 0257 #endif 0258 } 0259 0260 DEBUG_LOG_ACTION("lock [W]"); 0261 } 0262 0263 void KisTile::unlockForWrite() 0264 { 0265 unblockSwapping(); 0266 DEBUG_LOG_ACTION("unlock [W]"); 0267 0268 #ifdef DEAD_TILES_SANITY_CHECK 0269 m_sanityLockedForWrite.deref(); 0270 KIS_ASSERT(m_sanityLockedForWrite.loadAcquire() >= 0); 0271 #endif 0272 } 0273 0274 void KisTile::unlockForRead() const 0275 { 0276 unblockSwapping(); 0277 DEBUG_LOG_ACTION("unlock [R]"); 0278 0279 #ifdef DEAD_TILES_SANITY_CHECK 0280 m_sanityLockedForRead.deref(); 0281 KIS_ASSERT(m_sanityLockedForRead.loadAcquire() >= 0); 0282 #endif 0283 } 0284 0285 0286 #include <stdio.h> 0287 void KisTile::debugPrintInfo() 0288 { 0289 dbgTiles << "------\n" 0290 "Tile:\t\t\t" << this 0291 << "\n data:\t" << m_tileData 0292 << "\n next:\t" << m_nextTile.data(); 0293 0294 } 0295 0296 void KisTile::debugDumpTile() 0297 { 0298 lockForRead(); 0299 quint8 *data = this->data(); 0300 0301 for (int i = 0; i < KisTileData::HEIGHT; i++) { 0302 for (int j = 0; j < KisTileData::WIDTH; j++) { 0303 dbgTiles << data[(i*KisTileData::WIDTH+j)*pixelSize()]; 0304 } 0305 } 0306 unlockForRead(); 0307 } 0308 0309 #ifdef DEAD_TILES_SANITY_CHECK 0310 0311 void KisTile::sanityCheckIsNotDestroyedYet() 0312 { 0313 if (m_lockCounter) { 0314 qDebug() << this << ppVar(m_sanityLockedForRead); 0315 qDebug() << this << ppVar(m_sanityLockedForWrite); 0316 qDebug() << this << ppVar(m_lockCounter); 0317 0318 KIS_ASSERT(!m_lockCounter || !m_sanityLockedForWrite && "sanityCheckIsNotDestroyedYet() failed"); 0319 } 0320 } 0321 0322 void KisTile::sanityCheckIsNotLockedForWrite() 0323 { 0324 if (m_sanityHasBeenDetached.loadAcquire()) { 0325 qDebug() << this << ppVar(m_sanityNumCOWHappened); 0326 qDebug() << this << ppVar(m_sanityHasBeenDetached); 0327 qDebug() << this << ppVar(m_sanityMMHasBeenInitializedManually); 0328 qDebug() << this << ppVar(m_sanityIsDead); 0329 KIS_ASSERT(0 && "sanityCheckIsNotLockedForWrite() failed"); 0330 } 0331 } 0332 0333 #endif