• Skip to content
  • Skip to link menu
KDE 4.6 API Reference
  • KDE API Reference
  • kdelibs
  • KDE Home
  • Contact Us
 

KDECore

kshareddatacache_p.h

Go to the documentation of this file.
00001 /*
00002  * This file is part of the KDE project.
00003  * Copyright © 2010 Michael Pyne <mpyne@kde.org>
00004  *
00005  * This library is free software; you can redistribute it and/or
00006  * modify it under the terms of the GNU Library General Public
00007  * License version 2 as published by the Free Software Foundation.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public License
00015  * along with this library; see the file COPYING.LIB.  If not, write to
00016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018  */
00019 
00020 #ifndef KSHAREDDATACACHE_P_H
00021 #define KSHAREDDATACACHE_P_H
00022 
00023 #include <config.h> // HAVE_SYS_MMAN_H
00024 
00025 #include <QtCore/QSharedPointer>
00026 
00027 #include <unistd.h>
00028 #include <time.h>
00029 
00030 #include <kdebug.h>
00031 
00032 // Mac OS X, for all its POSIX compliance, does not support timeouts on its
00033 // mutexes, which is kind of a disaster for cross-process support. However
00034 // synchronization primitives still work, they just might hang if the cache is
00035 // corrupted, so keep going.
00036 #if defined(_POSIX_TIMEOUTS) && ((_POSIX_TIMEOUTS == 0) || (_POSIX_TIMEOUTS >= 200112L))
00037 #define KSDC_TIMEOUTS_SUPPORTED 1
00038 #endif
00039 
00040 #if defined(__GNUC__) && !defined(KSDC_TIMEOUTS_SUPPORTED)
00041 #warning "No support for POSIX timeouts -- application hangs are possible if the cache is corrupt"
00042 #endif
00043 
00044 #if defined(_POSIX_THREAD_PROCESS_SHARED) && ((_POSIX_THREAD_PROCESS_SHARED == 0) || (_POSIX_THREAD_PROCESS_SHARED >= 200112L))
00045 #include <pthread.h>
00046 #define KSDC_THREAD_PROCESS_SHARED_SUPPORTED 1
00047 #endif
00048 
00049 #if defined(_POSIX_SEMAPHORES) && ((_POSIX_SEMAPHORES == 0) || (_POSIX_SEMAPHORES >= 200112L))
00050 #include <semaphore.h>
00051 #define KSDC_SEMAPHORES_SUPPORTED 1
00052 #endif
00053 
00054 #if defined(__GNUC__) && !defined(KSDC_SEMAPHORES_SUPPORTED) && !defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED)
00055 #warning "No system support claimed for process-shared synchronization, KSharedDataCache will be mostly useless."
00056 #endif
00057 
00058 // BSD/Mac OS X compat
00059 #ifdef HAVE_SYS_MMAN_H
00060 #include <sys/mman.h>
00061 #endif
00062 #if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
00063 #define MAP_ANONYMOUS MAP_ANON
00064 #endif
00065 
00071 class KSDCLock {
00072 public:
00073     virtual ~KSDCLock()
00074     {
00075     }
00076 
00077     // Return value indicates if the mutex was properly initialized (including
00078     // threads-only as a fallback).
00079     virtual bool initialize(bool &processSharingSupported)
00080     {
00081         processSharingSupported = false;
00082         return false;
00083     }
00084 
00085     virtual bool lock()
00086     {
00087         return false;
00088     }
00089 
00090     virtual void unlock()
00091     {
00092     }
00093 };
00094 
00095 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
00096 class pthreadLock : public KSDCLock
00097 {
00098 public:
00099     pthreadLock(pthread_mutex_t &mutex)
00100         : m_mutex(mutex)
00101     {
00102     }
00103 
00104     virtual bool initialize(bool &processSharingSupported)
00105     {
00106         // Setup process-sharing.
00107         pthread_mutexattr_t mutexAttr;
00108         processSharingSupported = false;
00109 
00110         // Initialize attributes, enable process-shared primitives, and setup
00111         // the mutex.
00112         if (::sysconf(_SC_THREAD_PROCESS_SHARED) >= 200112L && pthread_mutexattr_init(&mutexAttr) == 0) {
00113             if (pthread_mutexattr_setpshared(&mutexAttr, PTHREAD_PROCESS_SHARED) == 0 &&
00114                 pthread_mutex_init(&m_mutex, &mutexAttr) == 0)
00115             {
00116                 processSharingSupported = true;
00117             }
00118             pthread_mutexattr_destroy(&mutexAttr);
00119         }
00120 
00121         // Attempt to setup for thread-only synchronization.
00122         if (!processSharingSupported && pthread_mutex_init(&m_mutex, NULL) != 0) {
00123             return false;
00124         }
00125 
00126         return true;
00127     }
00128 
00129     virtual bool lock()
00130     {
00131         return pthread_mutex_lock(&m_mutex) == 0;
00132     }
00133 
00134     virtual void unlock()
00135     {
00136         pthread_mutex_unlock(&m_mutex);
00137     }
00138 
00139 protected:
00140     pthread_mutex_t &m_mutex;
00141 };
00142 #endif
00143 
00144 #if defined(KSDC_THREAD_PROCESS_SHARED_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
00145 class pthreadTimedLock : public pthreadLock
00146 {
00147 public:
00148     pthreadTimedLock(pthread_mutex_t &mutex)
00149         : pthreadLock(mutex)
00150     {
00151     }
00152 
00153     virtual bool lock()
00154     {
00155         struct timespec timeout;
00156 
00157         // Long timeout, but if we fail to meet this timeout it's probably a cache
00158         // corruption (and if we take 8 seconds then it should be much much quicker
00159         // the next time anyways since we'd be paged back in from disk)
00160         timeout.tv_sec = 10 + ::time(NULL); // Absolute time, so 10 seconds from now
00161         timeout.tv_nsec = 0;
00162 
00163         return pthread_mutex_timedlock(&m_mutex, &timeout) >= 0;
00164     }
00165 };
00166 #endif
00167 
00168 #ifdef KSDC_SEMAPHORES_SUPPORTED
00169 class semaphoreLock : public KSDCLock
00170 {
00171 public:
00172     semaphoreLock(sem_t &semaphore)
00173         : m_semaphore(semaphore)
00174     {
00175     }
00176 
00177     virtual bool initialize(bool &processSharingSupported)
00178     {
00179         processSharingSupported = false;
00180         if (::sysconf(_SC_SEMAPHORES) < 200112L) {
00181             return false;
00182         }
00183 
00184         // sem_init sets up process-sharing for us.
00185         if (sem_init(&m_semaphore, 1, 1) == 0) {
00186             processSharingSupported = true;
00187         }
00188         // If not successful try falling back to thread-shared.
00189         else if (sem_init(&m_semaphore, 0, 1) != 0) {
00190             return false;
00191         }
00192 
00193         return true;
00194     }
00195 
00196     virtual bool lock()
00197     {
00198         return sem_wait(&m_semaphore) == 0;
00199     }
00200 
00201     virtual void unlock()
00202     {
00203         sem_post(&m_semaphore);
00204     }
00205 
00206 protected:
00207     sem_t &m_semaphore;
00208 };
00209 #endif
00210 
00211 #if defined(KSDC_SEMAPHORES_SUPPORTED) && defined(KSDC_TIMEOUTS_SUPPORTED)
00212 class semaphoreTimedLock : public semaphoreLock
00213 {
00214 public:
00215     semaphoreTimedLock(sem_t &semaphore)
00216         : semaphoreLock(semaphore)
00217     {
00218     }
00219 
00220     virtual bool lock()
00221     {
00222         struct timespec timeout;
00223 
00224         // Long timeout, but if we fail to meet this timeout it's probably a cache
00225         // corruption (and if we take 8 seconds then it should be much much quicker
00226         // the next time anyways since we'd be paged back in from disk)
00227         timeout.tv_sec = 10 + ::time(NULL); // Absolute time, so 10 seconds from now
00228         timeout.tv_nsec = 0;
00229 
00230         return sem_timedwait(&m_semaphore, &timeout) == 0;
00231     }
00232 };
00233 #endif
00234 
00235 // This enum controls the type of the locking used for the cache to allow
00236 // for as much portability as possible. This value will be stored in the
00237 // cache and used by multiple processes, therefore you should consider this
00238 // a versioned field, do not re-arrange.
00239 enum SharedLockId {
00240     LOCKTYPE_MUTEX     = 1,  // pthread_mutex
00241     LOCKTYPE_SEMAPHORE = 2   // sem_t
00242 };
00243 
00244 // This type is a union of all possible lock types, with a SharedLockId used
00245 // to choose which one is actually in use.
00246 struct SharedLock
00247 {
00248     union
00249     {
00250         pthread_mutex_t mutex;
00251 #if defined(KSDC_SEMAPHORES_SUPPORTED)
00252         sem_t semaphore;
00253 #endif
00254 
00255         // It would be highly unfortunate if a simple glibc upgrade or kernel
00256         // addition caused this structure to change size when an existing
00257         // lock was thought present, so reserve enough size to cover any
00258         // reasonable locking structure
00259         char unused[64];
00260     };
00261 
00262     SharedLockId type;
00263 };
00264 
00270 static SharedLockId findBestSharedLock()
00271 {
00272     // We would prefer a process-shared capability that also supports
00273     // timeouts. Failing that, process-shared is preferred over timeout
00274     // support. Failing that we'll go thread-local
00275     bool pthreadsSupported = false;
00276     bool semaphoresSupported = false;
00277     bool timeoutsSupported = false;
00278     bool pthreadsProcessShared = false;
00279     bool semaphoresProcessShared = false;
00280 
00281 #ifdef KSDC_TIMEOUTS_SUPPORTED
00282     timeoutsSupported = ::sysconf(_SC_TIMEOUTS) >= 200112L;
00283 #endif
00284 
00285     // Now that we've queried timeouts, try actually creating real locks and
00286     // seeing if there's issues with that.
00287 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
00288     {
00289         pthread_mutex_t tempMutex;
00290         QSharedPointer<KSDCLock> tempLock(0);
00291         if (timeoutsSupported) {
00292 #ifdef KSDC_TIMEOUTS_SUPPORTED
00293             tempLock = QSharedPointer<KSDCLock>(new pthreadTimedLock(tempMutex));
00294 #endif
00295         }
00296         else {
00297             tempLock = QSharedPointer<KSDCLock>(new pthreadLock(tempMutex));
00298         }
00299 
00300         pthreadsSupported = tempLock->initialize(pthreadsProcessShared);
00301     }
00302 #endif
00303 
00304     // Our first choice is pthread_mutex_t for compatibility.
00305     if(timeoutsSupported && pthreadsProcessShared) {
00306         return LOCKTYPE_MUTEX;
00307     }
00308 
00309 #ifdef KSDC_SEMAPHORES_SUPPORTED
00310     {
00311         sem_t tempSemaphore;
00312         QSharedPointer<KSDCLock> tempLock(0);
00313         if (timeoutsSupported) {
00314             tempLock = QSharedPointer<KSDCLock>(new semaphoreTimedLock(tempSemaphore));
00315         }
00316         else {
00317             tempLock = QSharedPointer<KSDCLock>(new semaphoreLock(tempSemaphore));
00318         }
00319 
00320         semaphoresSupported = tempLock->initialize(semaphoresProcessShared);
00321     }
00322 #endif
00323 
00324     if(timeoutsSupported && semaphoresProcessShared) {
00325         return LOCKTYPE_SEMAPHORE;
00326     }
00327     else if(pthreadsProcessShared) {
00328         return LOCKTYPE_MUTEX;
00329     }
00330     else if(semaphoresProcessShared) {
00331         return LOCKTYPE_SEMAPHORE;
00332     }
00333     else if(pthreadsSupported) {
00334         return LOCKTYPE_MUTEX;
00335     }
00336     else if(semaphoresSupported) {
00337         return LOCKTYPE_SEMAPHORE;
00338     }
00339 
00340     // If we get to this point we'll likely fail later but this is the
00341     // standard behavior that has existed as well, so...
00342     return static_cast<SharedLockId>(0);
00343 }
00344 
00345 static KSDCLock *createLockFromId(SharedLockId id, SharedLock &lock)
00346 {
00347     switch(id) {
00348 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
00349     case LOCKTYPE_MUTEX:
00350 #ifdef KSDC_TIMEOUTS_SUPPORTED
00351         if (::sysconf(_SC_TIMEOUTS) >= 200112L) {
00352             return new pthreadTimedLock(lock.mutex);
00353         }
00354 #endif
00355         return new pthreadLock(lock.mutex);
00356 
00357     break;
00358 #endif
00359 
00360 #ifdef KSDC_SEMAPHORES_SUPPORTED
00361     case LOCKTYPE_SEMAPHORE:
00362 #ifdef KSDC_TIMEOUTS_SUPPORTED
00363         if (::sysconf(_SC_SEMAPHORES) >= 200112L) {
00364             return new semaphoreTimedLock(lock.semaphore);
00365         }
00366 #endif
00367         return new semaphoreLock(lock.semaphore);
00368 
00369     break;
00370 #endif
00371 
00372     default:
00373         kError(264) << "Creating shell of a lock!";
00374         return new KSDCLock;
00375     }
00376 }
00377 
00378 #endif /* KSHAREDDATACACHE_P_H */

KDECore

Skip menu "KDECore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.7.3
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal