1/*
2 * This file is part of the KDE project.
3 *
4 * SPDX-FileCopyrightText: 2010 Michael Pyne <mpyne@kde.org>
5 * SPDX-License-Identifier: LGPL-2.0-only
6 */
7
8#include "ksdclock_p.h"
9
10#include "kcoreaddons_debug.h"
11
12#include <memory>
13
14/**
15 * This is a method to determine the best lock type to use for a
16 * shared cache, based on local support. An identifier to the appropriate
17 * SharedLockId is returned, which can be passed to createLockFromId().
18 */
19SharedLockId findBestSharedLock()
20{
21 // We would prefer a process-shared capability that also supports
22 // timeouts. Failing that, process-shared is preferred over timeout
23 // support. Failing that we'll go thread-local
24 bool timeoutsSupported = false;
25 bool pthreadsProcessShared = false;
26 bool semaphoresProcessShared = false;
27
28#ifdef KSDC_TIMEOUTS_SUPPORTED
29 timeoutsSupported = ::sysconf(_SC_TIMEOUTS) >= 200112L;
30#endif
31
32// Now that we've queried timeouts, try actually creating real locks and
33// seeing if there's issues with that.
34#ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
35 {
36 pthread_mutex_t tempMutex;
37 std::unique_ptr<KSDCLock> tempLock;
38 if (timeoutsSupported) {
39#ifdef KSDC_TIMEOUTS_SUPPORTED
40 tempLock = std::make_unique<pthreadTimedLock>(args&: tempMutex);
41#endif
42 } else {
43 tempLock = std::make_unique<pthreadLock>(args&: tempMutex);
44 }
45
46 tempLock->initialize(processSharingSupported&: pthreadsProcessShared);
47 }
48#endif // KSDC_THREAD_PROCESS_SHARED_SUPPORTED
49
50 // Our first choice is pthread_mutex_t for compatibility.
51 if (timeoutsSupported && pthreadsProcessShared) {
52 return LOCKTYPE_MUTEX;
53 }
54
55#ifdef KSDC_SEMAPHORES_SUPPORTED
56 {
57 sem_t tempSemaphore;
58 std::unique_ptr<KSDCLock> tempLock;
59 if (timeoutsSupported) {
60 tempLock = std::make_unique<semaphoreTimedLock>(args&: tempSemaphore);
61 } else {
62 tempLock = std::make_unique<semaphoreLock>(args&: tempSemaphore);
63 }
64
65 tempLock->initialize(processSharingSupported&: semaphoresProcessShared);
66 }
67#endif // KSDC_SEMAPHORES_SUPPORTED
68
69 if (timeoutsSupported && semaphoresProcessShared) {
70 return LOCKTYPE_SEMAPHORE;
71 } else if (pthreadsProcessShared) {
72 return LOCKTYPE_MUTEX;
73 } else if (semaphoresProcessShared) {
74 return LOCKTYPE_SEMAPHORE;
75 }
76
77 // Fallback to a dumb-simple but possibly-CPU-wasteful solution.
78 return LOCKTYPE_SPINLOCK;
79}
80
81KSDCLock *createLockFromId(SharedLockId id, SharedLock &lock)
82{
83 switch (id) {
84#ifdef KSDC_THREAD_PROCESS_SHARED_SUPPORTED
85 case LOCKTYPE_MUTEX:
86#ifdef KSDC_TIMEOUTS_SUPPORTED
87 if (::sysconf(_SC_TIMEOUTS) >= 200112L) {
88 return new pthreadTimedLock(lock.mutex);
89 }
90#endif
91 return new pthreadLock(lock.mutex);
92
93 break;
94#endif // KSDC_THREAD_PROCESS_SHARED_SUPPORTED
95
96#ifdef KSDC_SEMAPHORES_SUPPORTED
97 case LOCKTYPE_SEMAPHORE:
98#ifdef KSDC_TIMEOUTS_SUPPORTED
99 if (::sysconf(_SC_SEMAPHORES) >= 200112L) {
100 return new semaphoreTimedLock(lock.semaphore);
101 }
102#endif
103 return new semaphoreLock(lock.semaphore);
104
105 break;
106#endif // KSDC_SEMAPHORES_SUPPORTED
107
108 case LOCKTYPE_SPINLOCK:
109 return new simpleSpinLock(lock.spinlock);
110 break;
111
112 default:
113 qCCritical(KCOREADDONS_DEBUG) << "Creating shell of a lock!";
114 return new KSDCLock;
115 }
116}
117

source code of kcoreaddons/src/lib/caching/ksdclock.cpp