Finishing the network protocol

Kristian Høgsberg krh at bitplanet.net
Thu Mar 3 12:14:01 PST 2011


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.

> 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