<div dir="ltr"><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div><div>I wonder if the same effect could be achieved by few smaller changes. What I'm thinking about is something like:<br><br></div>wl_resource_set_intact()<br><br></div>So far I've got three ways how to achieve that:<br></div>1) change scanner so that it saves opcode of destructor events in wl_interface, so when we invoke a closure, we can bail out if the resource is intact and it is not a destructor<br></div>2) do the same but with wl_message<br><br></div>These first two options would break ABI, so I'm not fond of these.<br><br></div>3) add a sign to the siganture that the message is a destructor.<br><br></div>I went ahead and tried the last one locally. Generally, it work like this:<br><br></div>get_closure()<br></div>if (resource_is_intact && message_is_not_destructor)<br></div>    return<br></div><div>else</div>   invoke<br><br></div>(message_is_not_destructor <=> signature does not contain 'D')<br><br></div>This approach does not break ABI and is nicely compatible with old protocols. It only adds one function wl_resource_set_intact() (thus changes API) and the protocols must be re-generated and re-linked, but since it is backward-compatible it is not crucial dependency (old protocols will work, but message_is_not_destructor always return true)<br><br></div>What do you think?<br><br></div>Cheers,<br></div>Marek<br><div><div><div><div><div><div><div><br></div></div></div></div></div></div></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Feb 25, 2015 at 9:03 AM, David FORT <span dir="ltr"><<a href="mailto:rdp.effort@gmail.com" target="_blank">rdp.effort@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">As stated in the very good blog post[1] of Pekka Paalanen, server-side we can have<br>
sometime troubles with object that the server has deleted but that the client<br>
is still requesting. This patch complements the scanner to create some code<br>
that will return inert objects, ie objects that will do nothing and will never<br>
return anything else but an inert object. An example is a get_pointer() on<br>
a wl_seat, with an unplugged mouse (and so no pointer). Instead of keeping alive<br>
the old pointer, we could bind that inert object and wait that the client release<br>
it (which should happen very quickly as a wl_global_remove should be in the wire).<br>
<br>
[1]: <a href="http://ppaalanen.blogspot.fi/2014/07/wayland-protocol-design-object-lifespan.html" target="_blank">http://ppaalanen.blogspot.fi/2014/07/wayland-protocol-design-object-lifespan.html</a><br>
---<br>
 src/scanner.c      | 173 +++++++++++++++++++++++++++++++++++++++++++++++++----<br>
 <a href="http://wayland-scanner.mk" target="_blank">wayland-scanner.mk</a> |   3 +<br>
 2 files changed, 166 insertions(+), 10 deletions(-)<br>
<br>
diff --git a/src/scanner.c b/src/scanner.c<br>
index 1f1e59a..dbdd1f6 100644<br>
--- a/src/scanner.c<br>
+++ b/src/scanner.c<br>
@@ -39,7 +39,7 @@ enum side {<br>
 static int<br>
 usage(int ret)<br>
 {<br>
-       fprintf(stderr, "usage: ./scanner [client-header|server-header|code]\n");<br>
+       fprintf(stderr, "usage: ./scanner [client-header|server-header|code|server-inert]\n");<br>
        fprintf(stderr, "\n");<br>
        fprintf(stderr, "Converts XML protocol descriptions supplied on "<br>
                        "stdin to client headers,\n"<br>
@@ -626,6 +626,18 @@ emit_type(struct arg *a)<br>
        }<br>
 }<br>
<br>
+static struct arg *<br>
+get_return_type(struct message *m)<br>
+{<br>
+       struct arg *a, *ret = NULL;<br>
+<br>
+       wl_list_for_each(a, &m->arg_list, link) {<br>
+               if (a->type == NEW_ID)<br>
+                       ret = a;<br>
+       }<br>
+       return ret;<br>
+}<br>
+<br>
 static void<br>
 emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
 {<br>
@@ -688,11 +700,7 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)<br>
                        continue;<br>
                }<br>
<br>
-               ret = NULL;<br>
-               wl_list_for_each(a, &m->arg_list, link) {<br>
-                       if (a->type == NEW_ID)<br>
-                               ret = a;<br>
-               }<br>
+               ret = get_return_type(m);<br>
<br>
                if (ret && ret->interface_name == NULL)<br>
                        printf("static inline void *\n");<br>
@@ -1103,8 +1111,7 @@ emit_types(struct protocol *protocol, struct wl_list *message_list)<br>
                        case NEW_ID:<br>
                        case OBJECT:<br>
                                if (a->interface_name)<br>
