LD_PRELOAD poll implementation

- add poll implementation
- implementation based on vppcom_poll
- implementation based on vppcom_select
- currently vppcom_select implementation is picked

Change-Id: If6c2862ae72e9969335aca5b8085957c98287dc0
Signed-off-by: shrinivasan ganapathy <shrinivasanganapathy@gmail.com>
Signed-off-by: Dave Wallace <dwallacelf@gmail.com>
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
index d5b3e12..35dbf57 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.c
@@ -19,6 +19,7 @@
 #include <pthread.h>
 #include <time.h>
 #include <stdarg.h>
+#include <sys/resource.h>
 
 #include <libvcl-ldpreload/vcom_socket_wrapper.h>
 #include <libvcl-ldpreload/vcom.h>
@@ -2940,24 +2941,319 @@
 
    This function is a cancellation point and therefore not marked with
    __THROW.  */
+
 int
 vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
 {
-  if (vcom_init () != 0)
+  int rv = 0;
+  pid_t pid = getpid ();
+
+  struct rlimit nofile_limit;
+  struct pollfd vcom_fds[MAX_POLL_NFDS_DEFAULT];
+  nfds_t fds_idx = 0;
+
+  /* actual set of file descriptors to be monitored */
+  nfds_t libc_nfds = 0;
+  nfds_t vcom_nfds = 0;
+
+  /* ready file descriptors
+   *
+   * number of structures which have nonzero revents  fields
+   * in other words, descriptors  with events or errors reported.
+   * */
+  /* after call to libc_poll () */
+  int rlibc_nfds = 0;
+  /* after call to vcom_socket_poll () */
+  int rvcom_nfds = 0;
+
+
+  /* timeout value in units of timespec */
+  struct timespec timeout_ts;
+  struct timespec start_time, now, end_time;
+
+
+  /* get start_time */
+  rv = clock_gettime (CLOCK_MONOTONIC, &start_time);
+  if (rv == -1)
     {
-      return -1;
+      rv = -errno;
+      goto poll_done;
     }
 
-  return -EOPNOTSUPP;
+  /* set timeout_ts & end_time */
+  if (__timeout >= 0)
+    {
+      /* set timeout_ts */
+      timeout_ts.tv_sec = __timeout / MSEC_PER_SEC;
+      timeout_ts.tv_nsec = (__timeout % MSEC_PER_SEC) * NSEC_PER_MSEC;
+      set_normalized_timespec (&timeout_ts,
+			       timeout_ts.tv_sec, timeout_ts.tv_nsec);
+      /* set end_time */
+      if (__timeout)
+	{
+	  end_time = timespec_add (start_time, timeout_ts);
+	}
+      else
+	{
+	  end_time = start_time;
+	}
+    }
+
+  if (vcom_init () != 0)
+    {
+      rv = -1;
+      goto poll_done;
+    }
+
+  /* validate __fds */
+  if (!__fds)
+    {
+      rv = -EFAULT;
+      goto poll_done;
+    }
+
+  /* validate __nfds */
+  /*TBD: call getrlimit once when vcl-ldpreload library is init */
+  rv = getrlimit (RLIMIT_NOFILE, &nofile_limit);
+  if (rv != 0)
+    {
+      rv = -errno;
+      goto poll_done;
+    }
+  if (__nfds >= nofile_limit.rlim_cur || __nfds < 0)
+    {
+      rv = -EINVAL;
+      goto poll_done;
+    }
+
+  /*
+   * for the POC, it's fair to assume that nfds is less than 1024
+   * */
+  if (__nfds >= MAX_POLL_NFDS_DEFAULT)
+    {
+      rv = -EINVAL;
+      goto poll_done;
+    }
+
+  /* set revents field (output parameter)
+   * to zero
+   * */
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      __fds[fds_idx].revents = 0;
+    }
+
+#if 0
+  /* set revents field (output parameter)
+   * to zero for user ignored fds
+   * */
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /*
+       * if negative fd, ignore events field
+       * and set output parameter (revents field) to zero */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  __fds[fds_idx].revents = 0;
+	}
+    }
+#endif
+
+  /*
+   * 00. prepare __fds and vcom_fds for polling
+   *     copy __fds to vcom_fds
+   * 01. negate all except libc fds in __fds,
+   *     ignore user negated fds
+   * 02. negate all except vcom_fds in vocm fds,
+   *     ignore user negated fds
+   *     ignore fd 0 by setting it to negative number
+   * */
+  memcpy (vcom_fds, __fds, sizeof (*__fds) * __nfds);
+  libc_nfds = 0;
+  vcom_nfds = 0;
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      /*
+       * 00. ignore vcom fds in __fds
+       * 01. ignore libc fds in vcom_fds,
+       *     ignore fd 0 by setting it to negative number.
+       *     as fd 0 cannot be ignored.
+       */
+      if (is_vcom_socket_fd (__fds[fds_idx].fd) ||
+	  is_vcom_epfd (__fds[fds_idx].fd))
+	{
+	  __fds[fds_idx].fd = -__fds[fds_idx].fd;
+	  vcom_nfds++;
+	}
+      else
+	{
+	  libc_nfds++;
+	  /* ignore fd 0 by setting it to negative number */
+	  if (!vcom_fds[fds_idx].fd)
+	    {
+	      vcom_fds[fds_idx].fd = -1;
+	    }
+	  vcom_fds[fds_idx].fd = -vcom_fds[fds_idx].fd;
+	}
+    }
+
+  /*
+   * polling loop
+   *
+   * poll on libc fds and vcom fds
+   *
+   * specifying a timeout of zero causes libc_poll() and
+   * vcom_socket_poll() to return immediately, even if no
+   * file descriptors are ready
+   * */
+  do
+    {
+      rlibc_nfds = 0;
+      rvcom_nfds = 0;
+
+      /*
+       * timeout parameter for libc_poll () set to zero
+       * to poll on libc fds
+       * */
+
+      /* poll on libc fds */
+      if (libc_nfds)
+	{
+	  /*
+	   * a timeout of zero causes libc_poll()
+	   * to return immediately
+	   * */
+	  rlibc_nfds = libc_poll (__fds, __nfds, 0);
+	  if (VCOM_DEBUG > 0)
+	    fprintf (stderr,
+		     "[%d] poll libc: "
+		     "'%04d'='%08lu'\n", pid, rlibc_nfds, __nfds);
+
+	  if (rlibc_nfds < 0)
+	    {
+	      rv = -errno;
+	      goto poll_done_update_nfds;
+	    }
+	}
+
+      /*
+       * timeout parameter for vcom_socket_poll () set to zero
+       * to poll on vcom fds
+       * */
+
+      /* poll on vcom fds */
+      if (vcom_nfds)
+	{
+	  /*
+	   * a timeout of zero causes vcom_socket_poll()
+	   * to return immediately
+	   * */
+	  rvcom_nfds = vcom_socket_poll (vcom_fds, __nfds, 0);
+	  if (VCOM_DEBUG > 0)
+	    fprintf (stderr,
+		     "[%d] poll vcom: "
+		     "'%04d'='%08lu'\n", pid, rvcom_nfds, __nfds);
+	  if (rvcom_nfds < 0)
+	    {
+	      rv = rvcom_nfds;
+	      goto poll_done_update_nfds;
+	    }
+	}
+
+      /* check if any file descriptors changed status */
+      if ((libc_nfds && rlibc_nfds > 0) || (vcom_nfds && rvcom_nfds > 0))
+	{
+	  /* something interesting happened */
+	  rv = rlibc_nfds + rvcom_nfds;
+	  goto poll_done_update_nfds;
+	}
+
+      rv = clock_gettime (CLOCK_MONOTONIC, &now);
+      if (rv == -1)
+	{
+	  rv = -errno;
+	  goto poll_done_update_nfds;
+	}
+    }
+
+  /* block indefinitely || timeout elapsed  */
+  while ((__timeout < 0) || timespec_compare (&now, &end_time) < 0);
+
+  /* timeout expired before anything interesting happened */
+  rv = 0;
+
+poll_done_update_nfds:
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds in vcom_fds
+       * 00. user negated fds
+       * 01. libc fds
+       * */
+      if (vcom_fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      /* from here on handle positive vcom fds */
+      /*
+       * restore vcom fds to positive number in __fds
+       * and update revents in __fds with the events
+       * that actually occurred in vcom fds
+       * */
+      __fds[fds_idx].fd = -__fds[fds_idx].fd;
+      if (rvcom_nfds)
+	{
+	  __fds[fds_idx].revents = vcom_fds[fds_idx].revents;
+	}
+    }
+
+poll_done:
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] vpoll: " "'%04d'='%08lu'\n", pid, rv, __nfds);
+  return rv;
 }
 
