• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-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 "epoll.h"
32 #include <stdint.h>
33 #include <poll.h>
34 #include <errno.h>
35 #include <string.h>
36 #include "pthread.h"
37 
38 /* 100, the number of fd one epollfd can control */
39 #define EPOLL_DEFAULT_SIZE 100
40 
41 /* Internal data, used to manage each epoll fd */
42 struct epoll_head {
43     int size;
44     int nodeCount;
45     struct epoll_event *evs;
46 };
47 
48 STATIC pthread_mutex_t g_epollMutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
49 
50 #ifndef MAX_EPOLL_FD
51 #define MAX_EPOLL_FD CONFIG_EPOLL_DESCRIPTORS
52 #endif
53 
54 /* Record the kernel fd of epoll  */
55 STATIC fd_set g_epollFdSet;
56 
57 /* Record the private data of epoll  */
58 STATIC struct epoll_head *g_epPrivBuf[MAX_EPOLL_FD];
59 
60 /**
61  * Alloc sysFd, storage epoll private data, set using bit.
62  *
63  * @param maxfdp: Maximum allowed application of sysFd.
64  * @param head: Private data.
65  * @return the index of the new fd; -1 on error
66  */
EpollAllocSysFd(int maxfdp,struct epoll_head * head)67 static int EpollAllocSysFd(int maxfdp, struct epoll_head *head)
68 {
69     int i;
70 
71     fd_set *fdset = &g_epollFdSet;
72 
73     for (i = 0; i < maxfdp; i++) {
74         if (fdset && !(FD_ISSET(i, fdset))) {
75             FD_SET(i, fdset);
76             if (!g_epPrivBuf[i]) {
77                 g_epPrivBuf[i] = head;
78                 return i + EPOLL_FD_OFFSET;
79             }
80         }
81     }
82 
83     set_errno(EMFILE);
84     return -1;
85 }
86 
87 /**
88  * free sysFd, delete epoll private data, clear using bit.
89  *
90  * @param fd: epoll fd.
91  * @return 0 or -1
92  */
EpollFreeSysFd(int fd)93 static int EpollFreeSysFd(int fd)
94 {
95     int efd = fd - EPOLL_FD_OFFSET;
96 
97     if ((efd < 0) || (efd >= MAX_EPOLL_FD)) {
98         set_errno(EMFILE);
99         return -1;
100     }
101 
102     fd_set *fdset = &g_epollFdSet;
103     if (fdset && FD_ISSET(efd, fdset)) {
104         FD_CLR(efd, fdset);
105         g_epPrivBuf[efd] = NULL;
106     }
107 
108     return 0;
109 }
110 
111 /**
112  * get private data by epoll fd
113  *
114  * @param fd: epoll fd.
115  * @return point to epoll_head
116  */
EpollGetDataBuff(int fd)117 static struct epoll_head *EpollGetDataBuff(int fd)
118 {
119     int id = fd - EPOLL_FD_OFFSET;
120 
121     if ((id < 0) || (id >= MAX_EPOLL_FD)) {
122         return NULL;
123     }
124 
125     return g_epPrivBuf[id];
126 }
127 
128 /**
129  * when do EPOLL_CTL_ADD, need check if fd exist
130  *
131  * @param epHead: epoll control head, find by epoll id .
132  * @param fd: ctl add fd.
133  * @return 0 or -1
134  */
CheckFdExist(struct epoll_head * epHead,int fd)135 static int CheckFdExist(struct epoll_head *epHead, int fd)
136 {
137     int i;
138     for (i = 0; i < epHead->nodeCount; i++) {
139         if (epHead->evs[i].data.fd == fd) {
140             return -1;
141         }
142     }
143 
144     return 0;
145 }
146 
147 /**
148  * close epoll
149  *
150  * @param epHead: epoll control head.
151  * @return void
152  */
DoEpollClose(struct epoll_head * epHead)153 static VOID DoEpollClose(struct epoll_head *epHead)
154 {
155     if (epHead != NULL) {
156         if (epHead->evs != NULL) {
157             free(epHead->evs);
158         }
159 
160         free(epHead);
161     }
162 
163     return;
164 }
165 
166 /**
167  * epoll_create unsupported api
168  *
169  * epoll_create is implemented by calling epoll_create1, it's parameter 'size' is useless.
170  *
171  * epoll_create1,
172  * The simple version of epoll does not use red-black trees,
173  * so when fd is normal value (greater than 0),
174  * actually allocated epoll can manage num of EPOLL_DEFAULT_SIZE
175  *
176  * @param flags: not actually used
177  * @return epoll fd
178  */
epoll_create1(int flags)179 int epoll_create1(int flags)
180 {
181     (void)flags;
182     int fd = -1;
183 
184     struct epoll_head *epHead = (struct epoll_head *)malloc(sizeof(struct epoll_head));
185     if (epHead == NULL) {
186         set_errno(ENOMEM);
187         return fd;
188     }
189 
190     /* actually allocated epoll can manage num is EPOLL_DEFAULT_SIZE */
191     epHead->size = EPOLL_DEFAULT_SIZE;
192     epHead->nodeCount = 0;
193     epHead->evs = malloc(sizeof(struct epoll_event) * EPOLL_DEFAULT_SIZE);
194     if (epHead->evs == NULL) {
195         free(epHead);
196         set_errno(ENOMEM);
197         return fd;
198     }
199 
200     /* fd set, get sysfd, for close */
201     (VOID)pthread_mutex_lock(&g_epollMutex);
202     fd = EpollAllocSysFd(MAX_EPOLL_FD, epHead);
203     if (fd == -1) {
204         (VOID)pthread_mutex_unlock(&g_epollMutex);
205         DoEpollClose(epHead);
206         set_errno(EMFILE);
207         return fd;
208     }
209     (VOID)pthread_mutex_unlock(&g_epollMutex);
210     return fd;
211 }
212 
213 /**
214  * epoll_close,
215  * called by close
216  * @param epfd: epoll fd
217  * @return 0 or -1
218  */
epoll_close(int epfd)219 int epoll_close(int epfd)
220 {
221     struct epoll_head *epHead = NULL;
222 
223     epHead = EpollGetDataBuff(epfd);
224     if (epHead == NULL) {
225         set_errno(EBADF);
226         return -1;
227     }
228 
229     DoEpollClose(epHead);
230     return EpollFreeSysFd(epfd);
231 }
232 
epoll_ctl(int epfd,int op,int fd,struct epoll_event * ev)233 int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
234 {
235     struct epoll_head *epHead = NULL;
236     int i;
237     int ret = -1;
238 
239     epHead = EpollGetDataBuff(epfd);
240     if (epHead == NULL) {
241         set_errno(EBADF);
242         return ret;
243     }
244 
245     if (ev == NULL) {
246         set_errno(EINVAL);
247         return -1;
248     }
249 
250     switch (op) {
251         case EPOLL_CTL_ADD:
252             ret = CheckFdExist(epHead, fd);
253             if (ret == -1) {
254                 set_errno(EEXIST);
255                 return -1;
256             }
257 
258             if (epHead->nodeCount == EPOLL_DEFAULT_SIZE) {
259                 set_errno(ENOMEM);
260                 return -1;
261             }
262 
263             epHead->evs[epHead->nodeCount].events = ev->events | POLLERR | POLLHUP;
264             epHead->evs[epHead->nodeCount].data.fd = fd;
265             epHead->nodeCount++;
266             return 0;
267         case EPOLL_CTL_DEL:
268             for (i = 0; i < epHead->nodeCount; i++) {
269                 if (epHead->evs[i].data.fd != fd) {
270                     continue;
271                 }
272 
273                 if (i != epHead->nodeCount - 1) {
274                     memmove_s(&epHead->evs[i], epHead->nodeCount - i, &epHead->evs[i + 1],
275                               epHead->nodeCount - i);
276                 }
277                 epHead->nodeCount--;
278                 return 0;
279             }
280             set_errno(ENOENT);
281             return -1;
282         case EPOLL_CTL_MOD:
283             for (i = 0; i < epHead->nodeCount; i++) {
284                 if (epHead->evs[i].data.fd == fd) {
285                     epHead->evs[i].events = ev->events | POLLERR | POLLHUP;
286                     return 0;
287                 }
288             }
289             set_errno(ENOENT);
290             return -1;
291         default:
292             set_errno(EINVAL);
293             return -1;
294     }
295 }
296 
epoll_wait(int epfd,FAR struct epoll_event * evs,int maxevents,int timeout)297 int epoll_wait(int epfd, FAR struct epoll_event *evs, int maxevents, int timeout)
298 {
299     struct epoll_head *epHead = NULL;
300     int ret;
301     int counter;
302     int i;
303     struct pollfd *pFd = NULL;
304     int pollSize;
305 
306     epHead = EpollGetDataBuff(epfd);
307     if (epHead == NULL) {
308         set_errno(EBADF);
309         return -1;
310     }
311 
312     if ((maxevents <= 0) || (evs == NULL)) {
313         set_errno(EINVAL);
314         return -1;
315     }
316 
317     if (maxevents > epHead->nodeCount) {
318         pollSize = epHead->nodeCount;
319     } else {
320         pollSize = maxevents;
321     }
322 
323     pFd = malloc(sizeof(struct pollfd) * pollSize);
324     if (pFd == NULL) {
325         set_errno(EINVAL);
326         return -1;
327     }
328 
329     for (i = 0; i < epHead->nodeCount; i++) {
330         pFd[i].fd = epHead->evs[i].data.fd;
331         pFd[i].events = (short)epHead->evs[i].events;
332     }
333 
334 
335     ret = poll(pFd, pollSize, timeout);
336     if (ret <= 0) {
337         free(pFd);
338         return 0;
339     }
340 
341     for (i = 0, counter = 0; i < ret && counter < pollSize; counter++) {
342         if (pFd[counter].revents != 0) {
343             evs[i].data.fd = pFd[counter].fd;
344             evs[i].events  = pFd[counter].revents;
345             i++;
346         }
347     }
348 
349     free(pFd);
350     return i;
351 }
352 
353