[PATCH] event-loop: Allow source dispatches to remove other sources
Ander Conselvan de Oliveira
conselvan2 at gmail.com
Tue Mar 20 05:19:22 PDT 2012
Hi,
See comments below.
On 03/20/2012 12:31 PM, Andreas Ericsson wrote:
> When a dispatch for sourceA wishes to remove sourceB and sourceB
> has input that isn't yet processed, we would run into the dreaded
> "undefined behaviour" previously.
>
> With this patch, the destroyed source is ignored while processing
> input and is later free()'d in the post_dispatch_check() loop.
>
> Signed-off-by: Andreas Ericsson<ae at op5.se>
> ---
>
> I actually haven't managed to build wayland yet, and since I'm stuck
> with an nvidia videocard it's not likely to happen anytime in the
> near future either, so this patch is, unfortunately, totally untested.
>
> src/event-loop.c | 42 ++++++++++++++++++++++++++++++++++++++----
> 1 files changed, 38 insertions(+), 4 deletions(-)
>
> diff --git a/src/event-loop.c b/src/event-loop.c
> index 2dfe0ae..02d5163 100644
> --- a/src/event-loop.c
> +++ b/src/event-loop.c
> @@ -37,6 +37,7 @@
>
> struct wl_event_loop {
> int epoll_fd;
> + int *source_flags;
> struct wl_list check_list;
> struct wl_list idle_list;
> };
This field is not used anywhere. I guess you meant to add 'int
dispatching;' instead that is used below.
> @@ -48,6 +49,7 @@ struct wl_event_source_interface {
> };
>
> struct wl_event_source {
> + int destroyed;
> struct wl_event_source_interface *interface;
> struct wl_event_loop *loop;
> struct wl_list link;
> @@ -85,7 +87,21 @@ wl_event_source_fd_remove(struct wl_event_source *source)
> int fd;
>
> fd = fd_source->fd;
> - free(source);
> +
> + /*
> + * a running dispatch can remove another source, which
> + * will cause crashes if that other source is also queued
> + * for dispatch, since we'll grab the source pointer from
> + * the epoll event. If that happens, we have to mark the
> + * source as destroyed here instead of free()'ing so we
> + * know not to touch it later.
> + */
> + if (loop->dispatching) {
> + source->destroyed = 1;
> + wl_event_source_check(source);
> + } else {
> + free(source);
> + }
>
> return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
> }
This logic should be in wl_event_source_remove() so that it also covers
signal source, timer sources, etc. I'm not sure how you would do
EPOLL_CTL_DEL from there though. Maybe there could be a disable hook, so
you call disable early but remove only on post dispatch check.
Also, wl_event_source_check() does not check if source is already in the
check list. If the same item is inserted twice you end up with a
corrupted list.
> @@ -104,7 +120,10 @@ wl_event_loop_add_fd(struct wl_event_loop *loop,
> struct wl_event_source_fd *source;
> struct epoll_event ep;
>
> - source = malloc(sizeof *source);
> + if (fd< 0)
> + return NULL;
> +
> + source = calloc(1, sizeof *source);
> if (source == NULL)
> return NULL;
All of wl_event_loop_add_{signal,timer,idle} need to initialize
source->destroyed.
Cheers,
Ander
More information about the wayland-devel
mailing list