Line data Source code
1 1 : /*
2 : * Copyright (c) 2019 Intel Corporation
3 : *
4 : * SPDX-License-Identifier: Apache-2.0
5 : */
6 :
7 : /**
8 : * @file
9 : *
10 : * @brief public sys_sem APIs.
11 : */
12 :
13 : #ifndef ZEPHYR_INCLUDE_SYS_SEM_H_
14 : #define ZEPHYR_INCLUDE_SYS_SEM_H_
15 :
16 : /*
17 : * sys_sem exists in user memory working as counter semaphore for
18 : * user mode thread when user mode enabled. When user mode isn't
19 : * enabled, sys_sem behaves like k_sem.
20 : */
21 :
22 : #include <zephyr/kernel.h>
23 : #include <zephyr/sys/atomic.h>
24 : #include <zephyr/types.h>
25 : #include <zephyr/sys/iterable_sections.h>
26 : #include <zephyr/sys/__assert.h>
27 :
28 : #ifdef __cplusplus
29 : extern "C" {
30 : #endif
31 :
32 : /**
33 : * sys_sem structure
34 : */
35 1 : struct sys_sem {
36 : #ifdef CONFIG_USERSPACE
37 0 : struct k_futex futex;
38 0 : int limit;
39 : #else
40 : struct k_sem kernel_sem;
41 : #endif
42 : };
43 :
44 : /**
45 : * @defgroup user_semaphore_apis User mode semaphore APIs
46 : * @ingroup kernel_apis
47 : * @{
48 : */
49 :
50 : /**
51 : * @brief Statically define and initialize a sys_sem
52 : *
53 : * The semaphore can be accessed outside the module where it is defined using:
54 : *
55 : * @code extern struct sys_sem <name>; @endcode
56 : *
57 : * Route this to memory domains using K_APP_DMEM().
58 : *
59 : * @param _name Name of the semaphore.
60 : * @param _initial_count Initial semaphore count.
61 : * @param _count_limit Maximum permitted semaphore count.
62 : */
63 : #ifdef CONFIG_USERSPACE
64 1 : #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
65 : struct sys_sem _name = { \
66 : .futex = { _initial_count }, \
67 : .limit = _count_limit \
68 : }; \
69 : BUILD_ASSERT(((_count_limit) != 0) && \
70 : ((_initial_count) <= (_count_limit)))
71 : #else
72 : /* Stuff this in the section with the rest of the k_sem objects, since they
73 : * are identical and can be treated as a k_sem in the boot initialization code
74 : */
75 : #define SYS_SEM_DEFINE(_name, _initial_count, _count_limit) \
76 : STRUCT_SECTION_ITERABLE_ALTERNATE(k_sem, sys_sem, _name) = { \
77 : .kernel_sem = Z_SEM_INITIALIZER(_name.kernel_sem, \
78 : _initial_count, _count_limit) \
79 : }; \
80 : BUILD_ASSERT(((_count_limit) != 0) && \
81 : ((_initial_count) <= (_count_limit)))
82 : #endif
83 :
84 : /**
85 : * @brief Initialize a semaphore.
86 : *
87 : * This routine initializes a semaphore instance, prior to its first use.
88 : *
89 : * @param sem Address of the semaphore.
90 : * @param initial_count Initial semaphore count.
91 : * @param limit Maximum permitted semaphore count.
92 : *
93 : * @retval 0 Initial success.
94 : * @retval -EINVAL Bad parameters, the value of limit should be located in
95 : * (0, INT_MAX] and initial_count shouldn't be greater than limit.
96 : */
97 1 : int sys_sem_init(struct sys_sem *sem, unsigned int initial_count,
98 : unsigned int limit);
99 :
100 : /**
101 : * @brief Give a semaphore.
102 : *
103 : * This routine gives @a sem, unless the semaphore is already at its
104 : * maximum permitted count.
105 : *
106 : * @param sem Address of the semaphore.
107 : *
108 : * @retval 0 Semaphore given.
109 : * @retval -EINVAL Parameter address not recognized.
110 : * @retval -EACCES Caller does not have enough access.
111 : * @retval -EAGAIN Count reached Maximum permitted count and try again.
112 : */
113 1 : int sys_sem_give(struct sys_sem *sem);
114 :
115 : /**
116 : * @brief Take a sys_sem.
117 : *
118 : * This routine takes @a sem.
119 : *
120 : * @param sem Address of the sys_sem.
121 : * @param timeout Waiting period to take the sys_sem,
122 : * or one of the special values K_NO_WAIT and K_FOREVER.
123 : *
124 : * @retval 0 sys_sem taken.
125 : * @retval -EINVAL Parameter address not recognized.
126 : * @retval -ETIMEDOUT Waiting period timed out.
127 : * @retval -EACCES Caller does not have enough access.
128 : */
129 1 : int sys_sem_take(struct sys_sem *sem, k_timeout_t timeout);
130 :
131 : /**
132 : * @brief Get sys_sem's value
133 : *
134 : * This routine returns the current value of @a sem.
135 : *
136 : * @param sem Address of the sys_sem.
137 : *
138 : * @return Current value of sys_sem.
139 : */
140 1 : unsigned int sys_sem_count_get(struct sys_sem *sem);
141 :
142 : /**
143 : * @cond INTERNAL_HIDDEN
144 : */
145 :
146 : #if defined(__GNUC__)
147 : static ALWAYS_INLINE void z_sys_sem_lock_onexit(__maybe_unused int *rc)
148 : {
149 : __ASSERT(*rc == 1, "SYS_SEM_LOCK exited with goto, break or return, "
150 : "use SYS_SEM_LOCK_BREAK instead.");
151 : }
152 : #define SYS_SEM_LOCK_ONEXIT __attribute__((__cleanup__(z_sys_sem_lock_onexit)))
153 : #else
154 : #define SYS_SEM_LOCK_ONEXIT
155 : #endif
156 :
157 : /**
158 : * INTERNAL_HIDDEN @endcond
159 : */
160 :
161 : /**
162 : * @brief Leaves a code block guarded with @ref SYS_SEM_LOCK after releasing the
163 : * lock.
164 : *
165 : * See @ref SYS_SEM_LOCK for details.
166 : */
167 1 : #define SYS_SEM_LOCK_BREAK continue
168 :
169 : /**
170 : * @brief Guards a code block with the given sys_sem, automatically acquiring
171 : * the semaphore before executing the code block. The semaphore will be
172 : * released either when reaching the end of the code block or when leaving the
173 : * block with @ref SYS_SEM_LOCK_BREAK.
174 : *
175 : * @details Example usage:
176 : *
177 : * @code{.c}
178 : * SYS_SEM_LOCK(&sem) {
179 : *
180 : * ...execute statements with the semaphore held...
181 : *
182 : * if (some_condition) {
183 : * ...release the lock and leave the guarded section prematurely:
184 : * SYS_SEM_LOCK_BREAK;
185 : * }
186 : *
187 : * ...execute statements with the lock held...
188 : *
189 : * }
190 : * @endcode
191 : *
192 : * Behind the scenes this pattern expands to a for-loop whose body is executed
193 : * exactly once:
194 : *
195 : * @code{.c}
196 : * for (sys_sem_take(&sem, K_FOREVER); ...; sys_sem_give(&sem)) {
197 : * ...
198 : * }
199 : * @endcode
200 : *
201 : * @warning The code block must execute to its end or be left by calling
202 : * @ref SYS_SEM_LOCK_BREAK. Otherwise, e.g. if exiting the block with a break,
203 : * goto or return statement, the semaphore will not be released on exit.
204 : *
205 : * @param sem Semaphore (@ref sys_sem) used to guard the enclosed code block.
206 : */
207 1 : #define SYS_SEM_LOCK(sem) \
208 : for (int __rc SYS_SEM_LOCK_ONEXIT = sys_sem_take((sem), K_FOREVER); ({ \
209 : __ASSERT(__rc >= 0, "Failed to take sem: %d", __rc); \
210 : __rc == 0; \
211 : }); \
212 : ({ \
213 : __rc = sys_sem_give((sem)); \
214 : __ASSERT(__rc == 0, "Failed to give sem: %d", __rc); \
215 : }), \
216 : __rc = 1)
217 :
218 : /**
219 : * @}
220 : */
221 :
222 : #ifdef __cplusplus
223 : }
224 : #endif
225 :
226 : #endif
|