On Mon, 25 Sep 2023 17:10:30 +0100 John Cox <j...@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
pgpMhYVsnH4gl.pgp
Description: OpenPGP digital signature