+/*
+ * 00. The  field  __fds[i].fd contains a file descriptor for an
+ *     open file.
+ *     If this field is negative, then the corresponding
+ *     events field is ignored and the revents field returns zero.
+ *     The field __fds[i].events is an input parameter.
+ *     The field __fds[i].revents is an output parameter.
+ * 01. Specifying a negative value in  timeout
+ *     means  an infinite timeout.
+ *     Specifying a timeout of zero causes poll() to return
+ *     immediately, even if no file descriptors are ready.
+ *
+ * NOTE: observed __nfds is less than 128 from kubecon strace files
+ */
+
+
 int
 poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
 {
   int rv = 0;
+  pid_t pid = getpid ();
 
-  errno = EOPNOTSUPP;
-  rv = -1;
+
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] poll1: " "'%04d'='%08lu, %d, 0x%x'\n",
+	     pid, rv, __nfds, __fds[0].fd, __fds[0].events);
+  rv = vcom_poll (__fds, __nfds, __timeout);
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr, "[%d] poll2: " "'%04d'='%08lu, %d, 0x%x'\n",
+	     pid, rv, __nfds, __fds[0].fd, __fds[0].revents);
+  if (rv < 0)
+    {
+      errno = -rv;
+      return -1;
+    }
   return rv;
 }
 
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.h b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
index bedeef8..5871b52 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom.h
@@ -178,6 +178,12 @@
 vcom_epoll_pwait (int __epfd, struct epoll_event *__events,
 		  int __maxevents, int __timeout, const __sigset_t * __ss);
 