-                                       printf("\t&%s_interface,\n",<br>
-                                              a->interface_name);<br>
+                                       printf("\t&%s_interface,\n", a->interface_name);<br>
                                else<br>
                                        printf("\tNULL,\n");<br>
                                break;<br>
@@ -1248,6 +1255,140 @@ emit_code(struct protocol *protocol)<br>
        }<br>
 }<br>
<br>
+static void<br>
+emit_inert_request(struct protocol *protocol, struct interface *interface, struct wl_list *message_list)<br>
+{<br>
+       struct message *m;<br>
+       struct arg *a, *ret;<br>
+       const char *newid_name;<br>
+<br>
+       wl_list_for_each(m, message_list, link) {<br>
+               ret = get_return_type(m);<br>
+<br>
+               /* forward declaration for the returned object */<br>
+               if (ret && ret->interface_name) {<br>
+                       printf("static void\n"<br>
+                                       "create_inert_%s(struct wl_client *client, uint32_t version, uint32_t id);\n"<br>
+                                       "\n",<br>
+                                       ret->interface_name);<br>
+               }<br>
+<br>
+               printf("static inline void inert_%s_%s(struct wl_client *client, struct wl_resource *resource",<br>
+                      interface->name, m->name<br>
+                      );<br>
+<br>
+               wl_list_for_each(a, &m->arg_list, link) {<br>
+                       if (a->type == NEW_ID) {<br>
+                               newid_name = a->name;<br>
+<br>
+                               if (a->interface_name == NULL) {<br>
+                                       printf(", const struct wl_interface *interface"<br>
+                                                  ", uint32_t version");<br>
+                                       continue;<br>
+                               }<br>
+                       }<br>
+<br>
+                       if (a->type == OBJECT) {<br>
+                               printf(", struct wl_resource *");<br>
+                       } else {<br>
+                               printf(", ");<br>
+                               emit_type(a);<br>
+                       }<br>
+                       printf("%s", a->name);<br>
+               }<br>
+<br>
+               printf(")\n"<br>
+                      "{\n");<br>
+<br>
+               if (ret && ret->interface_name) {<br>
+                       printf("\tcreate_inert_%s(client, wl_resource_get_version(resource), %s);\n",<br>
+                                       ret->interface_name, newid_name);<br>
+               } else if (m->destructor) {<br>
+                       printf("\twl_resource_destroy(resource);\n");<br>
+               }<br>
+               printf("}\n\n");<br>
+       }<br>
+}<br>
+<br>
+static void<br>
+emit_inert_interface(struct protocol *protocol, struct interface *i, struct wl_array *types) {<br>
+       struct message *m;<br>
+<br>
+<br>
+       if(wl_list_length(&i->request_list)) {<br>
+               emit_inert_request(protocol, i, &i->request_list);<br>
+<br>
+               printf ("static const struct %s_interface inert_%s_implementation = {\n",<br>
+                               i->name, i->name);<br>
+               wl_list_for_each(m, &i->request_list, link) {<br>
+                       printf("\tinert_%s_%s,\n", i->name, m->name);<br>
+               }<br>
+               printf ("};\n"<br>
+                               "\n");<br>
+       }<br>
+<br>
+       printf("static inline void\n"<br>
+                       "create_inert_%s(struct wl_client *client, uint32_t version, uint32_t id) {\n",<br>
+                       i->name<br>
+       );<br>
+<br>
+       if(wl_list_length(&i->request_list)) {<br>
+               /* emit the method body only when there is requests on the object */<br>
+               printf("\tstruct wl_resource *resource;\n"<br>
+                               "\tresource = wl_resource_create(client, &%s_interface, MIN(version, %d), id);\n"<br>
+                               "\twl_resource_set_implementation(resource, &inert_%s_implementation, NULL, wl_resource_destroy);\n",<br>
+                               i->name, i->version, i->name);<br>
+       }<br>
+<br>
+       printf("}\n"<br>
+                       "\n");<br>
+<br>
+}<br>
+<br>
+<br>
+static<br>
+void emit_inert(struct protocol *protocol) {<br>
+       struct interface *i;<br>
+       struct wl_array types;<br>
+<br>
+       if (protocol->copyright)<br>
+               format_copyright(protocol->copyright);<br>
+<br>
+       printf("#ifndef __%s_SERVER_INERT__\n"<br>
+                       "#define __%s_SERVER_INERT__\n"<br>
+                       "\n"<br>
+                       "#include \"%s-server-protocol.h\"\n"<br>
+                       "\n"<br>
+                       "#ifdef  __cplusplus\n"<br>
+                       "extern \"C\" {\n"<br>
+                       "#endif\n"<br>
+                       "\n"<br>
+                       "#ifndef MIN\n"<br>
+                       "#define MIN(x,y) (((x) < (y)) ? (x) : (y))\n"<br>
+                       "#endif\n"<br>
+                       "\n",<br>
+                       protocol->uppercase_name,<br>
+                       protocol->uppercase_name,<br>
+                       //protocol->name,<br>
+                       protocol->name<br>
+                       );<br>
+<br>
+       wl_list_for_each(i, &protocol->interface_list, link) {<br>
+               if (!strcmp(i->name, "wl_registry") || !strcmp(i->name, "wl_display"))<br>
+                       continue;<br>
+<br>
+               emit_inert_interface(protocol, i, &types);<br>
+       }<br>
+<br>
+       printf("\n"<br>
+                       "#ifdef  __cplusplus\n"<br>
+                       "}\n"<br>
+                       "#endif\n"<br>
+                       "\n"<br>
+                       "#endif\n");<br>
+<br>
+}<br>
+<br>
 int main(int argc, char *argv[])<br>
 {<br>
        struct parse_context ctx;<br>
@@ -1257,17 +1398,26 @@ int main(int argc, char *argv[])<br>
        enum {<br>
                CLIENT_HEADER,<br>
                SERVER_HEADER,<br>
+               SERVER_INERT,<br>
                CODE,<br>
        } mode;<br>
<br>
-       if (argc != 2)<br>
+       if (argc < 2) {<br>
                usage(EXIT_FAILURE);<br>
-       else if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0)<br>
+       }<br>
+<br>
+       if (argc > 2) {<br>
+               stdin = fopen(argv[2], "r");<br>
+       }<br>
+<br>
+       if (strcmp(argv[1], "help") == 0 || strcmp(argv[1], "--help") == 0)<br>
                usage(EXIT_SUCCESS);<br>
        else if (strcmp(argv[1], "client-header") == 0)<br>
                mode = CLIENT_HEADER;<br>
        else if (strcmp(argv[1], "server-header") == 0)<br>
                mode = SERVER_HEADER;<br>
