summaryrefslogtreecommitdiffstats
path: root/server/red_client_shared_cache.h
diff options
context:
space:
mode:
authorYaniv Kamay <ykamay@redhat.com>2009-09-19 21:25:46 +0300
committerYaniv Kamay <ykamay@redhat.com>2009-10-14 15:06:41 +0200
commitc1b79eb035fa158fb2ac3bc8e559809611070016 (patch)
tree3348dd749a700dedf87c9b16fe8be77c62928df8 /server/red_client_shared_cache.h
downloadspice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.gz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.tar.xz
spice-c1b79eb035fa158fb2ac3bc8e559809611070016.zip
fresh start
Diffstat (limited to 'server/red_client_shared_cache.h')
-rw-r--r--server/red_client_shared_cache.h216
1 files changed, 216 insertions, 0 deletions
diff --git a/server/red_client_shared_cache.h b/server/red_client_shared_cache.h
new file mode 100644
index 00000000..1d3c4528
--- /dev/null
+++ b/server/red_client_shared_cache.h
@@ -0,0 +1,216 @@
+/*
+ Copyright (C) 2009 Red Hat, Inc.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. 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 RED_DISPLAY_INVAL_ALL_PIXMAPS
+#else
+
+#error "no cache type."
+
+#endif
+
+
+static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, CHANNEL *channel)
+{
+ NewCacheItem *item;
+ uint64_t serial;
+
+ serial = channel_message_serial((RedChannel *)channel);
+ pthread_mutex_lock(&cache->lock);
+ 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);
+ ASSERT(channel->base.id < MAX_CACHE_CLIENTS)
+ item->sync[channel->base.id] = serial;
+ cache->sync[channel->base.id] = serial;
+ break;
+ }
+ item = item->next;
+ }
+ pthread_mutex_unlock(&cache->lock);
+
+ return !!item;
+}
+
+static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, CHANNEL *channel)
+{
+ NewCacheItem *item;
+ uint64_t serial;
+ int key;
+
+ ASSERT(size > 0);
+
+ item = malloc(sizeof(*item));
+ if (!item) {
+ return FALSE;
+ }
+ serial = channel_message_serial((RedChannel *)channel);
+
+ pthread_mutex_lock(&cache->lock);
+
+ if (cache->generation != channel->CACH_GENERATION) {
+ if (!channel->pending_pixmaps_sync) {
+ red_pipe_add_type((RedChannel *)channel, PIPE_ITEM_TYPE_PIXMAP_SYNC);
+ channel->pending_pixmaps_sync = TRUE;
+ }
+ pthread_mutex_unlock(&cache->lock);
+ 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[channel->base.id] == serial) {
+ cache->available += size;
+ pthread_mutex_unlock(&cache->lock);
+ free(item);
+ return FALSE;
+ }
+
+ now = &cache->hash_table[CACHE_HASH_KEY(tail->id)];
+ for (;;) {
+ 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[channel->base.id] = serial;
+ display_channel_push_release(channel, RED_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;
+ memset(item->sync, 0, sizeof(item->sync));
+ item->sync[channel->base.id] = serial;
+ cache->sync[channel->base.id] = serial;
+ pthread_mutex_unlock(&cache->lock);
+ 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, CHANNEL *channel, RedWaitForChannels* sync_data)
+{
+ uint8_t wait_count;
+ uint64_t serial;
+ uint32_t i;
+
+ serial = channel_message_serial((RedChannel *)channel);
+ pthread_mutex_lock(&cache->lock);
+ PRIVATE_FUNC_NAME(clear)(cache);
+
+ channel->CACH_GENERATION = ++cache->generation;
+ cache->generation_initiator.client = channel->base.id;
+ cache->generation_initiator.message = serial;
+ cache->sync[channel->base.id] = serial;
+
+ wait_count = 0;
+ for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
+ if (cache->sync[i] && i != channel->base.id) {
+ sync_data->wait_list[wait_count].channel_type = RED_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)
+{
+ 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
+