+/*
+ * NOTE: observed __nfds is less than 128 from kubecon strace files
+ * for the POC, it's fair to assume that nfds is less than 1024.
+ * TBD: make it thread safe and design to scale.
+ * */
+#define MAX_POLL_NFDS_DEFAULT   1024
 extern int vcom_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
 
 #ifdef __USE_GNU
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h
index 0f1b174..4eb60fb 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_glibc_socket.h
@@ -23,6 +23,8 @@
 #include <fcntl.h>
 
 #include <sys/epoll.h>
+
+#include <signal.h>
 #include <poll.h>
 
 /*
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
index 96108af..4a5f285 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.c
@@ -2793,6 +2793,395 @@
   return rv;
 }
 
+static inline void
+vcom_pollfds_2_selectfds (
+			   /* src */
+			   struct pollfd *__fds, nfds_t __nfds,
+			   /* dest */
+			   int vcom_nfds,
+			   fd_set * __restrict vcom_readfds,
+			   fd_set * __restrict vcom_writefds,
+			   fd_set * __restrict vcom_exceptfds)
+{
+  nfds_t fds_idx = 0;
+
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
+      FD_SET (__fds[fds_idx].fd, vcom_exceptfds);
+
+      /* requested events */
+      if (__fds[fds_idx].events)
+	{
+	  if (__fds[fds_idx].events & POLLIN)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_readfds);
+	    }
+	  if (__fds[fds_idx].events & POLLPRI)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_readfds);
+	    }
+	  if (__fds[fds_idx].events & POLLOUT)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_writefds);
+	    }
+#if defined __USE_XOPEN || defined __USE_XOPEN2K8
+	  if (__fds[fds_idx].events & POLLRDNORM)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_readfds);
+	    }
+	  if (__fds[fds_idx].events & POLLRDBAND)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_readfds);
+	    }
+	  if (__fds[fds_idx].events & POLLWRNORM)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_writefds);
+	    }
+	  if (__fds[fds_idx].events & POLLWRBAND)
+	    {
+	      FD_SET (__fds[fds_idx].fd, vcom_writefds);
+	    }
+#endif
+	}
+    }				/* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
+}
+
+static inline void
+vcom_selectfds_2_pollfds (
+			   /* dest */
+			   struct pollfd *__fds, nfds_t __nfds, int *nfd,
+			   /* src */
+			   int vcom_nfds,
+			   fd_set * __restrict vcom_readfds,
+			   fd_set * __restrict vcom_writefds,
+			   fd_set * __restrict vcom_exceptfds)
+{
+  nfds_t fds_idx = 0;
+
+
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  __fds[fds_idx].revents = 0;
+	}
+
+      /* for POLLRDHUP, POLLERR, POLLHUP and  POLLNVAL */
+      if (FD_ISSET (__fds[fds_idx].fd, vcom_exceptfds))
+	{
+	  /*
+	   * TBD: for now any select exception
+	   *      is flagged as POLLERR
+	   * */
+	  __fds[fds_idx].revents |= POLLERR;
+	}
+
+      /* requested events */
+      if (__fds[fds_idx].events & POLLIN)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
+	    {
+	      __fds[fds_idx].revents |= POLLIN;
+	    }
+	}
+      if (__fds[fds_idx].events & POLLPRI)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
+	    {
+	      __fds[fds_idx].revents |= POLLIN;
+	    }
+	}
+      if (__fds[fds_idx].events & POLLOUT)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
+	    {
+	      __fds[fds_idx].revents |= POLLOUT;
+	    }
+	}
+#if defined __USE_XOPEN || defined __USE_XOPEN2K8
+      if (__fds[fds_idx].events & POLLRDNORM)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
+	    {
+	      __fds[fds_idx].revents |= POLLRDNORM;
+	    }
+	}
+      if (__fds[fds_idx].events & POLLRDBAND)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_readfds))
+	    {
+	      __fds[fds_idx].revents |= POLLRDBAND;
+	    }
+	}
+      if (__fds[fds_idx].events & POLLWRNORM)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
+	    {
+	      __fds[fds_idx].revents |= POLLWRNORM;
+	    }
+	}
+      if (__fds[fds_idx].events & POLLWRBAND)
+	{
+	  if (FD_ISSET (__fds[fds_idx].fd, vcom_writefds))
+	    {
+	      __fds[fds_idx].revents |= POLLWRBAND;
+	    }
+	}
+#endif
+    }				/* for (fds_idx = 0; fds_idx < __nfds; fds_idx++) */
+
+  /*
+   * nfd:
+   * the number of structures which have nonzero revents  fields
+   * (in  other  words,  those  descriptors  with events or
+   * errors reported)
+   * */
+  *nfd = 0;
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      if (__fds[fds_idx].revents)
+	{
+	  (*nfd)++;
+	}
+    }
+}
+
+/*
+ * PRE: parameters are validated,
+ *      vcom_socket_poll is always called with __timeout set to zero
+ *      hence returns immediately
+ *
+ * ACTION: handle non negative validated vcom fds and ignore rest
+ */
+
+/*
+ * implements vcom_socket_poll () interface
+ *
+ * internally uses vcom_socket_select ()
+ * to realize the behavior
+ * */
+int
+vcom_socket_poll_select_impl (struct pollfd *__fds, nfds_t __nfds,
+			      int __timeout)
+{
+  int rv;
+  pid_t pid = getpid ();
+
+  nfds_t fds_idx = 0;
+  int nfd = 0;
+
+  /* vcom */
+  int vcom_nfds = 0;
+  fd_set vcom_readfds;
+  fd_set vcom_writefds;
+  fd_set vcom_exceptfds;
+  int vcom_nfd = -1;
+  /* invalid max_vcom_fd is -1 */
+  int max_vcom_fd = -1;
+
+  /* __timeout is zero to get ready events and return immediately */
+  struct timeval tv = {.tv_sec = 0,.tv_usec = 0 };
+
+  /* validate __nfds from select perspective */
+  if (__nfds < 0 || __nfds > FD_SETSIZE)
+    {
+      rv = -EINVAL;
+      goto poll_done;
+    }
+
+  /* zero vcom fd sets */
+  /*
+   * V vcom fd set
+   */
+#define _(V)      \
+    FD_ZERO ((V))
+
+  _(&vcom_readfds);
+  _(&vcom_writefds);
+  _(&vcom_exceptfds);
+#undef _
+
+  vcom_nfds = 0;
+  vcom_nfd = -1;
+
+
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      /* non negative validated vcom fds */
+      if (__fds[fds_idx].fd > FD_SETSIZE)
+	{
+	  rv = -EINVAL;
+	  goto poll_done;
+	}
+
+      /* max_vcom_fd and vcom_nfd */
+      if (__fds[fds_idx].fd > max_vcom_fd)
+	{
+	  /* requested events */
+	  if (__fds[fds_idx].events)
+	    {
+	      max_vcom_fd = __fds[fds_idx].fd;
+	    }
+	}
+      ++vcom_nfd;
+    }
+
+  vcom_nfds = max_vcom_fd != -1 ? max_vcom_fd + 1 : 0;
+
+  if (!vcom_nfds)
+    {
+      rv = vcom_nfds;
+      goto poll_done;
+    }
+
+  vcom_pollfds_2_selectfds (
+			     /* src */
+			     __fds, __nfds,
+			     /* dest */
+			     vcom_nfds,
+			     &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
+
+  /* select on vcom fds */
+  vcom_nfd = vcom_socket_select (vcom_nfds,
+				 &vcom_readfds,
+				 &vcom_writefds, &vcom_exceptfds, &tv);
+  if (VCOM_DEBUG > 0)
+    fprintf (stderr,
+	     "[%d] vcom_socket_select: "
+	     "'%04d'='%04d'\n", pid, vcom_nfd, vcom_nfds);
+
+  if (vcom_nfd < 0)
+    {
+      rv = vcom_nfd;
+      goto poll_done;
+    }
+
+  vcom_selectfds_2_pollfds (
+			     /* dest */
+			     __fds, __nfds, &nfd,
+			     /* src */
+			     vcom_nfds,
+			     &vcom_readfds, &vcom_writefds, &vcom_exceptfds);
+
+  rv = nfd;
+
+poll_done:
+  return rv;
+}
+
+/*
+ * TBD: remove this static function once vppcom
+ *      has an implementation in place
+ *
+ * ACTION:
+ */
+static int
+vppcom_poll (struct pollfd *__fds, nfds_t __nfds, double time_to_wait)
+{
+  return -EOPNOTSUPP;
+}
+
+int
+vcom_socket_poll_vppcom_impl (struct pollfd *__fds, nfds_t __nfds,
+			      int __timeout)
+{
+  nfds_t fds_idx = 0;
+
+  /* in seconds eg. 3.123456789 seconds */
+  double time_to_wait = (double) 0;
+
+  i32 sid;
+  i32 vep_idx;
+
+  /* replace vcom fd with session idx */
+  for (fds_idx = 0; fds_idx < __nfds; fds_idx++)
+    {
+      /* ignore negative fds */
+      if (__fds[fds_idx].fd < 0)
+	{
+	  continue;
+	}
+
+      /* non negative validated vcom fds */
+      sid = vcom_socket_get_sid (__fds[fds_idx].fd);
+      if (sid != INVALID_SESSION_ID)
+	{
+	  __fds[fds_idx].fd = sid;
+	}
+      else
+	{
+	  /* get vep_idx */
+	  vep_idx = vcom_socket_get_vep_idx (__fds[fds_idx].fd);
+	  if (vep_idx != INVALID_VEP_IDX)
+	    {
+	      __fds[fds_idx].fd = vep_idx;
+	    }
+	  else
+	    {
+	      return -EBADF;
+	    }
+	}
+    }
+
+  /* validate __timeout */
+  if (__timeout > 0)
+    {
+      time_to_wait = (double) __timeout / (double) 1000;
+    }
+  else if (__timeout == 0)
+    {
+      time_to_wait = (double) 0;
+    }
+  else if (__timeout < 0)
+    {
+      time_to_wait = ~0;
+    }
+  else
+    {
+      return -EBADF;
+    }
+
+  return vppcom_poll (__fds, __nfds, time_to_wait);
+}
+
+int
+vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+  /* select an implementation */
+
+  /* return vcom_socket_poll_vppcom_impl (__fds, __nfds, __timeout); */
+  return vcom_socket_poll_select_impl (__fds, __nfds, __timeout);
+}
+
+#ifdef __USE_GNU
+int
+vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
+		   const struct timespec *__timeout, const __sigset_t * __ss)
+{
+  return -EOPNOTSUPP;
+}
+#endif
+
 int
 vcom_socket_main_init (void)
 {
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
index ef57646..9dc18f5 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket.h
@@ -448,6 +448,17 @@
 			 int __maxevents, int __timeout,
 			 const __sigset_t * __ss);
 
