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 file is part of ObjFW. It may be distributed under the terms of the
7 * Q Public License 1.0, which can be found in the file LICENSE.QPL included in
8 * the packaging of this file.
9 *
10 * Alternatively, it may be distributed under the terms of the GNU General
11 * Public License, either version 2 or 3, which can be found in the file
12 * LICENSE.GPLv2 or LICENSE.GPLv3 respectively included in the packaging of this
13 * file.
14 */
15
16#include "objfw-defs.h"
17
18#include <errno.h>
19
20#include "platform.h"
21
22#if !defined(OF_HAVE_THREADS) || \
23 (!defined(OF_HAVE_PTHREADS) && !defined(OF_WINDOWS) && !defined(OF_AMIGAOS))
24# error No mutexes available!
25#endif
26
27#import "macros.h"
28
29#if defined(OF_HAVE_PTHREADS)
30# include <pthread.h>
31typedef pthread_mutex_t OFPlainMutex;
32#elif defined(OF_WINDOWS)
33# include <windows.h>
34typedef CRITICAL_SECTION OFPlainMutex;
35#elif defined(OF_AMIGAOS)
36# include <exec/semaphores.h>
37typedef struct SignalSemaphore OFPlainMutex;
38#endif
39
40#if defined(OF_HAVE_ATOMIC_OPS)
41# import "OFAtomic.h"
42typedef volatile int OFSpinlock;
43#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
44typedef pthread_spinlock_t OFSpinlock;
45#else
46typedef OFPlainMutex OFSpinlock;
47#endif
48
49#ifdef OF_HAVE_SCHED_YIELD
50# include <sched.h>
51#endif
52
53#if defined(OF_HAVE_RECURSIVE_PTHREAD_MUTEXES) || defined(OF_WINDOWS) || \
54 defined(OF_AMIGAOS)
55# define OFPlainRecursiveMutex OFPlainMutex
56#else
57# import "OFTLSKey.h"
58typedef struct {
59 OFPlainMutex mutex;
60 OFTLSKey count;
61} OFPlainRecursiveMutex;
62#endif
63
64#ifdef __cplusplus
65extern "C" {
66#endif
67extern int OFPlainMutexNew(OFPlainMutex *mutex);
68extern int OFPlainMutexLock(OFPlainMutex *mutex);
69extern int OFPlainMutexTryLock(OFPlainMutex *mutex);
70extern int OFPlainMutexUnlock(OFPlainMutex *mutex);
71extern int OFPlainMutexFree(OFPlainMutex *mutex);
72extern int OFPlainRecursiveMutexNew(OFPlainRecursiveMutex *rmutex);
73extern int OFPlainRecursiveMutexLock(OFPlainRecursiveMutex *rmutex);
74extern int OFPlainRecursiveMutexTryLock(OFPlainRecursiveMutex *rmutex);
75extern int OFPlainRecursiveMutexUnlock(OFPlainRecursiveMutex *rmutex);
76extern int OFPlainRecursiveMutexFree(OFPlainRecursiveMutex *rmutex);
77#ifdef __cplusplus
78}
79#endif
80
81/* Spinlocks are inlined for performance. */
82
83static OF_INLINE void
84OFYieldThread(void)
85{
86#if defined(OF_HAVE_SCHED_YIELD)
87 sched_yield();
88#elif defined(OF_WINDOWS)
89 Sleep(0);
90#endif
91}
92
93static OF_INLINE int
94OFSpinlockNew(OFSpinlock *spinlock)
95{
96#if defined(OF_HAVE_ATOMIC_OPS)
97 *spinlock = 0;
98 return 0;
99#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
100 return pthread_spin_init(spinlock, 0);
101#else
102 return OFPlainMutexNew(spinlock);
103#endif
104}
105
106static OF_INLINE int
107OFSpinlockTryLock(OFSpinlock *spinlock)
108{
109#if defined(OF_HAVE_ATOMIC_OPS)
110 if (OFAtomicIntCompareAndSwap(spinlock, 0, 1)) {
111 OFAcquireMemoryBarrier();
112 return 0;
113 }
114
115 return EBUSY;
116#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
117 return pthread_spin_trylock(spinlock);
118#else
119 return OFPlainMutexTryLock(spinlock);
120#endif
121}
122
123static OF_INLINE int
124OFSpinlockLock(OFSpinlock *spinlock)
125{
126#if defined(OF_HAVE_ATOMIC_OPS)
127 size_t i;
128
129 for (i = 0; i < 10; i++)
130 if (OFSpinlockTryLock(spinlock) == 0)
131 return 0;
132
133 while (OFSpinlockTryLock(spinlock) == EBUSY)
134 OFYieldThread();
135
136 return 0;
137#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
138 return pthread_spin_lock(spinlock);
139#else
140 return OFPlainMutexLock(spinlock);
141#endif
142}
143
144static OF_INLINE int
145OFSpinlockUnlock(OFSpinlock *spinlock)
146{
147#if defined(OF_HAVE_ATOMIC_OPS)
148 bool ret = OFAtomicIntCompareAndSwap(spinlock, 1, 0);
149
150 OFReleaseMemoryBarrier();
151
152 return (ret ? 0 : EINVAL);
153#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
154 return pthread_spin_unlock(spinlock);
155#else
156 return OFPlainMutexUnlock(spinlock);
157#endif
158}
159
160static OF_INLINE int
161OFSpinlockFree(OFSpinlock *spinlock)
162{
163#if defined(OF_HAVE_ATOMIC_OPS)
164 return 0;
165#elif defined(OF_HAVE_PTHREAD_SPINLOCKS)
166 return pthread_spin_destroy(spinlock);
167#else
168 return OFPlainMutexFree(spinlock);
169#endif
170}