Rebased ref, commits from common ancestor:
commit 1361da9cd5a719b32d978485a29920429a31ed25
Author: Bryce Harrington <br...@osg.samsung.com>
Date:   Tue Feb 21 13:27:16 2017 -0800

    configure.ac: bump to version 1.13.0 for the official release

diff --git a/configure.ac b/configure.ac
index c50027b..fcce4ce 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
 AC_PREREQ([2.64])
 
 m4_define([wayland_major_version],  [1])
-m4_define([wayland_minor_version], [12])
-m4_define([wayland_micro_version], [93])
+m4_define([wayland_minor_version], [13])
+m4_define([wayland_micro_version],  [0])
 m4_define([wayland_version],
           [wayland_major_version.wayland_minor_version.wayland_micro_version])
 

commit 24df0fb6b3835c3b4574847491eecae769af4c2c
Author: Bryce Harrington <br...@osg.samsung.com>
Date:   Tue Feb 14 12:56:55 2017 -0800

    configure.ac: bump to version 1.12.93 for the RC1 release

diff --git a/configure.ac b/configure.ac
index 2a3d5e3..c50027b 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ([2.64])
 
 m4_define([wayland_major_version],  [1])
 m4_define([wayland_minor_version], [12])
-m4_define([wayland_micro_version], [92])
+m4_define([wayland_micro_version], [93])
 m4_define([wayland_version],
           [wayland_major_version.wayland_minor_version.wayland_micro_version])
 

commit 6161d7dd0efd33339a90bdfbc6f2575ff16f1b2f
Author: Bryce Harrington <br...@osg.samsung.com>
Date:   Tue Feb 7 15:14:56 2017 -0800

    configure.ac: bump to version 1.12.92 for the beta release

diff --git a/configure.ac b/configure.ac
index 7520b24..2a3d5e3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2,7 +2,7 @@ AC_PREREQ([2.64])
 
 m4_define([wayland_major_version],  [1])
 m4_define([wayland_minor_version], [12])
-m4_define([wayland_micro_version], [91])
+m4_define([wayland_micro_version], [92])
 m4_define([wayland_version],
           [wayland_major_version.wayland_minor_version.wayland_micro_version])
 

commit 56f2dad6d2ac04e179d43d525f6213031dcb4d62
Author: Pekka Paalanen <pekka.paala...@collabora.co.uk>
Date:   Wed Jan 25 14:24:44 2017 +0200

    wayland-server: hide wl_priv_signal from doxygen
    
    Fix this set of warnings appearing three times during a build:
    
    /home/pq/git/wayland/src/wayland-server.c:1868: warning: class
    `wl_priv_signal' for related function `wl_priv_signal_init' is not
    documented.
    /home/pq/git/wayland/src/wayland-server.c:1884: warning: class
    `wl_priv_signal' for related function `wl_priv_signal_add' is not
    documented.
    /home/pq/git/wayland/src/wayland-server.c:1899: warning: class
    `wl_priv_signal' for related function `wl_priv_signal_get' is not
    documented.
    
    Our Wayland docbook don't include private things, so make sure these do
    not end up there. This removes the mention of wl_priv_signal_emit from
    the Server API docbook. I have no idea why the other functions did not
    appear there.
    
    Signed-off-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>
    Reviewed-by: Yong Bakos <yba...@humanoriented.com>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index cdd46fa..6a8b3e4 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -1881,6 +1881,8 @@ wl_client_for_each_resource(struct wl_client *client,
        wl_map_for_each(&client->objects, resource_iterator_helper, &context);
 }
 
+/** \cond INTERNAL */
+
 /** Initialize a wl_priv_signal object
  *
  * wl_priv_signal is a safer implementation of a signal type, with the same API
@@ -1972,6 +1974,8 @@ wl_priv_signal_emit(struct wl_priv_signal *signal, void 
*data)
        }
 }
 
+/** \endcond INTERNAL */
+
 /** \cond */ /* Deprecated functions below. */
 
 uint32_t

