summaryrefslogtreecommitdiff
path: root/src/cairo-xcb-shm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-xcb-shm.c')
-rw-r--r--src/cairo-xcb-shm.c114
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,