uploaded original spice-server-0.12.4 and celt-0.5.1.3
[sdk/emulator/libs/spice-server.git] / server / red_client_shared_cache.h
1 /*
2    Copyright (C) 2009 Red Hat, Inc.
3
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.
8
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.
13
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/>.
16 */
17
18 #if defined(CLIENT_PIXMAPS_CACHE)
19
20 #define CACHE PixmapCache
21
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
31 #else
32
33 #error "no cache type."
34
35 #endif
36
37 #define CHANNEL_FROM_RCC(rcc) SPICE_CONTAINEROF((rcc)->channel, CHANNEL, common.base);
38
39 static int FUNC_NAME(hit)(CACHE *cache, uint64_t id, int *lossy, DisplayChannelClient *dcc)
40 {
41     NewCacheItem *item;
42     uint64_t serial;
43
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)];
47
48     while (item) {
49         if (item->id == 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;
55             *lossy = item->lossy;
56             break;
57         }
58         item = item->next;
59     }
60     pthread_mutex_unlock(&cache->lock);
61
62     return !!item;
63 }
64
65 static int FUNC_NAME(set_lossy)(CACHE *cache, uint64_t id, int lossy)
66 {
67     NewCacheItem *item;
68     pthread_mutex_lock(&cache->lock);
69
70     item = cache->hash_table[CACHE_HASH_KEY(id)];
71
72     while (item) {
73         if (item->id == id) {
74             item->lossy = lossy;
75             break;
76         }
77         item = item->next;
78     }
79     pthread_mutex_unlock(&cache->lock);
80     return !!item;
81 }
82
83 static int FUNC_NAME(add)(CACHE *cache, uint64_t id, uint32_t size, int lossy, DisplayChannelClient *dcc)
84 {
85     NewCacheItem *item;
86     uint64_t serial;
87     int key;
88
89     spice_assert(size > 0);
90
91     item = spice_new(NewCacheItem, 1);
92     serial = red_channel_client_get_message_serial(&dcc->common.base);
93
94     pthread_mutex_lock(&cache->lock);
95
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;
101         }
102         pthread_mutex_unlock(&cache->lock);
103         free(item);
104         return FALSE;
105     }
106
107     cache->available -= size;
108     while (cache->available < 0) {
109         NewCacheItem *tail;
110         NewCacheItem **now;
111
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);
116             free(item);
117             return FALSE;
118         }
119
120         now = &cache->hash_table[CACHE_HASH_KEY(tail->id)];
121         for (;;) {
122             spice_assert(*now);
123             if (*now == tail) {
124                 *now = tail->next;
125                 break;
126             }
127             now = &(*now)->next;
128         }
129         ring_remove(&tail->lru_link);
130         cache->items--;
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);
134         free(tail);
135     }
136     ++cache->items;
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);
141     item->id = id;
142     item->size = size;
143     item->lossy = lossy;
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);
148     return TRUE;
149 }
150
151 static void PRIVATE_FUNC_NAME(clear)(CACHE *cache)
152 {
153     NewCacheItem *item;
154
155     if (cache->freezed) {
156         cache->lru.next = cache->freezed_head;
157         cache->lru.prev = cache->freezed_tail;
158         cache->freezed = FALSE;
159     }
160
161     while ((item = (NewCacheItem *)ring_get_head(&cache->lru))) {
162         ring_remove(&item->lru_link);
163         free(item);
164     }
165     memset(cache->hash_table, 0, sizeof(*cache->hash_table) * CACHE_HASH_SIZE);
166
167     cache->available = cache->size;
168     cache->items = 0;
169 }
170
171 static void FUNC_NAME(reset)(CACHE *cache, DisplayChannelClient *dcc, SpiceMsgWaitForChannels* sync_data)
172 {
173     uint8_t wait_count;
174     uint64_t serial;
175     uint32_t i;
176
177     serial = red_channel_client_get_message_serial(&dcc->common.base);
178     pthread_mutex_lock(&cache->lock);
179     PRIVATE_FUNC_NAME(clear)(cache);
180
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;
185
186     wait_count = 0;
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];
192         }
193     }
194     sync_data->wait_count = wait_count;
195     pthread_mutex_unlock(&cache->lock);
196 }
197
198 static int FUNC_NAME(freeze)(CACHE *cache)
199 {
200     pthread_mutex_lock(&cache->lock);
201
202     if (cache->freezed) {
203         pthread_mutex_unlock(&cache->lock);
204         return FALSE;
205     }
206
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;
213
214     pthread_mutex_unlock(&cache->lock);
215     return TRUE;
216 }
217
218 static void FUNC_NAME(destroy)(CACHE *cache)
219 {
220     spice_assert(cache);
221
222     pthread_mutex_lock(&cache->lock);
223     PRIVATE_FUNC_NAME(clear)(cache);
224     pthread_mutex_unlock(&cache->lock);
225 }
226
227 #undef CACHE_NAME
228 #undef CACHE_HASH_KEY
229 #undef CACHE_HASH_SIZE
230 #undef CACHE_INVAL_TYPE
231 #undef CACHE_MAX_CLIENT_SIZE
232 #undef FUNC_NAME
233 #undef VAR_NAME
234 #undef CHANNEL
235 #undef CHANNEL_FROM_RCC