1 /* SPDX-License-Identifier: BSD-2-Clause */
2 /*
3 * Copyright (c) 2014-2017, Linaro Limited
4 */
5 #ifndef __KERNEL_MUTEX_H
6 #define __KERNEL_MUTEX_H
7
8 #include <kernel/refcount.h>
9 #include <kernel/wait_queue.h>
10 #include <sys/queue.h>
11 #include <types_ext.h>
12
13 struct mutex {
14 unsigned spin_lock; /* used when operating on this struct */
15 struct wait_queue wq;
16 short state; /* -1: write, 0: unlocked, > 0: readers */
17 };
18
19 #define MUTEX_INITIALIZER { .wq = WAIT_QUEUE_INITIALIZER }
20
21 struct recursive_mutex {
22 struct mutex m; /* used when lock_depth goes 0 -> 1 or 1 -> 0 */
23 short int owner;
24 struct refcount lock_depth;
25 };
26
27 #define RECURSIVE_MUTEX_INITIALIZER { .m = MUTEX_INITIALIZER, \
28 .owner = THREAD_ID_INVALID }
29
30 TAILQ_HEAD(mutex_head, mutex);
31
32 void mutex_init(struct mutex *m);
33 void mutex_destroy(struct mutex *m);
34
35 void mutex_init_recursive(struct recursive_mutex *m);
36 void mutex_destroy_recursive(struct recursive_mutex *m);
37 unsigned int mutex_get_recursive_lock_depth(struct recursive_mutex *m);
38
39 #ifdef CFG_MUTEX_DEBUG
40 void mutex_unlock_debug(struct mutex *m, const char *fname, int lineno);
41 #define mutex_unlock(m) mutex_unlock_debug((m), __FILE__, __LINE__)
42
43 void mutex_lock_debug(struct mutex *m, const char *fname, int lineno);
44 #define mutex_lock(m) mutex_lock_debug((m), __FILE__, __LINE__)
45
46 bool mutex_trylock_debug(struct mutex *m, const char *fname, int lineno);
47 #define mutex_trylock(m) mutex_trylock_debug((m), __FILE__, __LINE__)
48
49 void mutex_read_unlock_debug(struct mutex *m, const char *fname, int lineno);
50 #define mutex_read_unlock(m) mutex_read_unlock_debug((m), __FILE__, __LINE__)
51
52 void mutex_read_lock_debug(struct mutex *m, const char *fname, int lineno);
53 #define mutex_read_lock(m) mutex_read_lock_debug((m), __FILE__, __LINE__)
54
55 bool mutex_read_trylock_debug(struct mutex *m, const char *fname, int lineno);
56 #define mutex_read_trylock(m) mutex_read_trylock_debug((m), __FILE__, __LINE__)
57
58 void mutex_unlock_recursive_debug(struct recursive_mutex *m, const char *fname,
59 int lineno);
60 #define mutex_unlock_recursive(m) mutex_unlock_recursive_debug((m), __FILE__, \
61 __LINE__)
62
63 void mutex_lock_recursive_debug(struct recursive_mutex *m, const char *fname,
64 int lineno);
65 #define mutex_lock_recursive(m) mutex_lock_recursive_debug((m), __FILE__, \
66 __LINE__)
67 #else
68 void mutex_unlock(struct mutex *m);
69 void mutex_lock(struct mutex *m);
70 bool mutex_trylock(struct mutex *m);
71 void mutex_read_unlock(struct mutex *m);
72 void mutex_read_lock(struct mutex *m);
73 bool mutex_read_trylock(struct mutex *m);
74
75 void mutex_unlock_recursive(struct recursive_mutex *m);
76 void mutex_lock_recursive(struct recursive_mutex *m);
77 #endif
78
79 struct condvar {
80 unsigned int spin_lock;
81 struct mutex *m;
82 };
83 #define CONDVAR_INITIALIZER { .m = NULL }
84
85 void condvar_init(struct condvar *cv);
86 void condvar_destroy(struct condvar *cv);
87
88 #ifdef CFG_MUTEX_DEBUG
89 void condvar_signal_debug(struct condvar *cv, const char *fname, int lineno);
90 #define condvar_signal(cv) condvar_signal_debug((cv), __FILE__, __LINE__)
91
92 void condvar_broadcast_debug(struct condvar *cv, const char *fname, int lineno);
93 #define condvar_broadcast(cv) condvar_broadcast_debug((cv), __FILE__, __LINE__)
94
95 void condvar_wait_debug(struct condvar *cv, struct mutex *m,
96 const char *fname, int lineno);
97 #define condvar_wait(cv, m) condvar_wait_debug((cv), (m), __FILE__, __LINE__)
98
99 /*
100 * Return TEE_ERROR_TIMEOUT if the normal world returns before
101 * the condvar has been signaled.
102 */
103 TEE_Result condvar_wait_timeout_debug(struct condvar *cv, struct mutex *m,
104 uint32_t timeout_ms, const char *fname,
105 int lineno);
106 #define condvar_wait_timeout(cv, m, timeout_ms) \
107 condvar_wait_timeout_debug((cv), (m), (timeout_ms), __FILE__, __LINE__)
108 #else
109 void condvar_signal(struct condvar *cv);
110 void condvar_broadcast(struct condvar *cv);
111 void condvar_wait(struct condvar *cv, struct mutex *m);
112 /*
113 * Return TEE_ERROR_TIMEOUT if the normal world returns before
114 * the condvar has been signaled.
115 */
116 TEE_Result condvar_wait_timeout(struct condvar *cv, struct mutex *m,
117 uint32_t timeout_ms);
118 #endif
119
120 /*
121 * Helper for testing that a given mutex is locked for writing. This helper
122 * is to be used with caution since it does not guarantee that the executing
123 * thread is holding the mutex.
124 */
mutex_is_locked(struct mutex * m)125 static inline bool mutex_is_locked(struct mutex *m)
126 {
127 return m->state == -1; /* write locked */
128 }
129 #endif /*__KERNEL_MUTEX_H*/
130
131