@ -1,5 +1,6 @@
# define _POSIX_C_SOURCE 200809L
# define _POSIX_C_SOURCE 200809L
# include <errno.h>
# include <errno.h>
# include <limits.h>
# include <stdbool.h>
# include <stdbool.h>
# include <stdlib.h>
# include <stdlib.h>
# include <string.h>
# include <string.h>
@ -16,26 +17,12 @@
# include "list.h"
# include "list.h"
# include "log.h"
# include "log.h"
/**
* How long we should wait for views to respond to the configure before giving
* up and applying the transaction anyway .
*/
int txn_timeout_ms = 200 ;
/**
* If enabled , sway will always wait for the transaction timeout before
* applying it , rather than applying it when the views are ready . This allows us
* to observe the rendered state while a transaction is in progress .
*/
bool txn_debug = false ;
struct sway_transaction {
struct sway_transaction {
struct wl_event_source * timer ;
struct wl_event_source * timer ;
list_t * instructions ; // struct sway_transaction_instruction *
list_t * instructions ; // struct sway_transaction_instruction *
size_t num_waiting ;
size_t num_waiting ;
size_t num_configures ;
size_t num_configures ;
uint32_t con_ids ; // Bitwise XOR of view container IDs
uint32_t con_ids ; // Bitwise XOR of view container IDs
struct timespec create_time ;
struct timespec commit_time ;
struct timespec commit_time ;
} ;
} ;
@ -53,9 +40,6 @@ static struct sway_transaction *transaction_create() {
return NULL ;
return NULL ;
}
}
transaction - > instructions = create_list ( ) ;
transaction - > instructions = create_list ( ) ;
if ( server . debug_txn_timings ) {
clock_gettime ( CLOCK_MONOTONIC , & transaction - > create_time ) ;
}
return transaction ;
return transaction ;
}
}
@ -149,19 +133,14 @@ static void transaction_add_container(struct sway_transaction *transaction,
*/
*/
static void transaction_apply ( struct sway_transaction * transaction ) {
static void transaction_apply ( struct sway_transaction * transaction ) {
wlr_log ( WLR_DEBUG , " Applying transaction %p " , transaction ) ;
wlr_log ( WLR_DEBUG , " Applying transaction %p " , transaction ) ;
if ( server. debug_ txn_timings) {
if ( debug. txn_timings) {
struct timespec now ;
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
struct timespec * create = & transaction - > create_time ;
struct timespec * commit = & transaction - > commit_time ;
struct timespec * commit = & transaction - > commit_time ;
float ms_arranging = ( commit - > tv_sec - create - > tv_sec ) * 1000 +
float ms = ( now . tv_sec - commit - > tv_sec ) * 1000 +
( commit - > tv_nsec - create - > tv_nsec ) / 1000000.0 ;
float ms_waiting = ( now . tv_sec - commit - > tv_sec ) * 1000 +
( now . tv_nsec - commit - > tv_nsec ) / 1000000.0 ;
( now . tv_nsec - commit - > tv_nsec ) / 1000000.0 ;
float ms_total = ms_arranging + ms_waiting ;
wlr_log ( WLR_DEBUG , " Transaction %p: %.1fms waiting "
wlr_log ( WLR_DEBUG , " Transaction %p: %.1fms arranging, %.1fms waiting, "
" (%.1f frames if 60Hz) " , transaction , ms , ms / ( 1000.0f / 60 ) ) ;
" %.1fms total (%.1f frames if 60Hz) " , transaction ,
ms_arranging , ms_waiting , ms_total , ms_total / ( 1000.0f / 60 ) ) ;
}
}
// Apply the instruction state to the container's current state
// Apply the instruction state to the container's current state
@ -310,25 +289,30 @@ static void transaction_commit(struct sway_transaction *transaction) {
con - > instruction = instruction ;
con - > instruction = instruction ;
}
}
transaction - > num_configures = transaction - > num_waiting ;
transaction - > num_configures = transaction - > num_waiting ;
if ( server. debug_ txn_timings) {
if ( debug. txn_timings) {
clock_gettime ( CLOCK_MONOTONIC , & transaction - > commit_time ) ;
clock_gettime ( CLOCK_MONOTONIC , & transaction - > commit_time ) ;
}
}
if ( debug . noatomic ) {
transaction - > num_waiting = 0 ;
} else if ( debug . txn_wait ) {
// Force the transaction to time out even if all views are ready.
// We do this by inflating the waiting counter.
transaction - > num_waiting + = 1000000 ;
}
if ( transaction - > num_waiting ) {
if ( transaction - > num_waiting ) {
// Set up a timer which the views must respond within
// Set up a timer which the views must respond within
transaction - > timer = wl_event_loop_add_timer ( server . wl_event_loop ,
transaction - > timer = wl_event_loop_add_timer ( server . wl_event_loop ,
handle_timeout , transaction ) ;
handle_timeout , transaction ) ;
if ( transaction - > timer ) {
if ( transaction - > timer ) {
wl_event_source_timer_update ( transaction - > timer , txn_timeout_ms ) ;
wl_event_source_timer_update ( transaction - > timer ,
server . txn_timeout_ms ) ;
} else {
} else {
wlr_log ( WLR_ERROR , " Unable to create transaction timer (%s). "
wlr_log ( WLR_ERROR , " Unable to create transaction timer (%s). "
" Some imperfect frames might be rendered. " ,
" Some imperfect frames might be rendered. " ,
strerror ( errno ) ) ;
strerror ( errno ) ) ;
handle_timeout ( transaction ) ;
transaction - > num_waiting = 0 ;
}
}
} else {
wlr_log ( WLR_DEBUG ,
" Transaction %p has nothing to wait for " , transaction ) ;
}
}
// The debug tree shows the pending/live tree. Here is a good place to
// The debug tree shows the pending/live tree. Here is a good place to
@ -341,7 +325,7 @@ static void set_instruction_ready(
struct sway_transaction_instruction * instruction ) {
struct sway_transaction_instruction * instruction ) {
struct sway_transaction * transaction = instruction - > transaction ;
struct sway_transaction * transaction = instruction - > transaction ;
if ( server. debug_ txn_timings) {
if ( debug. txn_timings) {
struct timespec now ;
struct timespec now ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
clock_gettime ( CLOCK_MONOTONIC , & now ) ;
struct timespec * start = & transaction - > commit_time ;
struct timespec * start = & transaction - > commit_time ;
@ -352,15 +336,12 @@ static void set_instruction_ready(
transaction - > num_configures - transaction - > num_waiting + 1 ,
transaction - > num_configures - transaction - > num_waiting + 1 ,
transaction - > num_configures , ms ,
transaction - > num_configures , ms ,
instruction - > container - > name ) ;
instruction - > container - > name ) ;
}
}
// If the transaction has timed out then its num_waiting will be 0 already.
// If the transaction has timed out then its num_waiting will be 0 already.
if ( transaction - > num_waiting > 0 & & - - transaction - > num_waiting = = 0 ) {
if ( transaction - > num_waiting > 0 & & - - transaction - > num_waiting = = 0 ) {
if ( ! txn_debug ) {
wlr_log ( WLR_DEBUG , " Transaction %p is ready " , transaction ) ;
wlr_log ( WLR_DEBUG , " Transaction %p is ready " , transaction ) ;
wl_event_source_timer_update ( transaction - > timer , 0 ) ;
wl_event_source_timer_update ( transaction - > timer , 0 ) ;
}
}
}
instruction - > container - > instruction = NULL ;
instruction - > container - > instruction = NULL ;