[vlc-commits] input: add vlc_poll_i11e() for interruptible poll()

Rémi Denis-Courmont git at videolan.org
Wed Jul 1 18:22:09 CEST 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Jun 30 23:52:51 2015 +0300| [bf6dcb5d0b1ca1c9241764de1054b0418c82ad01] | committer: Rémi Denis-Courmont

input: add vlc_poll_i11e() for interruptible poll()

This is a generic and inefficient but functional implementation.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=bf6dcb5d0b1ca1c9241764de1054b0418c82ad01
---

 include/vlc_interrupt.h |   22 ++++++
 src/libvlccore.sym      |    1 +
 src/misc/interrupt.c    |  171 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 194 insertions(+)

diff --git a/include/vlc_interrupt.h b/include/vlc_interrupt.h
index fc075a2..fedbcd8 100644
--- a/include/vlc_interrupt.h
+++ b/include/vlc_interrupt.h
@@ -26,6 +26,9 @@
 #ifndef VLC_INTERRUPT_H
 # define VLC_INTERRUPT_H 1
 # include <vlc_threads.h>
+
+struct pollfd;
+
 /**
  * @defgroup interrupt Interruptible sleep
  * @{
@@ -50,6 +53,25 @@
 VLC_API int vlc_sem_wait_i11e(vlc_sem_t *);
 
 /**
+ * Waits for file descriptors I/O events, a timeout, a signal or a VLC I/O
+ * interruption. Except for VLC I/O interruptions, this function behaves
+ * just like the standard poll().
+ *
+ * @note This function is always a cancellation point (as poll()).
+ * @see poll() manual page
+ *
+ * @param fds table of events to wait for
+ * @param nfds number of entries in the table
+ * @param timeout time to wait in milliseconds or -1 for infinite
+ *
+ * @return A strictly positive result represent the number of pending events.
+ * 0 is returned if the time-out is reached without events.
+ * -1 is returned if a VLC I/O interrupt occurs (and errno is set to EINTR)
+ * or if an error occurs.
+ */
+VLC_API int vlc_poll_i11e(struct pollfd *, unsigned, int);
+
+/**
  * @}
  * @defgroup interrupt_context Interrupt context signaling and manipulation
  * @{
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index d71e43b..7f10d51 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -539,6 +539,7 @@ vlc_ngettext
 vlc_iconv
 vlc_iconv_close
 vlc_iconv_open
+vlc_poll_i11e
 vlc_sem_wait_i11e
 vlc_interrupt_create
 vlc_interrupt_destroy
diff --git a/src/misc/interrupt.c b/src/misc/interrupt.c
index ec02601..f24ab34 100644
--- a/src/misc/interrupt.c
+++ b/src/misc/interrupt.c
@@ -29,7 +29,13 @@
 #include <stdbool.h>
 #include <stdlib.h>
 
+#ifdef HAVE_POLL
+#include <poll.h>
+#endif
+
 #include <vlc_common.h>
+#include <vlc_fs.h> /* vlc_pipe */
+
 #include "interrupt.h"
 #include "libvlc.h"
 
@@ -231,3 +237,168 @@ int vlc_sem_wait_i11e(vlc_sem_t *sem)
 
     return vlc_interrupt_finish(ctx);
 }