commit 8fe8a2bb1e2b893bd39899f7481d5cf5fa303b29
Author: Yong Bakos <yba...@humanoriented.com>
Date:   Wed Nov 23 07:38:01 2016 -0800

    tests: Test wl_argument_from_va_list
    
    connection-test.c did not cover wl_argument_from_va_list, so add one
    test that specifically tests this method.
    
    Signed-off-by: Yong Bakos <yba...@humanoriented.com>
    Reviewed-by: Daniel Stone <dani...@collabora.com>

diff --git a/tests/connection-test.c b/tests/connection-test.c
index 3e34f77..1c688f1 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -130,6 +130,41 @@ TEST(connection_queue)
        close(s[1]);
 }
 
+static void
+va_list_wrapper(const char *signature, union wl_argument *args, int count, ...)
+{
+       va_list ap;
+       va_start(ap, count);
+       wl_argument_from_va_list(signature, args, count, ap);
+       va_end(ap);
+}
+
+TEST(argument_from_va_list)
+{
+       union wl_argument args[WL_CLOSURE_MAX_ARGS];
+       struct wl_object fake_object;
+       struct wl_array fake_array;
+
+       va_list_wrapper("i", args, 1, 100);
+       assert(args[0].i == 100);
+
+       va_list_wrapper("is", args, 2, 101, "value");
+       assert(args[0].i == 101);
+       assert(strcmp(args[1].s, "value") == 0);
+
+       va_list_wrapper("?iuf?sonah", args, 8,
+                       102, 103, wl_fixed_from_int(104), "value",
+                       &fake_object, 105, &fake_array, 106);
+       assert(args[0].i == 102);
+       assert(args[1].u == 103);
+       assert(args[2].f == wl_fixed_from_int(104));
+       assert(strcmp(args[3].s, "value") == 0);
+       assert(args[4].o == &fake_object);
+       assert(args[5].n == 105);
+       assert(args[6].a == &fake_array);
+       assert(args[7].h == 106);
+}
+
 struct marshal_data {
        struct wl_connection *read_connection;
        struct wl_connection *write_connection;

commit e89d0a66843eb3cb4d888c594ad87ef731e51697
Author: Yong Bakos <yba...@humanoriented.com>
Date:   Mon Jan 23 06:16:30 2017 -0800

    dtddata: Use standard permission notice
    
    Signed-off-by: Yong Bakos <yba...@humanoriented.com>
    Reviewed-by: Daniel Stone <dani...@collabora.com>

diff --git a/src/dtddata.S b/src/dtddata.S
index ce51133..2405066 100644
--- a/src/dtddata.S
+++ b/src/dtddata.S
@@ -1,23 +1,26 @@
 /*
  * Copyright � 2015 Collabora, Ltd.
  *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
  *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
  */
 
 /*

commit de908658945ef8e13b27b32a7a69f14b3f9356df
Author: Derek Foreman <der...@osg.samsung.com>
Date:   Tue Jan 24 12:07:21 2017 -0600

    wayland-server: log an error for events with wrong client objects
    
    Check that all the objects in an event belong to the same client as
    the resource posting it.  This prevents a compositor from accidentally
    mixing client objects and posting an event that causes a client to
    abort with a cryptic message.
    
    Instead the client will now be disconnected as it is when the compositor
    tries to send a null for a non-nullable object, and a log message
    will be printed by the compositor.
    
    Reviewed-by: Yong Bakos <yba...@humanoriented.com>
    Reviewed-by: Bryce Harrington <br...@osg.samsung.com>
    Signed-off-by: Derek Foreman <der...@osg.samsung.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index 0a5eacb..cdd46fa 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -168,6 +168,36 @@ log_closure(struct wl_resource *resource,
        }
 }
 
+static bool
+verify_objects(struct wl_resource *resource, uint32_t opcode,
+              union wl_argument *args)
+{
+       struct wl_object *object = &resource->object;
+       const char *signature = object->interface->events[opcode].signature;
+       struct argument_details arg;
+       struct wl_resource *res;
+       int count, i;
+
+       count = arg_count_for_signature(signature);
+       for (i = 0; i < count; i++) {
+               signature = get_next_argument(signature, &arg);
+               switch (arg.type) {
+               case 'n':
+               case 'o':
+                       res = (struct wl_resource *) (args[i].o);
+                       if (res && res->client != resource->client) {
+                               wl_log("compositor bug: The compositor "
+                                      "tried to use an object from one "
+                                      "client in a '%s.%s' for a different "
+                                      "client.\n", object->interface->name,
+                                      object->interface->events[opcode].name);
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
 static void
 handle_array(struct wl_resource *resource, uint32_t opcode,
             union wl_argument *args,
@@ -179,6 +209,11 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
        if (resource->client->error)
                return;
 
+       if (!verify_objects(resource, opcode, args)) {
+               resource->client->error = 1;
+               return;
+       }
+
        closure = wl_closure_marshal(object, opcode, args,
                                     &object->interface->events[opcode]);
 

commit efae9532e82e1faeb737fe0d3cf5932026ce1e6f
Author: Derek Foreman <der...@osg.samsung.com>
Date:   Tue Jan 24 12:07:20 2017 -0600

    server: Disallow sending events to clients after posting an error
    
    Until now, we haven't done anything to prevent sending additional
    events to clients after posting an error.
    
    Acked-by: Daniel Stone <dani...@collabora.com>
    Signed-off-by: Derek Foreman <der...@osg.samsung.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index a981fda..0a5eacb 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -176,6 +176,9 @@ handle_array(struct wl_resource *resource, uint32_t opcode,
        struct wl_closure *closure;
        struct wl_object *object = &resource->object;
 
+       if (resource->client->error)
+               return;
+
        closure = wl_closure_marshal(object, opcode, args,
                                     &object->interface->events[opcode]);
 
@@ -249,8 +252,6 @@ wl_resource_post_error(struct wl_resource *resource,
        vsnprintf(buffer, sizeof buffer, msg, ap);
        va_end(ap);
 
-       client->error = 1;
-
        /*
         * When a client aborts, its resources are destroyed in id order,
         * which means the display resource is destroyed first. If destruction
@@ -258,11 +259,12 @@ wl_resource_post_error(struct wl_resource *resource,
         * with a NULL display_resource. Do not try to send errors to an
         * already dead client.
         */
-       if (!client->display_resource)
+       if (client->error || !client->display_resource)
                return;
 
        wl_resource_post_event(client->display_resource,
                               WL_DISPLAY_ERROR, resource, code, buffer);
+       client->error = 1;
 }
 
 static int

