ObjFW
OFPlainMutex.h
Go to the documentation of this file.
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 
35 #if defined(OF_HAVE_PTHREADS)
36 # include <pthread.h>
37 typedef pthread_mutex_t OFPlainMutex;
38 #elif defined(OF_WINDOWS)
39 # include <windows.h>
40 typedef CRITICAL_SECTION OFPlainMutex;
41 #elif defined(OF_AMIGAOS)
42 # include <exec/semaphores.h>
43 typedef struct SignalSemaphore OFPlainMutex;
44 #endif
45 
46 #if defined(OF_HAVE_ATOMIC_OPS)
47 # import "OFAtomic.h"
48 typedef volatile int OFSpinlock;
49 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
50 typedef pthread_spinlock_t OFSpinlock;
51 #else
52 typedef OFPlainMutex OFSpinlock;
53 #endif
54 
55 #ifdef OF_HAVE_SCHED_YIELD
56 # include <sched.h>
57 #endif
58 
59 #if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \
60  defined(OF_AMIGAOS)
61 # define OFPlainRecursiveMutex OFPlainMutex
62 #else
63 # import "OFTLSKey.h"
64 typedef struct {
65  OFPlainMutex mutex;
66  OFTLSKey count;
67 } OFPlainRecursiveMutex;
68 #endif
69 
70 #ifdef __cplusplus
71 extern "C" {
72 #endif
73 
82 extern int OFPlainMutexNew(OFPlainMutex *mutex);
83 
90 extern int OFPlainMutexLock(OFPlainMutex *mutex);
91 
98 extern int OFPlainMutexTryLock(OFPlainMutex *mutex);
99 
106 extern int OFPlainMutexUnlock(OFPlainMutex *mutex);
107 
114 extern int OFPlainMutexFree(OFPlainMutex *mutex);
115 
127 extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex);
128 
135 extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex);
136 
143 extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex);
144 
151 extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex);
152 
159 extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex);
160 #ifdef __cplusplus
161 }
162 #endif
163 
164 /* Spinlocks are inlined for performance. */
165 
170 static OF_INLINE void
172 {
173 #if defined(OF_HAVE_SCHED_YIELD)
174  sched_yield();
175 #elif defined(OF_WINDOWS)
176  Sleep(0);
177 #endif
178 }
179 
186 static OF_INLINE int
187 OFSpinlockNew(OFSpinlock *spinlock)
188 {
189 #if defined(OF_HAVE_ATOMIC_OPS)
190  *spinlock = 0;
191  return 0;
192 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
193  return pthread_spin_init(spinlock, 0);
194 #else
195  return OFPlainMutexNew(spinlock);
196 #endif
197 }
198 
205 static OF_INLINE int
206 OFSpinlockTryLock(OFSpinlock *spinlock)
207 {
208 #if defined(OF_HAVE_ATOMIC_OPS)
209  if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) {
210  OFAcquireMemoryBarrier();
211  return 0;
212  }
213 
214  return EBUSY;
215 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
216  return pthread_spin_trylock(spinlock);
217 #else
218  return OFPlainMutexTryLock(spinlock);
219 #endif
220 }
221 
228 static OF_INLINE int
229 OFSpinlockLock(OFSpinlock *spinlock)
230 {
231 #if defined(OF_HAVE_ATOMIC_OPS)
232  size_t i;
233 
234  for (i = 0; i < 10; i++)
235  if (OFSpinlockTryLock(spinlock) == 0)
236  return 0;
237 
238  while (OFSpinlockTryLock(spinlock) == EBUSY)
239  OFYieldThread();
240 
241  return 0;
242 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
243  return pthread_spin_lock(spinlock);
244 #else
245  return OFPlainMutexLock(spinlock);
246 #endif
247 }
248 
255 static OF_INLINE int
256 OFSpinlockUnlock(OFSpinlock *spinlock)
257 {
258 #if defined(OF_HAVE_ATOMIC_OPS)
259  bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0);
260 
261  OFReleaseMemoryBarrier();
262 
263  return (ret ? 0 : EINVAL);
264 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
265  return pthread_spin_unlock(spinlock);
266 #else
267  return OFPlainMutexUnlock(spinlock);
268 #endif
269 }
270 
277 static OF_INLINE int
278 OFSpinlockFree(OFSpinlock *spinlock)
279 {
280 #if defined(OF_HAVE_ATOMIC_OPS)
281  (void)spinlock;
282 
283  return 0;
284 #elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
285  return pthread_spin_destroy(spinlock);
286 #else
287  return OFPlainMutexFree(spinlock);
288 #endif
289 }
int OFPlainMutexLock(OFPlainMutex *mutex)
Locks the specified mutex.
static OF_INLINE void OFYieldThread(void)
Yield the current thread, indicating to the OS that another thread should execute instead...
Definition: OFPlainMutex.h:171
int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex)
Unlocks the specified recursive mutex.
static OF_INLINE int OFSpinlockNew(OFSpinlock *spinlock)
Creates a new spinlock.
Definition: OFPlainMutex.h:187
int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex)
Destroys the specified recursive mutex.
int OFPlainMutexFree(OFPlainMutex *mutex)
Destroys the specified mutex.
int OFPlainMutexTryLock(OFPlainMutex *mutex)
Tries to lock the specified mutex without blocking.
static OF_INLINE int OFSpinlockTryLock(OFSpinlock *spinlock)
Tries to lock a spinlock.
Definition: OFPlainMutex.h:206
int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex)
Creates a new plain recursive mutex.
int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex)
Tries to lock the specified recursive mutex without blocking.
int OFPlainMutexUnlock(OFPlainMutex *mutex)
Unlocks the specified mutex.
int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex)
Locks the specified recursive mutex.
static OF_INLINE int OFSpinlockLock(OFSpinlock *spinlock)
Locks a spinlock.
Definition: OFPlainMutex.h:229
static OF_INLINE int OFSpinlockUnlock(OFSpinlock *spinlock)
Unlocks a spinlock.
Definition: OFPlainMutex.h:256
static OF_INLINE int OFSpinlockFree(OFSpinlock *spinlock)
Destroys a spinlock.
Definition: OFPlainMutex.h:278
int OFPlainMutexNew(OFPlainMutex *mutex)
Creates a new plain mutex.