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