ObjFW
Loading...
Searching...
No Matches
OFPlainMutex.h
1/*
2 * Copyright (c) 2008-2024 Jonathan Schleifer <js@nil.im>
3 *
4 * All rights reserved.
5 *
6 * This program is free software: you can redistribute it and/or modify it
7 * under the terms of the GNU Lesser General Public License version 3.0 only,
8 * as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
13 * version 3.0 for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * version 3.0 along with this program. If not, see
17 * <https://www.gnu.org/licenses/>.
18 */
19
20#include "objfw-defs.h"
21
22#include <errno.h>
23
24#include "platform.h"
25
26#if !defined(OF_HAVE_THREADS) || \
27 (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS))
28# error No mutexes available!
29#endif
30
31#import "macros.h"
32
33#if defined(OF_HAVE_PTHREADS)
34# include <pthread.h>
35typedef pthread_mutex_t OFPlainMutex;
36#elif defined(OF_WINDOWS)
37# include <windows.h>
38typedef CRITICAL_SECTION OFPlainMutex;
39#elif defined(OF_AMIGAOS)
40# include <exec/semaphores.h>
41typedef struct SignalSemaphore OFPlainMutex;
42#endif
43
44#if defined(OF_HAVE_ATOMIC_OPS)
45# import "OFAtomic.h"
46typedef volatile int OFSpinlock;
47#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
48typedef pthread_spinlock_t OFSpinlock;
49#else
50typedef OFPlainMutex OFSpinlock;
51#endif
52
53#ifdef OF_HAVE_SCHED_YIELD
54# include <sched.h>
55#endif
56
57#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \
58 defined(OF_AMIGAOS)
59# define OFPlainRecursiveMutex OFPlainMutex
60#else
61# import "OFTLSKey.h"
62typedef struct {
63 OFPlainMutex mutex;
64 OFTLSKey count;
65} OFPlainRecursiveMutex;
66#endif
67
68#ifdef __cplusplus
69extern "C" {
70#endif
71extern int OFPlainMutexNew(OFPlainMutex *mutex);
72extern int OFPlainMutexLock(OFPlainMutex *mutex);
73extern int OFPlainMutexTryLock(OFPlainMutex *mutex);
74extern int OFPlainMutexUnlock(OFPlainMutex *mutex);
75extern int OFPlainMutexFree(OFPlainMutex *mutex);
76extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex);
77extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex);
78extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex);
79extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex);
80extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex);
81#ifdef __cplusplus
82}
83#endif
84
85/* Spinlocks are inlined for performance. */
86
87static OF_INLINE void
88OFYieldThread(void)
89{
90#if defined(OF_HAVE_SCHED_YIELD)
91 sched_yield();
92#elif defined(OF_WINDOWS)
93 Sleep(0);
94#endif
95}
96
97static OF_INLINE int
98OFSpinlockNew(OFSpinlock *spinlock)
99{
100#if defined(OF_HAVE_ATOMIC_OPS)
101 *spinlock = 0;
102 return 0;
103#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
104 return pthread_spin_init(spinlock, 0);
105#else
106 return OFPlainMutexNew(spinlock);
107#endif
108}
109
110static OF_INLINE int
111OFSpinlockTryLock(OFSpinlock *spinlock)
112{
113#if defined(OF_HAVE_ATOMIC_OPS)
114 if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) {
115 OFAcquireMemoryBarrier();
116 return 0;
117 }
118
119 return EBUSY;
120#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
121 return pthread_spin_trylock(spinlock);
122#else
123 return OFPlainMutexTryLock(spinlock);
124#endif
125}
126
127static OF_INLINE int
128OFSpinlockLock(OFSpinlock *spinlock)
129{
130#if defined(OF_HAVE_ATOMIC_OPS)
131 size_t i;
132
133 for (i = 0; i < 10; i++)
134 if (OFSpinlockTryLock(spinlock) == 0)
135 return 0;
136
137 while (OFSpinlockTryLock(spinlock) == EBUSY)
138 OFYieldThread();
139
140 return 0;
141#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
142 return pthread_spin_lock(spinlock);
143#else
144 return OFPlainMutexLock(spinlock);
145#endif
146}
147
148static OF_INLINE int
149OFSpinlockUnlock(OFSpinlock *spinlock)
150{
151#if defined(OF_HAVE_ATOMIC_OPS)
152 bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0);
153
154 OFReleaseMemoryBarrier();
155
156 return (ret ? 0 : EINVAL);
157#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
158 return pthread_spin_unlock(spinlock);
159#else
160 return OFPlainMutexUnlock(spinlock);
161#endif
162}
163
164static OF_INLINE int
165OFSpinlockFree(OFSpinlock *spinlock)
166{
167#if defined(OF_HAVE_ATOMIC_OPS)
168 return 0;
169#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
170 return pthread_spin_destroy(spinlock);
171#else
172 return OFPlainMutexFree(spinlock);
173#endif
174}