>From 5c9a9fb7067059b699d09df7a271a9efa2bbee4c Mon Sep 17 00:00:00 2001 From: KO Myung-Hun 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 +# include + +# 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