[RFC wayland 10/18] scanner: Add the concept of "pre hooks"

Mike Blumenkrantz zmike at samsung.com
Tue Feb 9 17:50:01 UTC 2016


On Tue, 09 Feb 2016 10:55:57 -0600
Derek Foreman <derekf at osg.samsung.com> wrote:

> A pre hook is a wayland library call made on the client side before the
> request is sent.
> 
> Until now the wayland library has simply passed requests on without any
> knowledge of what they mean, and the receiving compositor has all the
> logic.  For network transparency to be truly transparent, the library
> needs to intercept some things on the client side (buffer set-up, damage
> posting) and send along additional information.
> 
> pre-hooks make that possible.
> 
> Signed-off-by: Derek Foreman <derekf at osg.samsung.com>
> ---
>  protocol/wayland.dtd      |   1 +
>  src/scanner.c             | 108 +++++++++++++++++++++++++++++++++++++++++++---
>  src/wayland-client-core.h |  10 +++++
>  src/wayland-client.c      |  13 ++++++
>  4 files changed, 126 insertions(+), 6 deletions(-)
> 
> diff --git a/protocol/wayland.dtd b/protocol/wayland.dtd
> index 15f20ab..15ca9cc 100644
> --- a/protocol/wayland.dtd
> +++ b/protocol/wayland.dtd
> @@ -8,6 +8,7 @@
>    <!ATTLIST request name CDATA #REQUIRED>
>    <!ATTLIST request type CDATA #IMPLIED>
>    <!ATTLIST request since CDATA #IMPLIED>
> +  <!ATTLIST request hooked CDATA #IMPLIED>
>  <!ELEMENT event (description?,arg*)>
>    <!ATTLIST event name CDATA #REQUIRED>
>    <!ATTLIST event since CDATA #IMPLIED>
> diff --git a/src/scanner.c b/src/scanner.c
> index 9a74e93..e598200 100644
> --- a/src/scanner.c
> +++ b/src/scanner.c
> @@ -170,6 +170,7 @@ struct message {
>  	int destructor;
>  	int since;
>  	struct description *description;
> +	bool hooked;
>  };
>  
>  enum arg_type {
> @@ -609,6 +610,7 @@ start_element(void *data, const char *element_name, const char **atts)
>  	const char *allow_null = NULL;
>  	const char *enumeration_name = NULL;
>  	const char *bitfield = NULL;
> +	const char *hooked = NULL;
>  	int i, version = 0;
>  
>  	ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
> @@ -636,6 +638,8 @@ start_element(void *data, const char *element_name, const char **atts)
>  			enumeration_name = atts[i + 1];
>  		if (strcmp(atts[i], "bitfield") == 0)
>  			bitfield = atts[i + 1];
> +		if (strcmp(atts[i], "hooked") == 0)
> +			hooked = atts[i + 1];
>  	}
>  
>  	ctx->character_data_length = 0;
> @@ -665,6 +669,15 @@ start_element(void *data, const char *element_name, const char **atts)
>  
>  		message = create_message(ctx->loc, name);
>  
> +		if (hooked) {
> +			if (strcmp(hooked, "true") == 0)
> +				message->hooked = true;
> +			else if (strcmp(hooked, "false") != 0)
> +				fail(&ctx->loc,
> +				     "invalid value for hooked attribute (%s)",
> +				     hooked);
> +		}
> +
>  		if (strcmp(element_name, "request") == 0)
>  			wl_list_insert(ctx->interface->request_list.prev,
>  				       &message->link);
> @@ -938,6 +951,79 @@ emit_type(struct arg *a)
>  }
>  
>  static void
> +emit_pre_hook_prototype(struct message *m, struct interface *interface, struct arg *r)
> +{
> +	struct arg *a;
> +
> +	if (r)
> +		printf("void *\n");
> +	else
> +		printf("void\n");
> +
> +	printf("%s_%s_pre_hook(struct %s *",
> +	       interface->name, m->name, interface->name);
> +	wl_list_for_each(a, &m->arg_list, link) {
> +		if (a->type == NEW_ID && a->interface_name == NULL) {
> +			printf(", const struct wl_interface *interface"
> +			       ", uint32_t version");
> +			continue;
> +		} else if (a->type == NEW_ID)
> +			continue;
> +		printf(", ");
> +		emit_type(a);
> +		printf("%s", a->name);
> +	}
> +	printf(");");
> +}
> +
> +static void
> +emit_pre_hooks(struct wl_list *message_list, struct interface *interface)
> +{
> +	struct message *m;
> +	int hooks = 0;
> +
> +	if (wl_list_empty(message_list))
> +		return;
> +	wl_list_for_each(m, message_list, link) {
> +		struct arg *a, *ret = NULL;
> +
> +		if (!m->hooked)
> +			continue;
> +
> +		wl_list_for_each(a, &m->arg_list, link) {
> +			if (a->type == NEW_ID)
> +				ret = a;
> +		}
> +
> +		emit_pre_hook_prototype(m, interface, ret);
> +		hooks++;
> +	}
> +	if (hooks)
> +		printf("\n");
> +}
> +
> +static void emit_call_pre_hook(struct interface *interface, struct arg *ret, struct message *m)
> +{
> +	struct arg *a;
> +
> +	if (ret) {
> +		printf("\tvoid *hook_data = %s_%s_pre_hook(%s", interface->name, m->name, interface->name);
> +	} else
> +		printf("\t%s_%s_pre_hook(%s", interface->name, m->name, interface->name);
> +	wl_list_for_each(a, &m->arg_list, link) {
> +		if (a->type == NEW_ID && a->interface_name == NULL) {
> +			printf(", interface"
> +			       ", version");
> +			continue;
> +		} else if (a->type == NEW_ID)
> +			continue;
> +		printf(", ");
> +		printf("%s", a->name);
> +	}
> +	printf(");\n");
> +}
> +
> +static void
>  emit_stubs(struct wl_list *message_list, struct interface *interface)
>  {
>  	struct message *m;
> @@ -1042,27 +1128,33 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
>  		if (ret && ret->interface_name == NULL) {
>  			/* an arg has type ="new_id" but interface is not
>  			 * provided, such as in wl_registry.bind */
> -			printf("\tstruct wl_proxy *%s;\n\n"
> -			       "\t%s = wl_proxy_marshal_constructor_versioned("
> +			printf("\tstruct wl_proxy *%s;\n\n", ret->name);
> +			if (m->hooked)
> +				emit_call_pre_hook(interface, ret, m);
> +			printf("\t%s = wl_proxy_marshal_constructor_versioned("
>  			       "(struct wl_proxy *) %s,\n"
>  			       "\t\t\t %s_%s, interface, version",
> -			       ret->name, ret->name,
> +			       ret->name,
>  			       interface->name,
>  			       interface->uppercase_name,
>  			       m->uppercase_name);
>  		} else if (ret) {
>  			/* Normal factory case, an arg has type="new_id" and
>  			 * an interface is provided */
> -			printf("\tstruct wl_proxy *%s;\n\n"
> -			       "\t%s = wl_proxy_marshal_constructor("
> +			printf("\tstruct wl_proxy *%s;\n\n", ret->name);
> +			if (m->hooked)
> +				emit_call_pre_hook(interface, ret, m);
> +			printf("\t%s = wl_proxy_marshal_constructor("
>  			       "(struct wl_proxy *) %s,\n"
>  			       "\t\t\t %s_%s, &%s_interface",
> -			       ret->name, ret->name,
> +			       ret->name,
>  			       interface->name,
>  			       interface->uppercase_name,
>  			       m->uppercase_name,
>  			       ret->interface_name);
>  		} else {
> +			if (m->hooked)
> +				emit_call_pre_hook(interface, ret, m);
>  			/* No args have type="new_id" */
>  			printf("\twl_proxy_marshal((struct wl_proxy *) %s,\n"
>  			       "\t\t\t %s_%s",
> @@ -1087,6 +1179,9 @@ emit_stubs(struct wl_list *message_list, struct interface *interface)
>  			       "(struct wl_proxy *) %s);\n",
>  			       interface->name);
>  
> +		if (ret && m->hooked)
> +			printf("\twl_proxy_set_hook_data(id, hook_data);\n");
> +
>  		if (ret && ret->interface_name == NULL)
>  			printf("\n\treturn (void *) %s;\n", ret->name);
>  		else if (ret)
> @@ -1434,6 +1529,7 @@ emit_header(struct protocol *protocol, enum side side)
>  			emit_structs(&i->event_list, i, side);
>  			emit_opcodes(&i->request_list, i);
>  			emit_opcode_versions(&i->request_list, i);
> +			emit_pre_hooks(&i->request_list, i);
>  			emit_stubs(&i->request_list, i);
>  		}
>  
> diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
> index 91f7e7b..782b736 100644
> --- a/src/wayland-client-core.h
> +++ b/src/wayland-client-core.h
> @@ -28,6 +28,7 @@
>  
>  #include "wayland-util.h"
>  #include "wayland-version.h"
> +#include <stdbool.h>
>  
>  #ifdef  __cplusplus
>  extern "C" {
> @@ -176,6 +177,15 @@ wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
>  void *
>  wl_proxy_get_user_data(struct wl_proxy *proxy);
>  
> +void
> +wl_proxy_set_hook_data(struct wl_proxy *proxy, void *hook_data);
> +
> +void *
> +wl_proxy_get_hook_data(struct wl_proxy *proxy);
> +
> +bool
> +wl_proxy_get_remote(struct wl_proxy *proxy);
> +
>  uint32_t
>  wl_proxy_get_version(struct wl_proxy *proxy);
>  
> diff --git a/src/wayland-client.c b/src/wayland-client.c
> index 5c5ecd3..8e7f612 100644
> --- a/src/wayland-client.c
> +++ b/src/wayland-client.c
> @@ -63,6 +63,7 @@ struct wl_proxy {
>  	void *user_data;
>  	wl_dispatcher_func_t dispatcher;
>  	uint32_t version;
> +	void *hook_data;
>  };
>  
>  struct wl_global {
> @@ -1856,6 +1857,12 @@ wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
>  	proxy->user_data = user_data;
>  }
>  
> +WL_EXPORT void
> +wl_proxy_set_hook_data(struct wl_proxy *proxy, void *hook_data)
> +{
> +	proxy->hook_data = hook_data;
> +}
> +
>  /** Get the user data associated with a proxy
>   *
>   * \param proxy The proxy object
> @@ -1891,6 +1898,12 @@ wl_proxy_get_version(struct wl_proxy *proxy)
>  	return proxy->version;
>  }
>  
> +WL_EXPORT void *
> +wl_proxy_get_hook_data(struct wl_proxy *proxy)
> +{
> +	return proxy->hook_data;
> +}
> +
>  /** Get the id of a proxy object
>   *
>   * \param proxy The proxy object

Is "hook" the best term? I think I like "intercept" better in this case: consider that something here is "intercepting" the marshallization process and modifying it to contain an additional payload rather than "hooking" it to perform an action.


More information about the wayland-devel mailing list