1 /*
2 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without modification,
5 * are permitted provided that the following conditions are met:
6 *
7 * 1. Redistributions of source code must retain the above copyright notice, this list of
8 * conditions and the following disclaimer.
9 *
10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
11 * of conditions and the following disclaimer in the documentation and/or other materials
12 * provided with the distribution.
13 *
14 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
15 * to endorse or promote products derived from this software without specific prior written
16 * permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
20 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
21 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
22 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
25 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
27 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
28 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31 #include "poll.h"
32 #include <sys/time.h>
33 #include <time.h>
34 #include "securec.h"
35 #include "poll_impl.h"
36 #include "los_interrupt.h"
37 #include "los_memory.h"
38
PollWaitQueueInit(struct PollWaitQueue * waitQueue)39 VOID PollWaitQueueInit(struct PollWaitQueue *waitQueue)
40 {
41 if (waitQueue == NULL) {
42 return;
43 }
44 LOS_ListInit(&waitQueue->queue);
45 }
46
SetAddPollWaitFlag(struct PollTable * table,BOOL addQueueFlag)47 STATIC INLINE VOID SetAddPollWaitFlag(struct PollTable *table, BOOL addQueueFlag)
48 {
49 table->addQueueFlag = addQueueFlag;
50 }
51
DestroyPollWait(struct PollTable * table)52 STATIC VOID DestroyPollWait(struct PollTable *table)
53 {
54 UINT32 intSave;
55 struct PollWaitNode *waitNode = table->node;
56
57 intSave = LOS_IntLock();
58 LOS_ListDelete(&waitNode->node);
59 LOS_IntRestore(intSave);
60
61 (VOID)LOS_MemFree(OS_SYS_MEM_ADDR, waitNode);
62 if (LOS_SemDelete(table->sem) != LOS_OK) {
63 PRINT_ERR("destroy poll sem failed!\n");
64 }
65 }
66
AddPollWaitQueue(struct PollWaitQueue * waitQueue,struct PollTable * table)67 STATIC VOID AddPollWaitQueue(struct PollWaitQueue *waitQueue, struct PollTable *table)
68 {
69 UINT32 intSave;
70 struct PollWaitNode *waitNode = LOS_MemAlloc(OS_SYS_MEM_ADDR, sizeof(struct PollWaitNode));
71 if (waitNode == NULL) {
72 return;
73 }
74
75 intSave = LOS_IntLock();
76 waitNode->table = table;
77 LOS_ListAdd(&waitQueue->queue, &waitNode->node);
78 table->node = waitNode;
79 LOS_IntRestore(intSave);
80 }
81
WaitSemTime(struct PollTable * table,UINT32 timeout)82 STATIC INT32 WaitSemTime(struct PollTable *table, UINT32 timeout)
83 {
84 if (timeout != 0) {
85 return LOS_SemPend(table->sem, LOS_MS2Tick(timeout));
86 } else {
87 return LOS_SemPend(table->sem, LOS_WAIT_FOREVER);
88 }
89 }
90
QueryFds(struct pollfd * fds,nfds_t nfds,struct PollTable * table)91 STATIC INT32 QueryFds(struct pollfd *fds, nfds_t nfds, struct PollTable *table)
92 {
93 UINT32 i;
94 INT32 ret;
95 INT32 count = 0;
96
97 if (((nfds != 0) && (fds == NULL)) || (table == NULL)) {
98 errno = EINVAL;
99 return -1;
100 }
101
102 for (i = 0; i < nfds; i++) {
103 struct pollfd *tmpFds = &fds[i];
104 if (tmpFds->fd < 0) {
105 errno = EBADF;
106 return -1;
107 }
108 table->event = tmpFds->events | POLLERR | POLLHUP;
109
110 ret = PollQueryFd(tmpFds->fd, table);
111 if (ret < 0) {
112 errno = -ret;
113 return -1;
114 }
115
116 tmpFds->revents = (tmpFds->events | POLLERR | POLLHUP) & (PollEvent)ret;
117 if (tmpFds->revents != 0) {
118 count++;
119 SetAddPollWaitFlag(table, FALSE);
120 }
121 }
122
123 return count;
124 }
125
PollNotify(struct PollWaitQueue * waitQueue,PollEvent event)126 VOID PollNotify(struct PollWaitQueue *waitQueue, PollEvent event)
127 {
128 UINT32 intSave;
129 struct PollWaitNode *waitNode = NULL;
130
131 if (waitQueue == NULL) {
132 return;
133 }
134
135 intSave = LOS_IntLock();
136 LOS_DL_LIST_FOR_EACH_ENTRY(waitNode, &waitQueue->queue, struct PollWaitNode, node) {
137 if (!event || (event & waitNode->table->event)) {
138 if (LOS_SemPost(waitNode->table->sem) != LOS_OK) {
139 PRINT_ERR("poll notify sem post failed!\n");
140 }
141 }
142 }
143 LOS_IntRestore(intSave);
144 }
145
PollWait(struct PollWaitQueue * waitQueue,struct PollTable * table)146 VOID PollWait(struct PollWaitQueue *waitQueue, struct PollTable *table)
147 {
148 if ((waitQueue == NULL) || (table == NULL)) {
149 return;
150 }
151
152 if (table->addQueueFlag == TRUE) {
153 AddPollWaitQueue(waitQueue, table);
154 }
155 }
156
PollTimedWait(struct pollfd * fds,nfds_t nfds,struct PollTable * table,INT32 timeout)157 STATIC INLINE INT32 PollTimedWait(struct pollfd *fds, nfds_t nfds, struct PollTable *table, INT32 timeout)
158 {
159 struct timespec startTime = {0};
160 struct timespec curTime = {0};
161 INT32 left, last;
162 INT32 ret;
163 INT32 count = 0;
164
165 if (timeout > 0) {
166 clock_gettime(CLOCK_REALTIME, &startTime);
167 }
168
169 left = timeout;
170 while (count == 0) {
171 if (timeout < 0) {
172 ret = WaitSemTime(table, 0);
173 if (ret != 0) {
174 break;
175 }
176 } else if (left <= 0) {
177 break;
178 } else {
179 clock_gettime(CLOCK_REALTIME, &curTime);
180 last = (INT32)((curTime.tv_sec - startTime.tv_sec) * OS_SYS_MS_PER_SECOND +
181 (curTime.tv_nsec - startTime.tv_nsec) / (OS_SYS_NS_PER_SECOND / OS_SYS_MS_PER_SECOND));
182 if (last >= timeout) {
183 break;
184 } else {
185 left = timeout - last;
186 }
187
188 ret = WaitSemTime(table, left);
189 if (ret == LOS_ERRNO_SEM_TIMEOUT) {
190 errno = ETIMEDOUT;
191 break;
192 }
193 }
194 count = QueryFds(fds, nfds, table);
195 }
196
197 return count;
198 }
199
poll(struct pollfd * fds,nfds_t nfds,int timeout)200 int poll(struct pollfd *fds, nfds_t nfds, int timeout)
201 {
202 struct PollTable table = {0};
203 INT32 count;
204
205 if (LOS_SemCreate(0, &table.sem) != LOS_OK) {
206 errno = EINVAL;
207 return -1;
208 }
209
210 SetAddPollWaitFlag(&table, ((timeout == 0) ? FALSE : TRUE));
211
212 count = QueryFds(fds, nfds, &table);
213 if (count != 0) {
214 goto DONE;
215 }
216
217 if (timeout == 0) {
218 goto DONE;
219 }
220
221 SetAddPollWaitFlag(&table, FALSE);
222
223 count = PollTimedWait(fds, nfds, &table, timeout);
224
225 DONE:
226 DestroyPollWait(&table);
227 return count;
228 }
229