input handlig in separate thread

Bill Spitzak spitzak at gmail.com
Fri Oct 18 21:43:13 CEST 2013


Giulio Camuffo wrote:
> And what is it that doesn't work? As a wild bet I'd say you probably
> want to look at wl_event_queue.
> See http://wayland.freedesktop.org/docs/html/chap-Library.html#sect-Library-Client

This brings up some questions I have had about making a complete wayland 
client. The documentation says you should do this:

   while (wl_display_prepare_read(display) != 0)
     wl_display_dispatch_pending(display);
   wl_display_flush(display);
   poll(fds, nfds, -1);
   wl_display_read_events(display);
   wl_display_dispatch_pending(display);

Now a "real" application or toolkit will need to do a few other things:

* It has to loop

* It has to respond to other fds than the wayland one (yes this could be 
done with threads but I am assuming situations where the overhead and 
difficulty with threads is greater than just handling it in the main 
thread).

* It has to handle timeouts (same comment about threads)

* Most important: it has to have an "idle" (Qt calls it "aboutToBlock") 
handling. FLTK and our Qt programs rely on doing perhaps 90% of their 
work in this, to produce smooth and responsive update with minimal 
overhead. I think *all* toolkits use this as a "now is the time to draw 
all the windows" event.

I will add them here in what I think is the proper places, please inform 
me if this is wrong. The trick is that I have to make sure I don't call 
poll() when any pending events or the queue unlocked, and that any of 
the dispatches can cause more pending events:

   while (!quit) { //ADDED
     while (wl_display_prepare_read(display) != 0) {
       wl_display_dispatch_pending(display);
       dispatch_idle(); // ADDED
     }
     wl_display_flush(display);
     poll(...); // with timeout if necessary
     dispatch_other_fds(); // ADDED
     dispatch_expired_timeouts(); // ADDED
     wl_display_read_events(display);
     wl_display_dispatch_pending(display);
     dispatch_idle(); // ADDED
   }

The above code assumes that wl_display_dispatch_pending() will consume 
events made pending by it's own dispatches (ie it loops until the queue 
is empty, rather than looping over all events that happen to be in the 
queue when it is called). If this is not true then dispatch_idle() will 
be called more than necessary.

This I believe can be simplified by moving the end of the loop to the 
start to merge identical code, is this correct: ? This reduces the 
number of checks that the queue is empty by at least one:

   bool first = true;
   while (!quit) {
     if (first) first = false;
     else wl_display_read_events(display);
     do {
       wl_display_dispatch_pending(display);
       dispatch_idle();
     } while (wl_display_prepare_read(display) != 0);
     wl_display_flush(display);
     poll(...); // with timeout if necessary
     dispatch_other_fds();
     dispatch_expired_timeouts();
   }

Note: the reason it does the "first" check, rather than putting the 
wl_display_read_events at the end, is because I don't want to call 
wl_display_read_events when quit is true. The earlier version does this 
incorrectly if a timeout or fd turns on quit.

Assuming this is correct, it looks to me like the client has little 
choice about rearranging this and must call in a precise order. So I 
will propose a new function called "wl_i_want_a_pony" so that the main 
loop looks like this:

   while (!quit) {
     wl_i_want_a_pony(display, dispatch_idle);
     poll(...);
     dispatch_other_fds();
     dispatch_expired_timeouts();
   }

The implementation of wl_i_want_a_pony is this:

   wl_i_want_a_pony(display, dispatch_idle) {
     static bool did_prepare_read = false;
     if (did_prepare_read)
       wl_display_read_events(display);
     do {
       wl_display_dispatch_pending(display);
       dispatch_idle();
     } while (wl_display_prepare_read(display) != 0);
     wl_display_flush(display);
     did_prepare_read = true;
   }

Of course in reality the dispatch_idle would be registered with another 
call, and multiple ones allowed. Still this seems like it would reduce 
the size of the wayland client api a lot and remove some of these 
questions, and allow a simpler and more efficient implementation.


More information about the wayland-devel mailing list