Wayland generic dispatching API proposal version 2
Jason Ekstrand
jason at jlekstrand.net
Mon Jan 14 19:34:34 PST 2013
Wayland devs:
A few weeks ago, I sent out a proposal on how we could extend the current
Wayland API to allow for more general event and request dispatching. I finally
got around to talking to Kristian about it and some of the ABI issues and
here's a second version of my proposal. I will also try and organize things a
bit better.
The core of the generic dispatching API would be a dispatcher function of the
following type:
void wl_libffi_server_dispatcher(struct wl_object * reciever, uint32_t opcode,
void *client, void *resource, union wl_argument *args);
where wl_argument is given by the following union:
union wl_argument {
int32_t i;
uint32_t u;
wl_fixed_t f;
const char * s;
struct wl_object * o;
uint32_t n;
struct wl_array * a;
int32_t h;
};
The exact meaning of the two void pointer arguments depends on whether the
dispatcher is for client-side or server-side. On the client side, the first is
the void pointer given to the library by the client code and the second is the
server-side object from which the event originates. On the server side, the
first is a pointer to the wl_client while the second is a pointer to the
wl_resource.
In order to allow the use of these dispatchers, we would modify wl_interface
and wl_object in the following way:
struct wl_interface {
const char *name;
unt32_t version;
int method_count;
const struct wl_message *methods;
int event_count;
const struct wl_message *events;
/* Added in version 1 */
void (*dispatcher)(struct wl_object *, uint32_t, void *, void *,
union wl_argument *);
};
struct wl_object {
const struct wl_interface *interface;
void *implementation;
uint32_t id;
};
First note that I have only made 3 changes:
* version is now of type int32_t in wl_interface
* added dispatcher field to the end of wl_interface
* implementation is now of type void * in wl_object
There would then be a few changes to the semantics of wl_interface.
Specifically, the version field would now come in two parts: an interface
version and a struct version. The bottom 16 bits would represent the interface
version as before while the top 16 bits would represent a structure version
with the original version of the structure being version 0. In this way, code
built against the original version of libwayland should not need any
modification as it should already be setting the version number to something
sufficiently low that the top 16 bits are zeros. However, of code wishes to
take advantage of the dispatcher field, it can set the top 16 bits to 1 to
specify the next version of the structure.
When sending an request (or an event in the client case), libwayland will look
at the structure version. If the structure version is at least 1, it will look
at the dispatcher. If the structure version is zero or if the dispatcher is
null, it will use the default dispatcher that uses libffi and attempt to call a
function off the C function table provided in the implementation field. If the
structure version is at least one and the dispatcher is not null, then it will
attempt to use the provided dispatcher. If it uses an external dispatcher,
then the implementation field in the wl_object is used by the external
dispatcher in whatever way it pleases.
Concerning ABI: The only change that should change the layout or packing of any
of the structures is the addition of the dispatcher field. However, we only
ever use pointers to wl_interface objects. Because of this, even if the
wl_interface object is created in client code that is using old header files,
the dispatcher field should never get accessed as long as version is set
reasonably.
Added functions: The second part of this proposal is to add a third version to
each of our sets of variadic functions (such as wl_resource_post_event). Each
of our variadic functions comes in both a variadic form and one that takes a
va_args argument. We would add a third version that takes an argument of type
union wl_argument * to allow for dynamic argument conversion. These functions
should be fairly simple and straightforward to implement.
There are a couple of specific advantages to adding custom dispatchers. The
first is that it makes it much easier to write language bindings for dynamic
languages like Java or Python since you can do argument conversion in a dynamic
way rather than having to auto-generate the argument conversion code. If, for
some reason, you wanted to be able to avoid libffi, it is easy to generate a
dispatcher for a specific C interface. For example, a dispatcher for
wl_display might look something like this:
void
wl_shm_pool_dispatcher(struct wl_object *object, uint32_t opcode, void *client,
void *resource, union wl_argument *args)
{
wl_display_interface *impl;
impl = (wl_display_interface *)object->implementation;
switch(opcode) {
case 0:
(*impl->sync)(client, resource, args[0].n);
break;
case 1:
(*impl->get_registry)(client, resource, args[0].n);
break;
}
}
Please forgive my probably incorrect function pointer casting and calling
semantics. I haven't tried to compile the above. If you wanted to create a
dispatcher for a specific implementation of an interface, it could be even
simpler. This provides at least the possibility of not having to depend on
libffi.
As always, questions and comments are welcome!
--Jason Ekstrand
More information about the wayland-devel
mailing list