You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nuttx.apache.org by xi...@apache.org on 2020/12/27 17:08:25 UTC
[incubator-nuttx] 02/02: fs/epoll: add asynchronous epoll control
support
This is an automated email from the ASF dual-hosted git repository.
xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-nuttx.git
commit 39146ee367c4b93922c6d894417c8dc3c5eddd88
Author: chao.an <an...@xiaomi.com>
AuthorDate: Wed Dec 23 10:45:10 2020 +0800
fs/epoll: add asynchronous epoll control support
In current implementation, the asynchronous call "epoll_ctl()" unable
to wakeup the thread if pending on "epoll_wait()", the newly
added/delete FD cannot be used in the current waiting list,
this patch uses a reserved file object to wake up pending poll internal,
re-traverse the waiting list when a new event comes.
Signed-off-by: chao.an <an...@xiaomi.com>
---
fs/vfs/fs_epoll.c | 125 ++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 93 insertions(+), 32 deletions(-)
diff --git a/fs/vfs/fs_epoll.c b/fs/vfs/fs_epoll.c
index 83adf12..c36ccff 100644
--- a/fs/vfs/fs_epoll.c
+++ b/fs/vfs/fs_epoll.c
@@ -48,6 +48,8 @@
#include <string.h>
#include <debug.h>
+#include <nuttx/clock.h>
+#include <nuttx/fs/fs.h>
#include <nuttx/kmalloc.h>
/****************************************************************************
@@ -58,11 +60,39 @@ struct epoll_head
{
int size;
int occupied;
+ struct file fp;
+ struct inode in;
FAR epoll_data_t *data;
FAR struct pollfd *poll;
};
/****************************************************************************
+ * Private Function Prototypes
+ ****************************************************************************/
+
+static int epoll_poll(FAR struct file *filep,
+ FAR struct pollfd *fds, bool setup);
+
+/****************************************************************************
+ * Private Data
+ ****************************************************************************/
+
+static const struct file_operations g_epoll_ops =
+{
+ .poll = epoll_poll
+};
+
+/****************************************************************************
+ * Private Functions
+ ****************************************************************************/
+
+static int epoll_poll(FAR struct file *filep,
+ FAR struct pollfd *fds, bool setup)
+{
+ return OK;
+}
+
+/****************************************************************************
* Public Functions
****************************************************************************/
@@ -79,15 +109,25 @@ struct epoll_head
int epoll_create(int size)
{
- FAR struct epoll_head *eph =
- (FAR struct epoll_head *)kmm_malloc(sizeof(struct epoll_head) +
- sizeof(epoll_data_t) * size +
- sizeof(struct pollfd) * size);
+ FAR struct epoll_head *eph;
+ int reserve = size + 1;
+
+ eph = (FAR struct epoll_head *)
+ kmm_zalloc(sizeof(struct epoll_head) +
+ sizeof(epoll_data_t) * reserve +
+ sizeof(struct pollfd) * reserve);
eph->size = size;
- eph->occupied = 0;
eph->data = (FAR epoll_data_t *)(eph + 1);
- eph->poll = (FAR struct pollfd *)(eph->data + size);
+ eph->poll = (FAR struct pollfd *)(eph->data + reserve);
+
+ INODE_SET_DRIVER(&eph->in);
+ eph->in.u.i_ops = &g_epoll_ops;
+ eph->fp.f_inode = &eph->in;
+ eph->in.i_private = eph;
+
+ eph->poll[0].ptr = &eph->fp;
+ eph->poll[0].events = POLLIN | POLLFILE;
/* REVISIT: This will not work on machines where:
* sizeof(struct epoll_head *) > sizeof(int)
@@ -175,7 +215,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
return -1;
}
- for (i = 0; i < eph->occupied; i++)
+ for (i = 1; i <= eph->occupied; i++)
{
if (eph->poll[i].fd == fd)
{
@@ -184,14 +224,14 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
}
}
- eph->data[eph->occupied] = ev->data;
+ eph->data[++eph->occupied] = ev->data;
eph->poll[eph->occupied].events = ev->events | POLLERR | POLLHUP;
- eph->poll[eph->occupied++].fd = fd;
+ eph->poll[eph->occupied].fd = fd;
break;
case EPOLL_CTL_DEL:
- for (i = 0; i < eph->occupied; i++)
+ for (i = 1; i <= eph->occupied; i++)
{
if (eph->poll[i].fd == fd)
{
@@ -214,8 +254,7 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
case EPOLL_CTL_MOD:
finfo("%08x CTL MOD(%d): fd=%d ev=%08" PRIx32 "\n",
epfd, eph->occupied, fd, ev->events);
-
- for (i = 0; i < eph->occupied; i++)
+ for (i = 1; i <= eph->occupied; i++)
{
if (eph->poll[i].fd == fd)
{
@@ -233,6 +272,12 @@ int epoll_ctl(int epfd, int op, int fd, struct epoll_event *ev)
return -1;
}
+ if (eph->poll[0].sem)
+ {
+ eph->poll[0].revents |= eph->poll[0].events;
+ nxsem_post(eph->poll[0].sem);
+ }
+
return 0;
}
@@ -248,48 +293,64 @@ int epoll_pwait(int epfd, FAR struct epoll_event *evs,
*/
FAR struct epoll_head *eph = (FAR struct epoll_head *)((intptr_t)epfd);
+ struct timespec expire;
+ struct timespec curr;
+ struct timespec diff;
int counter;
int rc;
int i;
+ if (timeout >= 0)
+ {
+ expire.tv_sec = timeout / 1000;
+ expire.tv_nsec = timeout % 1000 * 1000;
+
+#ifdef CONFIG_CLOCK_MONOTONIC
+ clock_gettime(CLOCK_MONOTONIC, &curr);
+#else
+ clock_gettime(CLOCK_REALTIME, &curr);
+#endif
+
+ clock_timespec_add(&curr, &expire, &expire);
+ }
+
+again:
if (timeout < 0)
{
- rc = ppoll(eph->poll, eph->occupied, NULL, sigmask);
+ rc = ppoll(eph->poll, eph->occupied + 1, NULL, sigmask);
}
else
{
- struct timespec timeout_ts;
-
- timeout_ts.tv_sec = timeout / 1000;
- timeout_ts.tv_nsec = timeout % 1000 * 1000;
-
- rc = ppoll(eph->poll, eph->occupied, &timeout_ts, sigmask);
+#ifdef CONFIG_CLOCK_MONOTONIC
+ clock_gettime(CLOCK_MONOTONIC, &curr);
+#else
+ clock_gettime(CLOCK_REALTIME, &curr);
+#endif
+ clock_timespec_subtract(&expire, &curr, &diff);
+
+ rc = ppoll(eph->poll, eph->occupied + 1, &diff, sigmask);
}
if (rc <= 0)
{
- if (rc < 0)
+ return rc;
+ }
+ else if (eph->poll[0].revents != 0)
+ {
+ if (--rc == 0)
{
- ferr("ERROR: %08x poll fail: %d for %d, %d msecs\n",
- epfd, rc, eph->occupied, timeout);
-
- for (i = 0; i < eph->occupied; i++)
- {
- ferr(" %02d: fd=%d\n", i, eph->poll[i].fd);
- }
+ goto again;
}
-
- return rc;
}
- /* Iterate over non NULL event fds */
-
if (rc > maxevents)
{
rc = maxevents;
}
- for (i = 0, counter = 0; i < rc && counter < eph->occupied; counter++)
+ /* Iterate over non NULL event fds */
+
+ for (i = 0, counter = 1; i < rc && counter <= eph->occupied; counter++)
{
if (eph->poll[counter].revents != 0)
{