race between (say) wl_display_sync and wl_callback_add_listener?
John Cox
jc at kynesim.co.uk
Tue Sep 26 15:24:32 UTC 2023
Hi
>On Tue, Sep 26, 2023 at 10:08:55AM +0100, John Cox wrote:
>> Hi
>>
>> Many thanks for your comprehensive answer
>>
>> >On Mon, Sep 25, 2023 at 05:10:30PM +0100, John Cox wrote:
>> >> Hi
>> >
>> >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?
>> >
>> >This is indeed a racy interaction, in more ways than one:
>> >
>> >1. There is an inherent data race setting and using the
>> > listener/user_data concurrently from different threads.
>> > Neither adding a listener/user_data (see wl_proxy_add_listener()),
>> > nor the actual dispatching operation in libwayland (which uses the
>> > listener, see wayland-client.c:dispatch_event()) is protected by
>> > the internal "display lock".
>>
>> So are all interactions from another thread than the dispatch thread
>> unsafe e.g. buffer creation, setup & assignment to a surface or is it
>> just the obviously racy subset?
>
>From a low-level libwayland API perspective, creating objects or making
>requests from another thread is generally fine. It's this particular
>case of requests that create object and cause events to be emitted
>immediately for them that's problematic.
>
>Many requests that fall in this category are in fact global binds (e.g.,
>wl_shm, wl_seat, wl_output), which are typically handled in the context of the
>wl_registry.global handler, thus in the dispatch thread, in which case no
>special consideration is required.
>
>There are also some requests that at first glance seem problematic,
>but in fact they are not (if things are done properly, and assuming
>correct compositor behavior). For example:
>
> struct wl_callback *wl_surface_frame(struct wl_surface *surface);
>
>seems suspiciously similar to wl_display_sync(). However, this request
>takes effect (i.e., the callback will receive events) only after the next
>wl_surface_commit(), so the following is safe:
>
>cb = wl_surface_frame(surface);
>/* As long as the listener is set before the commit we are good. */
>wl_callback_add_listener(cb);
>wl_surface_commit(surface);
>
>Of course, on top of all these there are also the typical higher-level
>multithreading synchronization considerations.
>
><snip>
Good - I think my current expectations align with what you and pq have
said.
So thank you once again for taking the time to help me
John Cox
<snip>
More information about the wayland-devel
mailing list