render/drm_syncobj: Add a callback when ready

The old approach of using a signal is fundamentally broken for a common
usecase: When the waiter is ready, it's common to immediately finish and
free any resources associated with it.
Because of the semantics of wl_signal_emit_mutable() this is UB.
wl_signal_emit_mutable() always excepts that the waiter hasn't been freed
until the signal has finished being emitted.

Instead of over engineering the solution, let's just add a callback required
by wlr_drm_syncobj_timeline_waiter_init(). In this callback, the implementation
is free to finish() or free() any resource it likes.
This commit is contained in:
Alexander Orzechowski 2025-01-26 17:35:47 -05:00
parent 211eb9d60e
commit 82223e451a
5 changed files with 21 additions and 19 deletions

View file

@ -64,7 +64,6 @@ struct wlr_wl_buffer {
bool has_drm_syncobj_waiter;
struct wlr_drm_syncobj_timeline_waiter drm_syncobj_waiter;
struct wl_listener drm_syncobj_ready;
struct wlr_drm_syncobj_timeline *fallback_signal_timeline;
uint64_t fallback_signal_point;

View file

@ -37,6 +37,11 @@ struct wlr_drm_syncobj_timeline {
} WLR_PRIVATE;
};
struct wlr_drm_syncobj_timeline_waiter;
typedef void (*wlr_drm_syncobj_timeline_ready_callback)(
struct wlr_drm_syncobj_timeline_waiter *waiter);
struct wlr_drm_syncobj_timeline_waiter {
struct {
struct wl_signal ready;
@ -45,6 +50,7 @@ struct wlr_drm_syncobj_timeline_waiter {
struct {
int ev_fd;
struct wl_event_source *event_source;
wlr_drm_syncobj_timeline_ready_callback callback;
} WLR_PRIVATE;
};
@ -92,10 +98,12 @@ bool wlr_drm_syncobj_timeline_check(struct wlr_drm_syncobj_timeline *timeline,
* Asynchronously wait for a timeline point.
*
* See wlr_drm_syncobj_timeline_check() for a definition of flags.
*
* A callback must be provided that will be invoked when the waiter has finished.
*/
bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter *waiter,
struct wlr_drm_syncobj_timeline *timeline, uint64_t point, uint32_t flags,
struct wl_event_loop *loop);
struct wl_event_loop *loop, wlr_drm_syncobj_timeline_ready_callback callback);
/**
* Cancel a timeline waiter.
*/