1 /*
2  * Copyright (C) 2015-2020 Alibaba Group Holding Limited
3  */
4 
5 #include <string.h>
6 #include <stdio.h>
7 #include <stddef.h>
8 #include <stdbool.h>
9 #include <errno.h>
10 #include <aos/kernel.h>
11 #include <aos/list.h>
12 #include <aos/vfs.h>
13 #include "epoll.h"
14 #include "private/epoll_inner.h"
15 #include "private/rbtree_wrapper.h"
16 
17 #define   EVENT_FLAG   0x01
18 
epoll2poll(uint32_t in)19 static inline uint16_t epoll2poll(uint32_t in)
20 {
21     return (uint16_t)(in & 0xffff);
22 }
23 
poll2epoll(uint16_t in)24 static inline uint32_t poll2epoll(uint16_t in)
25 {
26     return (uint32_t)(in & 0xffff);
27 }
28 
29 typedef void (*epoll_event_cb_t)(uint32_t revent, void *data);
30 
31 #if CONFIG_EPOLL_LWIP
32     extern int lwip_set_epoll_callback(int fd, epoll_event_cb_t cb, void *data);
33 #endif
34 
lwip_epoll_notify(uint32_t revent,void * arg)35 void lwip_epoll_notify(uint32_t revent, void *arg)
36 {
37     epoll_dev_t *pdev = NULL;
38     epoll_item_t *item = (epoll_item_t *)arg;
39 
40     if (arg == NULL) {
41         return;
42     }
43 
44     pdev = item->epoll;
45     if (pdev == NULL) {
46         return;
47     }
48 
49     aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
50     item->revents = revent;
51     if ((revent & (~EP_PRIVATE_BITS)) & item->event.events) {
52         if (item->rdy == 0) {
53             dlist_add(&item->link_node, &pdev->ready_list);
54             item->rdy = 1;
55         }
56         aos_event_set(&pdev->event, EVENT_FLAG, AOS_EVENT_OR_CLEAR);
57     } else { /*clean events*/
58         if (item->rdy == 1) {
59             dlist_del(&item->link_node);
60             item->rdy = 0;
61         }
62     }
63     aos_mutex_unlock(&pdev->evt_mutex);
64 }
65 
vfs_epoll_notify(void * data,void * arg)66 static void vfs_epoll_notify(void *data, void *arg)
67 {
68     struct pollfd *pfd = (struct pollfd *)data;
69     epoll_dev_t *pdev = NULL;
70     epoll_item_t *item = (epoll_item_t *)arg;
71 
72     if (arg == NULL || data == NULL) {
73         return;
74     }
75 
76     pdev = item->epoll;
77     if (pdev == NULL) {
78         return;
79     }
80 
81     aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
82     if (poll2epoll(pfd->revents) & item->event.events) {
83         item->revents = poll2epoll(pfd->revents);
84         if (item->rdy == 0) {
85             dlist_add(&item->link_node, &pdev->ready_list);
86             item->rdy = 1;
87         }
88         aos_event_set(&pdev->event, EVENT_FLAG, AOS_EVENT_OR_CLEAR);
89     }
90     aos_mutex_unlock(&pdev->evt_mutex);
91 }
92 
epoll_add_event_cb(epoll_item_t * item)93 static int epoll_add_event_cb(epoll_item_t *item)
94 {
95     int ret = 0;
96     /* register lwip cb */
97     if (item->fd < aos_vfs_fd_offset_get()) {
98 #if CONFIG_EPOLL_LWIP
99         ret = lwip_set_epoll_callback(item->fd, lwip_epoll_notify, item);
100         if (ret < 0) {
101             ret = -EBADF;
102         }
103 #endif
104     } else { /*register vfs cb */
105         ret = aos_do_pollfd(item->fd, true, vfs_epoll_notify, &item->compat_evt, item);
106         if (ret < 0) {
107             if (ret == -1) {
108                 ret = -EBADF;
109             }
110         }
111     }
112     return ret;
113 }
114 
epoll_delete_event_cb(int fd)115 static int epoll_delete_event_cb(int fd)
116 {
117     int ret = 0;
118 
119     if (fd < aos_vfs_fd_offset_get()) { // register lwip cb
120 #if CONFIG_EPOLL_LWIP
121         ret = lwip_set_epoll_callback(fd, NULL, NULL);
122         if (ret < 0) {
123             errno = EBADF;
124             return -1;
125         }
126 #endif
127     } else {  /* unregister vfs cb */
128         ret = aos_do_pollfd(fd, false, NULL, NULL, NULL);
129         if (ret < 0) {
130             if (ret < -1) {
131                 errno = -ret;
132             }
133             return -1;
134         }
135     }
136     return ret;
137 }
138 
epoll_open(inode_t * node,file_t * file)139 static int epoll_open(inode_t *node, file_t *file)
140 {
141     int ret = -1;
142     epoll_dev_t *pdev = malloc(sizeof(epoll_dev_t));
143     if (pdev == NULL) {
144         printf("epoll malloc failed\r\n");
145         errno = ENOMEM;
146         return -1;
147     }
148     memset(pdev, 0, sizeof(epoll_dev_t));
149 
150     ret = aos_mutex_new(&pdev->rbt_mutex);
151     if (ret < 0) {
152         goto err;
153     }
154     ret = aos_mutex_new(&pdev->evt_mutex);
155     if (ret < 0) {
156         goto err;
157     }
158     ret = aos_event_new(&pdev->event, 0);
159 
160     if (ret < 0) {
161         goto err;
162     }
163 
164     pdev->rb_tree = RBT_ROOT;
165     dlist_init(&pdev->ready_list);
166 
167     file->f_arg = pdev;
168     return 0;
169 err:
170     printf("epoll open failed\r\n");
171     errno = ENOMEM;
172     if (*(aos_mutex_t*)(&(pdev->rbt_mutex))) {
173         aos_mutex_free(&pdev->rbt_mutex);
174     }
175     if (*(aos_mutex_t*)(&(pdev->evt_mutex))) {
176         aos_mutex_free(&pdev->evt_mutex);
177     }
178     if (*(aos_event_t*)(&(pdev->event)))
179 	{
180         aos_event_free(&pdev->event);
181     }
182     file->f_arg = NULL;
183     free(pdev);
184     return -1;
185 }
186 
187 
epoll_close(file_t * file)188 static int epoll_close(file_t *file)
189 {
190     epoll_dev_t *pdev = file->f_arg;
191     epoll_item_t *node, *rb_tmp;
192     dlist_t *tmp;
193 
194     if (pdev == NULL) {
195         return 0;
196     }
197 
198     aos_mutex_lock(&pdev->rbt_mutex, AOS_WAIT_FOREVER);
199     dlist_for_each_entry_safe(&pdev->ready_list, tmp, node, epoll_item_t, link_node) {
200         dlist_del(&node->link_node);
201     }
202 
203     k_rbtree_postorder_for_each_entry_safe(node, rb_tmp, &pdev->rb_tree, tree_node) {
204         epoll_delete_event_cb(node->fd);
205         k_rbtree_erase(&node->tree_node, &pdev->rb_tree);
206         free(node);
207     }
208 
209     aos_mutex_unlock(&pdev->rbt_mutex);
210 
211     if (*(aos_mutex_t*)(&(pdev->rbt_mutex))) {
212         aos_mutex_free(&pdev->rbt_mutex);
213     }
214     if (*(aos_mutex_t*)(&(pdev->evt_mutex))) {
215         aos_mutex_free(&pdev->evt_mutex);
216     }
217     if (*(aos_event_t*)(&(pdev->event)))
218 	{
219         aos_event_free(&pdev->event);
220     }
221 
222     free(pdev);
223     file->f_arg = NULL;
224     return 0;
225 }
226 
epoll_set_item(epoll_item_t * item,epoll_dev_t * dev,epoll_ctl_data_t * data)227 static int epoll_set_item(epoll_item_t *item, epoll_dev_t *dev, epoll_ctl_data_t *data)
228 {
229     if (data->event == NULL) {
230         return -1;
231     }
232     item->fd = data->fd;
233     item->rdy = 0;
234     memcpy(&item->event, data->event, sizeof(struct epoll_event));
235     item->epoll = dev;
236     /*compat to vfs poll*/
237     item->compat_evt.fd = data->fd;
238     item->compat_evt.events = (uint16_t) data->event->events;
239     return 0;
240 }
epoll_control(epoll_dev_t * pdev,epoll_ctl_data_t * data)241 static int epoll_control(epoll_dev_t *pdev, epoll_ctl_data_t *data)
242 {
243     int ret = -1;
244     epoll_item_t *item = NULL;
245     aos_mutex_lock(&pdev->rbt_mutex, AOS_WAIT_FOREVER);
246 
247     switch (data->op) {
248         case EPOLL_CTL_ADD: {
249             item = rbr_find(&pdev->rb_tree, data->fd);
250             if (item != NULL) {
251                 printf("epoll:fd:%d already added\r\n", data->fd);
252                 errno = EEXIST;
253                 break;
254             }
255             item = malloc(sizeof(epoll_item_t));
256             if (item == NULL) {
257                 errno = ENOMEM;
258                 break;
259             }
260             memset(item, 0, sizeof(epoll_item_t));
261             if (epoll_set_item(item, pdev, data) < 0) {
262                 errno = EINVAL;
263                 free(item);
264                 break;
265             }
266             ret = rbt_insert(&pdev->rb_tree, item);
267             if (ret < 0) {
268                 errno = EINVAL;
269                 free(item);
270                 break;
271             }
272 
273             ret = epoll_add_event_cb(item);
274             if (ret < 0) {
275                 rbt_delete(&pdev->rb_tree, data->fd);
276                 errno = -ret;
277                 printf("add cb failed \r\n");
278                 ret = -1;
279             }
280         }
281         break;
282         case EPOLL_CTL_DEL: {
283             epoll_item_t *node;
284             dlist_t *tmp;
285             epoll_delete_event_cb(data->fd);
286 
287             dlist_for_each_entry_safe(&pdev->ready_list, tmp, node, epoll_item_t, link_node) {
288                 if (node->fd == data->fd) {
289                     dlist_del(&node->link_node);
290                 }
291             }
292             ret = rbt_delete(&pdev->rb_tree, data->fd);
293             if (ret < 0) {
294                 errno = ENOENT;
295             }
296         }
297         break;
298         case EPOLL_CTL_MOD: {
299             if (data->event == NULL) {
300                 errno = EINVAL;
301                 break;
302             }
303             item = rbr_find(&pdev->rb_tree, data->fd);
304             if (item == NULL) {
305                 errno = ENOENT;
306                 printf("epoll:fd:%d does not exist\r\n", data->fd);
307                 break;
308             }
309             aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
310             memcpy(&item->event, data->event, sizeof(struct epoll_event));
311             aos_mutex_unlock(&pdev->evt_mutex);
312             ret = 0;
313         }
314         break;
315     }
316     aos_mutex_unlock(&pdev->rbt_mutex);
317     return ret;
318 }
319 
epoll_waitting(epoll_dev_t * pdev,epoll_wait_data_t * data)320 static int epoll_waitting(epoll_dev_t *pdev, epoll_wait_data_t *data)
321 {
322     epoll_item_t *node;
323     dlist_t *tmp;
324     int i = 0;
325     int ret = 0;
326     uint32_t real_flag = 0;
327     aos_mutex_lock(&pdev->rbt_mutex, AOS_WAIT_FOREVER);
328     dlist_for_each_entry_safe(&pdev->ready_list, tmp, node, epoll_item_t, link_node) {
329 
330 
331         if (node->fd < aos_vfs_fd_offset_get()) {
332 
333         } else {
334             aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
335             node->revents = 0;
336             aos_mutex_unlock(&pdev->evt_mutex);
337             ret = aos_do_pollfd(node->fd, true, vfs_epoll_notify, &node->compat_evt, node);
338             if (ret < 0) {
339                 printf("aos_do_pollfd err, node->fd = %d,ret = %d\r\n", node->fd, ret);
340                 if (ret < -1) {
341                     errno = -ret;
342                 }
343                 ret = -1;
344                 break;
345             }
346         }
347 
348         aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
349         if (!(node->event.events & node->revents)) {
350             dlist_del(&node->link_node);
351             node->revents = 0;
352             node->rdy = 0;
353             aos_mutex_unlock(&pdev->evt_mutex);
354             continue;
355         }
356         data->events[i].events = node->event.events & node->revents;
357         memcpy(&data->events[i].data, &node->event.data, sizeof(data->events[i].data));
358 
359         if ((node->event.events & EPOLLET) != 0) {
360             dlist_del(&node->link_node);
361             node->revents = 0;
362             node->rdy = 0;
363         }
364 
365         if ((node->event.events & EPOLLONESHOT) != 0) {
366             node->event.events &= EP_PRIVATE_BITS;
367         }
368         aos_mutex_unlock(&pdev->evt_mutex);
369         if (++i == data->maxevents) {
370             break;
371         }
372     }
373     aos_mutex_unlock(&pdev->rbt_mutex);
374     if (i > 0) {
375         return i;
376     }
377 
378     aos_event_get(&pdev->event, EVENT_FLAG, AOS_EVENT_OR_CLEAR, &real_flag, data->timeout);
379 
380     aos_mutex_lock(&pdev->rbt_mutex, AOS_WAIT_FOREVER);
381     dlist_for_each_entry_safe(&pdev->ready_list, tmp, node, epoll_item_t, link_node) {
382         if (node->fd < aos_vfs_fd_offset_get()) {
383 
384         } else {
385             ret = aos_do_pollfd(node->fd, true, vfs_epoll_notify, &node->compat_evt, node);
386             if (ret < 0) {
387                 printf("aos_do_pollfd err, node->fd = %d,ret = %d\r\n", node->fd, ret);
388                 if (ret < -1) {
389                     errno = -ret;
390                 }
391                 ret = -1;
392                 break;
393             }
394         }
395         aos_mutex_lock(&pdev->evt_mutex, AOS_WAIT_FOREVER);
396 
397         if (!(node->event.events & node->revents)) {
398             dlist_del(&node->link_node);
399             node->revents = 0;
400             node->rdy = 0;
401             aos_mutex_unlock(&pdev->evt_mutex);
402             continue;
403         }
404         data->events[i].events = node->event.events & node->revents;
405         memcpy(&data->events[i].data, &node->event.data, sizeof(data->events[i].data));
406 
407         if ((node->event.events & EPOLLET) != 0) {
408             dlist_del(&node->link_node);
409             node->revents = 0;
410             node->rdy = 0;
411         }
412 
413         if ((node->event.events & EPOLLONESHOT) != 0) {
414             node->event.events &= EP_PRIVATE_BITS;
415         }
416         aos_mutex_unlock(&pdev->evt_mutex);
417         if (++i == data->maxevents) {
418             break;
419         }
420     }
421 
422     aos_mutex_unlock(&pdev->rbt_mutex);
423     if (i > 0) {
424         return i;
425     }
426     return ret;
427 }
428 
epoll_ioctl(file_t * f,int cmd,unsigned long arg)429 static int epoll_ioctl(file_t *f, int cmd, unsigned long arg)
430 {
431     epoll_dev_t *pdev = f->f_arg;
432     if (pdev == NULL || arg == 0) {
433         errno = EINVAL;
434         return -1;
435     }
436 
437     if (EPOLL_VFS_CTL == cmd) {
438         return epoll_control(pdev, (epoll_ctl_data_t *)arg);
439     } else if (EPOLL_VFS_WAIT == cmd) {
440         return epoll_waitting(pdev, (epoll_wait_data_t *)arg);
441     }
442     errno = EINVAL;
443     return -1;
444 }
445 
epoll_write(file_t * f,const void * buf,size_t len)446 ssize_t epoll_write(file_t *f, const void *buf, size_t len)
447 {
448     printf("epoll:not support!\r\n");
449     return 0;
450 }
451 
epoll_read(file_t * f,void * buf,size_t len)452 static ssize_t epoll_read(file_t *f, void *buf, size_t len)
453 {
454     printf("epoll:not support!\r\n");
455     return 0;
456 }
457 
epoll_poll(file_t * f,int setup,poll_notify_t notify,void * fd,void * opa)458 static int epoll_poll(file_t *f, int setup, poll_notify_t notify,
459                       void *fd, void *opa)
460 {
461     printf("epoll:not support!\r\n");
462     return 0;
463 }
464 
465 static file_ops_t epoll_fops = {
466     .open = epoll_open,
467     .read = epoll_read,
468     .write = epoll_write,
469     .close = epoll_close,
470     .poll = epoll_poll,
471     .ioctl = epoll_ioctl,
472 };
473 
vfs_device_epoll_init(void)474 int vfs_device_epoll_init(void)
475 {
476     int ret;
477     static uint8_t inited = 0;
478     if (inited == 1) {
479         return 0;
480     }
481 
482     ret = aos_register_driver("/dev/epoll", &epoll_fops, NULL);
483     if (ret < 0) {
484         if (ret < -1) {
485             errno = -ret;
486         }
487         return -1;
488     }
489 
490     inited = 1;
491     return 0;
492 }
493