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