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

@ -193,12 +193,15 @@ static int handle_eventfd_ready(int ev_fd, uint32_t mask, void *data) {
}
wl_signal_emit_mutable(&waiter->events.ready, NULL);
waiter->callback(waiter);
return 0;
}
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) {
assert(callback);
int ev_fd;
#if HAVE_EVENTFD
ev_fd = eventfd(0, EFD_CLOEXEC);
@ -235,6 +238,7 @@ bool wlr_drm_syncobj_timeline_waiter_init(struct wlr_drm_syncobj_timeline_waiter
*waiter = (struct wlr_drm_syncobj_timeline_waiter){
.ev_fd = ev_fd,
.event_source = source,
.callback = callback,
};
wl_signal_init(&waiter->events.ready);
return true;