diff options
Diffstat (limited to 'src/cairo-xcb-shm.c')
-rw-r--r-- | src/cairo-xcb-shm.c | 114 |
1 files changed, 90 insertions, 24 deletions
diff --git a/src/cairo-xcb-shm.c b/src/cairo-xcb-shm.c index 417496e..c3e3d35 100644 --- a/src/cairo-xcb-shm.c +++ b/src/cairo-xcb-shm.c @@ -49,6 +49,11 @@ typedef struct _cairo_xcb_shm_mem_block cairo_xcb_shm_mem_block_t; +typedef enum { + PENDING_WAIT, + PENDING_POLL +} shm_wait_type_t; + struct _cairo_xcb_shm_mem_block { unsigned int bits; cairo_list_t link; @@ -412,6 +417,70 @@ _cairo_xcb_shm_mem_pool_destroy (cairo_xcb_shm_mem_pool_t *pool) free (pool); } +static void +_cairo_xcb_shm_info_finalize (cairo_xcb_shm_info_t *shm_info) +{ + cairo_xcb_connection_t *connection = shm_info->connection; + + assert (CAIRO_MUTEX_IS_LOCKED (connection->shm_mutex)); + + _cairo_xcb_shm_mem_pool_free (shm_info->pool, shm_info->mem); + _cairo_freepool_free (&connection->shm_info_freelist, shm_info); + + /* scan for old, unused pools - hold at least one in reserve */ + if (! cairo_list_is_singular (&connection->shm_pools)) + { + cairo_xcb_shm_mem_pool_t *pool, *next; + cairo_list_t head; + + cairo_list_init (&head); + cairo_list_move (connection->shm_pools.next, &head); + + cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, + &connection->shm_pools, link) + { + if (pool->free_bytes == pool->max_bytes) { + _cairo_xcb_connection_shm_detach (connection, pool->shmseg); + _cairo_xcb_shm_mem_pool_destroy (pool); + } + } + + cairo_list_move (head.next, &connection->shm_pools); + } +} + +static void +_cairo_xcb_shm_process_pending (cairo_xcb_connection_t *connection, shm_wait_type_t wait) +{ + cairo_xcb_shm_info_t *info, *next; + xcb_get_input_focus_reply_t *reply; + + assert (CAIRO_MUTEX_IS_LOCKED (connection->shm_mutex)); + cairo_list_foreach_entry_safe (info, next, cairo_xcb_shm_info_t, + &connection->shm_pending, pending) + { + switch (wait) { + case PENDING_WAIT: + reply = xcb_wait_for_reply (connection->xcb_connection, + info->sync.sequence, NULL); + break; + case PENDING_POLL: + if (! xcb_poll_for_reply (connection->xcb_connection, + info->sync.sequence, + (void **) &reply, NULL)) + /* We cannot be sure the server finished with this image yet, so + * try again later. All other shm info are guranteed to have a + * larger sequence number and thus don't have to be checked. */ + return; + break; + } + + free (reply); + cairo_list_del (&info->pending); + _cairo_xcb_shm_info_finalize (info); + } +} + cairo_int_status_t _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection, size_t size, @@ -426,6 +495,8 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection, assert (connection->flags & CAIRO_XCB_HAS_SHM); CAIRO_MUTEX_LOCK (connection->shm_mutex); + _cairo_xcb_shm_process_pending (connection, PENDING_POLL); + cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, &connection->shm_pools, link) { @@ -513,6 +584,7 @@ _cairo_xcb_connection_allocate_shm_info (cairo_xcb_connection_t *connection, shm_info->shm = pool->shmseg; shm_info->offset = (char *) mem - (char *) pool->base; shm_info->mem = mem; + shm_info->sync.sequence = XCB_NONE; /* scan for old, unused pools */ cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, @@ -535,39 +607,33 @@ _cairo_xcb_shm_info_destroy (cairo_xcb_shm_info_t *shm_info) { cairo_xcb_connection_t *connection = shm_info->connection; - CAIRO_MUTEX_LOCK (connection->shm_mutex); - - _cairo_xcb_shm_mem_pool_free (shm_info->pool, shm_info->mem); - _cairo_freepool_free (&connection->shm_info_freelist, shm_info); - - /* scan for old, unused pools - hold at least one in reserve */ - if (! cairo_list_is_singular (&connection->shm_pools) && - _cairo_xcb_connection_take_socket (connection) == CAIRO_STATUS_SUCCESS) - { - cairo_xcb_shm_mem_pool_t *pool, *next; - cairo_list_t head; - - cairo_list_init (&head); - cairo_list_move (connection->shm_pools.next, &head); + /* We can only return shm_info->mem to the allocator when we can be sure + * that the X server no longer reads from it. Since the X server processes + * requests in order, we send a GetInputFocus here. + * _cairo_xcb_shm_process_pending () will later check if the reply for that + * request was received and then actually mark this memory area as free. */ - cairo_list_foreach_entry_safe (pool, next, cairo_xcb_shm_mem_pool_t, - &connection->shm_pools, link) - { - if (pool->free_bytes == pool->max_bytes) { - _cairo_xcb_connection_shm_detach (connection, pool->shmseg); - _cairo_xcb_shm_mem_pool_destroy (pool); - } - } + CAIRO_MUTEX_LOCK (connection->shm_mutex); + assert (shm_info->sync.sequence == XCB_NONE); + shm_info->sync = xcb_get_input_focus (connection->xcb_connection); - cairo_list_move (head.next, &connection->shm_pools); - } + cairo_list_init (&shm_info->pending); + cairo_list_add_tail (&shm_info->pending, &connection->shm_pending); + CAIRO_MUTEX_UNLOCK (connection->shm_mutex); +} +void +_cairo_xcb_connection_shm_mem_pools_flush (cairo_xcb_connection_t *connection) +{ + CAIRO_MUTEX_LOCK (connection->shm_mutex); + _cairo_xcb_shm_process_pending (connection, PENDING_WAIT); CAIRO_MUTEX_UNLOCK (connection->shm_mutex); } void _cairo_xcb_connection_shm_mem_pools_fini (cairo_xcb_connection_t *connection) { + assert (cairo_list_is_empty (&connection->shm_pending)); while (! cairo_list_is_empty (&connection->shm_pools)) { _cairo_xcb_shm_mem_pool_destroy (cairo_list_first_entry (&connection->shm_pools, cairo_xcb_shm_mem_pool_t, |