<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>