From e0d474666c9af698535288bc764a9e3ac10d3230 Mon Sep 17 00:00:00 2001 From: Yuxuan Shui Date: Mon, 24 Jun 2024 08:17:00 +0100 Subject: [PATCH] x: give set_reply_action functions better names And use list.h for the pending reply actions list. Signed-off-by: Yuxuan Shui --- src/backend/xrender/xrender.c | 8 ++-- src/event.c | 4 +- src/render.c | 4 +- src/renderer/renderer.c | 10 ++--- src/vblank.c | 4 +- src/wm/win.c | 2 +- src/wm/wm.c | 2 +- src/x.c | 41 +++++++++++--------- src/x.h | 73 +++++++++++++++++------------------ 9 files changed, 75 insertions(+), 73 deletions(-) diff --git a/src/backend/xrender/xrender.c b/src/backend/xrender/xrender.c index fa38e09f86..738606d0a4 100644 --- a/src/backend/xrender/xrender.c +++ b/src/backend/xrender/xrender.c @@ -110,7 +110,7 @@ set_picture_scale(struct x_connection *c, xcb_render_picture_t picture, vec2 sca .matrix22 = DOUBLE_TO_XFIXED(1.0 / scale.y), .matrix33 = DOUBLE_TO_XFIXED(1.0), }; - set_cant_fail_cookie(c, xcb_render_set_picture_transform(c->c, picture, transform)); + x_set_error_action_abort(c, xcb_render_set_picture_transform(c->c, picture, transform)); } /// Make a picture of size width x height, which has a rounded rectangle of corner_radius @@ -198,9 +198,9 @@ static inline void xrender_set_picture_repeat(struct xrender_data *xd, xcb_render_change_picture_value_list_t values = { .repeat = repeat, }; - set_cant_fail_cookie(xd->base.c, xcb_render_change_picture(xd->base.c->c, pict, - XCB_RENDER_CP_REPEAT, - (uint32_t *)&values)); + x_set_error_action_abort( + xd->base.c, xcb_render_change_picture(xd->base.c->c, pict, XCB_RENDER_CP_REPEAT, + (uint32_t *)&values)); } static inline void xrender_record_back_damage(struct xrender_data *xd, diff --git a/src/event.c b/src/event.c index 7c81e06b46..0c3df0d965 100644 --- a/src/event.c +++ b/src/event.c @@ -542,7 +542,7 @@ static inline void repair_win(session_t *ps, struct win *w) { auto cookie = xcb_damage_subtract(ps->c.c, w->damage, XCB_NONE, ps->damage_ring.x_region); if (!ps->o.show_all_xerrors) { - set_ignore_cookie(&ps->c, cookie); + x_set_error_action_ignore(&ps->c, cookie); } x_fetch_region(&ps->c, ps->damage_ring.x_region, &parts); pixman_region32_translate(&parts, w->g.x + w->g.border_width, @@ -631,7 +631,7 @@ ev_selection_clear(session_t *ps, xcb_selection_clear_event_t attr_unused *ev) { void ev_handle(session_t *ps, xcb_generic_event_t *ev) { if (XCB_EVENT_RESPONSE_TYPE(ev) != KeymapNotify) { - x_discard_pending(&ps->c, ev->full_sequence); + x_discard_pending_errors(&ps->c, ev->full_sequence); } xcb_window_t wid = ev_window(ps, ev); diff --git a/src/render.c b/src/render.c index 990ed7c459..1e80623ae6 100644 --- a/src/render.c +++ b/src/render.c @@ -396,8 +396,8 @@ void paint_one(session_t *ps, struct win *w, const region_t *reg_paint) { // Fetch Pixmap if (!w->paint.pixmap) { w->paint.pixmap = x_new_id(&ps->c); - set_ignore_cookie(&ps->c, xcb_composite_name_window_pixmap( - ps->c.c, win_id(w), w->paint.pixmap)); + x_set_error_action_ignore(&ps->c, xcb_composite_name_window_pixmap( + ps->c.c, win_id(w), w->paint.pixmap)); } xcb_drawable_t draw = w->paint.pixmap; diff --git a/src/renderer/renderer.c b/src/renderer/renderer.c index 445e35b9ca..81fa6f4a37 100644 --- a/src/renderer/renderer.c +++ b/src/renderer/renderer.c @@ -494,8 +494,8 @@ bool renderer_render(struct renderer *r, struct backend_base *backend, if (xsync_fence != XCB_NONE) { // Trigger the fence but don't immediately wait on it. Let it run // concurrent with our CPU tasks to save time. - set_cant_fail_cookie(backend->c, - xcb_sync_trigger_fence(backend->c->c, xsync_fence)); + x_set_error_action_abort( + backend->c, xcb_sync_trigger_fence(backend->c->c, xsync_fence)); } // TODO(yshui) In some cases we can render directly into the back buffer, and // don't need the intermediate back_image. Several conditions need to be met: no @@ -568,13 +568,13 @@ bool renderer_render(struct renderer *r, struct backend_base *backend, } if (xsync_fence != XCB_NONE) { - set_cant_fail_cookie( + x_set_error_action_abort( backend->c, xcb_sync_await_fence(backend->c->c, 1, &xsync_fence)); // Making sure the wait is completed by receiving a response from the X // server xcb_aux_sync(backend->c->c); - set_cant_fail_cookie(backend->c, - xcb_sync_reset_fence(backend->c->c, xsync_fence)); + x_set_error_action_abort( + backend->c, xcb_sync_reset_fence(backend->c->c, xsync_fence)); } if (backend->ops.prepare) { diff --git a/src/vblank.c b/src/vblank.c index a02619d49f..270f93e2f6 100644 --- a/src/vblank.c +++ b/src/vblank.c @@ -373,7 +373,7 @@ static bool present_vblank_scheduler_init(struct vblank_scheduler *base) { auto select_input = xcb_present_select_input(base->c->c, self->event_id, base->target_window, XCB_PRESENT_EVENT_MASK_COMPLETE_NOTIFY); - set_cant_fail_cookie(base->c, select_input); + x_set_error_action_abort(base->c, select_input); self->event = xcb_register_for_special_xge(base->c->c, &xcb_present_id, self->event_id, NULL); return true; @@ -384,7 +384,7 @@ static void present_vblank_scheduler_deinit(struct vblank_scheduler *base) { ev_timer_stop(base->loop, &self->callback_timer); auto select_input = xcb_present_select_input(base->c->c, self->event_id, base->target_window, 0); - set_cant_fail_cookie(base->c, select_input); + x_set_error_action_abort(base->c, select_input); xcb_unregister_for_special_event(base->c->c, self->event); } diff --git a/src/wm/win.c b/src/wm/win.c index cb7c152399..6a6a878933 100644 --- a/src/wm/win.c +++ b/src/wm/win.c @@ -1370,7 +1370,7 @@ void free_win_res(session_t *ps, struct win *w) { pixman_region32_fini(&w->damaged); pixman_region32_fini(&w->bounding_shape); // BadDamage may be thrown if the window is destroyed - set_ignore_cookie(&ps->c, xcb_damage_destroy(ps->c.c, w->damage)); + x_set_error_action_ignore(&ps->c, xcb_damage_destroy(ps->c.c, w->damage)); rc_region_unref(&w->reg_ignore); free(w->name); free(w->class_instance); diff --git a/src/wm/wm.c b/src/wm/wm.c index f36aec8db5..c8d37156b0 100644 --- a/src/wm/wm.c +++ b/src/wm/wm.c @@ -326,7 +326,7 @@ static void wm_complete_import_single(struct wm *wm, struct x_connection *c, struct atom *atoms, struct wm_tree_node *node) { log_debug("Finishing importing window %#010x with parent %#010lx.", node->id.x, node->parent != NULL ? node->parent->id.x : XCB_NONE); - set_ignore_cookie( + x_set_error_action_ignore( c, xcb_change_window_attributes(c->c, node->id.x, XCB_CW_EVENT_MASK, (const uint32_t[]){WM_IMPORT_EV_MASK})); if (wid_has_prop(c->c, node->id.x, atoms->aWM_STATE)) { diff --git a/src/x.c b/src/x.c index 15e891743e..7eadae1da0 100644 --- a/src/x.c +++ b/src/x.c @@ -50,27 +50,32 @@ static int xerror(Display attr_unused *dpy, XErrorEvent *ev) { return 0; } -void x_discard_pending(struct x_connection *c, uint32_t sequence) { - while (c->pending_reply_head && sequence > c->pending_reply_head->sequence) { - auto next = c->pending_reply_head->next; - free(c->pending_reply_head); - c->pending_reply_head = next; - } - if (!c->pending_reply_head) { - c->pending_reply_tail = &c->pending_reply_head; +void x_discard_pending_errors(struct x_connection *c, uint32_t sequence) { + list_foreach_safe(struct pending_x_error, i, &c->pending_x_errors, siblings) { + if (sequence <= i->sequence) { + break; + } + list_remove(&i->siblings); + free(i); } } void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) { - x_discard_pending(c, ev->full_sequence); - if (c->pending_reply_head && c->pending_reply_head->sequence == ev->full_sequence) { - if (c->pending_reply_head->action != PENDING_REPLY_ACTION_IGNORE) { + x_discard_pending_errors(c, ev->full_sequence); + struct pending_x_error *first_error_action = NULL; + if (!list_is_empty(&c->pending_x_errors)) { + first_error_action = + list_entry(c->pending_x_errors.next, struct pending_x_error, siblings); + } + if (first_error_action != NULL && first_error_action->sequence == ev->full_sequence) { + if (first_error_action->action != PENDING_REPLY_ACTION_IGNORE) { x_log_error(LOG_LEVEL_ERROR, ev->full_sequence, ev->major_code, ev->minor_code, ev->error_code); } - switch (c->pending_reply_head->action) { + switch (first_error_action->action) { case PENDING_REPLY_ACTION_ABORT: - log_fatal("An unrecoverable X error occurred, aborting..."); + log_fatal("An unrecoverable X error occurred, " + "aborting..."); abort(); case PENDING_REPLY_ACTION_DEBUG_ABORT: assert(false); break; case PENDING_REPLY_ACTION_IGNORE: break; @@ -88,7 +93,7 @@ void x_handle_error(struct x_connection *c, xcb_generic_error_t *ev) { void x_connection_init(struct x_connection *c, Display *dpy) { c->dpy = dpy; c->c = XGetXCBConnection(dpy); - c->pending_reply_tail = &c->pending_reply_head; + list_init_head(&c->pending_x_errors); c->previous_xerror_handler = XSetErrorHandler(xerror); c->screen = DefaultScreen(dpy); @@ -411,7 +416,7 @@ x_create_picture_with_pictfmt(struct x_connection *c, int w, int h, xcb_render_picture_t picture = x_create_picture_with_pictfmt_and_pixmap( c, pictfmt, tmp_pixmap, valuemask, attr); - set_cant_fail_cookie(c, xcb_free_pixmap(c->c, tmp_pixmap)); + x_set_error_action_abort(c, xcb_free_pixmap(c->c, tmp_pixmap)); return picture; } @@ -508,7 +513,7 @@ uint32_t x_create_region(struct x_connection *c, const region_t *reg) { void x_destroy_region(struct x_connection *c, xcb_xfixes_region_t r) { if (r != XCB_NONE) { - set_debug_cant_fail_cookie(c, xcb_xfixes_destroy_region(c->c, r)); + x_set_error_action_debug_abort(c, xcb_xfixes_destroy_region(c->c, r)); } } @@ -557,7 +562,7 @@ void x_clear_picture_clip_region(struct x_connection *c, xcb_render_picture_t pi void x_free_picture(struct x_connection *c, xcb_render_picture_t p) { assert(p != XCB_NONE); auto cookie = xcb_render_free_picture(c->c, p); - set_debug_cant_fail_cookie(c, cookie); + x_set_error_action_debug_abort(c, cookie); } enum { @@ -776,7 +781,7 @@ bool x_fence_sync(struct x_connection *c, xcb_sync_fence_t f) { void x_request_vblank_event(struct x_connection *c, xcb_window_t window, uint64_t msc) { auto cookie = xcb_present_notify_msc(c->c, window, 0, msc, 1, 0); - set_cant_fail_cookie(c, cookie); + x_set_error_action_abort(c, cookie); } /** diff --git a/src/x.h b/src/x.h index d4e01f5a68..b6af8da6a1 100644 --- a/src/x.h +++ b/src/x.h @@ -17,6 +17,7 @@ #include "log.h" #include "region.h" #include "utils/kernel.h" +#include "utils/list.h" typedef struct session session_t; struct atom; @@ -44,17 +45,18 @@ typedef struct winprop_info { uint32_t length; } winprop_info_t; -enum pending_reply_action { +enum x_error_action { PENDING_REPLY_ACTION_IGNORE, PENDING_REPLY_ACTION_ABORT, PENDING_REPLY_ACTION_DEBUG_ABORT, }; -typedef struct pending_reply { - struct pending_reply *next; +/// Represents a X request we sent that might error. +struct pending_x_error { unsigned long sequence; - enum pending_reply_action action; -} pending_reply_t; + enum x_error_action action; + struct list_node siblings; +}; struct x_connection { // Public fields @@ -68,11 +70,8 @@ struct x_connection { int screen; // Private fields - /// Head pointer of the error ignore linked list. - pending_reply_t *pending_reply_head; - /// Pointer to the next member of tail element of the error - /// ignore linked list. - pending_reply_t **pending_reply_tail; + /// The error handling list. + struct list_node pending_x_errors; /// Previous handler of X errors XErrorHandler previous_xerror_handler; /// Information about the default screen @@ -133,34 +132,38 @@ static inline uint32_t x_new_id(struct x_connection *c) { return ret; } -static void set_reply_action(struct x_connection *c, uint32_t sequence, - enum pending_reply_action action) { - auto i = cmalloc(pending_reply_t); +/// Set error handler for a specific X request. +/// +/// @param c X connection +/// @param sequence sequence number of the X request to set error handler for +/// @param action action to take when error occurs +static void +x_set_error_action(struct x_connection *c, uint32_t sequence, enum x_error_action action) { + auto i = cmalloc(struct pending_x_error); i->sequence = sequence; - i->next = 0; i->action = action; - *c->pending_reply_tail = i; - c->pending_reply_tail = &i->next; + list_insert_before(&c->pending_x_errors, &i->siblings); } -/** - * Ignore X errors caused by given X request. - */ -static inline void attr_unused set_ignore_cookie(struct x_connection *c, - xcb_void_cookie_t cookie) { - set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_IGNORE); +/// Convenience wrapper for x_set_error_action with action `PENDING_REPLY_ACTION_IGNORE` +static inline void attr_unused x_set_error_action_ignore(struct x_connection *c, + xcb_void_cookie_t cookie) { + x_set_error_action(c, cookie.sequence, PENDING_REPLY_ACTION_IGNORE); } -static inline void attr_unused set_cant_fail_cookie(struct x_connection *c, - xcb_void_cookie_t cookie) { - set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_ABORT); +/// Convenience wrapper for x_set_error_action with action `PENDING_REPLY_ACTION_ABORT` +static inline void attr_unused x_set_error_action_abort(struct x_connection *c, + xcb_void_cookie_t cookie) { + x_set_error_action(c, cookie.sequence, PENDING_REPLY_ACTION_ABORT); } -static inline void attr_unused set_debug_cant_fail_cookie(struct x_connection *c, - xcb_void_cookie_t cookie) { +/// Convenience wrapper for x_set_error_action with action +/// `PENDING_REPLY_ACTION_DEBUG_ABORT` +static inline void attr_unused x_set_error_action_debug_abort(struct x_connection *c, + xcb_void_cookie_t cookie) { #ifndef NDEBUG - set_reply_action(c, cookie.sequence, PENDING_REPLY_ACTION_DEBUG_ABORT); + x_set_error_action(c, cookie.sequence, PENDING_REPLY_ACTION_DEBUG_ABORT); #else (void)c; (void)cookie; @@ -168,17 +171,11 @@ static inline void attr_unused set_debug_cant_fail_cookie(struct x_connection *c } static inline void attr_unused free_x_connection(struct x_connection *c) { - pending_reply_t *next = NULL; - for (auto ign = c->pending_reply_head; ign; ign = next) { - next = ign->next; - - free(ign); + list_foreach_safe(struct pending_x_error, i, &c->pending_x_errors, siblings) { + list_remove(&i->siblings); + free(i); } - // Reset head and tail - c->pending_reply_head = NULL; - c->pending_reply_tail = &c->pending_reply_head; - XSetErrorHandler(c->previous_xerror_handler); } @@ -193,7 +190,7 @@ void x_connection_init(struct x_connection *c, Display *dpy); /// We have received reply with sequence number `sequence`, which means all pending /// replies with sequence number less than `sequence` will never be received. So discard /// them. -void x_discard_pending(struct x_connection *c, uint32_t sequence); +void x_discard_pending_errors(struct x_connection *c, uint32_t sequence); /// Handle X errors. ///