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