[Spice-devel] [PATCH 4/5] server: move some pixmap cache code in own file

Frediano Ziglio fziglio at redhat.com
Fri Oct 16 06:30:01 PDT 2015


More updates, add license to files and renamed.
These changes are contained in later patches.



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            | 142 +++++++++++++++++++++
 server/pixmap-cache.h            |  76 +++++++++++
 server/red_client_shared_cache.h | 235 ----------------------------------
 server/red_worker.c              | 267 +++++++++++++++++++++------------------
 5 files changed, 364 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..b764a44 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..61d225e
--- /dev/null
+++ b/server/pixmap-cache.c
@@ -0,0 +1,142 @@
+/*
+   Copyright (C) 2009-2015 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/>.
+*/
+#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..336c9ae
--- /dev/null
+++ b/server/pixmap-cache.h
@@ -0,0 +1,76 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+   Copyright (C) 2009-2015 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/>.
+*/
+#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..757b780 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


More information about the Spice-devel mailing list