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)
         {