20#ifndef KSHAREDDATACACHE_P_H
21#define KSHAREDDATACACHE_P_H
23#include <config-util.h>
25#include <QtCore/QSharedPointer>
26#include <QtCore/QBasicAtomicInt>
47#if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS == 0) || (_POSIX_TIMEOUTS >= 200112L))
48#define KSDC_TIMEOUTS_SUPPORTED 1
51#if defined(__GNUC__) && !defined(KSDC_TIMEOUTS_SUPPORTED)
52#warning "No support for POSIX timeouts -- application hangs are possible if the cache is corrupt"
55#if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED == 0) || (_POSIX_THREAD_PROCESS_SHARED >= 200112L))
57#define KSDC_THREAD_PROCESS_SHARED_SUPPORTED 1
60#if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES == 0) || (_POSIX_SEMAPHORES >= 200112L))
62#define KSDC_SEMAPHORES_SUPPORTED 1
65#if defined(__GNUC__) && !defined(KSDC_SEMAPHORES_SUPPORTED) && !defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED)
66#warning "No system support claimed for process-shared synchronization, KSharedDataCache will be mostly useless."
69#if defined(_POSIX_MAPPED_FILES) && ((_POSIX_MAPPED_FILES == 0) || (_POSIX_MAPPED_FILES >= 200112L))
70#define KSDC_MAPPED_FILES_SUPPORTED 1
73#if defined(_POSIX_SYNCHRONIZED_IO) && ((_POSIX_SYNCHRONIZED_IO == 0) || (_POSIX_SYNCHRONIZED_IO >= 200112L))
74#define KSDC_SYNCHRONIZED_IO_SUPPORTED 1
78#if defined(KSDC_MAPPED_FILES_SUPPORTED) && defined(KSDC_SYNCHRONIZED_IO_SUPPORTED)
79#define KSDC_MSYNC_SUPPORTED
84#if (defined(_POSIX_ADVISORY_INFO) && ((_POSIX_ADVISORY_INFO == 0) || (_POSIX_ADVISORY_INFO >= 200112L))) || defined(__APPLE__)
85#define KSDC_POSIX_FALLOCATE_SUPPORTED 1
92#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
93#define MAP_ANONYMOUS MAP_ANON
111 processSharingSupported =
false;
134 : m_spinlock(spinlock)
142 processSharingSupported =
true;
150 for (
unsigned i = 50; i > 0; --i) {
151 if (m_spinlock.testAndSetAcquire(0, 1)) {
165 m_spinlock.testAndSetRelease(1, 0);
170 __attribute__((always_inline, gnu_inline, artificial))
172 static inline void loopSpinPause()
176#ifdef _POSIX_PRIORITY_SCHEDULING
180 struct timespec wait_time = { 0 , 100 };
181 ::nanosleep(&wait_time,
static_cast<struct timespec*
>(0));
185 QBasicAtomicInt &m_spinlock;
188#ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
192 pthreadLock(pthread_mutex_t &mutex)
197 virtual bool initialize(
bool &processSharingSupported)
200 pthread_mutexattr_t mutexAttr;
201 processSharingSupported =
false;
205 if (::sysconf(_SC_THREAD_PROCESS_SHARED) >= 200112L && pthread_mutexattr_init(&mutexAttr) == 0) {
206 if (pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED) == 0 &&
207 pthread_mutex_init(&m_mutex, &mutexAttr) == 0)
209 processSharingSupported =
true;
211 pthread_mutexattr_destroy(&mutexAttr);
215 if (!processSharingSupported && pthread_mutex_init(&m_mutex, NULL) != 0) {
224 return pthread_mutex_lock(&m_mutex) == 0;
229 pthread_mutex_unlock(&m_mutex);
233 pthread_mutex_t &m_mutex;
237#if defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
238class pthreadTimedLock :
public pthreadLock
241 pthreadTimedLock(pthread_mutex_t &mutex)
253 timeout.tv_sec = 10 + ::time(NULL);
256 return pthread_mutex_timedlock(&m_mutex, &
timeout) == 0;
261#ifdef KSDC_SEMAPHORES_SUPPORTED
262class semaphoreLock :
public KSDCLock
265 semaphoreLock(sem_t &semaphore)
266 : m_semaphore(semaphore)
270 virtual bool initialize(
bool &processSharingSupported)
272 processSharingSupported =
false;
273 if (::sysconf(_SC_SEMAPHORES) < 200112L) {
278 if (sem_init(&m_semaphore, 1, 1) == 0) {
279 processSharingSupported =
true;
282 else if (sem_init(&m_semaphore, 0, 1) != 0) {
291 return sem_wait(&m_semaphore) == 0;
296 sem_post(&m_semaphore);
304#if defined(KSDC_SEMAPHORES_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
305class semaphoreTimedLock :
public semaphoreLock
308 semaphoreTimedLock(sem_t &semaphore)
309 : semaphoreLock(semaphore)
320 timeout.tv_sec = 10 + ::time(NULL);
323 return sem_timedwait(&m_semaphore, &
timeout) == 0;
345#if defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED)
346 pthread_mutex_t mutex;
348#if defined(KSDC_SEMAPHORES_SUPPORTED)
373 bool timeoutsSupported =
false;
374 bool pthreadsProcessShared =
false;
375 bool semaphoresProcessShared =
false;
377#ifdef KSDC_TIMEOUTS_SUPPORTED
378 timeoutsSupported = ::sysconf(_SC_TIMEOUTS) >= 200112L;
383#ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
385 pthread_mutex_t tempMutex;
386 QSharedPointer<KSDCLock> tempLock(0);
387 if (timeoutsSupported) {
388#ifdef KSDC_TIMEOUTS_SUPPORTED
389 tempLock = QSharedPointer<KSDCLock>(
new pthreadTimedLock(tempMutex));
393 tempLock = QSharedPointer<KSDCLock>(
new pthreadLock(tempMutex));
396 tempLock->initialize(pthreadsProcessShared);
401 if(timeoutsSupported && pthreadsProcessShared) {
405#ifdef KSDC_SEMAPHORES_SUPPORTED
408 QSharedPointer<KSDCLock> tempLock(0);
409 if (timeoutsSupported) {
410 tempLock = QSharedPointer<KSDCLock>(
new semaphoreTimedLock(tempSemaphore));
413 tempLock = QSharedPointer<KSDCLock>(
new semaphoreLock(tempSemaphore));
416 tempLock->initialize(semaphoresProcessShared);
420 if(timeoutsSupported && semaphoresProcessShared) {
423 else if(pthreadsProcessShared) {
426 else if(semaphoresProcessShared) {
437#ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
439#ifdef KSDC_TIMEOUTS_SUPPORTED
440 if (::sysconf(_SC_TIMEOUTS) >= 200112L) {
441 return new pthreadTimedLock(lock.mutex);
444 return new pthreadLock(lock.mutex);
449#ifdef KSDC_SEMAPHORES_SUPPORTED
451#ifdef KSDC_TIMEOUTS_SUPPORTED
452 if (::sysconf(_SC_SEMAPHORES) >= 200112L) {
453 return new semaphoreTimedLock(lock.semaphore);
456 return new semaphoreLock(lock.semaphore);
473#ifdef KSDC_POSIX_FALLOCATE_SUPPORTED
482 <<
"bytes for mapped cache, "
483 "abandoning the cache for crash-safety.";
491#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."
494 " -- ensure this partition has room for at least"
495 << fileSize <<
"bytes.";
This class defines an interface used by KSharedDataCache::Private to offload proper locking and unloc...
virtual bool initialize(bool &processSharingSupported)
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 QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
static bool ensureFileAllocated(int fd, size_t fileSize)
static SharedLockId findBestSharedLock()
This is a method to determine the best lock type to use for a shared cache, based on local support.
static KSDCLock * createLockFromId(SharedLockId id, SharedLock &lock)
static int posix_fallocate(int fd, off_t offset, off_t len)