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