From c3ef36d6b5d36f783f41b8860cee321b652f91e3 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Wed, 15 Aug 2018 10:03:55 +1000 Subject: Simplify transactions Commit 4b8e3a885be74c588291c51f798de80bd81a92db makes it so only one transaction is committed (ie. configures sent) at a time. This commit removes the now-unnecessary code which was used to support concurrent committed transactions. * Instead of containers storing a list of instructions which they've been sent, it now stores a single instruction. * Containers now have an ntxnrefs property. Previously we knew how many references there were by the length of the instruction list. * Instructions no longer need a ready property. It was used to avoid marking an instruction ready twice when they were in a list, but this is now avoided because there is only one instruction and we nullify the container->instruction pointer when it's ready. * When a transaction applies, we no longer need to consider releasing and resaving the surface, as we know there are no other committed transactions. * transaction_notify_view_ready has been renamed to view_notify_view_ready_by_serial to make it consistent with transaction_notify_view_ready_by_size. * Out-of-memory checks have been added when creating transactions and instructions. --- sway/desktop/transaction.c | 99 +++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 67 deletions(-) (limited to 'sway/desktop/transaction.c') diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index a449ffaa..c08730ce 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -43,12 +43,14 @@ struct sway_transaction_instruction { struct sway_container *container; struct sway_container_state state; uint32_t serial; - bool ready; }; static struct sway_transaction *transaction_create() { struct sway_transaction *transaction = calloc(1, sizeof(struct sway_transaction)); + if (!sway_assert(transaction, "Unable to allocate transaction")) { + return NULL; + } transaction->instructions = create_list(); if (server.debug_txn_timings) { clock_gettime(CLOCK_MONOTONIC, &transaction->create_time); @@ -62,13 +64,11 @@ static void transaction_destroy(struct sway_transaction *transaction) { struct sway_transaction_instruction *instruction = transaction->instructions->items[i]; struct sway_container *con = instruction->container; - for (int j = 0; j < con->instructions->length; ++j) { - if (con->instructions->items[j] == instruction) { - list_del(con->instructions, j); - break; - } + con->ntxnrefs--; + if (con->instruction == instruction) { + con->instruction = NULL; } - if (con->destroying && !con->instructions->length) { + if (con->destroying && con->ntxnrefs == 0) { container_free(con); } free(instruction); @@ -130,12 +130,16 @@ static void transaction_add_container(struct sway_transaction *transaction, struct sway_container *container) { struct sway_transaction_instruction *instruction = calloc(1, sizeof(struct sway_transaction_instruction)); + if (!sway_assert(instruction, "Unable to allocate instruction")) { + return; + } instruction->transaction = transaction; instruction->container = container; copy_pending_state(container, &instruction->state); list_add(transaction->instructions, instruction); + container->ntxnrefs++; } /** @@ -195,21 +199,11 @@ static void transaction_apply(struct sway_transaction *transaction) { memcpy(&container->current, &instruction->state, sizeof(struct sway_container_state)); - if (container->type == C_VIEW) { - if (container->destroying) { - if (container->instructions->length == 1 && - container->sway_view->saved_buffer) { - view_remove_saved_buffer(container->sway_view); - } - } else { - if (container->sway_view->saved_buffer) { - view_remove_saved_buffer(container->sway_view); - } - if (container->instructions->length > 1) { - view_save_buffer(container->sway_view); - } - } + if (container->type == C_VIEW && container->sway_view->saved_buffer) { + view_remove_saved_buffer(container->sway_view); } + + container->instruction = NULL; } } @@ -269,20 +263,8 @@ static bool should_configure(struct sway_container *con, if (con->destroying) { return false; } - // The settled dimensions are what size the view will be once any pending - // configures have applied (excluding the one we might be configuring now). - // If these match the dimensions that this transaction wants then we don't - // need to configure it. - int settled_width = con->current.view_width; - int settled_height = con->current.view_height; - if (con->instructions->length) { - struct sway_transaction_instruction *last_instruction = - con->instructions->items[con->instructions->length - 1]; - settled_width = last_instruction->state.view_width; - settled_height = last_instruction->state.view_height; - } - if (settled_width == instruction->state.view_width && - settled_height == instruction->state.view_height) { + if (con->current.view_width == instruction->state.view_width && + con->current.view_height == instruction->state.view_height) { return false; } return true; @@ -312,10 +294,10 @@ static void transaction_commit(struct sway_transaction *transaction) { struct timespec when; wlr_surface_send_frame_done(con->sway_view->surface, &when); } - if (con->type == C_VIEW && !con->sway_view->saved_buffer) { + if (con->type == C_VIEW) { view_save_buffer(con->sway_view); } - list_add(con->instructions, instruction); + con->instruction = instruction; } transaction->num_configures = transaction->num_waiting; if (server.debug_txn_timings) { @@ -347,7 +329,6 @@ static void transaction_commit(struct sway_transaction *transaction) { static void set_instruction_ready( struct sway_transaction_instruction *instruction) { - instruction->ready = true; struct sway_transaction *transaction = instruction->transaction; if (server.debug_txn_timings) { @@ -371,44 +352,25 @@ static void set_instruction_ready( wl_event_source_timer_update(transaction->timer, 0); } } -} -/** - * Mark all of the view's instructions as ready up to and including the - * instruction at the given index. This allows the view to skip a configure. - */ -static void set_instructions_ready(struct sway_view *view, int index) { - for (int i = 0; i <= index; ++i) { - struct sway_transaction_instruction *instruction = - view->swayc->instructions->items[i]; - if (!instruction->ready) { - set_instruction_ready(instruction); - } - } + instruction->container->instruction = NULL; transaction_progress_queue(); } -void transaction_notify_view_ready(struct sway_view *view, uint32_t serial) { - for (int i = 0; i < view->swayc->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - view->swayc->instructions->items[i]; - if (instruction->serial == serial && !instruction->ready) { - set_instructions_ready(view, i); - return; - } +void transaction_notify_view_ready_by_serial(struct sway_view *view, + uint32_t serial) { + struct sway_transaction_instruction *instruction = view->swayc->instruction; + if (view->swayc->instruction->serial == serial) { + set_instruction_ready(instruction); } } void transaction_notify_view_ready_by_size(struct sway_view *view, int width, int height) { - for (int i = 0; i < view->swayc->instructions->length; ++i) { - struct sway_transaction_instruction *instruction = - view->swayc->instructions->items[i]; - if (!instruction->ready && instruction->state.view_width == width && - instruction->state.view_height == height) { - set_instructions_ready(view, i); - return; - } + struct sway_transaction_instruction *instruction = view->swayc->instruction; + if (instruction->state.view_width == width && + instruction->state.view_height == height) { + set_instruction_ready(instruction); } } @@ -417,6 +379,9 @@ void transaction_commit_dirty(void) { return; } struct sway_transaction *transaction = transaction_create(); + if (!transaction) { + return; + } for (int i = 0; i < server.dirty_containers->length; ++i) { struct sway_container *container = server.dirty_containers->items[i]; transaction_add_container(transaction, container); -- cgit v1.2.3