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
40extern "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 */
52typedef 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
65void __wake_up_interruptible(wait_queue_head_t *wait);
66void __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
240static 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