KallistiOS git master
Independent SDK for the Sega Dreamcast
Loading...
Searching...
No Matches
mutex.h
Go to the documentation of this file.
1/* KallistiOS ##version##
2
3 include/kos/mutex.h
4 Copyright (C) 2001, 2003 Megan Potter
5 Copyright (C) 2012, 2015 Lawrence Sebald
6
7*/
8
9/** \file kos/mutex.h
10 \brief Mutual exclusion locks.
11 \ingroup kthreads
12
13 This file defines mutual exclusion locks (or mutexes for short). The concept
14 of a mutex is one of the most common types of locks in a multi-threaded
15 environment. Mutexes do exactly what they sound like, they keep two (or
16 more) threads mutually exclusive from one another. A mutex is used around
17 a block of code to prevent two threads from interfering with one another
18 when only one would be appropriate to be in the block at a time.
19
20 KallistiOS implements 2 types of mutexes, normal mutexes and recursive
21 mutexes. Internally the implementation is the same, the only difference lies
22 in error-checking. When assert() calls are disabled (by setting the NDEBUG
23 macro), they should have the exact same behaviour.
24
25 A normal mutex (MUTEX_TYPE_NORMAL) is roughly equivalent to a semaphore that
26 has been initialized with a count of 1. If assert() is disabled, there is no
27 protection against threads unlocking normal mutexes they didn't lock, nor is
28 there any protection against a thread locking the same mutex twice.
29
30 A recursive mutex (MUTEX_TYPE_RECURSIVE) allows you to lock the mutex
31 N times in the same thread; in which case, the mutex has to be unlocked N
32 times for the mutex to be effectively released. Still only one thread can
33 hold the lock, but it may hold it as many times as it needs to.
34
35 \author Lawrence Sebald
36 \see kos/sem.h
37*/
38
39#ifndef __KOS_MUTEX_H
40#define __KOS_MUTEX_H
41
42#include <kos/cdefs.h>
43
44__BEGIN_DECLS
45
46/* Forward declare kthread to not expose all of thread.h here */
47struct kthread;
48
49/** \brief Mutual exclusion lock type.
50
51 All members of this structure should be considered to be private. It is
52 unsafe to change anything in here yourself.
53
54 \headerfile kos/mutex.h
55*/
56typedef struct kos_mutex {
57 unsigned int type;
58 struct kthread *holder;
59 int count;
60} mutex_t;
61
62/** \name Mutex types
63 \brief Types of Mutexes supported by KOS
64
65 The values defined in here are the various types of mutexes that KallistiOS
66 supports.
67
68 @{
69*/
70#define MUTEX_TYPE_NORMAL 0 /**< \brief Normal mutex type */
71#define MUTEX_TYPE_OLDNORMAL 1 /**< \brief Alias for MUTEX_TYPE_NORMAL */
72#define MUTEX_TYPE_RECURSIVE 3 /**< \brief Recursive mutex type */
73#define MUTEX_TYPE_DESTROYED 4 /**< \brief Mutex that has been destroyed */
74
75 __depr("Error-checking mutexes are deprecated")
76static const unsigned int MUTEX_TYPE_ERRORCHECK = 2;
77
78/** \brief Default mutex type */
79#define MUTEX_TYPE_DEFAULT MUTEX_TYPE_NORMAL
80/** @} */
81
82/** \brief Initializer for a transient mutex. */
83#define MUTEX_INITIALIZER { MUTEX_TYPE_NORMAL, NULL, 0 }
84
85/** \brief Initializer for a transient error-checking mutex. */
86#define ERRORCHECK_MUTEX_INITIALIZER { MUTEX_TYPE_ERRORCHECK, NULL, 0 }
87
88/** \brief Initializer for a transient recursive mutex. */
89#define RECURSIVE_MUTEX_INITIALIZER { MUTEX_TYPE_RECURSIVE, NULL, 0 }
90
91/** \brief Initialize a new mutex.
92
93 This function initializes a new mutex for use.
94
95 \param m The mutex to initialize
96 \param mtype The type of the mutex to initialize it to
97
98 \retval 0 On success
99 \retval -1 On error, errno will be set as appropriate
100
101 \par Error Conditions:
102 \em EINVAL - an invalid type of mutex was specified
103
104 \sa mutex_types
105*/
106int mutex_init(mutex_t *m, unsigned int mtype) __nonnull_all;
107
108/** \brief Destroy a mutex.
109
110 This function destroys a mutex, releasing any memory that may have been
111 allocated internally for it. It is your responsibility to make sure that all
112 threads waiting on the mutex are taken care of before destroying the mutex.
113
114 This function can be called on statically initialized as well as dynamically
115 initialized mutexes.
116
117 \param m The mutex to destroy
118
119 \retval 0 On success
120 \retval -1 On error, errno will be set as appropriate
121
122 \par Error Conditions:
123 \em EBUSY - the mutex is currently locked
124*/
125int mutex_destroy(mutex_t *m) __nonnull_all;
126
127/** \brief Lock a mutex.
128
129 This function will lock a mutex, if it is not already locked by another
130 thread. If it is locked by another thread already, this function will block
131 until the mutex has been acquired for the calling thread.
132 This function can be called from within an interrupt context. In that case,
133 if the mutex is already locked, an error will be returned.
134
135 The semantics of this function depend on the type of mutex that is used.
136
137 \param m The mutex to acquire
138 \retval 0 On success
139 \retval -1 On error, sets errno as appropriate
140
141 \par Error Conditions:
142 \em EAGAIN - lock has been acquired too many times (recursive), or the
143 function was called inside an interrupt and the mutex was
144 already locked \n
145*/
146int mutex_lock_irqsafe(mutex_t *m) __nonnull_all;
147
148/** \brief Lock a mutex (with a timeout).
149
150 This function will attempt to lock a mutex. If the lock can be acquired
151 immediately, the function will return immediately. If not, the function will
152 block for up to the specified number of milliseconds to wait for the lock.
153 If the lock cannot be acquired in this timeframe, this function will return
154 an error.
155
156 This function cannot be used in an interrupt context.
157
158 \param m The mutex to acquire
159 \param timeout The number of milliseconds to wait for the lock
160 \retval 0 On success
161 \retval -1 On error, errno will be set as appropriate
162
163 \par Error Conditions:
164 \em ETIMEDOUT - the timeout expired \n
165 \em EAGAIN - lock has been acquired too many times (recursive) \n
166*/
167int mutex_lock_timed(mutex_t *m, unsigned int timeout) __nonnull_all;
168
169/** \brief Lock a mutex.
170
171 This function will lock a mutex, if it is not already locked by another
172 thread. If it is locked by another thread already, this function will block
173 until the mutex has been acquired for the calling thread.
174
175 The semantics of this function depend on the type of mutex that is used.
176
177 This function cannot be used in an interrupt context.
178
179 \param m The mutex to acquire
180 \retval 0 On success
181 \retval -1 On error, sets errno as appropriate
182
183 \par Error Conditions:
184 \em EPERM - called inside an interrupt \n
185 \em EAGAIN - lock has been acquired too many times (recursive) \n
186*/
187__nonnull_all
188static inline int mutex_lock(mutex_t *m) {
189 return mutex_lock_timed(m, 0);
190}
191
192/** \brief Check if a mutex is locked.
193
194 This function will check whether or not a mutex is currently locked. This is
195 not a thread-safe way to determine if the mutex will be locked by the time
196 you get around to doing it. If you wish to attempt to lock a mutex without
197 blocking, look at mutex_trylock(), not this.
198
199 \param m The mutex to check
200 \retval 0 If the mutex is not currently locked
201 \retval 1 If the mutex is currently locked
202*/
203int __pure mutex_is_locked(const mutex_t *m) __nonnull_all;
204
205/** \brief Attempt to lock a mutex.
206
207 This function will attempt to acquire the mutex for the calling thread,
208 returning immediately whether or not it could be acquired. If the mutex
209 cannot be acquired, an error will be returned.
210
211 This function is safe to call inside an interrupt.
212
213 \param m The mutex to attempt to acquire
214 \retval 0 On successfully acquiring the mutex
215 \retval -1 If the mutex cannot be acquired without blocking
216
217 \par Error Conditions:
218 \em EBUSY - the mutex is already locked (mutex_lock() would block) \n
219 \em EAGAIN - lock has been acquired too many times (recursive) \n
220 \em EDEADLK - would deadlock (error-checking)
221*/
222int mutex_trylock(mutex_t *m) __nonnull_all;
223
224/** \brief Unlock a mutex.
225
226 This function will unlock a mutex, allowing other threads to acquire it.
227 The semantics of this operation depend on the mutex type in use.
228
229 \param m The mutex to unlock
230 \retval 0 On success
231 \retval -1 On error, errno will be set as appropriate.
232
233 \par Error Conditions: None defined
234*/
235int mutex_unlock(mutex_t *m) __nonnull_all;
236
237/** \cond */
238static inline void __mutex_scoped_cleanup(mutex_t **m) {
239 if(*m)
240 mutex_unlock(*m);
241}
242
243#define ___mutex_lock_scoped(m, l) \
244 mutex_t *__scoped_mutex_##l __attribute__((cleanup(__mutex_scoped_cleanup))) = mutex_lock(m) ? NULL : (m)
245
246#define __mutex_lock_scoped(m, l) ___mutex_lock_scoped(m, l)
247/** \endcond */
248
249/** \brief Lock a mutex with scope management
250
251 This macro will lock a mutex, similarly to mutex_lock, with the difference
252 that the mutex will automatically be unlocked once the execution exits the
253 functional block in which the macro was called.
254
255 \param m The mutex to acquire
256*/
257#define mutex_lock_scoped(m) __mutex_lock_scoped((m), __LINE__)
258
259__END_DECLS
260
261#endif /* __KOS_MUTEX_H */
Various common macros used throughout the codebase.
int mutex_destroy(mutex_t *m) __nonnull_all
Destroy a mutex.
int mutex_lock_timed(mutex_t *m, unsigned int timeout) __nonnull_all
Lock a mutex (with a timeout).
static const unsigned int MUTEX_TYPE_ERRORCHECK
Definition mutex.h:76
static __nonnull_all int mutex_lock(mutex_t *m)
Lock a mutex.
Definition mutex.h:188
int mutex_lock_irqsafe(mutex_t *m) __nonnull_all
Lock a mutex.
int mutex_init(mutex_t *m, unsigned int mtype) __nonnull_all
Initialize a new mutex.
int mutex_unlock(mutex_t *m) __nonnull_all
Unlock a mutex.
int __pure mutex_is_locked(const mutex_t *m) __nonnull_all
Check if a mutex is locked.
int mutex_trylock(mutex_t *m) __nonnull_all
Attempt to lock a mutex.
Mutual exclusion lock type.
Definition mutex.h:56
struct kthread * holder
Definition mutex.h:58
int count
Definition mutex.h:59
unsigned int type
Definition mutex.h:57