/*
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 .
*/
#ifdef HAVE_CONFIG_H
#include
#endif
#if defined(CLIENT_CURSOR_CACHE)
#define CACHE_NAME cursor_cache
#define CACHE_HASH_KEY CURSOR_CACHE_HASH_KEY
#define CACHE_HASH_SIZE CURSOR_CACHE_HASH_SIZE
#define CACHE_INVAL_TYPE SPICE_MSG_CURSOR_INVAL_ONE
#define FUNC_NAME(name) red_cursor_cache_##name
#define VAR_NAME(name) cursor_cache_##name
#define CHANNEL CursorChannel
#define CHANNELCLIENT CursorChannelClient
#elif defined(CLIENT_PALETTE_CACHE)
#define CACHE_NAME palette_cache
#define CACHE_HASH_KEY PALETTE_CACHE_HASH_KEY
#define CACHE_HASH_SIZE PALETTE_CACHE_HASH_SIZE
#define CACHE_INVAL_TYPE SPICE_MSG_DISPLAY_INVAL_PALETTE
#define FUNC_NAME(name) red_palette_cache_##name
#define VAR_NAME(name) palette_cache_##name
#define CHANNEL DisplayChannel
#define CHANNELCLIENT DisplayChannelClient
#else
#error "no cache type."
#endif
#define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
static CacheItem *FUNC_NAME(find)(CHANNELCLIENT *channel_client, uint64_t id)
{
CacheItem *item = channel_client->CACHE_NAME[CACHE_HASH_KEY(id)];
while (item) {
if (item->id == id) {
ring_remove(&item->u.cache_data.lru_link);
ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
break;
}
item = item->u.cache_data.next;
}
return item;
}
static void FUNC_NAME(remove)(CHANNELCLIENT *channel_client, CacheItem *item)
{
CacheItem **now;
spice_assert(item);
now = &channel_client->CACHE_NAME[CACHE_HASH_KEY(item->id)];
for (;;) {
spice_assert(*now);
if (*now == item) {
*now = item->u.cache_data.next;
break;
}
now = &(*now)->u.cache_data.next;
}
ring_remove(&item->u.cache_data.lru_link);
channel_client->VAR_NAME(items)--;
channel_client->VAR_NAME(available) += item->size;
pipe_item_init(&item->u.pipe_data, PIPE_ITEM_TYPE_INVAL_ONE);
red_channel_client_pipe_add_tail_and_push(&channel_client->common.base, &item->u.pipe_data); // for now
}
static int FUNC_NAME(add)(CHANNELCLIENT *channel_client, uint64_t id, size_t size)
{
CacheItem *item;
int key;
item = spice_new(CacheItem, 1);
channel_client->VAR_NAME(available) -= size;
while (channel_client->VAR_NAME(available) < 0) {
CacheItem *tail = (CacheItem *)ring_get_tail(&channel_client->VAR_NAME(lru));
if (!tail) {
channel_client->VAR_NAME(available) += size;
free(item);
return FALSE;
}
FUNC_NAME(remove)(channel_client, tail);
}
++channel_client->VAR_NAME(items);
item->u.cache_data.next = channel_client->CACHE_NAME[(key = CACHE_HASH_KEY(id))];
channel_client->CACHE_NAME[key] = item;
ring_item_init(&item->u.cache_data.lru_link);
ring_add(&channel_client->VAR_NAME(lru), &item->u.cache_data.lru_link);
item->id = id;
item->size = size;
item->inval_type = CACHE_INVAL_TYPE;
return TRUE;
}
static void FUNC_NAME(reset)(CHANNELCLIENT *channel_client, long size)
{
int i;
for (i = 0; i < CACHE_HASH_SIZE; i++) {
while (channel_client->CACHE_NAME[i]) {
CacheItem *item = channel_client->CACHE_NAME[i];
channel_client->CACHE_NAME[i] = item->u.cache_data.next;
free(item);
}
}
ring_init(&channel_client->VAR_NAME(lru));
channel_client->VAR_NAME(available) = size;
channel_client->VAR_NAME(items) = 0;
}
#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 CHANNELCLIENT
#undef CHANNEL_FROM_RCC