commit 5fbc9daa409371d15ffb9012cc21dddc934fad4a
Author: Derek Foreman <der...@osg.samsung.com>
Date:   Tue Jan 24 12:07:19 2017 -0600

    server: Refactor array send functions
    
    These have grown a little in size but are almost identical, factor
    out the common code.
    
    Signed-off-by: Derek Foreman <der...@osg.samsung.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index ac634da..a981fda 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -168,9 +168,10 @@ log_closure(struct wl_resource *resource,
        }
 }
 
-WL_EXPORT void
-wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
-                            union wl_argument *args)
+static void
+handle_array(struct wl_resource *resource, uint32_t opcode,
+            union wl_argument *args,
+            int (*send_func)(struct wl_closure *, struct wl_connection *))
 {
        struct wl_closure *closure;
        struct wl_object *object = &resource->object;
@@ -183,7 +184,7 @@ wl_resource_post_event_array(struct wl_resource *resource, 
uint32_t opcode,
                return;
        }
 
-       if (wl_closure_send(closure, resource->client->connection))
+       if (send_func(closure, resource->client->connection))
                resource->client->error = 1;
 
        log_closure(resource, closure, true);
@@ -192,6 +193,13 @@ wl_resource_post_event_array(struct wl_resource *resource, 
uint32_t opcode,
 }
 
 WL_EXPORT void
+wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
+                            union wl_argument *args)
+{
+       handle_array(resource, opcode, args, wl_closure_send);
+}
+
+WL_EXPORT void
 wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
 {
        union wl_argument args[WL_CLOSURE_MAX_ARGS];
@@ -211,23 +219,7 @@ WL_EXPORT void
 wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
                              union wl_argument *args)
 {
-       struct wl_closure *closure;
-       struct wl_object *object = &resource->object;
-
-       closure = wl_closure_marshal(object, opcode, args,
-                                    &object->interface->events[opcode]);
-
-       if (closure == NULL) {
-               resource->client->error = 1;
-               return;
-       }
-
-       if (wl_closure_queue(closure, resource->client->connection))
-               resource->client->error = 1;
-
-       log_closure(resource, closure, true);
-
-       wl_closure_destroy(closure);
+       handle_array(resource, opcode, args, wl_closure_queue);
 }
 
 WL_EXPORT void

