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