diff --git a/common/list.c b/common/list.c index 39cc10e19..cab10c1e5 100644 --- a/common/list.c +++ b/common/list.c @@ -62,6 +62,13 @@ void list_cat(list_t *list, list_t *source) { } } +void list_empty(list_t *list) { + list->capacity = 10; + list->length = 0; + free(list->items); + list->items = malloc(sizeof(void*) * list->capacity); +} + void list_qsort(list_t *list, int compare(const void *left, const void *right)) { qsort(list->items, list->length, sizeof(void *), compare); } diff --git a/include/list.h b/include/list.h index 7eead4acc..d352dbd5b 100644 --- a/include/list.h +++ b/include/list.h @@ -14,6 +14,7 @@ void list_add(list_t *list, void *item); void list_insert(list_t *list, int index, void *item); void list_del(list_t *list, int index); void list_cat(list_t *list, list_t *source); +void list_empty(list_t *list); // See qsort. Remember to use *_qsort functions as compare functions, // because they dereference the left and right arguments first! void list_qsort(list_t *list, int compare(const void *left, const void *right)); diff --git a/include/sway/server.h b/include/sway/server.h index bd96b0857..0efc6baa2 100644 --- a/include/sway/server.h +++ b/include/sway/server.h @@ -47,7 +47,7 @@ struct sway_server { bool debug_txn_timings; - struct sway_transaction *head_transaction; // singly linked list + list_t *transactions; // When a view is being destroyed and is waiting for a transaction to // complete it will be stored here. diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index c29b66613..7a2e78e55 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c @@ -32,7 +32,6 @@ struct sway_transaction { list_t *instructions; // struct sway_transaction_instruction * size_t num_waiting; size_t num_configures; - struct sway_transaction *next; struct timespec create_time; struct timespec commit_time; }; @@ -225,16 +224,24 @@ static void transaction_apply(struct sway_transaction *transaction) { } } +/** + * For simplicity, we only progress the queue if it can be completely flushed. + */ static void transaction_progress_queue() { - struct sway_transaction *transaction = server.head_transaction; - struct sway_transaction *next = NULL; - while (transaction && !transaction->num_waiting) { - next = transaction->next; + // We iterate this list in reverse because we're more likely to find a + // waiting transactions at the end of the list. + for (int i = server.transactions->length - 1; i >= 0; --i) { + struct sway_transaction *transaction = server.transactions->items[i]; + if (transaction->num_waiting) { + return; + } + } + for (int i = 0; i < server.transactions->length; ++i) { + struct sway_transaction *transaction = server.transactions->items[i]; transaction_apply(transaction); transaction_destroy(transaction); - transaction = next; } - server.head_transaction = transaction; + list_empty(server.transactions); } static int handle_timeout(void *data) { @@ -295,18 +302,8 @@ void transaction_commit(struct sway_transaction *transaction) { if (server.debug_txn_timings) { clock_gettime(CLOCK_MONOTONIC, &transaction->commit_time); } - if (server.head_transaction) { - // There is another transaction in progress - we must add this one to - // the queue so we complete after it. - struct sway_transaction *tail = server.head_transaction; - while (tail->next) { - tail = tail->next; - } - tail->next = transaction; - } else if (transaction->num_waiting) { - // There are no other transactions, but we're not applying immediately - // so we must jump in the queue so others will queue behind us. - server.head_transaction = transaction; + if (server.transactions->length || transaction->num_waiting) { + list_add(server.transactions, transaction); } else { // There are no other transactions in progress, and this one has nothing // to wait for, so we can skip the queue. @@ -359,12 +356,24 @@ static void set_instruction_ready( } } +/** + * 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]; + set_instruction_ready(instruction); + } +} + 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_instruction_ready(instruction); + set_instructions_ready(view, i); return; } } @@ -377,7 +386,7 @@ void transaction_notify_view_ready_by_size(struct sway_view *view, view->swayc->instructions->items[i]; if (!instruction->ready && instruction->state.view_width == width && instruction->state.view_height == height) { - set_instruction_ready(instruction); + set_instructions_ready(view, i); return; } } diff --git a/sway/server.c b/sway/server.c index a2bc57026..884d971ef 100644 --- a/sway/server.c +++ b/sway/server.c @@ -119,6 +119,8 @@ bool server_init(struct sway_server *server) { } server->destroying_containers = create_list(); + server->transactions = create_list(); + input_manager = input_manager_create(server); return true; } @@ -127,6 +129,7 @@ void server_fini(struct sway_server *server) { // TODO: free sway-specific resources wl_display_destroy(server->wl_display); list_free(server->destroying_containers); + list_free(server->transactions); } void server_run(struct sway_server *server) {