Updated Remove that hideous template header that should really be regular code since it's specialized and instanciated only for pixmap. --- server/Makefile.am | 3 +- server/pixmap_cache.c | 126 ++++++++++++++++++ server/pixmap_cache.h | 59 +++++++++ server/red_client_shared_cache.h | 235 ---------------------------------- server/red_worker.c | 267 +++++++++++++++++++++------------------ 5 files changed, 331 insertions(+), 359 deletions(-) create mode 100644 server/pixmap_cache.c create mode 100644 server/pixmap_cache.h delete mode 100644 server/red_client_shared_cache.h diff --git a/server/Makefile.am b/server/Makefile.am index 78ccac9..dfa9ea9 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -88,7 +88,6 @@ libspice_server_la_SOURCES = \ red_channel.c \ red_channel.h \ red_client_cache.h \ - red_client_shared_cache.h \ red_common.h \ dispatcher.c \ dispatcher.h \ @@ -126,6 +125,8 @@ libspice_server_la_SOURCES = \ spice_server_utils.h \ spice_image_cache.h \ spice_image_cache.c \ + pixmap_cache.h \ + pixmap_cache.c \ $(NULL) if SUPPORT_GL diff --git a/server/pixmap_cache.c b/server/pixmap_cache.c new file mode 100644 index 0000000..c6a2ac5 --- /dev/null +++ b/server/pixmap_cache.c @@ -0,0 +1,126 @@ +#include "pixmap_cache.h" + +int pixmap_cache_unlocked_set_lossy(PixmapCache *cache, uint64_t id, int lossy) +{ + NewCacheItem *item; + + item = cache->hash_table[BITS_CACHE_HASH_KEY(id)]; + + while (item) { + if (item->id == id) { + item->lossy = lossy; + break; + } + item = item->next; + } + return !!item; +} + +void pixmap_cache_clear(PixmapCache *cache) +{ + NewCacheItem *item; + + if (cache->freezed) { + cache->lru.next = cache->freezed_head; + cache->lru.prev = cache->freezed_tail; + cache->freezed = FALSE; + } + + while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) { + ring_remove(&item->lru_link); + free(item); + } + memset(cache->hash_table, 0, sizeof(*cache->hash_table) * BITS_CACHE_HASH_SIZE); + + cache->available = cache->size; + cache->items = 0; +} + +int pixmap_cache_freeze(PixmapCache *cache) +{ + pthread_mutex_lock(&cache->lock); + + if (cache->freezed) { + pthread_mutex_unlock(&cache->lock); + return FALSE; + } + + cache->freezed_head = cache->lru.next; + cache->freezed_tail = cache->lru.prev; + ring_init(&cache->lru); + memset(cache->hash_table, 0, sizeof(*cache->hash_table) * BITS_CACHE_HASH_SIZE); + cache->available = -1; + cache->freezed = TRUE; + + pthread_mutex_unlock(&cache->lock); + return TRUE; +} + +static void pixmap_cache_destroy(PixmapCache *cache) +{ + spice_assert(cache); + + pthread_mutex_lock(&cache->lock); + pixmap_cache_clear(cache); + pthread_mutex_unlock(&cache->lock); +} + + +static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; +static Ring pixmap_cache_list = {&pixmap_cache_list, &pixmap_cache_list}; + +static PixmapCache *pixmap_cache_new(RedClient *client, uint8_t id, int64_t size) +{ + PixmapCache *cache = spice_new0(PixmapCache, 1); + + ring_item_init(&cache->base); + pthread_mutex_init(&cache->lock, NULL); + cache->id = id; + cache->refs = 1; + ring_init(&cache->lru); + cache->available = size; + cache->size = size; + cache->client = client; + + return cache; +} + +PixmapCache *pixmap_cache_get(RedClient *client, uint8_t id, int64_t size) +{ + PixmapCache *ret = NULL; + RingItem *now; + pthread_mutex_lock(&cache_lock); + + now = &pixmap_cache_list; + while ((now = ring_next(&pixmap_cache_list, now))) { + PixmapCache *cache = (PixmapCache *)now; + if ((cache->client == client) && (cache->id == id)) { + ret = cache; + ret->refs++; + break; + } + } + if (!ret) { + ret = pixmap_cache_new(client, id, size); + ring_add(&pixmap_cache_list, &ret->base); + } + pthread_mutex_unlock(&cache_lock); + return ret; +} + + +void pixmap_cache_unref(PixmapCache *cache) +{ + if (!cache) + return; + + pthread_mutex_lock(&cache_lock); + if (--cache->refs) { + pthread_mutex_unlock(&cache_lock); + return; + } + ring_remove(&cache->base); + pthread_mutex_unlock(&cache_lock); + pixmap_cache_destroy(cache); + free(cache); +} diff --git a/server/pixmap_cache.h b/server/pixmap_cache.h new file mode 100644 index 0000000..6d147c5 --- /dev/null +++ b/server/pixmap_cache.h @@ -0,0 +1,59 @@ +#ifndef _PIXMAP_CACHE_H +# define _PIXMAP_CACHE_H + +#include "red_channel.h" +#include "spice_server_utils.h" + +#define MAX_CACHE_CLIENTS 4 + +#define BITS_CACHE_HASH_SHIFT 10 +#define BITS_CACHE_HASH_SIZE (1 << BITS_CACHE_HASH_SHIFT) +#define BITS_CACHE_HASH_MASK (BITS_CACHE_HASH_SIZE - 1) +#define BITS_CACHE_HASH_KEY(id) ((id) & BITS_CACHE_HASH_MASK) + +typedef struct DisplayChannelClient DisplayChannelClient; + +typedef struct PixmapCache PixmapCache; +typedef struct NewCacheItem NewCacheItem; + +struct NewCacheItem { + RingItem lru_link; + NewCacheItem *next; + uint64_t id; + uint64_t sync[MAX_CACHE_CLIENTS]; + size_t size; + int lossy; +}; + +struct PixmapCache { + RingItem base; + pthread_mutex_t lock; + uint8_t id; + uint32_t refs; + NewCacheItem *hash_table[BITS_CACHE_HASH_SIZE]; + Ring lru; + int64_t available; + int64_t size; + int32_t items; + + int freezed; + RingItem *freezed_head; + RingItem *freezed_tail; + + uint32_t generation; + struct { + uint8_t client; + uint64_t message; + } generation_initiator; + uint64_t sync[MAX_CACHE_CLIENTS]; // here CLIENTS refer to different channel + // clients of the same client + RedClient *client; +}; + +PixmapCache *pixmap_cache_get(RedClient *client, uint8_t id, int64_t size); +void pixmap_cache_unref(PixmapCache *cache); +void pixmap_cache_clear(PixmapCache *cache); +int pixmap_cache_unlocked_set_lossy(PixmapCache *cache, uint64_t id, int lossy); +int pixmap_cache_freeze(PixmapCache *cache); + +#endif /* _PIXMAP_CACHE_H */ diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h deleted file mode 100644 index 7feb28e..0000000 --- a/server/red_client_shared_cache.h +++ /dev/null @@ -1,235 +0,0 @@ -/* - Copyright (C) 2009 Red Hat, Inc. - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, see <http://www.gnu.org/licenses/>. -*/ - -#if defined(CLIENT_PIXMAPS_CACHE) - -#define CACHE PixmapCache - -#define CACHE_NAME bits_cache -#define CACHE_HASH_KEY BITS_CACHE_HASH_KEY -#define CACHE_HASH_SIZE BITS_CACHE_HASH_SIZE -#define PIPE_ITEM_TYPE PIPE_ITEM_TYPE_INVAL_PIXMAP -#define FUNC_NAME(name) pixmap_cache_##name -#define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name -#define CHANNEL DisplayChannel -#define CACH_GENERATION pixmap_cache_generation -#define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS -#else - -#error "no cache type." - -#endif - -#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base); - -static int FUNC_NAME(unlocked_hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc) -{ - NewCacheItem *item; - uint64_t serial; - - serial = red_channel_client_get_message_serial(&dcc->common.base); - item = cache->hash_table[CACHE_HASH_KEY(id)]; - - while (item) { - if (item->id == id) { - ring_remove(&item->lru_link); - ring_add(&cache->lru, &item->lru_link); - spice_assert(dcc->common.id < MAX_CACHE_CLIENTS); - item->sync[dcc->common.id] = serial; - cache->sync[dcc->common.id] = serial; - *lossy = item->lossy; - break; - } - item = item->next; - } - - return !!item; -} - -static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc) -{ - int hit; - pthread_mutex_lock(&cache->lock); - hit = FUNC_NAME(unlocked_hit)(cache,id,lossy, dcc); - pthread_mutex_unlock(&cache->lock); - return hit; -} - -static int FUNC_NAME(unlocked_set_lossy)(CACHE *cache, uint64_t id, int lossy) -{ - NewCacheItem *item; - - item = cache->hash_table[CACHE_HASH_KEY(id)]; - - while (item) { - if (item->id == id) { - item->lossy = lossy; - break; - } - item = item->next; - } - return !!item; -} - -static int FUNC_NAME(unlocked_add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc) -{ - NewCacheItem *item; - uint64_t serial; - int key; - - spice_assert(size > 0); - - item = spice_new(NewCacheItem, 1); - serial = red_channel_client_get_message_serial(&dcc->common.base); - - if (cache->generation != dcc->CACH_GENERATION) { - if (!dcc->pending_pixmaps_sync) { - red_channel_client_pipe_add_type( - &dcc->common.base, PIPE_ITEM_TYPE_PIXMAP_SYNC); - dcc->pending_pixmaps_sync = TRUE; - } - free(item); - return FALSE; - } - - cache->available -= size; - while (cache->available < 0) { - NewCacheItem *tail; - NewCacheItem **now; - - if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) || - tail->sync[dcc->common.id] == serial) { - cache->available += size; - free(item); - return FALSE; - } - - now = &cache->hash_table[CACHE_HASH_KEY(tail->id)]; - for (;;) { - spice_assert(*now); - if (*now == tail) { - *now = tail->next; - break; - } - now = &(*now)->next; - } - ring_remove(&tail->lru_link); - cache->items--; - cache->available += tail->size; - cache->sync[dcc->common.id] = serial; - display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync); - free(tail); - } - ++cache->items; - item->next = cache->hash_table[(key = CACHE_HASH_KEY(id))]; - cache->hash_table[key] = item; - ring_item_init(&item->lru_link); - ring_add(&cache->lru, &item->lru_link); - item->id = id; - item->size = size; - item->lossy = lossy; - memset(item->sync, 0, sizeof(item->sync)); - item->sync[dcc->common.id] = serial; - cache->sync[dcc->common.id] = serial; - return TRUE; -} - -static void PRIVATE_FUNC_NAME(clear)(CACHE *cache) -{ - NewCacheItem *item; - - if (cache->freezed) { - cache->lru.next = cache->freezed_head; - cache->lru.prev = cache->freezed_tail; - cache->freezed = FALSE; - } - - while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) { - ring_remove(&item->lru_link); - free(item); - } - memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE); - - cache->available = cache->size; - cache->items = 0; -} - -static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data) -{ - uint8_t wait_count; - uint64_t serial; - uint32_t i; - - serial = red_channel_client_get_message_serial(&dcc->common.base); - pthread_mutex_lock(&cache->lock); - PRIVATE_FUNC_NAME(clear)(cache); - - dcc->CACH_GENERATION = ++cache->generation; - cache->generation_initiator.client = dcc->common.id; - cache->generation_initiator.message = serial; - cache->sync[dcc->common.id] = serial; - - wait_count = 0; - for (i = 0; i < MAX_CACHE_CLIENTS; i++) { - if (cache->sync[i] && i != dcc->common.id) { - sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY; - sync_data->wait_list[wait_count].channel_id = i; - sync_data->wait_list[wait_count++].message_serial = cache->sync[i]; - } - } - sync_data->wait_count = wait_count; - pthread_mutex_unlock(&cache->lock); -} - -static int FUNC_NAME(freeze)(CACHE *cache) -{ - pthread_mutex_lock(&cache->lock); - - if (cache->freezed) { - pthread_mutex_unlock(&cache->lock); - return FALSE; - } - - cache->freezed_head = cache->lru.next; - cache->freezed_tail = cache->lru.prev; - ring_init(&cache->lru); - memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE); - cache->available = -1; - cache->freezed = TRUE; - - pthread_mutex_unlock(&cache->lock); - return TRUE; -} - -static void FUNC_NAME(destroy)(CACHE *cache) -{ - spice_assert(cache); - - pthread_mutex_lock(&cache->lock); - PRIVATE_FUNC_NAME(clear)(cache); - pthread_mutex_unlock(&cache->lock); -} - -#undef CACHE_NAME -#undef CACHE_HASH_KEY -#undef CACHE_HASH_SIZE -#undef CACHE_INVAL_TYPE -#undef CACHE_MAX_CLIENT_SIZE -#undef FUNC_NAME -#undef VAR_NAME -#undef CHANNEL -#undef CHANNEL_FROM_RCC diff --git a/server/red_worker.c b/server/red_worker.c index bc02b16..5550998 100644 --- a/server/red_worker.c +++ b/server/red_worker.c @@ -91,6 +91,7 @@ #include "red_time.h" #include "spice_bitmap_utils.h" #include "spice_image_cache.h" +#include "pixmap_cache.h" //#define COMPRESS_STAT //#define DUMP_BITMAP @@ -298,20 +299,8 @@ typedef struct VerbItem { uint16_t verb; } VerbItem; -#define MAX_CACHE_CLIENTS 4 #define MAX_LZ_ENCODERS MAX_CACHE_CLIENTS -typedef struct NewCacheItem NewCacheItem; - -struct NewCacheItem { - RingItem lru_link; - NewCacheItem *next; - uint64_t id; - uint64_t sync[MAX_CACHE_CLIENTS]; - size_t size; - int lossy; -}; - typedef struct CacheItem CacheItem; struct CacheItem { @@ -380,11 +369,6 @@ typedef struct LocalCursor { #define WIDE_CLIENT_ACK_WINDOW 40 #define NARROW_CLIENT_ACK_WINDOW 20 -#define BITS_CACHE_HASH_SHIFT 10 -#define BITS_CACHE_HASH_SIZE (1 << BITS_CACHE_HASH_SHIFT) -#define BITS_CACHE_HASH_MASK (BITS_CACHE_HASH_SIZE - 1) -#define BITS_CACHE_HASH_KEY(id) ((id) & BITS_CACHE_HASH_MASK) - #define CLIENT_CURSOR_CACHE_SIZE 256 #define CURSOR_CACHE_HASH_SHIFT 8 @@ -417,7 +401,6 @@ typedef struct ImageItem { typedef struct Drawable Drawable; typedef struct DisplayChannel DisplayChannel; -typedef struct DisplayChannelClient DisplayChannelClient; enum { STREAM_FRAME_NONE, @@ -506,35 +489,6 @@ static const int BITMAP_FMP_BYTES_PER_PIXEL[] = {0, 0, 0, 0, 0, 1, 2, 3, 4, 4, 1 (bitmap_fmt_is_rgb(f) && \ ((f) != SPICE_BITMAP_FMT_8BIT_A)) -pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER; -Ring pixmap_cache_list = {&pixmap_cache_list, &pixmap_cache_list}; - -typedef struct PixmapCache PixmapCache; -struct PixmapCache { - RingItem base; - pthread_mutex_t lock; - uint8_t id; - uint32_t refs; - NewCacheItem *hash_table[BITS_CACHE_HASH_SIZE]; - Ring lru; - int64_t available; - int64_t size; - int32_t items; - - int freezed; - RingItem *freezed_head; - RingItem *freezed_tail; - - uint32_t generation; - struct { - uint8_t client; - uint64_t message; - } generation_initiator; - uint64_t sync[MAX_CACHE_CLIENTS]; // here CLIENTS refer to different channel - // clients of the same client - RedClient *client; -}; - #define NUM_STREAMS 50 typedef struct WaitForChannels { @@ -1037,7 +991,6 @@ static inline void red_detach_stream(RedWorker *worker, Stream *stream, int deta static void red_stop_stream(RedWorker *worker, Stream *stream); static inline void red_stream_maintenance(RedWorker *worker, Drawable *candidate, Drawable *sect); static inline void display_begin_send_message(RedChannelClient *rcc); -static void red_release_pixmap_cache(DisplayChannelClient *dcc); static void red_release_glz(DisplayChannelClient *dcc); static void red_freeze_glz(DisplayChannelClient *dcc); static void display_channel_push_release(DisplayChannelClient *dcc, uint8_t type, uint64_t id, @@ -1619,10 +1572,6 @@ static void common_release_recv_buf(RedChannelClient *rcc, uint16_t type, uint32 } } -#define CLIENT_PIXMAPS_CACHE -#include "red_client_shared_cache.h" -#undef CLIENT_PIXMAPS_CACHE - #define CLIENT_CURSOR_CACHE #include "red_client_cache.h" #undef CLIENT_CURSOR_CACHE @@ -6361,6 +6310,70 @@ static inline int red_compress_image(DisplayChannelClient *dcc, } } +int dcc_pixmap_cache_unlocked_add(DisplayChannelClient *dcc, uint64_t id, uint32_t size, int lossy) +{ + PixmapCache *cache = dcc->pixmap_cache; + NewCacheItem *item; + uint64_t serial; + int key; + + spice_assert(size > 0); + + item = spice_new(NewCacheItem, 1); + serial = red_channel_client_get_message_serial(&dcc->common.base); + + if (cache->generation != dcc->pixmap_cache_generation) { + if (!dcc->pending_pixmaps_sync) { + red_channel_client_pipe_add_type( + &dcc->common.base, PIPE_ITEM_TYPE_PIXMAP_SYNC); + dcc->pending_pixmaps_sync = TRUE; + } + free(item); + return FALSE; + } + + cache->available -= size; + while (cache->available < 0) { + NewCacheItem *tail; + NewCacheItem **now; + + if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) || + tail->sync[dcc->common.id] == serial) { + cache->available += size; + free(item); + return FALSE; + } + + now = &cache->hash_table[BITS_CACHE_HASH_KEY(tail->id)]; + for (;;) { + spice_assert(*now); + if (*now == tail) { + *now = tail->next; + break; + } + now = &(*now)->next; + } + ring_remove(&tail->lru_link); + cache->items--; + cache->available += tail->size; + cache->sync[dcc->common.id] = serial; + display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync); + free(tail); + } + ++cache->items; + item->next = cache->hash_table[(key = BITS_CACHE_HASH_KEY(id))]; + cache->hash_table[key] = item; + ring_item_init(&item->lru_link); + ring_add(&cache->lru, &item->lru_link); + item->id = id; + item->size = size; + item->lossy = lossy; + memset(item->sync, 0, sizeof(item->sync)); + item->sync[dcc->common.id] = serial; + cache->sync[dcc->common.id] = serial; + return TRUE; +} + static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, SpiceImage *image, SpiceImage *io_image, int is_lossy) @@ -6371,9 +6384,9 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, if ((image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { spice_assert(image->descriptor.width * image->descriptor.height > 0); if (!(io_image->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_REPLACE_ME)) { - if (pixmap_cache_unlocked_add(dcc->pixmap_cache, image->descriptor.id, - image->descriptor.width * image->descriptor.height, is_lossy, - dcc)) { + if (dcc_pixmap_cache_unlocked_add(dcc, image->descriptor.id, + image->descriptor.width * image->descriptor.height, + is_lossy)) { io_image->descriptor.flags |= SPICE_IMAGE_FLAGS_CACHE_ME; dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = image->descriptor.id; @@ -6387,6 +6400,43 @@ static inline void red_display_add_image_to_pixmap_cache(RedChannelClient *rcc, } } +static int dcc_pixmap_cache_unlocked_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) +{ + PixmapCache *cache = dcc->pixmap_cache; + NewCacheItem *item; + uint64_t serial; + + serial = red_channel_client_get_message_serial(&dcc->common.base); + item = cache->hash_table[BITS_CACHE_HASH_KEY(id)]; + + while (item) { + if (item->id == id) { + ring_remove(&item->lru_link); + ring_add(&cache->lru, &item->lru_link); + spice_assert(dcc->common.id < MAX_CACHE_CLIENTS); + item->sync[dcc->common.id] = serial; + cache->sync[dcc->common.id] = serial; + *lossy = item->lossy; + break; + } + item = item->next; + } + + return !!item; +} + +static int dcc_pixmap_cache_hit(DisplayChannelClient *dcc, uint64_t id, int *lossy) +{ + int hit; + PixmapCache *cache = dcc->pixmap_cache; + + pthread_mutex_lock(&cache->lock); + hit = dcc_pixmap_cache_unlocked_hit(dcc, id, lossy); + pthread_mutex_unlock(&cache->lock); + return hit; +} + + typedef enum { FILL_BITS_TYPE_INVALID, FILL_BITS_TYPE_CACHE, @@ -6422,8 +6472,7 @@ static FillBitsType fill_bits(DisplayChannelClient *dcc, SpiceMarshaller *m, if ((simage->descriptor.flags & SPICE_IMAGE_FLAGS_CACHE_ME)) { int lossy_cache_item; - if (pixmap_cache_unlocked_hit(dcc->pixmap_cache, image.descriptor.id, - &lossy_cache_item, dcc)) { + if (dcc_pixmap_cache_unlocked_hit(dcc, image.descriptor.id, &lossy_cache_item)) { dcc->send_data.pixmap_cache_items[dcc->send_data.num_pixmap_cache_items++] = image.descriptor.id; if (can_lossy || !lossy_cache_item) { @@ -6673,8 +6722,7 @@ static int is_bitmap_lossy(RedChannelClient *rcc, SpiceImage *image, SpiceRect * int is_hit_lossy; out_data->id = image->descriptor.id; - if (pixmap_cache_hit(dcc->pixmap_cache, image->descriptor.id, - &is_hit_lossy, dcc)) { + if (dcc_pixmap_cache_hit(dcc, image->descriptor.id, &is_hit_lossy)) { out_data->type = BITMAP_DATA_TYPE_CACHE; if (is_hit_lossy) { return TRUE; @@ -8095,8 +8143,7 @@ static inline void display_channel_send_free_list(RedChannelClient *rcc) * But all this message pixmaps cache references used its old serial. * we use pixmap_cache_items to collect these pixmaps, and we update their serial * by calling pixmap_cache_hit. */ - pixmap_cache_hit(dcc->pixmap_cache, dcc->send_data.pixmap_cache_items[i], - &dummy, dcc); + dcc_pixmap_cache_hit(dcc, dcc->send_data.pixmap_cache_items[i], &dummy); } if (free_list->wait.header.wait_count) { @@ -8475,6 +8522,34 @@ static void display_channel_marshall_pixmap_sync(RedChannelClient *rcc, spice_marshall_msg_wait_for_channels(base_marshaller, &wait); } +static void dcc_pixmap_cache_reset(DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data) +{ + PixmapCache *cache = dcc->pixmap_cache; + uint8_t wait_count; + uint64_t serial; + uint32_t i; + + serial = red_channel_client_get_message_serial(&dcc->common.base); + pthread_mutex_lock(&cache->lock); + pixmap_cache_clear(cache); + + dcc->pixmap_cache_generation = ++cache->generation; + cache->generation_initiator.client = dcc->common.id; + cache->generation_initiator.message = serial; + cache->sync[dcc->common.id] = serial; + + wait_count = 0; + for (i = 0; i < MAX_CACHE_CLIENTS; i++) { + if (cache->sync[i] && i != dcc->common.id) { + sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY; + sync_data->wait_list[wait_count].channel_id = i; + sync_data->wait_list[wait_count++].message_serial = cache->sync[i]; + } + } + sync_data->wait_count = wait_count; + pthread_mutex_unlock(&cache->lock); +} + static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMarshaller *base_marshaller) { @@ -8482,7 +8557,7 @@ static void display_channel_marshall_reset_cache(RedChannelClient *rcc, SpiceMsgWaitForChannels wait; red_channel_client_init_send_data(rcc, SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS, NULL); - pixmap_cache_reset(dcc->pixmap_cache, dcc, &wait); + dcc_pixmap_cache_reset(dcc, &wait); spice_marshall_msg_display_inval_all_pixmaps(base_marshaller, &wait); @@ -9098,7 +9173,8 @@ static void display_channel_client_on_disconnect(RedChannelClient *rcc) #ifdef COMPRESS_STAT print_compress_stats(display_channel); #endif - red_release_pixmap_cache(dcc); + pixmap_cache_unref(dcc->pixmap_cache); + dcc->pixmap_cache = NULL; red_release_glz(dcc); red_reset_palette_cache(dcc); free(dcc->send_data.stream_outbuf); @@ -9666,67 +9742,12 @@ static void red_release_glz(DisplayChannelClient *dcc) free(shared_dict); } -static PixmapCache *red_create_pixmap_cache(RedClient *client, uint8_t id, int64_t size) -{ - PixmapCache *cache = spice_new0(PixmapCache, 1); - ring_item_init(&cache->base); - pthread_mutex_init(&cache->lock, NULL); - cache->id = id; - cache->refs = 1; - ring_init(&cache->lru); - cache->available = size; - cache->size = size; - cache->client = client; - return cache; -} - -static PixmapCache *red_get_pixmap_cache(RedClient *client, uint8_t id, int64_t size) -{ - PixmapCache *ret = NULL; - RingItem *now; - pthread_mutex_lock(&cache_lock); - - now = &pixmap_cache_list; - while ((now = ring_next(&pixmap_cache_list, now))) { - PixmapCache *cache = (PixmapCache *)now; - if ((cache->client == client) && (cache->id == id)) { - ret = cache; - ret->refs++; - break; - } - } - if (!ret) { - ret = red_create_pixmap_cache(client, id, size); - ring_add(&pixmap_cache_list, &ret->base); - } - pthread_mutex_unlock(&cache_lock); - return ret; -} - -static void red_release_pixmap_cache(DisplayChannelClient *dcc) -{ - PixmapCache *cache; - if (!(cache = dcc->pixmap_cache)) { - return; - } - dcc->pixmap_cache = NULL; - pthread_mutex_lock(&cache_lock); - if (--cache->refs) { - pthread_mutex_unlock(&cache_lock); - return; - } - ring_remove(&cache->base); - pthread_mutex_unlock(&cache_lock); - pixmap_cache_destroy(cache); - free(cache); -} - static int display_channel_init_cache(DisplayChannelClient *dcc, SpiceMsgcDisplayInit *init_info) { spice_assert(!dcc->pixmap_cache); - return !!(dcc->pixmap_cache = red_get_pixmap_cache(dcc->common.base.client, - init_info->pixmap_cache_id, - init_info->pixmap_cache_size)); + return !!(dcc->pixmap_cache = pixmap_cache_get(dcc->common.base.client, + init_info->pixmap_cache_id, + init_info->pixmap_cache_size)); } static int display_channel_init_glz_dictionary(DisplayChannelClient *dcc, @@ -9860,8 +9881,8 @@ static int display_channel_handle_migrate_data(RedChannelClient *rcc, uint32_t s * channel client that froze the cache on the src size receives the migrate * data and unfreezes the cache by setting its size > 0 and by triggering * pixmap_cache_reset */ - dcc->pixmap_cache = red_get_pixmap_cache(dcc->common.base.client, - migrate_data->pixmap_cache_id, -1); + dcc->pixmap_cache = pixmap_cache_get(dcc->common.base.client, + migrate_data->pixmap_cache_id, -1); if (!dcc->pixmap_cache) { return FALSE; } -- 2.4.3 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel