1 /*
2 * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 /**
16 * @defgroup wait Wait
17 * @ingroup linux
18 */
19 #ifndef _LINUX_WAIT_H
20 #define _LINUX_WAIT_H
21
22 #include <linux/spinlock.h>
23 #include "los_event.h"
24 #include "los_typedef.h"
25
26 #ifdef __cplusplus
27 extern "C" {
28 #endif /* __cplusplus */
29
30 /**
31 * Notice about wait_queue_head_t:
32 * 1.The stEvent is used for task-synchronization and has the same function as wait_event_head in Linux.
33 * In LiteOS, when wait_event is called, if the condition is not true, the task will be blocked and
34 * mounted on stEvent.stEventList. In Linux, the blocked task will be mounted on wait_queue_head.task_list.
35 * 2.The lock and poll_queue are only used for poll operation: poll_queue is used to link poll_wait_node,
36 * and lock is used to protect this poll_queue.
37 */
38 typedef struct wait_queue_head {
39 EVENT_CB_S stEvent;
40 spinlock_t lock;
41 LOS_DL_LIST poll_queue;
42 } wait_queue_head_t;
43
44 #define osWaitForever 0xFFFFFFFFU /* wait forever timeout value */
45 #define DECLARE_WAIT_QUEUE_HEAD(wq) wait_queue_head_t wq = { { 0, &wq.stEvent.stEventList, &wq.stEvent.stEventList }, \
46 SPIN_LOCK_INITIALIZER("wait_queue_spinlock"), \
47 { &wq.poll_queue, &wq.poll_queue } }
48
49 void __init_waitqueue_head(wait_queue_head_t *wait);
50
51 /**
52 * @ingroup wait
53 * @brief Initialize the waitqueue head.
54 *
55 * @par Description:
56 * This API is used to initialize the waitqueue head.
57 *
58 * @attention
59 * <ul>
60 * <li>Please make sure the input parameter wait is valid, otherwise, the system would crash.</li>
61 * </ul>
62 *
63 * @param wait [IN] Pointer to the waiting queue.
64 *
65 * @retval None.
66 * @par Dependency:
67 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
68 * @see None.
69 */
70 #define init_waitqueue_head(wait) __init_waitqueue_head(wait)
71
72 void __wake_up_interruptible(wait_queue_head_t *wait);
73
74 /**
75 * @ingroup wait
76 * @brief wakeup the process that registered on the wait queue.
77 *
78 * @par Description:
79 * This API is used to wakeup the process that registered on the wait queue.
80 *
81 * @attention
82 * <ul>
83 * <li>Please make sure the input parameter wait is valid, otherwise, the system would crash.</li>
84 * </ul>
85 *
86 * @param wait [IN] Pointer to the waiting queue.
87 *
88 * @retval None.
89 * @par Dependency:
90 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
91 * @see wake_up.
92 */
93 #define wake_up_interruptible(wait) __wake_up_interruptible(wait)
94
95 void __wake_up_interruptible_poll(wait_queue_head_t *wait, unsigned int key);
96
97 /**
98 * @ingroup wait
99 * @brief wakeup the process that registered on the wait queue.
100 *
101 * @par Description:
102 * This API is used to wakeup the process that registered on the wait queue.
103 *
104 * @attention
105 * <ul>
106 * <li>Please make sure the input parameter wait is valid, otherwise, the system would crash.</li>
107 * <li>This function is used to wake up the queue head with multiple events waiting.</li>
108 * </ul>
109 *
110 * @param wait [IN] Pointer to the waiting queue.
111 * @param key [IN] Mask for waiting events.
112 *
113 * @retval None.
114 * @par Dependency:
115 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
116 * @see wake_up_interruptible.
117 */
118 #define wake_up_interruptible_poll(wait, key) __wake_up_interruptible_poll(wait, key)
119
120 /**
121 * @ingroup wait
122 * @brief wakeup the process that registered on the wait queue.
123 *
124 * @par Description:
125 * This API is used to wake up the process that registered on the wait queue.
126 *
127 * @attention
128 * <ul>
129 * <li>Please make sure the input parameter wait is valid, otherwise, the system would crash.</li>
130 * </ul>
131 *
132 * @param wait [IN] Pointer to the waiting queue.
133 *
134 * @retval None.
135 * @par Dependency:
136 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
137 * @see wake_up_interruptible
138 */
139 #define wake_up(wait) wake_up_interruptible(wait)
140
141 /**
142 * @ingroup wait
143 * @brief sleep until a condition gets true.
144 *
145 * @attention
146 * <ul>
147 * <li>The OS does not support signal interrupts.</li>
148 * <li>This event does not support interrupting by a signal.</li>
149 * </ul>
150 * @param wait [IN] the waitqueue to wait on.
151 * @param condition [IN] a condition evaluates to true or false.
152 *
153 * @retval #0 always return 0
154 *
155 * @par Dependency:
156 * <ul><li>wait.h: the header file that contains the API declaration.</li></ul>
157 * @see wait_event.
158 */
159 #define wait_event_interruptible(wait, condition) ({ \
160 int ret = 0; \
161 \
162 while (!(condition)) { \
163 (void)LOS_EventRead(&(wait).stEvent, 0x1U, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); \
164 } \
165 ret; \
166 })
167
168 /**
169 * @ingroup wait
170 * @brief sleep until a condition gets true.
171 *
172 * @par Description:
173 * This API is used to sleep a process until the condition evaluates to true.
174 * The condition is checked each time when the waitqueue wait is woken up.
175 *
176 * @attention
177 * None.
178 *
179 * @param wait [IN] the waitqueue to wait on.
180 * @param condition [IN] a condition evaluates to true or false.
181 *
182 * @retval None.
183 *
184 * @par Dependency:
185 * <ul><li>wait.h: the header file that contains the API declaration.</li></ul>
186 * @see wait_event_interruptible.
187 */
188 #define wait_event(wait, condition) (VOID)wait_event_interruptible(wait, condition)
189
190 /**
191 * @ingroup wait
192 * @brief sleep until a condition gets true or a timeout elapses.
193 *
194 * @par Description:
195 * This API is used to sleep a process until the condition evaluates to true or a timeout elapses.
196 * The condition is checked each time when the waitqueue wait is woken up.
197 *
198 * @attention
199 * <ul>
200 * <li>This API does not fully adapt to Linux, and the returned values are different.</li>
201 * <li>The value range of parameter timeout is [0, 0xFFFFFFFF], and 0xFFFFFFFF means waiting forever.</li>
202 * <li>This event does not support interrupting by a signal.</li>
203 * </ul>
204 *
205 * @param wait [IN] the waitqueue to wait on.
206 * @param condition [IN] a condition evaluates to true or false.
207 * @param timeout [IN] the max sleep time (unit : Tick). it is jiffies in linux.
208 *
209 * @retval #0 return 0 if the condition evaluated to false after the timeout elapsed
210 * @retval #1 return 1 if the condition evaluated to true after the timeout elapsed
211 * @retval #2 return 2 if the condition evaluated to true and the timeout is osWaitForever
212 * @retval #others return the remaining ticks if the condition evaluated to true before the timeout elapsed
213 *
214 * @par Dependency:
215 * <ul><li>linux\wait.h: the header file that contains the API declaration.</li></ul>
216 * @see wait_event_interruptible.
217 */
218 #define wait_event_interruptible_timeout(wait, condition, timeout) ({ \
219 INT32 tmpTimeout; \
220 UINT32 ret = (timeout); \
221 UINT64 ticksnow; \
222 \
223 ticksnow = LOS_TickCountGet(); \
224 tmpTimeout = (timeout); \
225 if ((condition) && ((timeout) == 0)) { \
226 ret = 1; \
227 } \
228 while (!(condition)) { \
229 ret = LOS_EventRead(&(wait).stEvent, 0x1U, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, tmpTimeout); \
230 if ((timeout) == osWaitForever) { \
231 if (!(condition)) { \
232 continue; \
233 } \
234 ret = 2; \
235 break; \
236 } \
237 tmpTimeout = (INT32)((timeout) - (UINT32)(LOS_TickCountGet() - ticksnow)); \
238 \
239 /* If the timeout elapsed or read event times out, the wait ends. */ \
240 if ((tmpTimeout <= 0) || ((tmpTimeout > 0) && (ret == LOS_ERRNO_EVENT_READ_TIMEOUT))) { \
241 ret = (condition) ? 1 : 0; \
242 break; \
243 } \
244 \
245 if (condition) { \
246 ret = (UINT32)tmpTimeout; \
247 break; \
248 } \
249 } \
250 ret; \
251 })
252
253 #define add_wait_queue(wait, newWait) do {} while (0)
254 #define remove_wait_queue(wait, oldWait) do {} while (0)
255 #define DECLARE_WAITQUEUE(wait, current) do {} while (0)
256
257 /**
258 * @ingroup wait
259 * @brief Check whether the waitqueue is active.
260 *
261 * @par Description:
262 * This API is used to check whether the waitqueue is active.
263 *
264 * @attention
265 * <ul>
266 * <li> The parameter passed in should be a legal pointer. </li>
267 * </ul>
268 *
269 * @param q [IN] The waitqueue to be checked.
270 *
271 * @retval #0 The queue is not active.
272 * @retval #1 The queue is active.
273 *
274 * @par Dependency:
275 * <ul><li>linux\wait.h: the header file that contains the API declaration.</li></ul>
276 * @see None.
277 */
waitqueue_active(wait_queue_head_t * q)278 static inline int waitqueue_active(wait_queue_head_t *q)
279 {
280 return !LOS_ListEmpty(&(q->stEvent.stEventList));
281 }
282
283 #ifdef __cplusplus
284 }
285 #endif /* __cplusplus */
286
287 #endif /* _LINUX_WAIT_H */
288