File indexing completed on 2024-12-22 04:17:22
0001 /*************************************************************************** 0002 rwlock.cpp 0003 ------------------- 0004 begin : Feb 21, 2004 0005 copyright : (C) 2004 The University of toronto 0006 email : netterfield@astro.utoronto.ca 0007 ***************************************************************************/ 0008 0009 /*************************************************************************** 0010 * * 0011 * This program is free software; you can redistribute it and/or modify * 0012 * it under the terms of the GNU General Public License as published by * 0013 * the Free Software Foundation; either version 2 of the License, or * 0014 * (at your option) any later version. * 0015 * * 0016 ***************************************************************************/ 0017 0018 #include "rwlock.h" 0019 0020 #include <qdebug.h> 0021 0022 //#define LOCKTRACE 0023 0024 #ifdef ONE_LOCK_TO_RULE_THEM_ALL 0025 QMutex KstRWLock::_mutex(true); 0026 #endif 0027 0028 KstRWLock::KstRWLock() 0029 : _readCount(0), _writeCount(0), _waitingReaders(0), _waitingWriters(0) { 0030 } 0031 0032 0033 KstRWLock::~KstRWLock() { 0034 } 0035 0036 0037 void KstRWLock::readLock() const { 0038 #ifndef ONE_LOCK_TO_RULE_THEM_ALL 0039 QMutexLocker lock(&_mutex); 0040 0041 #ifdef LOCKTRACE 0042 qDebug() << (void*)this << " KstRWLock::readLock() by tid=" << (int)QThread::currentThreadId() << endl; 0043 // qDebug() << kstdBacktrace(6) << endl; 0044 #endif 0045 0046 Qt::HANDLE me = QThread::currentThreadId(); 0047 0048 if (_writeCount > 0 && _writeLocker == me) { 0049 // thread already has a write lock 0050 #ifdef LOCKTRACE 0051 qDebug() << "Thread " << (int)QThread::currentThreadId() << " has a write lock on KstRWLock " << (void*)this << ", getting a read lock" << endl; 0052 #endif 0053 } else { 0054 QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); 0055 if (it != _readLockers.end() && it.value() > 0) { 0056 // thread already has another read lock 0057 } else { 0058 while (_writeCount > 0 || _waitingWriters) { // writer priority otherwise 0059 ++_waitingReaders; 0060 _readerWait.wait(&_mutex); 0061 --_waitingReaders; 0062 } 0063 } 0064 } 0065 0066 _readLockers[me] = _readLockers[me] + 1; 0067 ++_readCount; 0068 0069 #ifdef LOCKTRACE 0070 qDebug() << (void*)this << " KstRWLock::readLock() done by tid=" << (int)QThread::currentThread() << endl; 0071 #endif 0072 #else 0073 _mutex.lock(); 0074 #endif 0075 } 0076 0077 0078 void KstRWLock::writeLock() const { 0079 #ifndef ONE_LOCK_TO_RULE_THEM_ALL 0080 QMutexLocker lock(&_mutex); 0081 0082 #ifdef LOCKTRACE 0083 qDebug() << (void*)this << " KstRWLock::writeLock() by tid=" << (int)QThread::currentThreadId() << endl; 0084 // qDebug() << kstdBacktrace(6) << endl; 0085 #endif 0086 0087 Qt::HANDLE me = QThread::currentThreadId(); 0088 0089 if (_readCount > 0) { 0090 QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); 0091 if (it != _readLockers.end() && it.value() > 0) { 0092 // cannot acquire a write lock if I already have a read lock -- ERROR 0093 qDebug() << "Thread " << QThread::currentThread() << " tried to write lock KstRWLock " << (void*)this << " while holding a read lock" << endl; 0094 return; 0095 } 0096 } 0097 0098 while (_readCount > 0 || (_writeCount > 0 && _writeLocker != me)) { 0099 ++_waitingWriters; 0100 _writerWait.wait(&_mutex); 0101 --_waitingWriters; 0102 } 0103 _writeLocker = me; 0104 ++_writeCount; 0105 0106 #ifdef LOCKTRACE 0107 qDebug() << (void*)this << " KstRWLock::writeLock() done by tid=" << (int)QThread::currentThread() << endl; 0108 #endif 0109 #else 0110 _mutex.lock(); 0111 #endif 0112 } 0113 0114 0115 void KstRWLock::unlock() const { 0116 #ifndef ONE_LOCK_TO_RULE_THEM_ALL 0117 QMutexLocker lock(&_mutex); 0118 0119 #ifdef LOCKTRACE 0120 qDebug() << (void*)this << " KstRWLock::unlock() by tid=" << (int)QThread::currentThreadId() << endl; 0121 #endif 0122 0123 Qt::HANDLE me = QThread::currentThreadId(); 0124 0125 if (_readCount > 0) { 0126 QMap<Qt::HANDLE, int>::Iterator it = _readLockers.find(me); 0127 if (it == _readLockers.end()) { 0128 // read locked but not by me -- ERROR 0129 qDebug() << "Thread " << QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (read locked) without holding the lock" << endl; 0130 return; 0131 } else { 0132 --_readCount; 0133 if (it.value() == 1) { 0134 _readLockers.remove(it.key()); 0135 } else { 0136 --(it.value()); 0137 } 0138 } 0139 } else if (_writeCount > 0) { 0140 if (_writeLocker != me) { 0141 // write locked but not by me -- ERROR 0142 qDebug() << "Thread " << QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (write locked) without holding the lock" << endl; 0143 return; 0144 } else { 0145 --_writeCount; 0146 } 0147 } else if (_readCount == 0 && _writeCount == 0) { 0148 // not locked -- ERROR 0149 qDebug() << "Thread " << QThread::currentThread() << " tried to unlock KstRWLock " << (void*)this << " (unlocked) without holding the lock" << endl; 0150 return; 0151 } 0152 0153 if (_readCount == 0 && _writeCount == 0) { 0154 // no locks remaining 0155 if (_waitingWriters) { 0156 _writerWait.wakeOne(); 0157 } else if (_waitingReaders) { 0158 _readerWait.wakeAll(); 0159 } 0160 } 0161 0162 #ifdef LOCKTRACE 0163 qDebug() << (void*)this << " KstRWLock::unlock() done by tid=" << (int)QThread::currentThread() << endl; 0164 #endif 0165 #else 0166 _mutex.unlock(); 0167 #endif 0168 } 0169 0170 0171 KstRWLock::LockStatus KstRWLock::lockStatus() const { 0172 #ifndef ONE_LOCK_TO_RULE_THEM_ALL 0173 QMutexLocker lock(&_mutex); 0174 0175 if (_writeCount > 0) { 0176 return WRITELOCKED; 0177 } else if (_readCount > 0) { 0178 return READLOCKED; 0179 } else { 0180 return UNLOCKED; 0181 } 0182 #else 0183 #error lockStatus() not supported using the single lock 0184 return UNLOCKED; 0185 #endif 0186 } 0187 0188 0189 KstRWLock::LockStatus KstRWLock::myLockStatus() const { 0190 #ifndef ONE_LOCK_TO_RULE_THEM_ALL 0191 QMutexLocker lock(&_mutex); 0192 0193 Qt::HANDLE me = QThread::currentThreadId(); 0194 0195 if (_writeCount > 0 && _writeLocker == me) { 0196 return WRITELOCKED; 0197 } else if (_readCount > 0 && _readLockers.find(me) != _readLockers.end()) { 0198 return READLOCKED; 0199 } else { 0200 return UNLOCKED; 0201 } 0202 #else 0203 #error myLockStatus() not supported using the single lock 0204 return UNLOCKED; 0205 #endif 0206 } 0207 0208 // vim: ts=2 sw=2 et