20 #ifndef KSHAREDDATACACHE_P_H
21 #define KSHAREDDATACACHE_P_H
23 #include <config-util.h>
25 #include <QtCore/QSharedPointer>
26 #include <QtCore/QBasicAtomicInt>
43 #if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS == 0) || (_POSIX_TIMEOUTS >= 200112L))
44 #define KSDC_TIMEOUTS_SUPPORTED 1
47 #if defined(__GNUC__) && !defined(KSDC_TIMEOUTS_SUPPORTED)
48 #warning "No support for POSIX timeouts -- application hangs are possible if the cache is corrupt"
51 #if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED == 0) || (_POSIX_THREAD_PROCESS_SHARED >= 200112L)) && !defined(__APPLE__)
53 #define KSDC_THREAD_PROCESS_SHARED_SUPPORTED 1
56 #if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES == 0) || (_POSIX_SEMAPHORES >= 200112L))
57 #include <semaphore.h>
58 #define KSDC_SEMAPHORES_SUPPORTED 1
61 #if defined(__GNUC__) && !defined(KSDC_SEMAPHORES_SUPPORTED) && !defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED)
62 #warning "No system support claimed for process-shared synchronization, KSharedDataCache will be mostly useless."
65 #if defined(_POSIX_MAPPED_FILES) && ((_POSIX_MAPPED_FILES == 0) || (_POSIX_MAPPED_FILES >= 200112L))
66 #define KSDC_MAPPED_FILES_SUPPORTED 1
69 #if defined(_POSIX_SYNCHRONIZED_IO) && ((_POSIX_SYNCHRONIZED_IO == 0) || (_POSIX_SYNCHRONIZED_IO >= 200112L))
70 #define KSDC_SYNCHRONIZED_IO_SUPPORTED 1
74 #if defined(KSDC_MAPPED_FILES_SUPPORTED) && defined(KSDC_SYNCHRONIZED_IO_SUPPORTED)
75 #define KSDC_MSYNC_SUPPORTED
80 #if defined(_POSIX_ADVISORY_INFO) && ((_POSIX_ADVISORY_INFO == 0) || (_POSIX_ADVISORY_INFO >= 200112L))
81 #define KSDC_POSIX_FALLOCATE_SUPPORTED 1
88 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
89 #define MAP_ANONYMOUS MAP_ANON
107 processSharingSupported =
false;
130 : m_spinlock(spinlock)
138 processSharingSupported =
true;
146 for (
unsigned i = 50; i > 0; --i) {
147 if (m_spinlock.testAndSetAcquire(0, 1)) {
161 m_spinlock.testAndSetRelease(1, 0);
166 __attribute__((always_inline, gnu_inline, artificial))
168 static inline void loopSpinPause()
172 #ifdef _POSIX_PRIORITY_SCHEDULING
176 struct timespec wait_time = { 0 , 100 };
177 ::nanosleep(&wait_time, static_cast<struct timespec*>(0));
181 QBasicAtomicInt &m_spinlock;
184 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
188 pthreadLock(pthread_mutex_t &mutex)
193 virtual bool initialize(
bool &processSharingSupported)
196 pthread_mutexattr_t mutexAttr;
197 processSharingSupported =
false;
201 if (::sysconf(_SC_THREAD_PROCESS_SHARED) >= 200112L && pthread_mutexattr_init(&mutexAttr) == 0) {
202 if (pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED) == 0 &&
203 pthread_mutex_init(&m_mutex, &mutexAttr) == 0)
205 processSharingSupported =
true;
207 pthread_mutexattr_destroy(&mutexAttr);
211 if (!processSharingSupported && pthread_mutex_init(&m_mutex, NULL) != 0) {
220 return pthread_mutex_lock(&m_mutex) == 0;
225 pthread_mutex_unlock(&m_mutex);
229 pthread_mutex_t &m_mutex;
233 #if defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
234 class pthreadTimedLock :
public pthreadLock
237 pthreadTimedLock(pthread_mutex_t &mutex)
249 timeout.tv_sec = 10 + ::time(NULL);
252 return pthread_mutex_timedlock(&m_mutex, &
timeout) == 0;
257 #ifdef KSDC_SEMAPHORES_SUPPORTED
258 class semaphoreLock :
public KSDCLock
261 semaphoreLock(sem_t &semaphore)
262 : m_semaphore(semaphore)
266 virtual bool initialize(
bool &processSharingSupported)
268 processSharingSupported =
false;
269 if (::sysconf(_SC_SEMAPHORES) < 200112L) {
274 if (sem_init(&m_semaphore, 1, 1) == 0) {
275 processSharingSupported =
true;
278 else if (sem_init(&m_semaphore, 0, 1) != 0) {
287 return sem_wait(&m_semaphore) == 0;
292 sem_post(&m_semaphore);
300 #if defined(KSDC_SEMAPHORES_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
301 class semaphoreTimedLock :
public semaphoreLock
304 semaphoreTimedLock(sem_t &semaphore)
305 : semaphoreLock(semaphore)
316 timeout.tv_sec = 10 + ::time(NULL);
319 return sem_timedwait(&m_semaphore, &
timeout) == 0;
341 #if defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED)
342 pthread_mutex_t mutex;
344 #if defined(KSDC_SEMAPHORES_SUPPORTED)
369 bool timeoutsSupported =
false;
370 bool pthreadsProcessShared =
false;
371 bool semaphoresProcessShared =
false;
373 #ifdef KSDC_TIMEOUTS_SUPPORTED
374 timeoutsSupported = ::sysconf(_SC_TIMEOUTS) >= 200112L;
379 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
381 pthread_mutex_t tempMutex;
382 QSharedPointer<KSDCLock> tempLock(0);
383 if (timeoutsSupported) {
384 #ifdef KSDC_TIMEOUTS_SUPPORTED
385 tempLock = QSharedPointer<KSDCLock>(
new pthreadTimedLock(tempMutex));
389 tempLock = QSharedPointer<KSDCLock>(
new pthreadLock(tempMutex));
392 tempLock->initialize(pthreadsProcessShared);
397 if(timeoutsSupported && pthreadsProcessShared) {
401 #ifdef KSDC_SEMAPHORES_SUPPORTED
404 QSharedPointer<KSDCLock> tempLock(0);
405 if (timeoutsSupported) {
406 tempLock = QSharedPointer<KSDCLock>(
new semaphoreTimedLock(tempSemaphore));
409 tempLock = QSharedPointer<KSDCLock>(
new semaphoreLock(tempSemaphore));
412 tempLock->initialize(semaphoresProcessShared);
416 if(timeoutsSupported && semaphoresProcessShared) {
419 else if(pthreadsProcessShared) {
422 else if(semaphoresProcessShared) {
433 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
435 #ifdef KSDC_TIMEOUTS_SUPPORTED
436 if (::sysconf(_SC_TIMEOUTS) >= 200112L) {
437 return new pthreadTimedLock(lock.mutex);
440 return new pthreadLock(lock.mutex);
445 #ifdef KSDC_SEMAPHORES_SUPPORTED
447 #ifdef KSDC_TIMEOUTS_SUPPORTED
448 if (::sysconf(_SC_SEMAPHORES) >= 200112L) {
449 return new semaphoreTimedLock(lock.semaphore);
452 return new semaphoreLock(lock.semaphore);
469 #ifdef KSDC_POSIX_FALLOCATE_SUPPORTED
471 while ((result = ::posix_fallocate(fd, 0, fileSize)) == EINTR) {
478 <<
"bytes for mapped cache, "
479 "abandoning the cache for crash-safety.";
487 #warning "This system does not seem to support posix_fallocate, which is needed to ensure KSharedDataCache's underlying files are fully committed to disk to avoid crashes with low disk space."
490 " -- ensure this partition has room for at least"
491 << fileSize <<
"bytes.";
static SharedLockId findBestSharedLock()
This is a method to determine the best lock type to use for a shared cache, based on local support...
virtual bool initialize(bool &processSharingSupported)
static bool ensureFileAllocated(int fd, size_t fileSize)
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
This is a very basic lock that should work on any system where GCC atomic intrinsics are supported...
simpleSpinLock(QBasicAtomicInt &spinlock)
virtual bool initialize(bool &processSharingSupported)
static KSDCLock * createLockFromId(SharedLockId id, SharedLock &lock)
This class defines an interface used by KSharedDataCache::Private to offload proper locking and unloc...