commit c44eed1c064999f1e0297088bacd56c602dee2eb
Author: Giulio Camuffo <giuliocamu...@gmail.com>
Date:   Tue Jan 24 16:34:30 2017 +0200

    server: use the new wl_priv_signal for wl_resource
    
    The old wl_signal is kept for backwards compatibility, as that is also
    present in the deprecated public wl_resource struct, and that must be
    kept working.
    
    Signed-off-by: Giulio Camuffo <giulio.camu...@kdab.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index 06f8ba2..ac634da 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -120,11 +120,16 @@ struct wl_resource {
        struct wl_object object;
        wl_resource_destroy_func_t destroy;
        struct wl_list link;
-       struct wl_signal destroy_signal;
+       /* Unfortunately some users of libwayland (e.g. mesa) still use the
+        * deprecated wl_resource struct, even if creating it with the new
+        * wl_resource_create(). So we cannot change the layout of the struct
+        * unless after the data field. */
+       struct wl_signal deprecated_destroy_signal;
        struct wl_client *client;
        void *data;
        int version;
        wl_dispatcher_func_t dispatcher;
+       struct wl_priv_signal destroy_signal;
 };
 
 struct wl_protocol_logger {
@@ -600,6 +605,31 @@ wl_resource_post_no_memory(struct wl_resource *resource)
                               WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
 }
 
