Skip to content

Commit

Permalink
x: give set_reply_action functions better names
Browse files Browse the repository at this point in the history
And use list.h for the pending reply actions list.

Signed-off-by: Yuxuan Shui <[email protected]>
  • Loading branch information
yshui committed Jun 24, 2024
1 parent ae73f45 commit e0d4746
Show file tree
Hide file tree
Showing 9 changed files with 75 additions and 73 deletions.
8 changes: 4 additions & 4 deletions src/backend/xrender/xrender.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 2 additions & 2 deletions src/event.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions src/render.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions src/renderer/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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) {
Expand Down
4 changes: 2 additions & 2 deletions src/vblank.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

Expand Down
2 changes: 1 addition & 1 deletion src/wm/win.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/wm/wm.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
41 changes: 23 additions & 18 deletions src/x.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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));
}
}

Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);
}

/**
Expand Down
73 changes: 35 additions & 38 deletions src/x.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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 <code>next</code> 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
Expand Down Expand Up @@ -133,52 +132,50 @@ 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;
#endif
}

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);
}

Expand All @@ -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.
///
Expand Down

0 comments on commit e0d4746

Please sign in to comment.