+
+#ifndef _WIN32
+static void vlc_poll_i11e_wake(void *opaque)
+{
+    uint64_t value = 1;
+    int *fd = opaque;
+    int canc;
+
+    canc = vlc_savecancel();
+    write(fd[1], &value, sizeof (value));
+    vlc_restorecancel(canc);
+}
+
+static void vlc_poll_i11e_cleanup(void *opaque)
+{
+    vlc_interrupt_t *ctx = opaque;
+    int *fd = ctx->data;
+
+    vlc_interrupt_finish(ctx);
+    close(fd[1]);
+    close(fd[0]);
+}
+
+static int vlc_poll_i11e_inner(struct pollfd *restrict fds, unsigned nfds,
+                               int timeout, vlc_interrupt_t *ctx,
+                               struct pollfd *restrict ufd)
+{
+    int fd[2];
+    int ret = -1;
+    int canc;
+
+    /* TODO: cache this */
+    /* TODO: use eventfd on Linux */
+    if (vlc_pipe(fd))
+    {
+        vlc_testcancel();
+        errno = ENOMEM;
+        return -1;
+    }
+
+    for (unsigned i = 0; i < nfds; i++)
+    {
+        ufd[i].fd = fds[i].fd;
+        ufd[i].events = fds[i].events;
+    }
+    ufd[nfds].fd = fd[0];
+    ufd[nfds].events = POLLIN;
+
+    if (vlc_interrupt_prepare(ctx, vlc_poll_i11e_wake, fd))
+    {
+        vlc_testcancel();
+        errno = EINTR;
+        goto out;
+    }
+
+    vlc_cleanup_push(vlc_poll_i11e_cleanup, ctx);
+    ret = poll(ufd, nfds + 1, timeout);
+
+    for (unsigned i = 0; i < nfds; i++)
+        fds[i].revents = ufd[i].revents;
+
+    if (ret > 0 && ufd[nfds].revents)
+    {
+        uint64_t dummy;
+
+        read(fd[0], &dummy, sizeof (dummy));
+        ret--;
+    }
+    vlc_cleanup_pop();
+
+    if (vlc_interrupt_finish(ctx))
+    {
+        errno = EINTR;
+        ret = -1;
+    }
+out:
+    canc = vlc_savecancel();
+    close(fd[1]);
+    close(fd[0]);
+    vlc_restorecancel(canc);
+    return ret;
+}
+
+int vlc_poll_i11e(struct pollfd *fds, unsigned nfds, int timeout)
+{
+    vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
+    if (ctx == NULL)
+        return poll(fds, nfds, timeout);
+
+    int ret;
+
+    struct pollfd *ufd = malloc((nfds + 1) * sizeof (*ufd));
+    if (unlikely(ufd == NULL))
+        return -1; /* ENOMEM */
+
+    vlc_cleanup_push(free, ufd);
+    ret = vlc_poll_i11e_inner(fds, nfds, timeout, ctx, ufd);
+    vlc_cleanup_pop();
+    free(ufd);
+    return ret;
+}
+
+#else /* _WIN32 */
+
+static void CALLBACK vlc_poll_i11e_wake_self(ULONG_PTR data)
+{
+    (void) data; /* Nothing to do */
+}
+
+static void vlc_poll_i11e_wake(void *opaque)
+{
+#if !VLC_WINSTORE_APP
+    HANDLE th = opaque;
+    QueueUserAPC(vlc_poll_i11e_wake_self, th, 0);
+#else
+    (void) opaque;
+#endif
+}
+
+static void vlc_poll_i11e_cleanup(void *opaque)
+{
+    vlc_interrupt_t *ctx = opaque;
+    HANDLE th = ctx->data;
+
+    vlc_interrupt_finish(ctx);
+    CloseHandle(th);
+}
+
+int vlc_poll_i11e(struct pollfd *fds, unsigned nfds, int timeout)
+{
+    vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
+    if (ctx == NULL)
+        return vlc_poll(fds, nfds, timeout);
+
+    int ret = -1;
+    HANDLE th;
+
+    if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
+                         GetCurrentProcess(), &th, 0, FALSE,
+                         DUPLICATE_SAME_ACCESS))
+    {
+        errno = ENOMEM;
+        return -1;
+    }
+
+    if (vlc_interrupt_prepare(ctx, vlc_poll_i11e_wake, th))
+    {
+        errno = EINTR;
+        goto out;
+    }
+
+    vlc_cleanup_push(vlc_poll_i11e_cleanup, th);
+    ret = vlc_poll(fds, nfds, timeout);
+    vlc_cleanup_pop();
+
+    if (vlc_interrupt_finish(ctx))
+    {
+        errno = EINTR;
+        ret = -1;
+    }
+out:
+    CloseHandle(th);
+    return ret;
+}
+#endif



More information about the vlc-commits mailing list