+/** Detect if a wl_resource uses the deprecated public definition.
+ *
+ * Before Wayland 1.2.0, the definition of struct wl_resource was public.
+ * It was made opaque just before 1.2.0, and later new fields were added.
+ * The new fields cannot be accessed if a program is using the deprecated
+ * defition, as there would not be memory allocated for them.
+ *
+ * The creation pattern for the deprecated definition was wl_resource_init()
+ * followed by wl_client_add_resource(). wl_resource_init() was an inline
+ * function and no longer exists, but binaries might still carry it.
+ * wl_client_add_resource() still exists for ABI compatiblity.
+ */
+static bool
+resource_is_deprecated(struct wl_resource *resource)
+{
+       struct wl_map *map = &resource->client->objects;
+       int id = resource->object.id;
+
+       /* wl_client_add_resource() marks deprecated resources with the flag. */
+       if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY)
+               return true;
+
+       return false;
+}
+
 static enum wl_iterator_result
 destroy_resource(void *element, void *data)
 {
@@ -607,7 +637,11 @@ destroy_resource(void *element, void *data)
        struct wl_client *client = resource->client;
        uint32_t flags;
 
-       wl_signal_emit(&resource->destroy_signal, resource);
+       wl_signal_emit(&resource->deprecated_destroy_signal, resource);
+       /* Don't emit the new signal for deprecated resources, as that would
+        * access memory outside the bounds of the deprecated struct */
+       if (!resource_is_deprecated(resource))
+               wl_priv_signal_emit(&resource->destroy_signal, resource);
 
        flags = wl_map_lookup_flags(&client->objects, resource->object.id);
        if (resource->destroy)
@@ -719,14 +753,19 @@ WL_EXPORT void
 wl_resource_add_destroy_listener(struct wl_resource *resource,
                                 struct wl_listener * listener)
 {
-       wl_signal_add(&resource->destroy_signal, listener);
+       if (resource_is_deprecated(resource))
+               wl_signal_add(&resource->deprecated_destroy_signal, listener);
+       else
+               wl_priv_signal_add(&resource->destroy_signal, listener);
 }
 
 WL_EXPORT struct wl_listener *
 wl_resource_get_destroy_listener(struct wl_resource *resource,
                                 wl_notify_func_t notify)
 {
-       return wl_signal_get(&resource->destroy_signal, notify);
+       if (resource_is_deprecated(resource))
+               return wl_signal_get(&resource->deprecated_destroy_signal, 
notify);
+       return wl_priv_signal_get(&resource->destroy_signal, notify);
 }
 
 /** Retrieve the interface name (class) of a resource object.
@@ -1559,7 +1598,8 @@ wl_resource_create(struct wl_client *client,
        resource->object.interface = interface;
        resource->object.implementation = NULL;
 
-       wl_signal_init(&resource->destroy_signal);
+       wl_signal_init(&resource->deprecated_destroy_signal);
+       wl_priv_signal_init(&resource->destroy_signal);
 
        resource->destroy = NULL;
        resource->client = client;
@@ -1927,7 +1967,7 @@ wl_client_add_resource(struct wl_client *client,
        }
 
        resource->client = client;
-       wl_signal_init(&resource->destroy_signal);
+       wl_signal_init(&resource->deprecated_destroy_signal);
 
        return resource->object.id;
 }

commit 7454aa9bb9569a1d63f6bcb1938e165ea370a4a5
Author: Giulio Camuffo <giuliocamu...@gmail.com>
Date:   Tue Jan 24 16:34:29 2017 +0200

    server: use the new wl_priv_signal in wl_client
    
    Signed-off-by: Giulio Camuffo <giulio.camu...@kdab.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/src/wayland-server.c b/src/wayland-server.c
index 1482d5e..06f8ba2 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -78,10 +78,10 @@ struct wl_client {
        uint32_t mask;
        struct wl_list link;
        struct wl_map objects;
-       struct wl_signal destroy_signal;
+       struct wl_priv_signal destroy_signal;
        struct ucred ucred;
        int error;
-       struct wl_signal resource_created_signal;
+       struct wl_priv_signal resource_created_signal;
 };
 
 struct wl_display {
@@ -460,7 +460,7 @@ wl_client_create(struct wl_display *display, int fd)
        if (client == NULL)
                return NULL;
 
-       wl_signal_init(&client->resource_created_signal);
+       wl_priv_signal_init(&client->resource_created_signal);
        client->display = display;
        client->source = wl_event_loop_add_fd(display->loop, fd,
                                              WL_EVENT_READABLE,
@@ -483,7 +483,7 @@ wl_client_create(struct wl_display *display, int fd)
        if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0)
                goto err_map;
 
-       wl_signal_init(&client->destroy_signal);
+       wl_priv_signal_init(&client->destroy_signal);
        if (bind_display(client, display) < 0)
                goto err_map;
 
@@ -745,14 +745,14 @@ WL_EXPORT void
 wl_client_add_destroy_listener(struct wl_client *client,
                               struct wl_listener *listener)
 {
-       wl_signal_add(&client->destroy_signal, listener);
+       wl_priv_signal_add(&client->destroy_signal, listener);
 }
 
 WL_EXPORT struct wl_listener *
 wl_client_get_destroy_listener(struct wl_client *client,
                               wl_notify_func_t notify)
 {
-       return wl_signal_get(&client->destroy_signal, notify);
+       return wl_priv_signal_get(&client->destroy_signal, notify);
 }
 
 WL_EXPORT void
@@ -760,7 +760,7 @@ wl_client_destroy(struct wl_client *client)
 {
        uint32_t serial = 0;
 
-       wl_signal_emit(&client->destroy_signal, client);
+       wl_priv_signal_emit(&client->destroy_signal, client);
 
        wl_client_flush(client);
        wl_map_for_each(&client->objects, destroy_resource, &serial);
@@ -1575,7 +1575,7 @@ wl_resource_create(struct wl_client *client,
                return NULL;
        }
 
-       wl_signal_emit(&client->resource_created_signal, resource);
+       wl_priv_signal_emit(&client->resource_created_signal, resource);
        return resource;
 }
 
@@ -1763,7 +1763,7 @@ WL_EXPORT void
 wl_client_add_resource_created_listener(struct wl_client *client,
                                        struct wl_listener *listener)
 {
-       wl_signal_add(&client->resource_created_signal, listener);
+       wl_priv_signal_add(&client->resource_created_signal, listener);
 }
 
 struct wl_resource_iterator_context {

commit 5e6eb032294ecdee889600c604dfcaab0ffb9398
Author: Giulio Camuffo <giuliocamu...@gmail.com>
Date:   Tue Jan 24 16:34:28 2017 +0200

    server: add a safer signal type and port wl_display to it
    
    wl_list_for_each_safe, which is used by wl_signal_emit is not really
    safe. If a signal has two listeners, and the first one removes and
    re-inits the second one, it would enter an infinite loop, which was hit
    in weston on resource destruction, which emits a signal.
    This commit adds a new version of wl_signal, called wl_priv_signal,
    which is private in wayland-server.c and which does not have this problem.
    The old wl_signal cannot be improved without breaking backwards 
compatibility.
    
    Signed-off-by: Giulio Camuffo <giulio.camu...@kdab.com>
    Reviewed-by: Pekka Paalanen <pekka.paala...@collabora.co.uk>

diff --git a/Makefile.am b/Makefile.am
index d78a0ca..d0c8bd3 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -159,6 +159,7 @@ built_test_programs =                               \
        socket-test                             \
        queue-test                              \
        signal-test                             \
+       newsignal-test                          \
        resources-test                          \
        message-test                            \
        headers-test                            \
@@ -226,6 +227,9 @@ queue_test_SOURCES = tests/queue-test.c
 queue_test_LDADD = libtest-runner.la
 signal_test_SOURCES = tests/signal-test.c
 signal_test_LDADD = libtest-runner.la
+# wayland-server.c is needed here to access wl_priv_* functions
+newsignal_test_SOURCES = tests/newsignal-test.c src/wayland-server.c
+newsignal_test_LDADD = libtest-runner.la
 resources_test_SOURCES = tests/resources-test.c
 resources_test_LDADD = libtest-runner.la
 message_test_SOURCES = tests/message-test.c
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 676b181..434cb04 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -35,6 +35,7 @@
 #define WL_HIDE_DEPRECATED 1
 
 #include "wayland-util.h"
+#include "wayland-server-core.h"
 
 /* Invalid memory address */
 #define WL_ARRAY_POISON_PTR (void *) 4
@@ -233,4 +234,21 @@ zalloc(size_t s)
        return calloc(1, s);
 }
 
