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