mirror of
https://bitbucket.org/smil3y/kde-extraapps.git
synced 2025-02-24 19:02:53 +00:00
125 lines
4.2 KiB
C
125 lines
4.2 KiB
C
![]() |
/*
|
||
|
<one line to give the program's name and a brief idea of what it does.>
|
||
|
Copyright 2009 David Nolden <david.nolden.kdevelop@art-master.de>
|
||
|
|
||
|
This program is free software; you can redistribute it and/or modify
|
||
|
it under the terms of the GNU General Public License as published by
|
||
|
the Free Software Foundation; either version 2 of the License, or
|
||
|
(at your option) any later version.
|
||
|
|
||
|
This program is distributed in the hope that it will be useful,
|
||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
GNU General Public License for more details.
|
||
|
|
||
|
You should have received a copy of the GNU General Public License along
|
||
|
with this program; if not, write to the Free Software Foundation, Inc.,
|
||
|
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||
|
|
||
|
*/
|
||
|
|
||
|
#ifndef KDEVPLATFORM_SPINLOCK_H
|
||
|
#define KDEVPLATFORM_SPINLOCK_H
|
||
|
|
||
|
#include <QAtomicInt>
|
||
|
#include <QMutex>
|
||
|
#include <QWaitCondition>
|
||
|
#include <sys/time.h>
|
||
|
#include <unistd.h>
|
||
|
|
||
|
namespace KDevelop {
|
||
|
|
||
|
inline uint timevalToMilliSeconds(timeval v) {
|
||
|
return v.tv_sec * 1000 + v.tv_usec / 1000;
|
||
|
}
|
||
|
|
||
|
struct SpinLockData {
|
||
|
SpinLockData() : needWake(false) {
|
||
|
lock = 0;
|
||
|
}
|
||
|
|
||
|
QAtomicInt lock; //The variable that manages the lock
|
||
|
|
||
|
volatile bool needWake;
|
||
|
QMutex waitingMutex;
|
||
|
QWaitCondition waitingCondition;
|
||
|
};
|
||
|
|
||
|
///This spin-lock uses a QWaitCondition together with a QMutex as fallback in case the lock is already taken.
|
||
|
///That means that this spin-lock is only more efficient than a QMutex when there is a low amount of lock-contention.
|
||
|
///When there is a high amount of lock-contention, QMutex should be more efficient.
|
||
|
///@note This implementation does not guarantee an optimal behavior as QMutex does: There is no guarantee
|
||
|
/// that a waiting thread is really woken up in exactly the moment the lock becomes available.
|
||
|
/// In _most_ cases it should work, but in worst-case the thread sleeps @p mSleep milliseconds.
|
||
|
///@param mSleep maximum number of milliseconds to sleep when waiting for the lock
|
||
|
///@param Timeout the timeount value
|
||
|
template<uint mSleep = 10, int mTimeout = 0>
|
||
|
class SpinLock
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
SpinLock(SpinLockData& data) : m_data(data), m_locked(true) {
|
||
|
if(m_data.lock.testAndSetOrdered(0, 1)) {
|
||
|
//Success at the first try
|
||
|
}else if(mTimeout) {
|
||
|
//Spin with timeout
|
||
|
|
||
|
//Start spinning
|
||
|
timeval startTime;
|
||
|
gettimeofday(&startTime, 0);
|
||
|
|
||
|
while(!m_data.lock.testAndSetOrdered(0, 1))
|
||
|
{
|
||
|
timeval currentTime;
|
||
|
gettimeofday(¤tTime, 0);
|
||
|
timeval waited;
|
||
|
timersub(¤tTime, &startTime, &waited);
|
||
|
|
||
|
if(mTimeout && timevalToMilliSeconds(waited) > mTimeout) {
|
||
|
m_locked = false;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//We need to wait now
|
||
|
QMutexLocker lock(&m_data.waitingMutex);
|
||
|
m_data.needWake = true;
|
||
|
m_data.waitingCondition.wait(&m_data.waitingMutex, mSleep);
|
||
|
}
|
||
|
}else{
|
||
|
//No timeout
|
||
|
while(!m_data.lock.testAndSetOrdered(0, 1))
|
||
|
{
|
||
|
//We need to wait now
|
||
|
QMutexLocker lock(&m_data.waitingMutex);
|
||
|
m_data.needWake = true;
|
||
|
m_data.waitingCondition.wait(&m_data.waitingMutex, mSleep);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
~SpinLock() {
|
||
|
if(m_locked) {
|
||
|
bool needWake = m_data.needWake;
|
||
|
|
||
|
m_data.needWake = false;
|
||
|
m_data.lock = 0;
|
||
|
|
||
|
if(needWake)
|
||
|
m_data.waitingCondition.wakeOne();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//Returns whether the lock succeeded
|
||
|
bool locked() const {
|
||
|
return m_locked;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
SpinLockData& m_data;
|
||
|
bool m_locked;
|
||
|
};
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif // KDEVPLATFORM_SPINLOCK_H
|