[Mesa-dev] [PATCH] loader/dri3: Improve dri3 thread-safety
Nicolai Hähnle
nhaehnle at gmail.com
Tue Nov 7 16:54:21 UTC 2017
On 06.11.2017 12:53, Thomas Hellstrom wrote:
> On 11/06/2017 12:14 PM, Nicolai Hähnle wrote:
>> On 03.11.2017 12:02, Thomas Hellstrom wrote:
>>> It turned out that with recent changes that call into dri3 from
>>> glFinish(),
>>> it appears like different thread end up waiting for X events
>>> simultaneously,
>>> causing deadlocks since they steal events from eachoter and update
>>> the dri3
>>> counters behind eachothers backs.
>>>
>>> This patch intends to improve on that. It allows at most one thread at a
>>> time to wait on events for a single drawable. If another thread
>>> intends to
>>> do the same, it's put to sleep until the first thread finishes
>>> waiting, and
>>> then it rechecks counters and optionally retries the waiting. Threads
>>> that
>>> poll for X events never pulls X events off the event queue if there are
>>> other threads waiting for events on that drawable. Counters in the
>>> dri3 drawable structure are protected by a mutex. Finally, the mutex we
>>> introduce is never held while waiting for the X server to avoid
>>> unnecessary stalls.
>>>
>>> This does not make dri3 drawables completely thread-safe but at least
>>> it's a
>>> first step.
>>>
>>> Bugzilla:
>>> https://urldefense.proofpoint.com/v2/url?u=https-3A__bugs.freedesktop.org_show-5Fbug.cgi-3Fid-3D102358&d=DwICaQ&c=uilaK90D4TOVoH58JNXRgQ&r=wnSlgOCqfpNS4d02vP68_E9q2BNMCwfD2OZ_6dCFVQQ&m=yqE5Xb9bQg5hA8gP7s0b3dSSZoPWaAEKACqD8qfhdZo&s=wf-xBzPlZ805RCV1hnDgoyW0fYe2ZX3Qwie66SU936g&e=
>>>
>>> Fixes: d5ba75f8881 "st/dri2 Plumb the flush_swapbuffer functionality
>>> through to dri3"
>>> Signed-off-by: Thomas Hellstrom <thellstrom at vmware.com>
>>> ---
>>> src/loader/loader_dri3_helper.c | 77
>>> +++++++++++++++++++++++++++++++----------
>>> src/loader/loader_dri3_helper.h | 10 ++++++
>>> 2 files changed, 69 insertions(+), 18 deletions(-)
>>>
>>> diff --git a/src/loader/loader_dri3_helper.c
>>> b/src/loader/loader_dri3_helper.c
>>> index 19ab581..7e6b8b2 100644
>>> --- a/src/loader/loader_dri3_helper.c
>>> +++ b/src/loader/loader_dri3_helper.c
>>> @@ -32,7 +32,6 @@
>>> #include <X11/Xlib-xcb.h>
>>> -#include <c11/threads.h>
>>> #include "loader_dri3_helper.h"
>>> /* From xmlpool/options.h, user exposed so should be stable */
>>> @@ -186,8 +185,11 @@ dri3_fence_await(xcb_connection_t *c, struct
>>> loader_dri3_drawable *draw,
>>> {
>>> xcb_flush(c);
>>> xshmfence_await(buffer->shm_fence);
>>> - if (draw)
>>> + if (draw) {
>>> + mtx_lock(&draw->mtx);
>>> dri3_flush_present_events(draw);
>>> + mtx_unlock(&draw->mtx);
>>> + }
>>> }
>>> static void
>>> @@ -245,6 +247,9 @@ loader_dri3_drawable_fini(struct
>>> loader_dri3_drawable *draw)
>>> xcb_discard_reply(draw->conn, cookie.sequence);
>>> xcb_unregister_for_special_event(draw->conn,
>>> draw->special_event);
>>> }
>>> +
>>> + cnd_destroy(&draw->event_cnd);
>>> + mtx_destroy(&draw->mtx);
>>> }
>>> int
>>> @@ -276,6 +281,8 @@ loader_dri3_drawable_init(xcb_connection_t *conn,
>>> draw->cur_blit_source = -1;
>>> draw->back_format = __DRI_IMAGE_FORMAT_NONE;
>>> + mtx_init(&draw->mtx, mtx_plain);
>>> + cnd_init(&draw->event_cnd);
>>> if (draw->ext->config)
>>> draw->ext->config->configQueryi(draw->dri_screen,
>>> @@ -407,13 +414,27 @@ dri3_handle_present_event(struct
>>> loader_dri3_drawable *draw,
>>> }
>>> static bool
>>> -dri3_wait_for_event(struct loader_dri3_drawable *draw)
>>> +dri3_wait_for_event_locked(struct loader_dri3_drawable *draw)
>>> {
>>> xcb_generic_event_t *ev;
>>> xcb_present_generic_event_t *ge;
>>> xcb_flush(draw->conn);
>>
>> (Why) Doesn't the flush need to be protected as well? Can it be
>> removed entirely given that it's already called from
>> loader_dri3_wait_for_msc? Though dri3_find_back is different - why?
>>
>
> Thanks for reviewing.
>
> AFAIK, (correc me if I'm wrong) xcb should be thread-safe enough to
> allow multiple threads to call xcb_flush() simultaneously so we
> shouldn't need to explicitly "serialize" it.
>
> There might indeed be unnecessary xcb_flushes(). In the dri3_find_back
> case when we're initially just checking for arrived events, we know that
> any preceding swapbuffers (that govern the reuse of back buffers) will
> have flushed xcb. However when we explicitly wait for special events,
> any forgotten flush would be catastrophic, causing a deadlock.
>
> We should probably audit the code for unnecessary xcb flushes, but as a
> follow-up patch.
Fair enough.
Acked-by: Nicolai Hähnle <nicolai.haehnle at amd.com>
>
> /Thomas
>
>
>
>> Apart from that, the patch does indeed look like a good first step,
>> though Keep in mind that I'm not too familiar with this stuff...
>>
>> Cheers,
>> Nicolai
>
--
Lerne, wie die Welt wirklich ist,
Aber vergiss niemals, wie sie sein sollte.
More information about the mesa-dev
mailing list