2 Copyright (C) 2009 Red Hat, Inc.
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 #if defined(CLIENT_PIXMAPS_CACHE)
20 #define CACHE PixmapCache
22 #define CACHE_NAME bits_cache
23 #define CACHE_HASH_KEY BITS_CACHE_HASH_KEY
24 #define CACHE_HASH_SIZE BITS_CACHE_HASH_SIZE
25 #define PIPE_ITEM_TYPE PIPE_ITEM_TYPE_INVAL_PIXMAP
26 #define FUNC_NAME(name) pixmap_cache_##name
27 #define PRIVATE_FUNC_NAME(name) __pixmap_cache_##name
28 #define CHANNEL DisplayChannel
29 #define CACH_GENERATION pixmap_cache_generation
30 #define INVAL_ALL_VERB SPICE_MSG_DISPLAY_INVAL_ALL_PIXMAPS
33 #error "no cache type."
37 #define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
39 static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
44 serial = red_channel_client_get_message_serial(&dcc->common.base);
45 pthread_mutex_lock(&cache->lock);
46 item = cache->hash_table[CACHE_HASH_KEY(id)];
50 ring_remove(&item->lru_link);
51 ring_add(&cache->lru, &item->lru_link);
52 spice_assert(dcc->common.id < MAX_CACHE_CLIENTS);
53 item->sync[dcc->common.id] = serial;
54 cache->sync[dcc->common.id] = serial;
60 pthread_mutex_unlock(&cache->lock);
65 static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
68 pthread_mutex_lock(&cache->lock);
70 item = cache->hash_table[CACHE_HASH_KEY(id)];
79 pthread_mutex_unlock(&cache->lock);
83 static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc)
89 spice_assert(size > 0);
91 item = spice_new(NewCacheItem, 1);
92 serial = red_channel_client_get_message_serial(&dcc->common.base);
94 pthread_mutex_lock(&cache->lock);
96 if (cache->generation != dcc->CACH_GENERATION) {
97 if (!dcc->pending_pixmaps_sync) {
98 red_channel_client_pipe_add_type(
99 &dcc->common.base, PIPE_ITEM_TYPE_PIXMAP_SYNC);
100 dcc->pending_pixmaps_sync = TRUE;
102 pthread_mutex_unlock(&cache->lock);
107 cache->available -= size;
108 while (cache->available < 0) {
112 if (!(tail = (NewCacheItem *)ring_get_tail(&cache->lru)) ||
113 tail->sync[dcc->common.id] == serial) {
114 cache->available += size;
115 pthread_mutex_unlock(&cache->lock);
120 now = &cache->hash_table[CACHE_HASH_KEY(tail->id)];
129 ring_remove(&tail->lru_link);
131 cache->available += tail->size;
132 cache->sync[dcc->common.id] = serial;
133 display_channel_push_release(dcc, SPICE_RES_TYPE_PIXMAP, tail->id, tail->sync);
137 item->next = cache->hash_table[(key = CACHE_HASH_KEY(id))];
138 cache->hash_table[key] = item;
139 ring_item_init(&item->lru_link);
140 ring_add(&cache->lru, &item->lru_link);
144 memset(item->sync, 0, sizeof(item->sync));
145 item->sync[dcc->common.id] = serial;
146 cache->sync[dcc->common.id] = serial;
147 pthread_mutex_unlock(&cache->lock);
151 static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
155 if (cache->freezed) {
156 cache->lru.next = cache->freezed_head;
157 cache->lru.prev = cache->freezed_tail;
158 cache->freezed = FALSE;
161 while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) {
162 ring_remove(&item->lru_link);
165 memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE);
167 cache->available = cache->size;
171 static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
177 serial = red_channel_client_get_message_serial(&dcc->common.base);
178 pthread_mutex_lock(&cache->lock);
179 PRIVATE_FUNC_NAME(clear)(cache);
181 dcc->CACH_GENERATION = ++cache->generation;
182 cache->generation_initiator.client = dcc->common.id;
183 cache->generation_initiator.message = serial;
184 cache->sync[dcc->common.id] = serial;
187 for (i = 0; i < MAX_CACHE_CLIENTS; i++) {
188 if (cache->sync[i] && i != dcc->common.id) {
189 sync_data->wait_list[wait_count].channel_type = SPICE_CHANNEL_DISPLAY;
190 sync_data->wait_list[wait_count].channel_id = i;
191 sync_data->wait_list[wait_count++].message_serial = cache->sync[i];
194 sync_data->wait_count = wait_count;
195 pthread_mutex_unlock(&cache->lock);
198 static int FUNC_NAME(freeze)(CACHE *cache)
200 pthread_mutex_lock(&cache->lock);
202 if (cache->freezed) {
203 pthread_mutex_unlock(&cache->lock);
207 cache->freezed_head = cache->lru.next;
208 cache->freezed_tail = cache->lru.prev;
209 ring_init(&cache->lru);
210 memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE);
211 cache->available = -1;
212 cache->freezed = TRUE;
214 pthread_mutex_unlock(&cache->lock);
218 static void FUNC_NAME(destroy)(CACHE *cache)
222 pthread_mutex_lock(&cache->lock);
223 PRIVATE_FUNC_NAME(clear)(cache);
224 pthread_mutex_unlock(&cache->lock);
228 #undef CACHE_HASH_KEY
229 #undef CACHE_HASH_SIZE
230 #undef CACHE_INVAL_TYPE
231 #undef CACHE_MAX_CLIENT_SIZE
235 #undef CHANNEL_FROM_RCC