+struct wl_priv_signal {
+       struct wl_list listener_list;
+       struct wl_list emit_list;
+};
+
+void
+wl_priv_signal_init(struct wl_priv_signal *signal);
+
+void
+wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener 
*listener);
+
+struct wl_listener *
+wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify);
+
+void
+wl_priv_signal_emit(struct wl_priv_signal *signal, void *data);
+
 #endif
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 4360874..1482d5e 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -97,8 +97,8 @@ struct wl_display {
        struct wl_list client_list;
        struct wl_list protocol_loggers;
 
-       struct wl_signal destroy_signal;
-       struct wl_signal create_client_signal;
+       struct wl_priv_signal destroy_signal;
+       struct wl_priv_signal create_client_signal;
 
        struct wl_array additional_shm_formats;
 
@@ -489,7 +489,7 @@ wl_client_create(struct wl_display *display, int fd)
 
        wl_list_insert(display->client_list.prev, &client->link);
 
-       wl_signal_emit(&display->create_client_signal, client);
+       wl_priv_signal_emit(&display->create_client_signal, client);
 
        return client;
 
@@ -942,8 +942,8 @@ wl_display_create(void)
        wl_list_init(&display->registry_resource_list);
        wl_list_init(&display->protocol_loggers);
 
-       wl_signal_init(&display->destroy_signal);
-       wl_signal_init(&display->create_client_signal);
+       wl_priv_signal_init(&display->destroy_signal);
+       wl_priv_signal_init(&display->create_client_signal);
 
        display->id = 1;
        display->serial = 0;
@@ -1008,7 +1008,7 @@ wl_display_destroy(struct wl_display *display)
        struct wl_socket *s, *next;
        struct wl_global *global, *gnext;
 
-       wl_signal_emit(&display->destroy_signal, display);
+       wl_priv_signal_emit(&display->destroy_signal, display);
 
        wl_list_for_each_safe(s, next, &display->socket_list, link) {
                wl_socket_destroy(s);
@@ -1478,7 +1478,7 @@ WL_EXPORT void
 wl_display_add_destroy_listener(struct wl_display *display,
                                struct wl_listener *listener)
 {
-       wl_signal_add(&display->destroy_signal, listener);
+       wl_priv_signal_add(&display->destroy_signal, listener);
 }
 
 /** Registers a listener for the client connection signal.
@@ -1496,14 +1496,14 @@ WL_EXPORT void
 wl_display_add_client_created_listener(struct wl_display *display,
                                        struct wl_listener *listener)
 {
-       wl_signal_add(&display->create_client_signal, listener);
+       wl_priv_signal_add(&display->create_client_signal, listener);
 }
 
 WL_EXPORT struct wl_listener *
 wl_display_get_destroy_listener(struct wl_display *display,
                                wl_notify_func_t notify)
 {
-       return wl_signal_get(&display->destroy_signal, notify);
+       return wl_priv_signal_get(&display->destroy_signal, notify);
 }
 
 WL_EXPORT void
@@ -1812,6 +1812,97 @@ wl_client_for_each_resource(struct wl_client *client,
        wl_map_for_each(&client->objects, resource_iterator_helper, &context);
 }
 
+/** Initialize a wl_priv_signal object
+ *
+ * wl_priv_signal is a safer implementation of a signal type, with the same API
+ * as wl_signal, but kept as a private utility of libwayland-server.
+ * It is safer because listeners can be removed from within 
wl_priv_signal_emit()
+ * without corrupting the signal's list.
+ *
+ * Before passing a wl_priv_signal object to any other function it must be
+ * initialized by useing wl_priv_signal_init().
+ *
+ * \memberof wl_priv_signal
+ */
+void
+wl_priv_signal_init(struct wl_priv_signal *signal)
+{
+       wl_list_init(&signal->listener_list);
+       wl_list_init(&signal->emit_list);
+}
+
+/** Add a listener to a signal
+ *
+ * The new listener will be called when calling wl_signal_emit(). If a 
listener is
+ * added to the signal while wl_signal_emit() is running it will be called from
+ * the next time wl_priv_signal_emit() is called.
+ * To remove a listener call wl_list_remove() on its link member.
+ *
+ * \memberof wl_priv_signal
+ */
+void
+wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener)
+{
+       wl_list_insert(signal->listener_list.prev, &listener->link);
+}
+
+/** Get a listener added to a signal
+ *
+ * Returns the listener added to the given \a signal and with the given
+ * \a notify function, or NULL if there isn't any.
+ * Calling this function from withing wl_priv_signal_emit() is safe and will
+ * return the correct value.
+ *
+ * \memberof wl_priv_signal
+ */
+struct wl_listener *
+wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify)
+{
+       struct wl_listener *l;
+
+       wl_list_for_each(l, &signal->listener_list, link)
+               if (l->notify == notify)
+                       return l;
+       wl_list_for_each(l, &signal->emit_list, link)
+               if (l->notify == notify)
+                       return l;
+
+       return NULL;
+}
+
+/** Emit the signal, calling all the installed listeners
+ *
+ * Iterate over all the listeners added to this \a signal and call
+ * their \a notify function pointer, passing on the given \a data.
+ * Removing or adding a listener from within wl_priv_signal_emit()
+ * is safe.
+ */
+void
+wl_priv_signal_emit(struct wl_priv_signal *signal, void *data)
+{
+       struct wl_listener *l;
+       struct wl_list *pos;
+
+       wl_list_insert_list(&signal->emit_list, &signal->listener_list);
+       wl_list_init(&signal->listener_list);
+
+       /* Take every element out of the list and put them in a temporary list.
+        * This way, the 'it' func can remove any element it wants from the list
+        * without troubles, because we always get the first element, not the
+        * one after the current, which may be invalid.
+        * wl_list_for_each_safe tries to be safe but it fails: it works fine
+        * if the current item is removed, but not if the next one is. */
+       while (!wl_list_empty(&signal->emit_list)) {
+               pos = signal->emit_list.next;
+               l = wl_container_of(pos, l, link);
+
+               wl_list_remove(pos);
+               wl_list_insert(&signal->listener_list, pos);
+
+               l->notify(l, data);
+       }
+}
+
 /** \cond */ /* Deprecated functions below. */
 
 uint32_t