+       else if (strcmp(argv[1], "server-inert") == 0)<br>
+               mode = SERVER_INERT;<br>
        else if (strcmp(argv[1], "code") == 0)<br>
                mode = CODE;<br>
        else<br>
@@ -1317,6 +1467,9 @@ int main(int argc, char *argv[])<br>
                case SERVER_HEADER:<br>
                        emit_header(&protocol, SERVER);<br>
                        break;<br>
+               case SERVER_INERT:<br>
+                       emit_inert(&protocol);<br>
+                       break;<br>
                case CODE:<br>
                        emit_code(&protocol);<br>
                        break;<br>
diff --git a/<a href="http://wayland-scanner.mk" target="_blank">wayland-scanner.mk</a> b/<a href="http://wayland-scanner.mk" target="_blank">wayland-scanner.mk</a><br>
index 0a72062..fd994e0 100644<br>
--- a/<a href="http://wayland-scanner.mk" target="_blank">wayland-scanner.mk</a><br>
+++ b/<a href="http://wayland-scanner.mk" target="_blank">wayland-scanner.mk</a><br>
@@ -6,3 +6,6 @@<br>
<br>
 %-client-protocol.h : $(wayland_protocoldir)/%.xml<br>
        $(AM_V_GEN)$(wayland_scanner) client-header < $< > $@<br>
+<br>
+%-server-inert.h: $(wayland_protocoldir)/%.xml<br>
+       $(AM_V_GEN)$(wayland_scanner) server-inert < $< > $@<br>
\ No newline at end of file<br>
<span class="HOEnZb"><font color="#888888">--<br>
1.9.1<br>
<br>
_______________________________________________<br>
wayland-devel mailing list<br>
<a href="mailto:wayland-devel@lists.freedesktop.org">wayland-devel@lists.freedesktop.org</a><br>
<a href="http://lists.freedesktop.org/mailman/listinfo/wayland-devel" target="_blank">http://lists.freedesktop.org/mailman/listinfo/wayland-devel</a><br>
</font></span></blockquote></div><br></div>