[Cogl] [PATCH 1/2] wayland: Remove the Wayland socket FD if there are any errors
Robert Bragg
robert at sixbynine.org
Wed Jul 10 08:23:35 PDT 2013
This looks good to land to me:
Reviewed-by: Robert Bragg <robert at linux.intel.com>
thanks,
- Robert
On Tue, Jul 9, 2013 at 7:26 PM, Neil Roberts <neil at linux.intel.com> wrote:
> Previously if the Wayland socket gets closed then Cogl would ignore
> the error when dispatching events which meant the socket would be
> constantly ready for reading, the main loop would never go idle and it
> would sit at 100% CPU. When Wayland encounters an error it will
> actually close the socket which means if something else opened another
> file then we might even end up polling on a completely unrelated FD.
> This patch makes it remove the FD from the main loop as soon as it
> hits an error so that it will at least avoid breaking the main loop.
> However I think most applications would probably want to abort in this
> case so we might also want to add a way to inform the application of
> this or even just abort directly.
>
> The cogl_poll_* functions have been changed so that they can cope if
> the pending and dispatch callbacks remove their own FD while they are
> invoked.
> ---
> cogl/cogl-poll.c | 24 +++++++++----
> cogl/winsys/cogl-winsys-egl-wayland.c | 65 +++++++++++++++++++++++++++--------
> 2 files changed, 69 insertions(+), 20 deletions(-)
>
> diff --git a/cogl/cogl-poll.c b/cogl/cogl-poll.c
> index cb62327..f1c19f0 100644
> --- a/cogl/cogl-poll.c
> +++ b/cogl/cogl-poll.c
> @@ -46,23 +46,26 @@ cogl_poll_renderer_get_info (CoglRenderer *renderer,
> int *n_poll_fds,
> int64_t *timeout)
> {
> - GList *l;
> + GList *l, *next;
>
> _COGL_RETURN_VAL_IF_FAIL (cogl_is_renderer (renderer), 0);
> _COGL_RETURN_VAL_IF_FAIL (poll_fds != NULL, 0);
> _COGL_RETURN_VAL_IF_FAIL (n_poll_fds != NULL, 0);
> _COGL_RETURN_VAL_IF_FAIL (timeout != NULL, 0);
>
> - *poll_fds = (void *)renderer->poll_fds->data;
> - *n_poll_fds = renderer->poll_fds->len;
> *timeout = -1;
>
> if (!_cogl_list_empty (&renderer->idle_closures))
> *timeout = 0;
>
> - for (l = renderer->poll_sources; l; l = l->next)
> + /* This loop needs to cope with the prepare callback removing its
> + * own fd */
> + for (l = renderer->poll_sources; l; l = next)
> {
> CoglPollSource *source = l->data;
> +
> + next = l->next;
> +
> if (source->prepare)
> {
> int64_t source_timeout = source->prepare (source->user_data);
> @@ -72,6 +75,11 @@ cogl_poll_renderer_get_info (CoglRenderer *renderer,
> }
> }
>
> + /* This is deliberately set after calling the prepare callbacks in
> + * case one of them removes its fd */
> + *poll_fds = (void *)renderer->poll_fds->data;
> + *n_poll_fds = renderer->poll_fds->len;
> +
> return renderer->poll_fds_age;
> }
>
> @@ -80,17 +88,21 @@ cogl_poll_renderer_dispatch (CoglRenderer *renderer,
> const CoglPollFD *poll_fds,
> int n_poll_fds)
> {
> - GList *l;
> + GList *l, *next;
>
> _COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
>
> _cogl_closure_list_invoke_no_args (&renderer->idle_closures);
>
> - for (l = renderer->poll_sources; l; l = l->next)
> + /* This loop needs to cope with the dispatch callback removing its
> + * own fd */
> + for (l = renderer->poll_sources; l; l = next)
> {
> CoglPollSource *source = l->data;
> int i;
>
> + next = l->next;
> +
> if (source->fd == -1)
> {
> source->dispatch (source->user_data, 0);
> diff --git a/cogl/winsys/cogl-winsys-egl-wayland.c b/cogl/winsys/cogl-winsys-egl-wayland.c
> index f5a6047..075c258 100644
> --- a/cogl/winsys/cogl-winsys-egl-wayland.c
> +++ b/cogl/winsys/cogl-winsys-egl-wayland.c
> @@ -132,13 +132,28 @@ prepare_wayland_display_events (void *user_data)
>
> flush_ret = wl_display_flush (wayland_renderer->wayland_display);
>
> - /* If the socket buffer became full then we need to wake up the main
> - * loop once it is writable again */
> - if (flush_ret == -1 && errno == EAGAIN)
> - _cogl_poll_renderer_modify_fd (renderer,
> - wayland_renderer->fd,
> - COGL_POLL_FD_EVENT_IN |
> - COGL_POLL_FD_EVENT_OUT);
> + if (flush_ret == -1)
> + {
> + /* If the socket buffer became full then we need to wake up the
> + * main loop once it is writable again */
> + if (errno == EAGAIN)
> + {
> + _cogl_poll_renderer_modify_fd (renderer,
> + wayland_renderer->fd,
> + COGL_POLL_FD_EVENT_IN |
> + COGL_POLL_FD_EVENT_OUT);
> + }
> + else if (errno != EINTR)
> + {
> + /* If the flush failed for some other reason then it's
> + * likely that it's going to consistently fail so we'll stop
> + * waiting on the file descriptor instead of making the
> + * application take up 100% CPU. FIXME: it would be nice if
> + * there was some way to report this to the application so
> + * that it can quit or recover */
> + _cogl_poll_renderer_remove_fd (renderer, wayland_renderer->fd);
> + }
> + }
>
> /* Calling this here is a bit dodgy because Cogl usually tries to
> * say that it won't do any event processing until
> @@ -159,19 +174,41 @@ dispatch_wayland_display_events (void *user_data, int revents)
> CoglRendererWayland *wayland_renderer = egl_renderer->platform;
>
> if ((revents & COGL_POLL_FD_EVENT_IN))
> - wl_display_dispatch (wayland_renderer->wayland_display);
> + {
> + if (wl_display_dispatch (wayland_renderer->wayland_display) == -1 &&
> + errno != EAGAIN &&
> + errno != EINTR)
> + goto socket_error;
> + }
>
> if ((revents & COGL_POLL_FD_EVENT_OUT))
> {
> int ret = wl_display_flush (wayland_renderer->wayland_display);
>
> - if (ret != -1 || errno != EAGAIN)
> - /* There is no more data to write so we don't need to wake up
> - * when the write buffer is emptied anymore */
> - _cogl_poll_renderer_modify_fd (renderer,
> - wayland_renderer->fd,
> - COGL_POLL_FD_EVENT_IN);
> + if (ret == -1)
> + {
> + if (errno != EAGAIN && errno != EINTR)
> + goto socket_error;
> + }
> + else
> + {
> + /* There is no more data to write so we don't need to wake
> + * up when the write buffer is emptied anymore */
> + _cogl_poll_renderer_modify_fd (renderer,
> + wayland_renderer->fd,
> + COGL_POLL_FD_EVENT_IN);
> + }
> }
> +
> + return;
> +
> + socket_error:
> + /* If there was an error on the wayland socket then it's likely that
> + * it's going to consistently fail so we'll stop waiting on the file
> + * descriptor instead of making the application take up 100% CPU.
> + * FIXME: it would be nice if there was some way to report this to
> + * the application so that it can quit or recover */
> + _cogl_poll_renderer_remove_fd (renderer, wayland_renderer->fd);
> }
>
> static CoglBool
> --
> 1.7.11.3.g3c3efa5
>
> _______________________________________________
> Cogl mailing list
> Cogl at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/cogl
More information about the Cogl
mailing list