diff --git a/tests/newsignal-test.c b/tests/newsignal-test.c
new file mode 100644
index 0000000..47c429b
--- /dev/null
+++ b/tests/newsignal-test.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "test-runner.h"
+#include "wayland-private.h"
+
+static void
+signal_notify(struct wl_listener *listener, void *data)
+{
+       /* only increase counter*/
+       ++(*((int *) data));
+}
+
+TEST(signal_init)
+{
+       struct wl_priv_signal signal;
+
+       wl_priv_signal_init(&signal);
+
+       /* Test if listeners' list is initialized */
+       assert(&signal.listener_list == signal.listener_list.next
+               && "Maybe wl_priv_signal implementation changed?");
+       assert(signal.listener_list.next == signal.listener_list.prev
+               && "Maybe wl_priv_signal implementation changed?");
+}
+
+TEST(signal_add_get)
+{
+       struct wl_priv_signal signal;
+
+       /* we just need different values of notify */
+       struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1};
+       struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2};
+       struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3};
+       /* one real, why not */
+       struct wl_listener l4 = {.notify = signal_notify};
+
+       wl_priv_signal_init(&signal);
+
+       wl_priv_signal_add(&signal, &l1);
+       wl_priv_signal_add(&signal, &l2);
+       wl_priv_signal_add(&signal, &l3);
+       wl_priv_signal_add(&signal, &l4);
+
+       assert(wl_priv_signal_get(&signal, signal_notify) == &l4);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+
+       /* get should not be destructive */
+       assert(wl_priv_signal_get(&signal, signal_notify) == &l4);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+       assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+}
+
+TEST(signal_emit_to_one_listener)
+{
+       int count = 0;
+       int counter;
+
+       struct wl_priv_signal signal;
+       struct wl_listener l1 = {.notify = signal_notify};
+
+       wl_priv_signal_init(&signal);
+       wl_priv_signal_add(&signal, &l1);
+
+       for (counter = 0; counter < 100; counter++)
+               wl_priv_signal_emit(&signal, &count);
+
+       assert(counter == count);
+}
+
+TEST(signal_emit_to_more_listeners)
+{
+       int count = 0;
+       int counter;
+
+       struct wl_priv_signal signal;
+       struct wl_listener l1 = {.notify = signal_notify};
+       struct wl_listener l2 = {.notify = signal_notify};
+       struct wl_listener l3 = {.notify = signal_notify};
+
+       wl_priv_signal_init(&signal);
+       wl_priv_signal_add(&signal, &l1);
+       wl_priv_signal_add(&signal, &l2);

Reply via email to