>From 5c9a9fb7067059b699d09df7a271a9efa2bbee4c Mon Sep 17 00:00:00 2001
From: KO Myung-Hun <komh@chollian.net>
Date: Sun, 3 Mar 2013 00:02:37 +0900
Subject: [PATCH] vlccore: implement timeout-free poll()

---
 include/vlc_threads.h |   17 +-------
 src/misc/threads.c    |  117 +++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 118 insertions(+), 16 deletions(-)

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 12b56fd..95b5364 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -386,23 +386,8 @@ struct vlc_cleanup_t
 
 #ifndef LIBVLC_USE_PTHREAD_CANCEL
 /* poll() with cancellation */
-static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
-{
-    int val;
-
-    do
-    {
-        int ugly_timeout = ((unsigned)timeout >= 50) ? 50 : timeout;
-        if (timeout >= 0)
-            timeout -= ugly_timeout;
+int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout);
 
-        vlc_testcancel ();
-        val = poll (fds, nfds, ugly_timeout);
-    }
-    while (val == 0 && timeout != 0);
-
-    return val;
-}
 # define poll(u,n,t) vlc_poll(u, n, t)
 
 #endif /* LIBVLC_USE_PTHREAD_CANCEL */
diff --git a/src/misc/threads.c b/src/misc/threads.c
index 01e1d97..e1a8f30 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -173,3 +173,120 @@ void vlc_sem_wait (vlc_sem_t *sem)
     vlc_cleanup_run ();
 }
 #endif /* LIBVLC_NEED_SEMAPHORE */
+
+#ifndef LIBVLC_USE_PTHREAD_CANCEL
+/*** poll() with cancellation ****/
+# include <unistd.h>
+# include <sys/socket.h>
+
+# undef poll
+
+typedef struct
+{
+    int            cancel[2];
+    vlc_mutex_t    mutex;
+    vlc_cond_t     cond;
+    struct pollfd* fds;
+    unsigned       nfds;
+} vlc_poll_thread_data_t;
+
+static void *vlc_poll_thread (void* arg)
+{
+    vlc_poll_thread_data_t *data = (vlc_poll_thread_data_t *)arg;
+
+    int val = poll (data->fds, data->nfds, -1);
+
+    if (data->fds[data->nfds - 1].revents & POLLIN ) /* Canceled ? */
+        val = 0;
+    else
+        vlc_cond_signal (&data->cond);
+
+    return (void *)val;
+}
+
+static void vlc_poll_thread_cleanup (void *arg)
+{
+    vlc_poll_thread_data_t *data = (vlc_poll_thread_data_t *)arg;
+
+    /* Wake up if vlc_poll_thread() is sleeping */
+    write (data->cancel[1], &data->cancel[1], sizeof (data->cancel[1]));
+
+    vlc_mutex_unlock (&data->mutex );
+
+    vlc_cond_destroy (&data->cond);
+    vlc_mutex_destroy (&data->mutex);
+
+    close (data->cancel[0]);
+    close (data->cancel[1]);
+}
+
+int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
+{
+    if (!timeout)
+    {
+        vlc_testcancel();
+
+        return poll (fds, nfds, timeout);
+    }
+
+    vlc_poll_thread_data_t data;
+    struct pollfd          newfds[nfds + 1];
+
+    vlc_thread_t  th;
+    void         *val;
+
+    socketpair (AF_LOCAL, SOCK_STREAM, 0, data.cancel);
+
+    vlc_mutex_init (&data.mutex);
+    vlc_cond_init (&data.cond);
+
+    memcpy (newfds, fds, sizeof (*fds) * nfds);
+    newfds[nfds].fd      = data.cancel[0];
+    newfds[nfds].events  = POLLIN;
+    newfds[nfds].revents = 0;
+
+    data.fds  = newfds;
+    data.nfds = nfds + 1;
+
+    if (vlc_clone (&th, vlc_poll_thread, &data, VLC_THREAD_PRIORITY_INPUT))
+    {
+        vlc_cond_destroy (&data.cond);
+        vlc_mutex_destroy (&data.mutex);
+
+        close (data.cancel[0]);
+        close (data.cancel[1]);
+
+        return -1;
+    }
+
+    vlc_mutex_lock (&data.mutex);
+
+    vlc_cleanup_push (vlc_poll_thread_cleanup, &data);
+
+    if (timeout < 0)
+        vlc_cond_wait (&data.cond, &data.mutex);
+    else
+        vlc_cond_timedwait (&data.cond, &data.mutex,
+                            mdate () + timeout * CLOCK_FREQ / 1000);
+
+    vlc_cleanup_pop();
+
+    /* Wake up if vlcl_poll_thread() is sleeping */
+    write (data.cancel[1], &data.cancel[1], sizeof (data.cancel[1]));
+
+    vlc_mutex_unlock (&data.mutex);
+
+    /* Get a return value */
+    vlc_join (th, &val);
+
+    memcpy (fds, newfds, sizeof(*fds) * nfds);
+
+    vlc_cond_destroy (&data.cond);
+    vlc_mutex_destroy (&data.mutex);
+
+    close (data.cancel[0]);
+    close (data.cancel[1]);
+
+    return (int)val;
+}
+#endif /* !LIBVLC_USE_PTHREAD_CANCEL */
-- 
1.7.3.2

