Finishing the network protocol

Andreas Hartmetz ahartmetz at gmail.com
Thu Mar 3 12:47:03 PST 2011


On Thursday 03 March 2011 21:14:01 Kristian Høgsberg wrote:
> On Thu, Mar 3, 2011 at 12:34 PM, Andreas Hartmetz <ahartmetz at gmail.com> 
wrote:
> > On Thursday 03 March 2011 15:58:14 Kristian Høgsberg wrote:
> >> On Thu, Mar 3, 2011 at 9:32 AM, Andreas Hartmetz <ahartmetz at gmail.com>
> > 
> > wrote:
> >> > Hello again and sorry for taking a few days to reply.
> >> 
> >> ...
> >> 
> >> >> > - A scheme to recycle object IDs. When a new ID is needed, pick a
> >> >> > free one at random. This introduces a problem:
> >> >> >  Suppose the client destroys object A with ID n, then by chance
> >> >> >  immediately reuses ID n for object B.
> >> >> >  The server will only receive this information later, the Wayland
> >> >> >  protocol being asynchronous and the server not having to respond
> >> >> > to an object creation request, unless it goes wrong. In the
> >> >> > meantime the server could send an event intended for A which would
> >> >> > end up at B, causing Bad Things to happen - in my implementation
> >> >> > most likely an assert failure unless the objects are of the same
> >> >> > class.
> >> >> >  (This is the trickiest failure mode I could think of)
> >> >> >  The suggested solution is a kind of "rendezvous" for objects where
> >> >> > this can happen, or for simplicity all objects:
> >> >> >  On both client and server, have a function that needs to be called
> >> >> >  twice to unregister an object ID.
> >> >> >  One call from the destructor of the local object when it destroys
> >> >> >  itself, one call from the remote counterpart object when it
> >> >> > destroys itself. No matter in which order the method is called,
> >> >> > the first call removes the ID<->object mapping and puts the object
> >> >> > ID on a waiting list to avoid reuse. The second call removes the
> >> >> > ID from the waiting list, making it free to reuse.
> >> >> 
> >> >> Ah, yes, very good point.  I was going to suggest that there could be
> >> >> an event that the server sends to acknowledge that it has bound and
> >> >> object to a client ID (whether through the bind request above or from
> >> >> the client creating a client object), but if we reuse the same ID too
> >> >> fast, then it's still unclear which object the ID refers to.  That
> >> >> could be fixed by adding a serial number, but at that point I think
> >> >> your idea is better and simpler.  In fact, with your idea, we can
> >> >> distinguish between events sent from an object that we've destroyed
> >> >> and server errors where the server sends an event from an object that
> >> >> never existed.
> >> > 
> >> > I've started implementing this in my project and I've hit a problem:
> >> > while the destroy() methods are basically regular methods that get an
> >> > opcode the regular way, the confirmation message also needs an opcode.
> >> > The idea I outlined above, that I maybe didn't explain optimally,
> >> > contains that a destroy request looks exactly like a destroy
> >> > confirmation. That way both sides can handle destruction the same way:
> >> > If the object was locally destroyed, destroy the instance and send a
> >> > destroy() call to the other side. The other side will send back a
> >> > destroy() when it's done destroying. Both sides will unregister the ID
> >> > when destroy() has been both sent and received, keeping track with two
> >> > boolean flags. That way exactly one destroy() call is sent to the
> >> > other side.
> >> > 
> >> > In a nutshell, I think destroy() should implicitly be both a request
> >> > and a response whenever it appears in a client-created object. The
> >> > methods could actually be added implicitly to all client-created
> >> > objects which wouldn't be more of a hack than "doubling" one
> >> > ocurrence of destroy() or adding a flag like has_destructor="true",
> >> > which btw would also be fine with me.
> >> 
> >> Can't we just add a "destroyed" event to the display interface?
> > 
> > I really like the concept of doing everything to an object by calling
> > methods on that object, as far as possible. Destroying objects via the
> > display object breaks that concept, which is the main reason why I don't
> > like it. I program in languages with built-in OOP support most of the
> > time and it would seem wrong to ask object A to destroy object B.
> 
> No, what I suggested was adding an "event" to the display interface,
> not a request.  You still need to call surface.destroy, for example,
> but the server will acknowledge that it freed up the ID by sending
> display.destroyed to the client.
> 
> But I've been thinking about the problem some more, and we have the
> same problem when the server destroys one of its objects.  If the
> server quickly reuses the ID, a client may send a request to the old
> object ID, which is now in use by the new object.  The bind request
> solves this since the client will have to bind the new object ID
> before it can send requests to it so there's no longer any confusion.
> And I'm now leaning more towards having the server acknowledge the
> bind request instead.  The client can simply just refuse any events
> sent from an object that the server hasn't yet acknowledged the bind
> request for.
> 
The mechanism I suggested is completely symmetric, it doesn't matter who 
initiates destruction. Both sides can do it.
The destroy() call can serve to confirm or to initiate destruction of an 
object. Even if both sides decide to destroy the object at the same time, they 
will both send destroy() and not send anything back because they know from 
their internal state that it's already been sent.

I still think that adding an explicit subscription mechanism is not necessary 
(and therefore not right because protocols should be minimal), although a 
special mechanism to handle one object sending messages to all clients that 
have an instance of the respective listener interface still required. It could 
look just like creating an object to the client, with a little extra code on 
the server side to handle event distribution.

> > My Connection class provides most of the glue between the local socket
> > and the interfaces, which is IMHO not very much related to the display
> > interface. Connection is the place where ID-object maps are, which will
> > probably look similar in Wayland with per-client ID spaces. One good
> > reason for that is that Connection can be used almost the same way in
> > client and server
> > (symmetrically), while doing it via display would look quite different on
> > client and server side.
> > I have consciously avoided making display the "god interface" any more
> > than necessary for boostrapping in my network implementation. The
> > display class that comes out of the code generator is just another
> > Wayland object; notably it doesn't have a list of objects it owns. I
> > don't know what the implementation of display will look like, and I
> > certainly don't want to force any decisions about it.
> > I may or may not make Connection owned by a display instance later, but
> > so far it looks like most likely not.
> 
> Yeah, it was always my intention that the first and only hardcoded
> object shouldn't be graphics/compositor related but just a IPC
> management object type of thing.  The only thing that's out of place
> in the current display object is the frame request, and we need to
> move that to the surface interface anyway, so the server can take into
> account which output the surface is displayed on.  So when I move
> that, I think I'll rename "display" to "registry", since at that point
> it will be exclusively an object registry and IPC related requests and
> events.
> 
> Kristian


More information about the wayland-devel mailing list