1 /*-
2 * Copyright (c) 2010 Isilon Systems, Inc.
3 * Copyright (c) 2010 iX Systems, Inc.
4 * Copyright (c) 2010 Panasas, Inc.
5 * Copyright (c) 2013, 2014 Mellanox Technologies, Ltd.
6 * Copyright (c) 2017 Mark Johnston <markj@FreeBSD.org>
7 * All rights reserved.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice unmodified, this list of conditions, and the following
14 * disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #ifndef _LINUXKPI_LINUX_WAIT_H_
32 #define _LINUXKPI_LINUX_WAIT_H_
33
34 #include <linux/spinlock.h>
35 #include "los_event.h"
36 #include "los_sys.h"
37
38 #ifdef __cplusplus
39 #if __cplusplus
40 extern "C" {
41 #endif /* __cplusplus */
42 #endif /* __cplusplus */
43
44 /**
45 * Notice about wait_queue_head_t:
46 * 1.The stEvent is used for task-synchronization and has the same function as wait_event_head in Linux.
47 * In LiteOS, when wait_event is called, if the condition is not true, the task will be blocked and
48 * mounted on stEvent.stEventList. In Linux, the blocked task will be mounted on wait_queue_head.task_list.
49 * 2.The lock and poll_queue are only used for poll operation: poll_queue is used to link poll_wait_node,
50 * and lock is used to protect this poll_queue.
51 */
52 typedef struct wait_queue_head {
53 EVENT_CB_S stEvent;
54 spinlock_t lock;
55 LOS_DL_LIST poll_queue;
56 } wait_queue_head_t;
57
58 #define osWaitForever 0xFFFFFFFF
59 #define INVALID_ADDR 0xFFFFFFFF
60 #define DECLARE_WAIT_QUEUE_HEAD(wq) \
61 wait_queue_head_t wq = { { 0, { (struct LOS_DL_LIST *)0xFFFFFFFF, (struct LOS_DL_LIST *)0xFFFFFFFF } }, \
62 SPIN_LOCK_INITIALIZER("wait_queue_spinlock"), \
63 { &wq.poll_queue, &wq.poll_queue } }
64
65 void __wake_up_interruptible(wait_queue_head_t *wait);
66 void __init_waitqueue_head(wait_queue_head_t *wait);
67
68 /**
69 * @ingroup wait
70 * @brief Initialize the waitqueue head.
71 *
72 * @par Description:
73 * This API is used to initialize the waitqueue head.
74 *
75 * @attention
76 * <ul>
77 * <li>Please make sure the input parameter wait is valid, otherwise, the system would be crash.</li>
78 * </ul>
79 *
80 * @param wait [IN] struct of the process that registered on the wait queue .
81 *
82 * @retval None.
83 * @par Dependency:
84 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
85 * @see none
86 */
87 #define init_waitqueue_head(wait) __init_waitqueue_head(wait)
88
89 /**
90 * @ingroup wait
91 * @brief wakeup the process that registered on the wait queue.
92 *
93 * @par Description:
94 * This API is used to wakeup the process that registered on the wait queue.
95 *
96 * @attention
97 * <ul>
98 * <li>Please make sure the input parameter wait is valid, otherwise, the system would be crash.</li>
99 * </ul>
100 *
101 * @param wait [IN] struct of the process that registered on the wait queue .
102 *
103 * @retval None.
104 * @par Dependency:
105 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
106 * @see none
107 */
108 #define wake_up_interruptible(wait) __wake_up_interruptible(wait)
109 #define wake_up_interruptible_poll(wait, key) __wake_up_interruptible_poll(wait, key)
110
111 /**
112 * @ingroup wait
113 * @brief wakeup the process that registered on the wait queue.
114 *
115 * @par Description:
116 * This API is used to wakeup the process that registered on the wait queue.
117 *
118 * @attention
119 * <ul>
120 * <li>Please look up the function __wake_up_interruptible(wait).</li>
121 * </ul>
122 *
123 * @param None.
124 *
125 * @retval None.
126 * @par Dependency:
127 * <ul><li>Wait.h: the header file that contains the API declaration.</li></ul>
128 * @see wake_up_interruptible
129 */
130 #define wake_up wake_up_interruptible
131
132 /**
133 * @ingroup wait
134 * @brief sleep until a condition gets true.
135 *
136 * @par Description:
137 * This API is used to sleep a process until the condition evaluates to true.
138 * The condition is checked each time when the waitqueue wait is woken up.
139 *
140 * @attention
141 * <ul>
142 * <li>none.</li>
143 * </ul>
144 *
145 * @param wait [IN] the waitqueue to wait on.
146 * @param condition [IN] a condition evaluates to true or false.
147
148 * @retval #0 always return 0
149
150 * @par Dependency:
151 * <ul><li>linux\wait.h: the header file that contains the API declaration.</li></ul>
152 * @see
153 */
154 #define wait_event(wait, condition) ({ \
155 INT32 ret = 0; \
156 \
157 if ((wait).stEvent.stEventList.pstPrev == (struct LOS_DL_LIST *)INVALID_ADDR) { \
158 (VOID)LOS_EventInit(&(wait).stEvent); \
159 } \
160 while (!(condition)) { \
161 (VOID)LOS_EventRead(&(wait).stEvent, 0x1U, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER); \
162 } \
163 ret; \
164 })
165
166 #define wait_event_interruptible wait_event
167
168 /**
169 * @ingroup wait
170 * @brief sleep until a condition gets true or a timeout elapses.
171 *
172 * @par Description:
173 * This API is used to sleep a process until the condition evaluates to true or a timeout elapses.
174 * The condition is checked each time when the waitqueue wait is woken up.
175 *
176 * @attention
177 * <ul>
178 * <li>none.</li>
179 * </ul>
180 *
181 * @param wait [IN] the waitqueue to wait on.
182 * @param condition [IN] a condition evaluates to true or false.
183 * @param timeout [IN] the max sleep time (unit : Tick). it is jiffies in linux.
184 *
185 * @retval #0 return 0 if the condition evaluated to false after the timeout elapsed
186 * @retval #1 return 1 if the condition evaluated to true after the timeout elapsed
187 * @retval #2 return 2 if the condition evaluated to true and the timeout is osWaitForever
188 *
189 * @par Dependency:
190 * <ul><li>linux\wait.h: the header file that contains the API declaration.</li></ul>
191 * @see
192 */
193 #define wait_event_interruptible_timeout(wait, condition, timeout) ({ \
194 INT32 tmpTimeout; \
195 UINT32 ret = 2; \
196 UINT64 ticksnow; \
197 \
198 if ((wait).stEvent.stEventList.pstPrev == (struct LOS_DL_LIST *)INVALID_ADDR) { \
199 (VOID)LOS_EventInit(&(wait).stEvent); \
200 } \
201 while (!(condition)) { \
202 ticksnow = LOS_TickCountGet(); \
203 ret = LOS_EventRead(&(wait).stEvent, 0x1U, LOS_WAITMODE_AND | LOS_WAITMODE_CLR, (timeout)); \
204 if ((timeout) == osWaitForever) { \
205 if (condition) { \
206 ret = 2; \
207 break; \
208 } else { \
209 continue; \
210 } \
211 } \
212 tmpTimeout = (INT32)((timeout) - (UINT32)(LOS_TickCountGet() - ticksnow)); \
213 if (tmpTimeout <= 0) { \
214 ret = (condition) ? 1 : 0; \
215 break; \
216 } else { \
217 if (ret == LOS_ERRNO_EVENT_READ_TIMEOUT) { \
218 if (condition) { \
219 ret = 1; \
220 break; \
221 } else { \
222 ret = 0; \
223 break; \
224 } \
225 } else { \
226 if (condition) { \
227 ret = 2; \
228 break; \
229 } \
230 } \
231 } \
232 } \
233 ret; \
234 })
235
236 #define add_wait_queue(wait, newWait) do {} while (0)
237 #define remove_wait_queue(wait, oldWait) do {} while (0)
238 #define DECLARE_WAITQUEUE(wait, current) do {} while (0)
239
linux_waitqueue_active(wait_queue_head_t * q)240 static inline int linux_waitqueue_active(wait_queue_head_t *q)
241 {
242 return !LOS_ListEmpty(&(q->stEvent.stEventList));
243 }
244
245 #define waitqueue_active(wqh) linux_waitqueue_active(wqh)
246
247 #ifdef __cplusplus
248 #if __cplusplus
249 }
250 #endif /* __cplusplus */
251 #endif /* __cplusplus */
252
253 #endif /* _LINUXKPI_LINUX_WAIT_H_ */
254