race between (say) wl_display_sync and wl_callback_add_listener?

Pekka Paalanen ppaalanen at gmail.com
Tue Sep 26 10:02:06 UTC 2023


On Mon, 25 Sep 2023 17:10:30 +0100
John Cox <jc at kynesim.co.uk> wrote:

> Hi
> 
> Assuming I have a separate poll/read_events/dispatch_queue thread to my
> main thread. If I go wl_display_sync/wl_callback_add_listener on the
> main thread is there a race condition between those two calls where the
> other thread can read & dispatch the callback before the listener is
> added or is there some magic s.t. adding the listener will always work
> as expected?
> 
> I assume it must be safe if dispatch & create/add_listener are in the
> same thread.
> 
> The same question applies to adding listeners after binding (say) the
> shm extension where the bind provokes a set of events giving formats.
> 
> Is there a safe way of doing this? (mutex around the dispatch and
> create/add_listener pairs would seem plausible even if really not what I
> want to do)

Hi,

yeah, this requires some careful handling, because the race is real
otherwise. The following applies to the libwayland implementation.

The first thing is that you should have a separate wl_event_queue for
each "execution context". A thread is definitely an execution context,
but not the only possible case. Then, you dispatch that event queue
only from the correct execution context. This will serialize your own
actions with the dispatch, so when you send a wl_display.sync, even if
the compositor already responds with wl_callback.done, it won't get
dispatched until you explicitly call dispatch in that thread.

wl_display itself counts as one wl_event_queue, the default event queue.

wl_event_queues are also a way to filter events without dispatching
everything up to the event you wait for. This is the other case of
execution context. The disadvantage is that you lose the event ordering
between two queues.

The second thing is more subtle. wl_display is always on the default
event queue. A new protocol object inherits the event queue of the
object it is created from. That is, wl_display.sync creates a
wl_callback, and the wl_callback starts in the default event queue.

This is a problem if you send wl_display.sync from another thread. Your
main thread might dispatch the 'done' reply before you can set up the
listener or change the queue assignment. This problem is fixed by using
wl_proxy_create_wrapper(). See its documentation.

Proxy wrappers are used whenever you need to have the new protocol
object in a different event queue than the object creating it.

You can run the poll/read_events/dispatch_queue loop in any and all
execution contexts you like as long as at least one thread is always
quick to read the Wayland socket. The reader will direct events to all
queues.


Thanks,
pq
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <https://lists.freedesktop.org/archives/wayland-devel/attachments/20230926/c3c4157a/attachment.sig>


More information about the wayland-devel mailing list