mirror of
https://github.com/brl/mutter.git
synced 2024-11-25 09:30:45 -05:00
737806bcee
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. Reviewed-by: Robert Bragg <robert@linux.intel.com> (cherry picked from commit 85857b10687a5a246a0a4ef42711e560c7a6f45d)
261 lines
6.5 KiB
C
261 lines
6.5 KiB
C
/*
|
|
* Cogl
|
|
*
|
|
* An object oriented GL/GLES Abstraction/Utility Layer
|
|
*
|
|
* Copyright (C) 2012 Intel Corporation.
|
|
*
|
|
* This library 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 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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 library. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*
|
|
* Authors:
|
|
* Neil Roberts <neil@linux.intel.com>
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include "config.h"
|
|
#endif
|
|
|
|
#include "cogl-poll.h"
|
|
#include "cogl-poll-private.h"
|
|
#include "cogl-winsys-private.h"
|
|
#include "cogl-renderer-private.h"
|
|
|
|
struct _CoglPollSource
|
|
{
|
|
int fd;
|
|
CoglPollPrepareCallback prepare;
|
|
CoglPollDispatchCallback dispatch;
|
|
void *user_data;
|
|
};
|
|
|
|
int
|
|
cogl_poll_renderer_get_info (CoglRenderer *renderer,
|
|
CoglPollFD **poll_fds,
|
|
int *n_poll_fds,
|
|
int64_t *timeout)
|
|
{
|
|
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);
|
|
|
|
*timeout = -1;
|
|
|
|
if (!_cogl_list_empty (&renderer->idle_closures))
|
|
*timeout = 0;
|
|
|
|
/* 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);
|
|
if (source_timeout >= 0 &&
|
|
(*timeout == -1 || *timeout > source_timeout))
|
|
*timeout = source_timeout;
|
|
}
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
void
|
|
cogl_poll_renderer_dispatch (CoglRenderer *renderer,
|
|
const CoglPollFD *poll_fds,
|
|
int n_poll_fds)
|
|
{
|
|
GList *l, *next;
|
|
|
|
_COGL_RETURN_IF_FAIL (cogl_is_renderer (renderer));
|
|
|
|
_cogl_closure_list_invoke_no_args (&renderer->idle_closures);
|
|
|
|
/* 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);
|
|
continue;
|
|
}
|
|
|
|
for (i = 0; i < n_poll_fds; i++)
|
|
{
|
|
const CoglPollFD *pollfd = &poll_fds[i];
|
|
|
|
if (pollfd->fd == source->fd)
|
|
{
|
|
source->dispatch (source->user_data, pollfd->revents);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int
|
|
find_pollfd (CoglRenderer *renderer, int fd)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < renderer->poll_fds->len; i++)
|
|
{
|
|
CoglPollFD *pollfd = &g_array_index (renderer->poll_fds, CoglPollFD, i);
|
|
|
|
if (pollfd->fd == fd)
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void
|
|
_cogl_poll_renderer_remove_fd (CoglRenderer *renderer, int fd)
|
|
{
|
|
int i = find_pollfd (renderer, fd);
|
|
GList *l;
|
|
|
|
if (i < 0)
|
|
return;
|
|
|
|
g_array_remove_index_fast (renderer->poll_fds, i);
|
|
renderer->poll_fds_age++;
|
|
|
|
for (l = renderer->poll_sources; l; l = l->next)
|
|
{
|
|
CoglPollSource *source = l->data;
|
|
if (source->fd == fd)
|
|
{
|
|
renderer->poll_sources =
|
|
g_list_delete_link (renderer->poll_sources, l);
|
|
g_slice_free (CoglPollSource, source);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_poll_renderer_modify_fd (CoglRenderer *renderer,
|
|
int fd,
|
|
CoglPollFDEvent events)
|
|
{
|
|
int fd_index = find_pollfd (renderer, fd);
|
|
|
|
if (fd_index == -1)
|
|
g_warn_if_reached ();
|
|
else
|
|
{
|
|
CoglPollFD *pollfd =
|
|
&g_array_index (renderer->poll_sources, CoglPollFD, fd_index);
|
|
|
|
pollfd->events = events;
|
|
renderer->poll_fds_age++;
|
|
}
|
|
}
|
|
|
|
void
|
|
_cogl_poll_renderer_add_fd (CoglRenderer *renderer,
|
|
int fd,
|
|
CoglPollFDEvent events,
|
|
CoglPollPrepareCallback prepare,
|
|
CoglPollDispatchCallback dispatch,
|
|
void *user_data)
|
|
{
|
|
CoglPollFD pollfd = {
|
|
fd,
|
|
events
|
|
};
|
|
CoglPollSource *source;
|
|
|
|
_cogl_poll_renderer_remove_fd (renderer, fd);
|
|
|
|
source = g_slice_new0 (CoglPollSource);
|
|
source->fd = fd;
|
|
source->prepare = prepare;
|
|
source->dispatch = dispatch;
|
|
source->user_data = user_data;
|
|
|
|
renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
|
|
|
|
g_array_append_val (renderer->poll_fds, pollfd);
|
|
renderer->poll_fds_age++;
|
|
}
|
|
|
|
CoglPollSource *
|
|
_cogl_poll_renderer_add_source (CoglRenderer *renderer,
|
|
CoglPollPrepareCallback prepare,
|
|
CoglPollDispatchCallback dispatch,
|
|
void *user_data)
|
|
{
|
|
CoglPollSource *source;
|
|
|
|
source = g_slice_new0 (CoglPollSource);
|
|
source->fd = -1;
|
|
source->prepare = prepare;
|
|
source->dispatch = dispatch;
|
|
source->user_data = user_data;
|
|
|
|
renderer->poll_sources = g_list_prepend (renderer->poll_sources, source);
|
|
|
|
return source;
|
|
}
|
|
|
|
void
|
|
_cogl_poll_renderer_remove_source (CoglRenderer *renderer,
|
|
CoglPollSource *source)
|
|
{
|
|
GList *l;
|
|
|
|
for (l = renderer->poll_sources; l; l = l->next)
|
|
{
|
|
if (l->data == source)
|
|
{
|
|
renderer->poll_sources =
|
|
g_list_delete_link (renderer->poll_sources, l);
|
|
g_slice_free (CoglPollSource, source);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
CoglClosure *
|
|
_cogl_poll_renderer_add_idle (CoglRenderer *renderer,
|
|
CoglIdleCallback idle_cb,
|
|
void *user_data,
|
|
CoglUserDataDestroyCallback destroy_cb)
|
|
{
|
|
return _cogl_closure_list_add (&renderer->idle_closures,
|
|
idle_cb,
|
|
user_data,
|
|
destroy_cb);
|
|
}
|