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 <sys/atomic.h>
25 #include <zephyr/types.h>
26 #include <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  *
68  * @return N/A
69  */
sys_mutex_init(struct sys_mutex * mutex)70 static inline void sys_mutex_init(struct sys_mutex *mutex)
71 {
72 	ARG_UNUSED(mutex);
73 
74 	/* Nothing to do, kernel-side data structures are initialized at
75 	 * boot
76 	 */
77 }
78 
79 __syscall int z_sys_mutex_kernel_lock(struct sys_mutex *mutex,
80 				      k_timeout_t timeout);
81 
82 __syscall int z_sys_mutex_kernel_unlock(struct sys_mutex *mutex);
83 
84 /**
85  * @brief Lock a mutex.
86  *
87  * This routine locks @a mutex. If the mutex is locked by another thread,
88  * the calling thread waits until the mutex becomes available or until
89  * a timeout occurs.
90  *
91  * A thread is permitted to lock a mutex it has already locked. The operation
92  * completes immediately and the lock count is increased by 1.
93  *
94  * @param mutex Address of the mutex, which may reside in user memory
95  * @param timeout Waiting period to lock the mutex,
96  *                or one of the special values K_NO_WAIT and K_FOREVER.
97  *
98  * @retval 0 Mutex locked.
99  * @retval -EBUSY Returned without waiting.
100  * @retval -EAGAIN Waiting period timed out.
101  * @retval -EACCES Caller has no access to provided mutex address
102  * @retval -EINVAL Provided mutex not recognized by the kernel
103  */
sys_mutex_lock(struct sys_mutex * mutex,k_timeout_t timeout)104 static inline int sys_mutex_lock(struct sys_mutex *mutex, k_timeout_t timeout)
105 {
106 	/* For now, make the syscall unconditionally */
107 	return z_sys_mutex_kernel_lock(mutex, timeout);
108 }
109 
110 /**
111  * @brief Unlock a mutex.
112  *
113  * This routine unlocks @a mutex. The mutex must already be locked by the
114  * calling thread.
115  *
116  * The mutex cannot be claimed by another thread until it has been unlocked by
117  * the calling thread as many times as it was previously locked by that
118  * thread.
119  *
120  * @param mutex Address of the mutex, which may reside in user memory
121  * @retval 0 Mutex unlocked
122  * @retval -EACCES Caller has no access to provided mutex address
123  * @retval -EINVAL Provided mutex not recognized by the kernel or mutex wasn't
124  *                 locked
125  * @retval -EPERM Caller does not own the mutex
126  */
sys_mutex_unlock(struct sys_mutex * mutex)127 static inline int sys_mutex_unlock(struct sys_mutex *mutex)
128 {
129 	/* For now, make the syscall unconditionally */
130 	return z_sys_mutex_kernel_unlock(mutex);
131 }
132 
133 #include <syscalls/mutex.h>
134 
135 #else
136 #include <kernel.h>
137 #include <kernel_structs.h>
138 
139 struct sys_mutex {
140 	struct k_mutex kernel_mutex;
141 };
142 
143 #define SYS_MUTEX_DEFINE(name) \
144 	struct sys_mutex name = { \
145 		.kernel_mutex = Z_MUTEX_INITIALIZER(name.kernel_mutex) \
146 	}
147 
148 static inline void sys_mutex_init(struct sys_mutex *mutex)
149 {
150 	k_mutex_init(&mutex->kernel_mutex);
151 }
152 
153 static inline int sys_mutex_lock(struct sys_mutex *mutex, k_timeout_t timeout)
154 {
155 	return k_mutex_lock(&mutex->kernel_mutex, timeout);
156 }
157 
158 static inline int sys_mutex_unlock(struct sys_mutex *mutex)
159 {
160 	return k_mutex_unlock(&mutex->kernel_mutex);
161 }
162 
163 #endif /* CONFIG_USERSPACE */
164 
165 /**
166  * @}
167  */
168 
169 #ifdef __cplusplus
170 }
171 #endif
172 
173 #endif /* ZEPHYR_INCLUDE_SYS_MUTEX_H_ */
174