X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=gst%2Fgstpoll.c;h=5e0a668a89d92456b1be6f846940963b67bb6e51;hb=260b9791fc7ea524ad949b5cfdd81688d0a3013e;hp=fed594fc57590439cc3fa49eb59ec2553c849842;hpb=5e8cf7fee7cbe953bb394de6e40fc1715d78cb43;p=platform%2Fupstream%2Fgstreamer.git diff --git a/gst/gstpoll.c b/gst/gstpoll.c index fed594f..5e0a668 100644 --- a/gst/gstpoll.c +++ b/gst/gstpoll.c @@ -2,7 +2,7 @@ * Copyright (C) 1999 Erik Walthinsen * Copyright (C) 2004 Wim Taymans * Copyright (C) 2007 Peter Kjellerstedt - * Copyright (C) 2008 Ole André Vadla Ravnås + * Copyright (C) 2008 Ole André Vadla RavnÃ¥s * * gstpoll.c: File descriptor set * @@ -18,28 +18,29 @@ * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. */ /** * SECTION:gstpoll + * @title: GstPoll * @short_description: Keep track of file descriptors and make it possible - * to wait on them in a cancelable way + * to wait on them in a cancellable way * * A #GstPoll keeps track of file descriptors much like fd_set (used with * select()) or a struct pollfd array (used with poll()). Once created with * gst_poll_new(), the set can be used to wait for file descriptors to be - * readable and/or writeable. It is possible to make this wait be controlled + * readable and/or writable. It is possible to make this wait be controlled * by specifying %TRUE for the @controllable flag when creating the set (or * later calling gst_poll_set_controllable()). * * New file descriptors are added to the set using gst_poll_add_fd(), and * removed using gst_poll_remove_fd(). Controlling which file descriptors - * should be waited for to become readable and/or writeable are done using - * gst_poll_fd_ctl_read() and gst_poll_fd_ctl_write(). + * should be waited for to become readable and/or writable are done using + * gst_poll_fd_ctl_read(), gst_poll_fd_ctl_write() and gst_poll_fd_ctl_pri(). * * Use gst_poll_wait() to wait for the file descriptors to actually become - * readable and/or writeable, or to timeout if no file descriptor is available + * readable and/or writable, or to timeout if no file descriptor is available * in time. The wait can be controlled by calling gst_poll_restart() and * gst_poll_set_flushing(). * @@ -72,14 +73,24 @@ #ifdef G_OS_WIN32 #include -#define EINPROGRESS WSAEINPROGRESS #else #define _GNU_SOURCE 1 +#ifdef HAVE_SYS_POLL_H #include +#endif +#ifdef HAVE_POLL_H +#include +#endif #include #include #endif +#ifdef G_OS_WIN32 +# ifndef EWOULDBLOCK +# define EWOULDBLOCK EAGAIN /* This is just to placate gcc */ +# endif +#endif /* G_OS_WIN32 */ + /* OS/X needs this because of bad headers */ #include @@ -120,7 +131,7 @@ struct _GstPoll { GstPollMode mode; - GMutex *lock; + GMutex lock; /* array of fds, always written to and read from with lock */ GArray *fds; /* array of active fds, only written to from the waiting thread with the @@ -129,7 +140,6 @@ struct _GstPoll GArray *active_fds; #ifndef G_OS_WIN32 - gchar buf[1]; GstPollFD control_read_fd; GstPollFD control_write_fd; #else @@ -155,19 +165,114 @@ static gboolean gst_poll_add_fd_unlocked (GstPoll * set, GstPollFD * fd); #define IS_FLUSHING(s) (g_atomic_int_get(&(s)->flushing)) #define SET_FLUSHING(s,val) (g_atomic_int_set(&(s)->flushing, (val))) -#define INC_WAITING(s) (G_ATOMIC_INT_ADD(&(s)->waiting, 1)) -#define DEC_WAITING(s) (G_ATOMIC_INT_ADD(&(s)->waiting, -1)) +#define INC_WAITING(s) (g_atomic_int_add(&(s)->waiting, 1)) +#define DEC_WAITING(s) (g_atomic_int_add(&(s)->waiting, -1)) #define GET_WAITING(s) (g_atomic_int_get(&(s)->waiting)) #define TEST_REBUILD(s) (g_atomic_int_compare_and_exchange(&(s)->rebuild, 1, 0)) #define MARK_REBUILD(s) (g_atomic_int_set(&(s)->rebuild, 1)) #ifndef G_OS_WIN32 -#define WAKE_EVENT(s) (write ((s)->control_write_fd.fd, "W", 1) == 1) -#define RELEASE_EVENT(s) (read ((s)->control_read_fd.fd, (s)->buf, 1) == 1) + +static gboolean +wake_event (GstPoll * set) +{ + ssize_t num_written; + while ((num_written = write (set->control_write_fd.fd, "W", 1)) != 1) { + if (num_written == -1 && errno != EAGAIN && errno != EINTR) { + g_critical ("%p: failed to wake event: %s", set, strerror (errno)); + return FALSE; + } + } + return TRUE; +} + +static gboolean +release_event (GstPoll * set) +{ + gchar buf[1] = { '\0' }; + ssize_t num_read; + while ((num_read = read (set->control_read_fd.fd, buf, 1)) != 1) { + if (num_read == -1 && errno != EAGAIN && errno != EINTR) { + g_critical ("%p: failed to release event: %s", set, strerror (errno)); + return FALSE; + } + } + return TRUE; +} + #else -#define WAKE_EVENT(s) (SetEvent ((s)->wakeup_event), errno = GetLastError () == NO_ERROR ? 0 : EACCES, errno == 0 ? 1 : 0) -#define RELEASE_EVENT(s) (ResetEvent ((s)->wakeup_event)) + +static void +format_last_error (gchar * buf, size_t buf_len) +{ + DWORD flags = FORMAT_MESSAGE_FROM_SYSTEM; + LPCVOID src = NULL; + DWORD lang = 0; + DWORD id; + id = GetLastError (); + FormatMessage (flags, src, id, lang, buf, (DWORD) buf_len, NULL); + SetLastError (id); +} + +static gboolean +wake_event (GstPoll * set) +{ + SetLastError (0); + errno = 0; + if (!SetEvent (set->wakeup_event)) { + gchar msg[1024] = ""; + format_last_error (msg, sizeof (msg)); + g_critical ("%p: failed to set wakup_event: %s", set, msg); + errno = EBADF; + return FALSE; + } + + return TRUE; +} + +static gboolean +release_event (GstPoll * set) +{ + DWORD status; + SetLastError (0); + errno = 0; + + status = WaitForSingleObject (set->wakeup_event, INFINITE); + if (status) { + const gchar *reason = "unknown"; + gchar msg[1024] = ""; + switch (status) { + case WAIT_ABANDONED: + reason = "WAIT_ABANDONED"; + break; + case WAIT_TIMEOUT: + reason = "WAIT_TIMEOUT"; + break; + case WAIT_FAILED: + format_last_error (msg, sizeof (msg)); + reason = msg; + break; + default: + reason = "other"; + break; + } + g_critical ("%p: failed to block on wakup_event: %s", set, reason); + errno = EBADF; + return FALSE; + } + + if (!ResetEvent (set->wakeup_event)) { + gchar msg[1024] = ""; + format_last_error (msg, sizeof (msg)); + g_critical ("%p: failed to reset wakup_event: %s", set, msg); + errno = EBADF; + return FALSE; + } + + return TRUE; +} + #endif /* the poll/select call is also performed on a control socket, that way @@ -177,26 +282,50 @@ raise_wakeup (GstPoll * set) { gboolean result = TRUE; - if (G_ATOMIC_INT_ADD (&set->control_pending, 1) == 0) { + /* makes testing control_pending and WAKE_EVENT() atomic. */ + g_mutex_lock (&set->lock); + + if (set->control_pending == 0) { /* raise when nothing pending */ GST_LOG ("%p: raise", set); - result = WAKE_EVENT (set); + result = wake_event (set); } + + if (result) { + set->control_pending++; + } + + g_mutex_unlock (&set->lock); + return result; } -/* note how bad things can happen when the 2 threads both raise and release the - * wakeup. This is however not a problem because you must always pair a raise - * with a release */ static inline gboolean release_wakeup (GstPoll * set) { - gboolean result = TRUE; + gboolean result = FALSE; - if (g_atomic_int_dec_and_test (&set->control_pending)) { - GST_LOG ("%p: release", set); - result = RELEASE_EVENT (set); + /* makes testing/modifying control_pending and RELEASE_EVENT() atomic. */ + g_mutex_lock (&set->lock); + + if (set->control_pending > 0) { + /* release, only if this was the last pending. */ + if (set->control_pending == 1) { + GST_LOG ("%p: release", set); + result = release_event (set); + } else { + result = TRUE; + } + + if (result) { + set->control_pending--; + } + } else { + errno = EWOULDBLOCK; } + + g_mutex_unlock (&set->lock); + return result; } @@ -205,21 +334,20 @@ release_all_wakeup (GstPoll * set) { gint old; - while (TRUE) { - if (!(old = g_atomic_int_get (&set->control_pending))) - /* nothing pending, just exit */ - break; + /* makes testing control_pending and RELEASE_EVENT() atomic. */ + g_mutex_lock (&set->lock); - /* try to remove all pending control messages */ - if (g_atomic_int_compare_and_exchange (&set->control_pending, old, 0)) { - /* we managed to remove all messages, read the control socket */ - if (RELEASE_EVENT (set)) - break; - else - /* retry again until we read it successfully */ - G_ATOMIC_INT_ADD (&set->control_pending, 1); + if ((old = set->control_pending) > 0) { + GST_LOG ("%p: releasing %d", set, old); + if (release_event (set)) { + set->control_pending = 0; + } else { + old = 0; } } + + g_mutex_unlock (&set->lock); + return old; } @@ -267,24 +395,24 @@ find_index (GArray * array, GstPollFD * fd) #if !defined(HAVE_PPOLL) && defined(HAVE_POLL) /* check if all file descriptors will fit in an fd_set */ static gboolean -selectable_fds (const GstPoll * set) +selectable_fds (GstPoll * set) { guint i; - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); for (i = 0; i < set->fds->len; i++) { struct pollfd *pfd = &g_array_index (set->fds, struct pollfd, i); if (pfd->fd >= FD_SETSIZE) goto too_many; } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return TRUE; too_many: { - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return FALSE; } } @@ -307,7 +435,7 @@ pollable_timeout (GstClockTime timeout) #endif static GstPollMode -choose_mode (const GstPoll * set, GstClockTime timeout) +choose_mode (GstPoll * set, GstClockTime timeout) { GstPollMode mode; @@ -347,7 +475,7 @@ pollfd_to_fd_set (GstPoll * set, fd_set * readfds, fd_set * writefds, FD_ZERO (writefds); FD_ZERO (errorfds); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); for (i = 0; i < set->active_fds->len; i++) { struct pollfd *pfd = &g_array_index (set->fds, struct pollfd, i); @@ -364,7 +492,7 @@ pollfd_to_fd_set (GstPoll * set, fd_set * readfds, fd_set * writefds, } } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return max_fd; } @@ -375,7 +503,7 @@ fd_set_to_pollfd (GstPoll * set, fd_set * readfds, fd_set * writefds, { guint i; - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); for (i = 0; i < set->active_fds->len; i++) { struct pollfd *pfd = &g_array_index (set->active_fds, struct pollfd, i); @@ -391,7 +519,7 @@ fd_set_to_pollfd (GstPoll * set, fd_set * readfds, fd_set * writefds, } } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); } #else /* G_OS_WIN32 */ /* @@ -541,20 +669,17 @@ gst_poll_collect_winsock_events (GstPoll * set) * * Free-function: gst_poll_free * - * Returns: (transfer full): a new #GstPoll, or %NULL in case of an error. - * Free with gst_poll_free(). - * - * Since: 0.10.18 + * Returns: (transfer full) (nullable): a new #GstPoll, or %NULL in + * case of an error. Free with gst_poll_free(). */ GstPoll * gst_poll_new (gboolean controllable) { GstPoll *nset; - GST_DEBUG ("controllable : %d", controllable); - nset = g_slice_new0 (GstPoll); - nset->lock = g_mutex_new (); + GST_DEBUG ("%p: new controllable : %d", nset, controllable); + g_mutex_init (&nset->lock); #ifndef G_OS_WIN32 nset->mode = GST_POLL_MODE_AUTO; nset->fds = g_array_new (FALSE, FALSE, sizeof (struct pollfd)); @@ -567,9 +692,6 @@ gst_poll_new (gboolean controllable) if (socketpair (PF_UNIX, SOCK_STREAM, 0, control_sock) < 0) goto no_socket_pair; - fcntl (control_sock[0], F_SETFL, O_NONBLOCK); - fcntl (control_sock[1], F_SETFL, O_NONBLOCK); - nset->control_read_fd.fd = control_sock[0]; nset->control_write_fd.fd = control_sock[1]; @@ -591,6 +713,7 @@ gst_poll_new (gboolean controllable) MARK_REBUILD (nset); nset->controllable = controllable; + nset->control_pending = 0; return nset; @@ -612,14 +735,12 @@ no_socket_pair: * timeouts. * * A timeout is performed with gst_poll_wait(). Multiple timeouts can be - * performed from different threads. + * performed from different threads. * * Free-function: gst_poll_free * - * Returns: (transfer full): a new #GstPoll, or %NULL in case of an error. - * Free with gst_poll_free(). - * - * Since: 0.10.23 + * Returns: (transfer full) (nullable): a new #GstPoll, or %NULL in + * case of an error. Free with gst_poll_free(). */ GstPoll * gst_poll_new_timer (void) @@ -642,8 +763,6 @@ done: * @set: (transfer full): a file descriptor set. * * Free a file descriptor set. - * - * Since: 0.10.18 */ void gst_poll_free (GstPoll * set) @@ -674,7 +793,7 @@ gst_poll_free (GstPoll * set) g_array_free (set->active_fds, TRUE); g_array_free (set->fds, TRUE); - g_mutex_free (set->lock); + g_mutex_clear (&set->lock); g_slice_free (GstPoll, set); } @@ -685,8 +804,6 @@ gst_poll_free (GstPoll * set) * * Get a GPollFD for the reading part of the control socket. This is useful when * integrating with a GSource and GMainLoop. - * - * Since: 0.10.32 */ void gst_poll_get_read_gpollfd (GstPoll * set, GPollFD * fd) @@ -713,8 +830,6 @@ gst_poll_get_read_gpollfd (GstPoll * set, GPollFD * fd) * * Initializes @fd. Alternatively you can initialize it with * #GST_POLL_FD_INIT. - * - * Since: 0.10.18 */ void gst_poll_fd_init (GstPollFD * fd) @@ -761,7 +876,7 @@ gst_poll_add_fd_unlocked (GstPoll * set, GstPollFD * fd) #endif MARK_REBUILD (set); } else { - GST_WARNING ("%p: couldn't find fd !", set); + GST_WARNING ("%p: fd already added !", set); } return TRUE; @@ -775,8 +890,6 @@ gst_poll_add_fd_unlocked (GstPoll * set, GstPollFD * fd) * Add a file descriptor to the file descriptor set. * * Returns: %TRUE if the file descriptor was successfully added to the set. - * - * Since: 0.10.18 */ gboolean gst_poll_add_fd (GstPoll * set, GstPollFD * fd) @@ -787,11 +900,11 @@ gst_poll_add_fd (GstPoll * set, GstPollFD * fd) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); ret = gst_poll_add_fd_unlocked (set, fd); - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return ret; } @@ -804,8 +917,6 @@ gst_poll_add_fd (GstPoll * set, GstPollFD * fd) * Remove a file descriptor from the file descriptor set. * * Returns: %TRUE if the file descriptor was successfully removed from the set. - * - * Since: 0.10.18 */ gboolean gst_poll_remove_fd (GstPoll * set, GstPollFD * fd) @@ -819,7 +930,7 @@ gst_poll_remove_fd (GstPoll * set, GstPollFD * fd) GST_DEBUG ("%p: fd (fd:%d, idx:%d)", set, fd->fd, fd->idx); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); /* get the index, -1 is an fd that is not added */ idx = find_index (set->fds, fd); @@ -840,7 +951,7 @@ gst_poll_remove_fd (GstPoll * set, GstPollFD * fd) GST_WARNING ("%p: couldn't find fd !", set); } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return idx >= 0; } @@ -855,8 +966,6 @@ gst_poll_remove_fd (GstPoll * set, GstPollFD * fd) * writability. * * Returns: %TRUE if the descriptor was successfully updated. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_ctl_write (GstPoll * set, GstPollFD * fd, gboolean active) @@ -870,7 +979,7 @@ gst_poll_fd_ctl_write (GstPoll * set, GstPollFD * fd, gboolean active) GST_DEBUG ("%p: fd (fd:%d, idx:%d), active : %d", set, fd->fd, fd->idx, active); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); idx = find_index (set->fds, fd); if (idx >= 0) { @@ -882,7 +991,7 @@ gst_poll_fd_ctl_write (GstPoll * set, GstPollFD * fd, gboolean active) else pfd->events &= ~POLLOUT; - GST_LOG ("pfd->events now %d (POLLOUT:%d)", pfd->events, POLLOUT); + GST_LOG ("%p: pfd->events now %d (POLLOUT:%d)", set, pfd->events, POLLOUT); #else gst_poll_update_winsock_event_mask (set, idx, FD_WRITE | FD_CONNECT, active); @@ -892,7 +1001,7 @@ gst_poll_fd_ctl_write (GstPoll * set, GstPollFD * fd, gboolean active) GST_WARNING ("%p: couldn't find fd !", set); } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return idx >= 0; } @@ -912,9 +1021,9 @@ gst_poll_fd_ctl_read_unlocked (GstPoll * set, GstPollFD * fd, gboolean active) struct pollfd *pfd = &g_array_index (set->fds, struct pollfd, idx); if (active) - pfd->events |= (POLLIN | POLLPRI); + pfd->events |= POLLIN; else - pfd->events &= ~(POLLIN | POLLPRI); + pfd->events &= ~POLLIN; #else gst_poll_update_winsock_event_mask (set, idx, FD_READ | FD_ACCEPT, active); #endif @@ -936,8 +1045,6 @@ gst_poll_fd_ctl_read_unlocked (GstPoll * set, GstPollFD * fd, gboolean active) * readability. * * Returns: %TRUE if the descriptor was successfully updated. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_ctl_read (GstPoll * set, GstPollFD * fd, gboolean active) @@ -948,16 +1055,69 @@ gst_poll_fd_ctl_read (GstPoll * set, GstPollFD * fd, gboolean active) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); ret = gst_poll_fd_ctl_read_unlocked (set, fd, active); - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); return ret; } /** + * gst_poll_fd_ctl_pri: + * @set: a file descriptor set. + * @fd: a file descriptor. + * @active: a new status. + * + * Control whether the descriptor @fd in @set will be monitored for + * exceptional conditions (POLLPRI). + * + * Not implemented on Windows (will just return %FALSE there). + * + * Returns: %TRUE if the descriptor was successfully updated. + * + * Since: 1.16 + */ +gboolean +gst_poll_fd_ctl_pri (GstPoll * set, GstPollFD * fd, gboolean active) +{ +#ifdef G_OS_WIN32 + return FALSE; +#else + gint idx; + + g_return_val_if_fail (set != NULL, FALSE); + g_return_val_if_fail (fd != NULL, FALSE); + g_return_val_if_fail (fd->fd >= 0, FALSE); + + GST_DEBUG ("%p: fd (fd:%d, idx:%d), active : %d", set, + fd->fd, fd->idx, active); + + g_mutex_lock (&set->lock); + + idx = find_index (set->fds, fd); + if (idx >= 0) { + struct pollfd *pfd = &g_array_index (set->fds, struct pollfd, idx); + + if (active) + pfd->events |= POLLPRI; + else + pfd->events &= ~POLLPRI; + + GST_LOG ("%p: pfd->events now %d (POLLPRI:%d)", set, pfd->events, POLLOUT); + MARK_REBUILD (set); + } else { + GST_WARNING ("%p: couldn't find fd !", set); + } + + g_mutex_unlock (&set->lock); + + return idx >= 0; +#endif +} + +/** * gst_poll_fd_ignored: * @set: a file descriptor set. * @fd: a file descriptor. @@ -970,8 +1130,6 @@ gst_poll_fd_ctl_read (GstPoll * set, GstPollFD * fd, gboolean active) * The reason why this is needed is because the underlying implementation * might not allow querying the fd more than once between calls to one of * the re-enabling operations. - * - * Since: 0.10.18 */ void gst_poll_fd_ignored (GstPoll * set, GstPollFD * fd) @@ -983,7 +1141,7 @@ gst_poll_fd_ignored (GstPoll * set, GstPollFD * fd) g_return_if_fail (fd != NULL); g_return_if_fail (fd->fd >= 0); - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); idx = find_index (set->fds, fd); if (idx >= 0) { @@ -993,7 +1151,7 @@ gst_poll_fd_ignored (GstPoll * set, GstPollFD * fd) MARK_REBUILD (set); } - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); #endif } @@ -1005,8 +1163,6 @@ gst_poll_fd_ignored (GstPoll * set, GstPollFD * fd) * Check if @fd in @set has closed the connection. * * Returns: %TRUE if the connection was closed. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_has_closed (const GstPoll * set, GstPollFD * fd) @@ -1018,9 +1174,7 @@ gst_poll_fd_has_closed (const GstPoll * set, GstPollFD * fd) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - GST_DEBUG ("%p: fd (fd:%d, idx:%d)", set, fd->fd, fd->idx); - - g_mutex_lock (set->lock); + g_mutex_lock (&((GstPoll *) set)->lock); idx = find_index (set->active_fds, fd); if (idx >= 0) { @@ -1036,8 +1190,9 @@ gst_poll_fd_has_closed (const GstPoll * set, GstPollFD * fd) } else { GST_WARNING ("%p: couldn't find fd !", set); } + g_mutex_unlock (&((GstPoll *) set)->lock); - g_mutex_unlock (set->lock); + GST_DEBUG ("%p: fd (fd:%d, idx:%d) %d", set, fd->fd, fd->idx, res); return res; } @@ -1050,8 +1205,6 @@ gst_poll_fd_has_closed (const GstPoll * set, GstPollFD * fd) * Check if @fd in @set has an error. * * Returns: %TRUE if the descriptor has an error. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_has_error (const GstPoll * set, GstPollFD * fd) @@ -1063,9 +1216,7 @@ gst_poll_fd_has_error (const GstPoll * set, GstPollFD * fd) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - GST_DEBUG ("%p: fd (fd:%d, idx:%d)", set, fd->fd, fd->idx); - - g_mutex_lock (set->lock); + g_mutex_lock (&((GstPoll *) set)->lock); idx = find_index (set->active_fds, fd); if (idx >= 0) { @@ -1085,8 +1236,9 @@ gst_poll_fd_has_error (const GstPoll * set, GstPollFD * fd) } else { GST_WARNING ("%p: couldn't find fd !", set); } + g_mutex_unlock (&((GstPoll *) set)->lock); - g_mutex_unlock (set->lock); + GST_DEBUG ("%p: fd (fd:%d, idx:%d) %d", set, fd->fd, fd->idx, res); return res; } @@ -1097,14 +1249,12 @@ gst_poll_fd_can_read_unlocked (const GstPoll * set, GstPollFD * fd) gboolean res = FALSE; gint idx; - GST_DEBUG ("%p: fd (fd:%d, idx:%d)", set, fd->fd, fd->idx); - idx = find_index (set->active_fds, fd); if (idx >= 0) { #ifndef G_OS_WIN32 struct pollfd *pfd = &g_array_index (set->active_fds, struct pollfd, idx); - res = (pfd->revents & (POLLIN | POLLPRI)) != 0; + res = (pfd->revents & POLLIN) != 0; #else WinsockFd *wfd = &g_array_index (set->active_fds, WinsockFd, idx); @@ -1113,6 +1263,7 @@ gst_poll_fd_can_read_unlocked (const GstPoll * set, GstPollFD * fd) } else { GST_WARNING ("%p: couldn't find fd !", set); } + GST_DEBUG ("%p: fd (fd:%d, idx:%d) %d", set, fd->fd, fd->idx, res); return res; } @@ -1125,8 +1276,6 @@ gst_poll_fd_can_read_unlocked (const GstPoll * set, GstPollFD * fd) * Check if @fd in @set has data to be read. * * Returns: %TRUE if the descriptor has data to be read. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_can_read (const GstPoll * set, GstPollFD * fd) @@ -1137,11 +1286,11 @@ gst_poll_fd_can_read (const GstPoll * set, GstPollFD * fd) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - g_mutex_lock (set->lock); + g_mutex_lock (&((GstPoll *) set)->lock); res = gst_poll_fd_can_read_unlocked (set, fd); - g_mutex_unlock (set->lock); + g_mutex_unlock (&((GstPoll *) set)->lock); return res; } @@ -1154,8 +1303,6 @@ gst_poll_fd_can_read (const GstPoll * set, GstPollFD * fd) * Check if @fd in @set can be used for writing. * * Returns: %TRUE if the descriptor can be used for writing. - * - * Since: 0.10.18 */ gboolean gst_poll_fd_can_write (const GstPoll * set, GstPollFD * fd) @@ -1167,9 +1314,7 @@ gst_poll_fd_can_write (const GstPoll * set, GstPollFD * fd) g_return_val_if_fail (fd != NULL, FALSE); g_return_val_if_fail (fd->fd >= 0, FALSE); - GST_DEBUG ("%p: fd (fd:%d, idx:%d)", set, fd->fd, fd->idx); - - g_mutex_lock (set->lock); + g_mutex_lock (&((GstPoll *) set)->lock); idx = find_index (set->active_fds, fd); if (idx >= 0) { @@ -1185,10 +1330,55 @@ gst_poll_fd_can_write (const GstPoll * set, GstPollFD * fd) } else { GST_WARNING ("%p: couldn't find fd !", set); } + g_mutex_unlock (&((GstPoll *) set)->lock); + + GST_DEBUG ("%p: fd (fd:%d, idx:%d) %d", set, fd->fd, fd->idx, res); + + return res; +} + +/** + * gst_poll_fd_has_pri: + * @set: a file descriptor set. + * @fd: a file descriptor. + * + * Check if @fd in @set has an exceptional condition (POLLPRI). + * + * Not implemented on Windows (will just return %FALSE there). + * + * Returns: %TRUE if the descriptor has an exceptional condition. + * + * Since: 1.16 + */ +gboolean +gst_poll_fd_has_pri (const GstPoll * set, GstPollFD * fd) +{ +#ifdef G_OS_WIN32 + return FALSE; +#else + gboolean res = FALSE; + gint idx; + + g_return_val_if_fail (set != NULL, FALSE); + g_return_val_if_fail (fd != NULL, FALSE); + g_return_val_if_fail (fd->fd >= 0, FALSE); + + g_mutex_lock (&((GstPoll *) set)->lock); + + idx = find_index (set->active_fds, fd); + if (idx >= 0) { + struct pollfd *pfd = &g_array_index (set->active_fds, struct pollfd, idx); + + res = (pfd->revents & POLLPRI) != 0; + } else { + GST_WARNING ("%p: couldn't find fd !", set); + } + g_mutex_unlock (&((GstPoll *) set)->lock); - g_mutex_unlock (set->lock); + GST_DEBUG ("%p: fd (fd:%d, idx:%d) %d", set, fd->fd, fd->idx, res); return res; +#endif } /** @@ -1210,8 +1400,6 @@ gst_poll_fd_can_write (const GstPoll * set, GstPollFD * fd) * Returns: The number of #GstPollFD in @set that have activity or 0 when no * activity was detected after @timeout. If an error occurs, -1 is returned * and errno is set. - * - * Since: 0.10.18 */ gint gst_poll_wait (GstPoll * set, GstClockTime timeout) @@ -1223,7 +1411,7 @@ gst_poll_wait (GstPoll * set, GstClockTime timeout) g_return_val_if_fail (set != NULL, -1); - GST_DEBUG ("timeout :%" GST_TIME_FORMAT, GST_TIME_ARGS (timeout)); + GST_DEBUG ("%p: timeout :%" GST_TIME_FORMAT, set, GST_TIME_ARGS (timeout)); is_timer = set->timer; @@ -1247,7 +1435,7 @@ gst_poll_wait (GstPoll * set, GstClockTime timeout) mode = choose_mode (set, timeout); if (TEST_REBUILD (set)) { - g_mutex_lock (set->lock); + g_mutex_lock (&set->lock); #ifndef G_OS_WIN32 g_array_set_size (set->active_fds, set->fds->len); memcpy (set->active_fds->data, set->fds->data, @@ -1256,7 +1444,7 @@ gst_poll_wait (GstPoll * set, GstClockTime timeout) if (!gst_poll_prepare_winsock_active_sets (set)) goto winsock_error; #endif - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); } switch (mode) { @@ -1334,9 +1522,9 @@ gst_poll_wait (GstPoll * set, GstClockTime timeout) tvptr = NULL; } - GST_DEBUG ("Calling select"); + GST_DEBUG ("%p: Calling select", set); res = select (max_fd + 1, &readfds, &writefds, &errorfds, tvptr); - GST_DEBUG ("After select, res:%d", res); + GST_DEBUG ("%p: After select, res:%d", set, res); } else { #ifdef HAVE_PSELECT struct timespec ts; @@ -1349,10 +1537,10 @@ gst_poll_wait (GstPoll * set, GstClockTime timeout) tsptr = NULL; } - GST_DEBUG ("Calling pselect"); + GST_DEBUG ("%p: Calling pselect", set); res = pselect (max_fd + 1, &readfds, &writefds, &errorfds, tsptr, NULL); - GST_DEBUG ("After pselect, res:%d", res); + GST_DEBUG ("%p: After pselect, res:%d", set, res); #endif } @@ -1449,7 +1637,7 @@ flushing: winsock_error: { GST_LOG ("%p: winsock error", set); - g_mutex_unlock (set->lock); + g_mutex_unlock (&set->lock); DEC_WAITING (set); return -1; } @@ -1465,14 +1653,16 @@ winsock_error: * gst_poll_wait() will be affected by gst_poll_restart() and * gst_poll_set_flushing(). * - * Returns: %TRUE if the controllability of @set could be updated. + * This function only works for non-timer #GstPoll objects created with + * gst_poll_new(). * - * Since: 0.10.18 + * Returns: %TRUE if the controllability of @set could be updated. */ gboolean gst_poll_set_controllable (GstPoll * set, gboolean controllable) { g_return_val_if_fail (set != NULL, FALSE); + g_return_val_if_fail (!set->timer, FALSE); GST_LOG ("%p: controllable : %d", set, controllable); @@ -1490,12 +1680,14 @@ gst_poll_set_controllable (GstPoll * set, gboolean controllable) * * If @set is not controllable, then this call will have no effect. * - * Since: 0.10.18 + * This function only works for non-timer #GstPoll objects created with + * gst_poll_new(). */ void gst_poll_restart (GstPoll * set) { g_return_if_fail (set != NULL); + g_return_if_fail (!set->timer); if (set->controllable && GET_WAITING (set) > 0) { /* we are controllable and waiting, wake up the waiter. The socket will be @@ -1514,12 +1706,14 @@ gst_poll_restart (GstPoll * set) * * Unsetting the flushing state will restore normal operation of @set. * - * Since: 0.10.18 + * This function only works for non-timer #GstPoll objects created with + * gst_poll_new(). */ void gst_poll_set_flushing (GstPoll * set, gboolean flushing) { g_return_if_fail (set != NULL); + g_return_if_fail (!set->timer); GST_LOG ("%p: flushing: %d", set, flushing); @@ -1540,17 +1734,19 @@ gst_poll_set_flushing (GstPoll * set, gboolean flushing) * * Write a byte to the control socket of the controllable @set. * This function is mostly useful for timer #GstPoll objects created with - * gst_poll_new_timer(). + * gst_poll_new_timer(). * * It will make any current and future gst_poll_wait() function return with * 1, meaning the control socket is set. After an equal amount of calls to * gst_poll_read_control() have been performed, calls to gst_poll_wait() will * block again until their timeout expired. * - * Returns: %TRUE on success. %FALSE when @set is not controllable or when the - * byte could not be written. + * This function only works for timer #GstPoll objects created with + * gst_poll_new_timer(). * - * Since: 0.10.23 + * Returns: %TRUE on success. %FALSE when when the byte could not be written. + * errno contains the detailed error code but will never be EAGAIN, EINTR or + * EWOULDBLOCK. %FALSE always signals a critical error. */ gboolean gst_poll_write_control (GstPoll * set) @@ -1570,13 +1766,14 @@ gst_poll_write_control (GstPoll * set) * @set: a #GstPoll. * * Read a byte from the control socket of the controllable @set. - * This function is mostly useful for timer #GstPoll objects created with - * gst_poll_new_timer(). * - * Returns: %TRUE on success. %FALSE when @set is not controllable or when there - * was no byte to read. + * This function only works for timer #GstPoll objects created with + * gst_poll_new_timer(). * - * Since: 0.10.23 + * Returns: %TRUE on success. %FALSE when when there was no byte to read or + * reading the byte failed. If there was no byte to read, and only then, errno + * will contain EWOULDBLOCK or EAGAIN. For all other values of errno this always signals a + * critical error. */ gboolean gst_poll_read_control (GstPoll * set)