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 int type;
72 int count;
73} mutex_t;
74
75/** \name Mutex types
76 \brief Types of Mutexes supported by KOS
77
78 The values defined in here are the various types of mutexes that KallistiOS
79 supports.
80
81 @{
82*/
83#define MUTEX_TYPE_NORMAL 0 /**< \brief Normal mutex type */
84#define MUTEX_TYPE_OLDNORMAL 1 /**< \brief Alias for MUTEX_TYPE_NORMAL */
85#define MUTEX_TYPE_ERRORCHECK 2 /**< \brief Error-checking mutex type */
86#define MUTEX_TYPE_RECURSIVE 3 /**< \brief Recursive mutex type */
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, 0, NULL, 0 }
94
95/** \brief Initializer for a transient error-checking mutex. */
96#define ERRORCHECK_MUTEX_INITIALIZER { MUTEX_TYPE_ERRORCHECK, 0, NULL, 0 }
97
98/** \brief Initializer for a transient recursive mutex. */
99#define RECURSIVE_MUTEX_INITIALIZER { MUTEX_TYPE_RECURSIVE, 0, NULL, 0 }
100
101/** \brief Allocate a new mutex.
102
103 \deprecated
104 This function allocates and initializes a new mutex for use. This function
105 will always create mutexes of the type MUTEX_TYPE_NORMAL.
106
107 \return The newly created mutex on success, or NULL on
108 failure (errno will be set as appropriate).
109
110 \note This function is formally deprecated. It should not
111 be used in any future code, and may be removed in
112 the future. You should instead use mutex_init().
113*/
114mutex_t *mutex_create(void) __depr("Use mutex_init or an initializer.");
115
116/** \brief Initialize a new mutex.
117
118 This function initializes a new mutex for use.
119
120 \param m The mutex to initialize
121 \param mtype The type of the mutex to initialize it to
122
123 \retval 0 On success
124 \retval -1 On error, errno will be set as appropriate
125
126 \par Error Conditions:
127 \em EINVAL - an invalid type of mutex was specified
128
129 \sa mutex_types
130*/
131int mutex_init(mutex_t *m, int mtype);
132
133/** \brief Destroy a mutex.
134
135 This function destroys a mutex, releasing any memory that may have been
136 allocated internally for it. It is your responsibility to make sure that all
137 threads waiting on the mutex are taken care of before destroying the mutex.
138
139 This function can be called on statically initialized as well as dynamically
140 initialized mutexes.
141
142 \retval 0 On success
143 \retval -1 On error, errno will be set as appropriate
144
145 \par Error Conditions:
146 \em EBUSY - the mutex is currently locked
147*/
149
150/** \brief Lock a mutex.
151
152 This function will lock a mutex, if it is not already locked by another
153 thread. If it is locked by another thread already, this function will block
154 until the mutex has been acquired for the calling thread.
155
156 The semantics of this function depend on the type of mutex that is used.
157
158 \param m The mutex to acquire
159 \retval 0 On success
160 \retval -1 On error, sets errno as appropriate
161
162 \par Error Conditions:
163 \em EPERM - called inside an interrupt \n
164 \em EINVAL - the mutex has not been initialized properly \n
165 \em EAGAIN - lock has been acquired too many times (recursive) \n
166 \em EDEADLK - would deadlock (error-checking)
167*/
169
170/** \brief Lock a mutex.
171
172 This function will lock a mutex, if it is not already locked by another
173 thread. If it is locked by another thread already, this function will block
174 until the mutex has been acquired for the calling thread.
175 This function can be called from within an interrupt context. In that case,
176 if the mutex is already locked, an error will be returned.
177
178 The semantics of this function depend on the type of mutex that is used.
179
180 \param m The mutex to acquire
181 \retval 0 On success
182 \retval -1 On error, sets errno as appropriate
183
184 \par Error Conditions:
185 \em EINVAL - the mutex has not been initialized properly \n
186 \em EAGAIN - lock has been acquired too many times (recursive), or the
187 function was called inside an interrupt and the mutex was
188 already locked \n
189 \em EDEADLK - would deadlock (error-checking)
190*/
192
193/** \brief Lock a mutex (with a timeout).
194
195 This function will attempt to lock a mutex. If the lock can be acquired
196 immediately, the function will return immediately. If not, the function will
197 block for up to the specified number of milliseconds to wait for the lock.
198 If the lock cannot be acquired in this timeframe, this function will return
199 an error.
200
201 \param m The mutex to acquire
202 \param timeout The number of milliseconds to wait for the lock
203 \retval 0 On success
204 \retval -1 On error, errno will be set as appropriate
205
206 \par Error Conditions:
207 \em EPERM - called inside an interrupt \n
208 \em EINVAL - the mutex has not been initialized properly \n
209 \em EINVAL - the timeout value was invalid (less than 0) \n
210 \em ETIMEDOUT - the timeout expired \n
211 \em EAGAIN - lock has been acquired too many times (recursive) \n
212 \em EDEADLK - would deadlock (error-checking)
213*/
214int mutex_lock_timed(mutex_t *m, int timeout);
215
216/** \brief Check if a mutex is locked.
217
218 This function will check whether or not a mutex is currently locked. This is
219 not a thread-safe way to determine if the mutex will be locked by the time
220 you get around to doing it. If you wish to attempt to lock a mutex without
221 blocking, look at mutex_trylock(), not this.
222
223 \param m The mutex to check
224 \retval 0 If the mutex is not currently locked
225 \retval 1 If the mutex is currently locked
226*/
228
229/** \brief Attempt to lock a mutex.
230
231 This function will attempt to acquire the mutex for the calling thread,
232 returning immediately whether or not it could be acquired. If the mutex
233 cannot be acquired, an error will be returned.
234
235 This function is safe to call inside an interrupt.
236
237 \param m The mutex to attempt to acquire
238 \retval 0 On successfully acquiring the mutex
239 \retval -1 If the mutex cannot be acquired without blocking
240
241 \par Error Conditions:
242 \em EAGAIN - the mutex is already locked (mutex_lock() would block) \n
243 \em EINVAL - the mutex has not been initialized properly \n
244 \em EAGAIN - lock has been acquired too many times (recursive) \n
245 \em EDEADLK - would deadlock (error-checking)
246*/
248
249/** \brief Unlock a mutex.
250
251 This function will unlock a mutex, allowing other threads to acquire it.
252 The semantics of this operation depend on the mutex type in use.
253
254 \param m The mutex to unlock
255 \retval 0 On success
256 \retval -1 On error, errno will be set as appropriate.
257
258 \par Error Conditions:
259 \em EPERM - the current thread does not own the mutex (error-checking or
260 recursive)
261*/
263
264/** \brief Unlock a mutex under another thread's authority.
265
266 This function allows an IRQ handler to unlock a mutex that was locked by a
267 normal kernel thread. This function is only for use in IRQ handlers, so it
268 will generally not be of much use outside of the kernel itself.
269
270 \param m The mutex to unlock
271 \param thd The thread owning the mutex
272 \retval 0 On success
273 \retval -1 On error, errno will be set as appropriate.
274
275 \par Error Conditions:
276 \em EPERM - the specified thread does not own the mutex \n
277 \em EACCES - called outside an IRQ handler
278*/
280
281/** \cond */
282static inline void __mutex_scoped_cleanup(mutex_t **m) {
283 if(*m)
284 mutex_unlock(*m);
285}
286
287#define ___mutex_lock_scoped(m, l) \
288 mutex_t *__scoped_mutex_##l __attribute__((cleanup(__mutex_scoped_cleanup))) = mutex_lock(m) ? NULL : (m)
289
290#define __mutex_lock_scoped(m, l) ___mutex_lock_scoped(m, l)
291/** \endcond */
292
293/** \brief Lock a mutex with scope management
294
295 This macro will lock a mutex, similarly to mutex_lock, with the difference
296 that the mutex will automatically be unlocked once the execution exits the
297 functional block in which the macro was called.
298
299 \param m The mutex to acquire
300*/
301#define mutex_lock_scoped(m) __mutex_lock_scoped((m), __LINE__)
302
303__END_DECLS
304
305#endif /* __KOS_MUTEX_H */
Definitions for builtin attributes and compiler directives.
#define __depr(m)
Mark something as deprecated, with an informative message.
Definition cdefs.h:119
int mutex_is_locked(mutex_t *m)
Check if a mutex is locked.
int mutex_lock(mutex_t *m)
Lock a mutex.
int mutex_trylock(mutex_t *m)
Attempt to lock a mutex.
mutex_t * mutex_create(void) __depr("Use mutex_init or an initializer.")
Allocate a new mutex.
int mutex_lock_irqsafe(mutex_t *m)
Lock a mutex.
int mutex_unlock_as_thread(mutex_t *m, kthread_t *thd)
Unlock a mutex under another thread's authority.
int mutex_init(mutex_t *m, int mtype)
Initialize a new mutex.
int mutex_unlock(mutex_t *m)
Unlock a mutex.
int mutex_destroy(mutex_t *m)
Destroy a mutex.
int mutex_lock_timed(mutex_t *m, int timeout)
Lock a mutex (with a timeout).
Structure describing one running thread.
Definition thread.h:169
Mutual exclusion lock type.
Definition mutex.h:68
int count
Definition mutex.h:72
int dynamic
Definition mutex.h:70
kthread_t * holder
Definition mutex.h:71
int type
Definition mutex.h:69
Threading support.