1 /*
2  * Copyright (c) 2019 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_SYS_MUTEX_H_
8 #define ZEPHYR_INCLUDE_SYS_MUTEX_H_
9 
10 /*
11  * sys_mutex behaves almost exactly like k_mutex, with the added advantage
12  * that a sys_mutex instance can reside in user memory.
13  *
14  * Further enhancements will support locking/unlocking uncontended sys_mutexes
15  * with simple atomic ops instead of syscalls, similar to Linux's
16  * FUTEX_LOCK_PI and FUTEX_UNLOCK_PI
17  */
18 
19 #ifdef __cplusplus
20 extern "C" {
21 #endif
22 
23 #ifdef CONFIG_USERSPACE
24 #include <zephyr/sys/atomic.h>
25 #include <zephyr/types.h>
26 #include <zephyr/sys_clock.h>
27 
28 struct sys_mutex {
29 	/* Currently unused, but will be used to store state for fast mutexes
30 	 * that can be locked/unlocked with atomic ops if there is no
31 	 * contention
32 	 */
33 	atomic_t val;
34 };
35 
36 /**
37  * @defgroup user_mutex_apis User mode mutex APIs
38  * @ingroup kernel_apis
39  * @{
40  */
41 
42 /**
43  * @brief Statically define and initialize a sys_mutex
44  *
45  * The mutex can be accessed outside the module where it is defined using:
46  *
47  * @code extern struct sys_mutex <name>; @endcode
48  *
49  * Route this to memory domains using K_APP_DMEM().
50  *
51  * @param name Name of the mutex.
52  */
53 #define SYS_MUTEX_DEFINE(name) \
54 	struct sys_mutex name
55 
56 /**
57  * @brief Initialize a mutex.
58  *
59  * This routine initializes a mutex object, prior to its first use.
60  *
61  * Upon completion, the mutex is available and does not have an owner.
62  *
63  * This routine is only necessary to call when userspace is disabled
64  * and the mutex was not created with SYS_MUTEX_DEFINE().
65  *
66  * @param mutex Address of the mutex.
67  */
sys_mutex_init(struct sys_mutex * mutex)68 static inline void sys_mutex_init(struct sys_mutex *mutex)
69 {
70 	ARG_UNUSED(mutex);
71 
72 	/* Nothing to do, kernel-side data structures are initialized at
73 	 * boot
74 	 */
75 }
76 
77 __syscall int z_sys_mutex_kernel_lock(struct sys_mutex *mutex,
78 				      k_timeout_t timeout);
79 
80 __syscall int z_sys_mutex_kernel_unlock(struct sys_mutex *mutex);
81 
82 /**
83  * @brief Lock a mutex.
84  *
85  * This routine locks @a mutex. If the mutex is locked by another thread,
86  * the calling thread waits until the mutex becomes available or until
87  * a timeout occurs.
88  *
89  * A thread is permitted to lock a mutex it has already locked. The operation
90  * completes immediately and the lock count is increased by 1.
91  *
92  * @param mutex Address of the mutex, which may reside in user memory
93  * @param timeout Waiting period to lock the mutex,
94  *                or one of the special values K_NO_WAIT and K_FOREVER.
95  *
96  * @retval 0 Mutex locked.
97  * @retval -EBUSY Returned without waiting.
98  * @retval -EAGAIN Waiting period timed out.
99  * @retval -EACCES Caller has no access to provided mutex address
100  * @retval -EINVAL Provided mutex not recognized by the kernel
101  */
sys_mutex_lock(struct sys_mutex * mutex,k_timeout_t timeout)102 static inline int sys_mutex_lock(struct sys_mutex *mutex, k_timeout_t timeout)
103 {
104 	/* For now, make the syscall unconditionally */
105 	return z_sys_mutex_kernel_lock(mutex, timeout);
106 }
107 
108 /**
109  * @brief Unlock a mutex.
110  *
111  * This routine unlocks @a mutex. The mutex must already be locked by the
112  * calling thread.
113  *
114  * The mutex cannot be claimed by another thread until it has been unlocked by
115  * the calling thread as many times as it was previously locked by that
116  * thread.
117  *
118  * @param mutex Address of the mutex, which may reside in user memory
119  * @retval 0 Mutex unlocked
120  * @retval -EACCES Caller has no access to provided mutex address
121  * @retval -EINVAL Provided mutex not recognized by the kernel or mutex wasn't
122  *                 locked
123  * @retval -EPERM Caller does not own the mutex
124  */
sys_mutex_unlock(struct sys_mutex * mutex)125 static inline int sys_mutex_unlock(struct sys_mutex *mutex)
126 {
127 	/* For now, make the syscall unconditionally */
128 	return z_sys_mutex_kernel_unlock(mutex);
129 }
130 
131 #include <zephyr/syscalls/mutex.h>
132 
133 #else
134 #include <zephyr/kernel.h>
135 #include <zephyr/kernel_structs.h>
136 
137 struct sys_mutex {
138 	struct k_mutex kernel_mutex;
139 };
140 
141 #define SYS_MUTEX_DEFINE(name) \
142 	struct sys_mutex name = { \
143 		.kernel_mutex = Z_MUTEX_INITIALIZER(name.kernel_mutex) \
144 	}
145 
146 static inline void sys_mutex_init(struct sys_mutex *mutex)
147 {
148 	k_mutex_init(&mutex->kernel_mutex);
149 }
150 
151 static inline int sys_mutex_lock(struct sys_mutex *mutex, k_timeout_t timeout)
152 {
153 	return k_mutex_lock(&mutex->kernel_mutex, timeout);
154 }
155 
156 static inline int sys_mutex_unlock(struct sys_mutex *mutex)
157 {
158 	return k_mutex_unlock(&mutex->kernel_mutex);
159 }
160 
161 #endif /* CONFIG_USERSPACE */
162 
163 /**
164  * @}
165  */
166 
167 #ifdef __cplusplus
168 }
169 #endif
170 
171 #endif /* ZEPHYR_INCLUDE_SYS_MUTEX_H_ */
172