From f780bbbce877a90ce117b43f6fb062a54bbc274a 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] os2: implement poll() with timeout free cancellation

---
 include/vlc_threads.h |    5 ++
 src/Makefile.am       |    1 +
 src/os2/poll.c        |  141 +++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 147 insertions(+), 0 deletions(-)
 create mode 100644 src/os2/poll.c

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 12b56fd..ae83588 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -386,6 +386,9 @@ struct vlc_cleanup_t
 
 #ifndef LIBVLC_USE_PTHREAD_CANCEL
 /* poll() with cancellation */
+# ifdef __OS2__
+int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout);
+# else
 static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
 {
     int val;
@@ -403,6 +406,8 @@ static inline int vlc_poll (struct pollfd *fds, unsigned nfds, int timeout)
 
     return val;
 }
+# endif
+
 # define poll(u,n,t) vlc_poll(u, n, t)
 
 #endif /* LIBVLC_USE_PTHREAD_CANCEL */
diff --git a/src/Makefile.am b/src/Makefile.am
index fa283f3..1f1190a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -304,6 +304,7 @@ SOURCES_libvlc_os2 = \
 	os2/thread.c \
 	os2/specific.c \
 	os2/rand.c \
+	os2/poll.c \
 	$(NULL)
 
 SOURCES_libvlc_other = \
diff --git a/src/os2/poll.c b/src/os2/poll.c
new file mode 100644
index 0000000..f89cbf9
--- /dev/null
+++ b/src/os2/poll.c
@@ -0,0 +1,141 @@
+/*****************************************************************************
+ * poll.c : implementation of poll() with timeout free cancellation on OS/2
+ *****************************************************************************
+ * Copyright (C) 2013 VLC authors and VideoLAN
+ *
+ * Authors: KO Myung-Hun <komh@chollian.net>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#undef poll
+
+#include <io.h>
+#include <sys/socket.h>
+
+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;
+}
-- 
1.7.3.2

