File indexing completed on 2024-05-19 03:56:18

0001 /*
0002  *    This file is part of the KDE project.
0003  *
0004  *    SPDX-FileCopyrightText: 2010 Michael Pyne <mpyne@kde.org>
0005  *    SPDX-License-Identifier: LGPL-2.0-only
0006  */
0007 
0008 #include "ksdclock_p.h"
0009 
0010 #include "kcoreaddons_debug.h"
0011 
0012 #include <memory>
0013 
0014 /**
0015  * This is a method to determine the best lock type to use for a
0016  * shared cache, based on local support. An identifier to the appropriate
0017  * SharedLockId is returned, which can be passed to createLockFromId().
0018  */
0019 SharedLockId findBestSharedLock()
0020 {
0021     // We would prefer a process-shared capability that also supports
0022     // timeouts. Failing that, process-shared is preferred over timeout
0023     // support. Failing that we'll go thread-local
0024     bool timeoutsSupported = false;
0025     bool pthreadsProcessShared = false;
0026     bool semaphoresProcessShared = false;
0027 
0028 #ifdef KSDC_TIMEOUTS_SUPPORTED
0029     timeoutsSupported = ::sysconf(_SC_TIMEOUTS) >= 200112L;
0030 #endif
0031 
0032 // Now that we've queried timeouts, try actually creating real locks and
0033 // seeing if there's issues with that.
0034 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
0035     {
0036         pthread_mutex_t tempMutex;
0037         std::unique_ptr<KSDCLock> tempLock;
0038         if (timeoutsSupported) {
0039 #ifdef KSDC_TIMEOUTS_SUPPORTED
0040             tempLock = std::make_unique<pthreadTimedLock>(tempMutex);
0041 #endif
0042         } else {
0043             tempLock = std::make_unique<pthreadLock>(tempMutex);
0044         }
0045 
0046         tempLock->initialize(pthreadsProcessShared);
0047     }
0048 #endif // KSDC_THREAD_PROCESS_SHARED_SUPPORTED
0049 
0050     // Our first choice is pthread_mutex_t for compatibility.
0051     if (timeoutsSupported && pthreadsProcessShared) {
0052         return LOCKTYPE_MUTEX;
0053     }
0054 
0055 #ifdef KSDC_SEMAPHORES_SUPPORTED
0056     {
0057         sem_t tempSemaphore;
0058         std::unique_ptr<KSDCLock> tempLock;
0059         if (timeoutsSupported) {
0060             tempLock = std::make_unique<semaphoreTimedLock>(tempSemaphore);
0061         } else {
0062             tempLock = std::make_unique<semaphoreLock>(tempSemaphore);
0063         }
0064 
0065         tempLock->initialize(semaphoresProcessShared);
0066     }
0067 #endif // KSDC_SEMAPHORES_SUPPORTED
0068 
0069     if (timeoutsSupported && semaphoresProcessShared) {
0070         return LOCKTYPE_SEMAPHORE;
0071     } else if (pthreadsProcessShared) {
0072         return LOCKTYPE_MUTEX;
0073     } else if (semaphoresProcessShared) {
0074         return LOCKTYPE_SEMAPHORE;
0075     }
0076 
0077     // Fallback to a dumb-simple but possibly-CPU-wasteful solution.
0078     return LOCKTYPE_SPINLOCK;
0079 }
0080 
0081 KSDCLock *createLockFromId(SharedLockId id, SharedLock &lock)
0082 {
0083     switch (id) {
0084 #ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
0085     case LOCKTYPE_MUTEX:
0086 #ifdef KSDC_TIMEOUTS_SUPPORTED
0087         if (::sysconf(_SC_TIMEOUTS) >= 200112L) {
0088             return new pthreadTimedLock(lock.mutex);
0089         }
0090 #endif
0091         return new pthreadLock(lock.mutex);
0092 
0093         break;
0094 #endif // KSDC_THREAD_PROCESS_SHARED_SUPPORTED
0095 
0096 #ifdef KSDC_SEMAPHORES_SUPPORTED
0097     case LOCKTYPE_SEMAPHORE:
0098 #ifdef KSDC_TIMEOUTS_SUPPORTED
0099         if (::sysconf(_SC_SEMAPHORES) >= 200112L) {
0100             return new semaphoreTimedLock(lock.semaphore);
0101         }
0102 #endif
0103         return new semaphoreLock(lock.semaphore);
0104 
0105         break;
0106 #endif // KSDC_SEMAPHORES_SUPPORTED
0107 
0108     case LOCKTYPE_SPINLOCK:
0109         return new simpleSpinLock(lock.spinlock);
0110         break;
0111 
0112     default:
0113         qCCritical(KCOREADDONS_DEBUG) << "Creating shell of a lock!";
0114         return new KSDCLock;
0115     }
0116 }