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 3 types of mutexes, to bring it roughly in-line with
21 POSIX. The types of mutexes that can be made are normal, error-checking, and
22 recursive. Each has its own strengths and weaknesses, which are briefly
23 discussed below.
24
25 A normal mutex (MUTEX_TYPE_NORMAL) is the fastest and simplest mutex of the
26 bunch. This is roughly equivalent to a semaphore that has been initialized
27 with a count of 1. There is no protection against threads unlocking normal
28 mutexes they didn't lock, nor is there any protection against deadlocks that
29 would arise from locking the mutex twice.
30
31 An error-checking mutex (MUTEX_TYPE_ERRORCHECK) adds a small amount of error
32 checking on top of a normal mutex. This type will not allow you to lock the
33 mutex twice (it will return an error if the same thread tries to lock it two
34 times so it will not deadlock), and it will not allow a different thread to
35 unlock the mutex if it isn't the one holding the lock.
36
37 A recursive mutex (MUTEX_TYPE_RECURSIVE) extends the error checking mutex
38 by allowing you to lock the mutex twice in the same thread, but you must
39 also unlock it twice (this works for any number of locks -- lock it n times,
40 you must unlock it n times). Still only one thread can hold the lock, but it
41 may hold it as many times as it needs to. This is equivalent to the
42 recursive_lock_t type that was available in KallistiOS for a while (before
43 it was basically merged back into a normal mutex).
44
45 There is a fourth type of mutex defined (MUTEX_TYPE_DEFAULT), which maps to
46 the MUTEX_TYPE_NORMAL type. This is simply for alignment with POSIX.
47
48 \author Lawrence Sebald
49 \see kos/sem.h
50*/
51
52#ifndef __KOS_MUTEX_H
53#define __KOS_MUTEX_H
54
55#include <kos/cdefs.h>
56
57__BEGIN_DECLS
58
59#include <kos/thread.h>
60
61/** \brief Mutual exclusion lock type.
62
63 All members of this structure should be considered to be private. It is
64 unsafe to change anything in here yourself.
65
66 \headerfile kos/mutex.h
67*/
68typedef struct kos_mutex {
69 unsigned int type;
71 int count;
72} mutex_t;
73
74/** \name Mutex types
75 \brief Types of Mutexes supported by KOS
76
77 The values defined in here are the various types of mutexes that KallistiOS
78 supports.
79
80 @{
81*/
82#define MUTEX_TYPE_NORMAL 0 /**< \brief Normal mutex type */
83#define MUTEX_TYPE_OLDNORMAL 1 /**< \brief Alias for MUTEX_TYPE_NORMAL */
84#define MUTEX_TYPE_ERRORCHECK 2 /**< \brief Error-checking mutex type */
85#define MUTEX_TYPE_RECURSIVE 3 /**< \brief Recursive mutex type */
86#define MUTEX_TYPE_DESTROYED 4 /**< \brief Mutex that has been destroyed */
87
88/** \brief Default mutex type */
89#define MUTEX_TYPE_DEFAULT MUTEX_TYPE_NORMAL
90/** @} */
91
92/** \brief Initializer for a transient mutex. */
93#define MUTEX_INITIALIZER { MUTEX_TYPE_NORMAL, NULL, 0 }
94
95/** \brief Initializer for a transient error-checking mutex. */
96#define ERRORCHECK_MUTEX_INITIALIZER { MUTEX_TYPE_ERRORCHECK, NULL, 0 }
97
98/** \brief Initializer for a transient recursive mutex. */
99#define RECURSIVE_MUTEX_INITIALIZER { MUTEX_TYPE_RECURSIVE, NULL, 0 }
100
101/** \brief Initialize a new mutex.
102
103 This function initializes a new mutex for use.
104
105 \param m The mutex to initialize
106 \param mtype The type of the mutex to initialize it to
107
108 \retval 0 On success
109 \retval -1 On error, errno will be set as appropriate
110
111 \par Error Conditions:
112 \em EINVAL - an invalid type of mutex was specified
113
114 \sa mutex_types
115*/
116int mutex_init(mutex_t *m, unsigned int mtype) __nonnull_all;
117
118/** \brief Destroy a mutex.
119
120 This function destroys a mutex, releasing any memory that may have been
121 allocated internally for it. It is your responsibility to make sure that all
122 threads waiting on the mutex are taken care of before destroying the mutex.
123
124 This function can be called on statically initialized as well as dynamically
125 initialized mutexes.
126
127 \param m The mutex to destroy
128
129 \retval 0 On success
130 \retval -1 On error, errno will be set as appropriate
131
132 \par Error Conditions:
133 \em EBUSY - the mutex is currently locked
134*/
135int mutex_destroy(mutex_t *m) __nonnull_all;
136
137/** \brief Lock a mutex.
138
139 This function will lock a mutex, if it is not already locked by another
140 thread. If it is locked by another thread already, this function will block
141 until the mutex has been acquired for the calling thread.
142 This function can be called from within an interrupt context. In that case,
143 if the mutex is already locked, an error will be returned.
144
145 The semantics of this function depend on the type of mutex that is used.
146
147 \param m The mutex to acquire
148 \retval 0 On success
149 \retval -1 On error, sets errno as appropriate
150
151 \par Error Conditions:
152 \em EAGAIN - lock has been acquired too many times (recursive), or the
153 function was called inside an interrupt and the mutex was
154 already locked \n
155 \em EDEADLK - would deadlock (error-checking)
156*/
157int mutex_lock_irqsafe(mutex_t *m) __nonnull_all;
158
159/** \brief Lock a mutex (with a timeout).
160
161 This function will attempt to lock a mutex. If the lock can be acquired
162 immediately, the function will return immediately. If not, the function will
163 block for up to the specified number of milliseconds to wait for the lock.
164 If the lock cannot be acquired in this timeframe, this function will return
165 an error.
166
167 \param m The mutex to acquire
168 \param timeout The number of milliseconds to wait for the lock
169 \retval 0 On success
170 \retval -1 On error, errno will be set as appropriate
171
172 \par Error Conditions:
173 \em EPERM - called inside an interrupt \n
174 \em ETIMEDOUT - the timeout expired \n
175 \em EAGAIN - lock has been acquired too many times (recursive) \n
176 \em EDEADLK - would deadlock (error-checking)
177*/
178int mutex_lock_timed(mutex_t *m, unsigned int timeout) __nonnull_all;
179
180/** \brief Lock a mutex.
181
182 This function will lock a mutex, if it is not already locked by another
183 thread. If it is locked by another thread already, this function will block
184 until the mutex has been acquired for the calling thread.
185
186 The semantics of this function depend on the type of mutex that is used.
187
188 \param m The mutex to acquire
189 \retval 0 On success
190 \retval -1 On error, sets errno as appropriate
191
192 \par Error Conditions:
193 \em EPERM - called inside an interrupt \n
194 \em EAGAIN - lock has been acquired too many times (recursive) \n
195 \em EDEADLK - would deadlock (error-checking)
196*/
197__nonnull_all
198static inline int mutex_lock(mutex_t *m) {
199 return mutex_lock_timed(m, 0);
200}
201
202/** \brief Check if a mutex is locked.
203
204 This function will check whether or not a mutex is currently locked. This is
205 not a thread-safe way to determine if the mutex will be locked by the time
206 you get around to doing it. If you wish to attempt to lock a mutex without
207 blocking, look at mutex_trylock(), not this.
208
209 \param m The mutex to check
210 \retval 0 If the mutex is not currently locked
211 \retval 1 If the mutex is currently locked
212*/
213int __pure mutex_is_locked(const mutex_t *m) __nonnull_all;
214
215/** \brief Attempt to lock a mutex.
216
217 This function will attempt to acquire the mutex for the calling thread,
218 returning immediately whether or not it could be acquired. If the mutex
219 cannot be acquired, an error will be returned.
220
221 This function is safe to call inside an interrupt.
222
223 \param m The mutex to attempt to acquire
224 \retval 0 On successfully acquiring the mutex
225 \retval -1 If the mutex cannot be acquired without blocking
226
227 \par Error Conditions:
228 \em EBUSY - the mutex is already locked (mutex_lock() would block) \n
229 \em EAGAIN - lock has been acquired too many times (recursive) \n
230 \em EDEADLK - would deadlock (error-checking)
231*/
232int mutex_trylock(mutex_t *m) __nonnull_all;
233
234/** \brief Unlock a mutex.
235
236 This function will unlock a mutex, allowing other threads to acquire it.
237 The semantics of this operation depend on the mutex type in use.
238
239 \param m The mutex to unlock
240 \retval 0 On success
241 \retval -1 On error, errno will be set as appropriate.
242
243 \par Error Conditions:
244 \em EPERM - the current thread does not own the mutex (error-checking or
245 recursive)
246*/
247int mutex_unlock(mutex_t *m) __nonnull_all;
248
249/** \brief Unlock a mutex under another thread's authority.
250
251 This function allows an IRQ handler to unlock a mutex that was locked by a
252 normal kernel thread. This function is only for use in IRQ handlers, so it
253 will generally not be of much use outside of the kernel itself. It cannot
254 be used with recursive mutexes.
255
256 \param m The mutex to unlock
257 \param thd The thread owning the mutex
258 \retval 0 On success
259 \retval -1 On error, errno will be set as appropriate.
260
261 \par Error Conditions:
262 \em EPERM - the specified thread does not own the mutex \n
263 \em EACCES - called outside an IRQ handler
264*/
265int mutex_unlock_as_thread(mutex_t *m, kthread_t *thd) __nonnull_all;
266
267/** \cond */
268static inline void __mutex_scoped_cleanup(mutex_t **m) {
269 if(*m)
270 mutex_unlock(*m);
271}
272
273#define ___mutex_lock_scoped(m, l) \
274 mutex_t *__scoped_mutex_##l __attribute__((cleanup(__mutex_scoped_cleanup))) = mutex_lock(m) ? NULL : (m)
275
276#define __mutex_lock_scoped(m, l) ___mutex_lock_scoped(m, l)
277/** \endcond */
278
279/** \brief Lock a mutex with scope management
280
281 This macro will lock a mutex, similarly to mutex_lock, with the difference
282 that the mutex will automatically be unlocked once the execution exits the
283 functional block in which the macro was called.
284
285 \param m The mutex to acquire
286*/
287#define mutex_lock_scoped(m) __mutex_lock_scoped((m), __LINE__)
288
289__END_DECLS
290
291#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 __nonnull_all int mutex_lock(mutex_t *m)
Lock a mutex.
Definition mutex.h:198
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_as_thread(mutex_t *m, kthread_t *thd) __nonnull_all
Unlock a mutex under another thread's authority.
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.
Structure describing one running thread.
Definition thread.h:164
Mutual exclusion lock type.
Definition mutex.h:68
int count
Definition mutex.h:71
kthread_t * holder
Definition mutex.h:70
unsigned int type
Definition mutex.h:69
Threading support.