+/*
+ * handle only vcom fds
+ */
+int vcom_socket_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
+
+#ifdef __USE_GNU
+int
+vcom_socket_ppoll (struct pollfd *__fds, nfds_t __nfds,
+		   const struct timespec *__timeout, const __sigset_t * __ss);
+#endif
+
 #endif /* included_vcom_socket_h */
 
 /*
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
index 087cd6b..9b961af 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.c
@@ -263,6 +263,15 @@
 				   int __maxevents, int __timeout,
 				   const __sigset_t * __ss);
 
+typedef int (*__libc_poll) (struct pollfd * __fds, nfds_t __nfds,
+			    int __timeout);
+
+#ifdef __USE_GNU
+typedef int (*__libc_ppoll) (struct pollfd * __fds, nfds_t __nfds,
+			     const struct timespec * __timeout,
+			     const __sigset_t * __ss);
+#endif
+
 
 #define SWRAP_SYMBOL_ENTRY(i) \
         union { \
@@ -334,6 +343,10 @@
   SWRAP_SYMBOL_ENTRY (epoll_ctl);
   SWRAP_SYMBOL_ENTRY (epoll_wait);
   SWRAP_SYMBOL_ENTRY (epoll_pwait);
+  SWRAP_SYMBOL_ENTRY (poll);
+#ifdef __USE_GNU
+  SWRAP_SYMBOL_ENTRY (ppoll);
+#endif
 };
 
 struct swrap
@@ -811,6 +824,25 @@
 						 __ss);
 }
 
+int
+libc_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout)
+{
+  swrap_bind_symbol_libc (poll);
+
+  return swrap.libc.symbols._libc_poll.f (__fds, __nfds, __timeout);
+}
+
+#ifdef __USE_GNU
+int
+libc_ppoll (struct pollfd *__fds, nfds_t __nfds,
+	    const struct timespec *__timeout, const __sigset_t * __ss)
+{
+  swrap_bind_symbol_libc (ppoll);
+
+  return swrap.libc.symbols._libc_ppoll.f (__fds, __nfds, __timeout, __ss);
+}
+#endif
+
 static void
 swrap_thread_prepare (void)
 {
diff --git a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h
index 49ee7ee..9e85ecf 100644
--- a/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h
+++ b/extras/vcl-ldpreload/src/libvcl-ldpreload/vcom_socket_wrapper.h
@@ -63,6 +63,7 @@
 #include <sys/ioctl.h>
 #include <sys/select.h>
 #include <sys/epoll.h>
+#include <poll.h>
 #include <sys/uio.h>
 #include <stdlib.h>
 
@@ -212,6 +213,13 @@
 		      int __maxevents, int __timeout,
 		      const __sigset_t * __ss);
 
+int libc_poll (struct pollfd *__fds, nfds_t __nfds, int __timeout);
+
+#ifdef __USE_GNU
+int libc_ppoll (struct pollfd *__fds, nfds_t __nfds,
+		const struct timespec *__timeout, const __sigset_t * __ss);
+#endif
+
 void swrap_constructor (void);
 
 void swrap_destructor (void);