static void image_cache_put(SpiceImageCache *spice_cache, uint64_t id, pixman_image_t *image) { ImageCache *cache = SPICE_UPCAST(ImageCache, spice_cache); ImageCacheItem *item; #ifndef IMAGE_CACHE_AGE if (cache->num_items == IMAGE_CACHE_MAX_ITEMS) { SPICE_VERIFY(SPICE_OFFSETOF(ImageCacheItem, lru_link) == 0); ImageCacheItem *tail = (ImageCacheItem *)ring_get_tail(&cache->lru); spice_assert(tail); image_cache_remove(cache, tail); } #endif item = spice_new(ImageCacheItem, 1); item->id = id; #ifdef IMAGE_CACHE_AGE item->age = cache->age; #else cache->num_items++; #endif item->image = pixman_image_ref(image); ring_item_init(&item->lru_link); item->next = cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE]; cache->hash_table[item->id % IMAGE_CACHE_HASH_SIZE] = item; ring_add(&cache->lru, &item->lru_link); }
void image_cache_reset(ImageCache *cache) { ImageCacheItem *item; SPICE_VERIFY(SPICE_OFFSETOF(ImageCacheItem, lru_link) == 0); while ((item = (ImageCacheItem *)ring_get_head(&cache->lru))) { image_cache_remove(cache, item); } #ifdef IMAGE_CACHE_AGE cache->age = 0; #endif }
void image_cache_aging(ImageCache *cache) { SPICE_VERIFY(SPICE_OFFSETOF(ImageCacheItem, lru_link) == 0); #ifdef IMAGE_CACHE_AGE ImageCacheItem *item; cache->age++; while ((item = (ImageCacheItem *)ring_get_tail(&cache->lru)) && cache->age - item->age > IMAGE_CACHE_DEPTH) { image_cache_remove(cache, item); } #endif }
int main(int argc, char **argv) { RedMemSlotInfo mem_info; memslot_info_init(&mem_info, 1 /* groups */, 1 /* slots */, 1, 1, 0); memslot_info_add_slot(&mem_info, 0, 0, 0 /* delta */, 0 /* start */, ~0ul /* end */, 0 /* generation */); RedSurfaceCmd cmd; QXLSurfaceCmd qxl; RedCursorCmd red_cursor_cmd; QXLCursorCmd cursor_cmd; QXLCursor *cursor; QXLDataChunk *chunks[2]; void *surface_mem; memset(&qxl, 0, sizeof(qxl)); qxl.surface_id = 123; /* try to create a surface with no issues, should succeed */ test("no issues"); qxl.u.surface_create.format = SPICE_SURFACE_FMT_32_xRGB; qxl.u.surface_create.width = 128; qxl.u.surface_create.stride = 512; qxl.u.surface_create.height = 128; surface_mem = malloc(0x10000); qxl.u.surface_create.data = to_physical(surface_mem); if (red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) failure(); /* try to create a surface with a stride too small to fit * the entire width. * This can be used to cause buffer overflows so refuse it. */ test("stride too small"); qxl.u.surface_create.stride = 256; if (!red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) failure(); /* try to create a surface quite large. * The sizes (width and height) were chosen so the multiplication * using 32 bit values gives a very small value. * These kind of values should be refused as they will cause * overflows. Also the total memory for the card is not enough to * hold the surface so surely can't be accepted. */ test("too big image"); qxl.u.surface_create.stride = 0x08000004 * 4; qxl.u.surface_create.width = 0x08000004; qxl.u.surface_create.height = 0x40000020; if (!red_get_surface_cmd(&mem_info, 0, &cmd, to_physical(&qxl))) failure(); /* test base cursor with no problems */ test("base cursor command"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; cursor = create_chunk(SPICE_OFFSETOF(QXLCursor, chunk), 128 * 128 * 4, NULL, 0xaa); cursor->header.unique = 1; cursor->header.width = 128; cursor->header.height = 128; cursor->data_size = 128 * 128 * 4; cursor_cmd.u.set.shape = to_physical(cursor); if (red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) failure(); free(red_cursor_cmd.u.set.shape.data); free(cursor); /* a circular list of empty chunks should not be a problems */ test("circular empty chunks"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; cursor = create_chunk(SPICE_OFFSETOF(QXLCursor, chunk), 0, NULL, 0xaa); cursor->header.unique = 1; cursor->header.width = 128; cursor->header.height = 128; cursor->data_size = 128 * 128 * 4; chunks[0] = create_chunk(0, 0, &cursor->chunk, 0xaa); chunks[0]->next_chunk = to_physical(&cursor->chunk); cursor_cmd.u.set.shape = to_physical(cursor); memset(&red_cursor_cmd, 0xaa, sizeof(red_cursor_cmd)); if (!red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) { /* function does not return errors so there should be no data */ assert(red_cursor_cmd.type == QXL_CURSOR_SET); assert(red_cursor_cmd.u.set.position.x == 0); assert(red_cursor_cmd.u.set.position.y == 0); assert(red_cursor_cmd.u.set.shape.data_size == 0); } free(cursor); free(chunks[0]); /* a circular list of small chunks should not be a problems */ test("circular small chunks"); memset(&cursor_cmd, 0, sizeof(cursor_cmd)); cursor_cmd.type = QXL_CURSOR_SET; cursor = create_chunk(SPICE_OFFSETOF(QXLCursor, chunk), 1, NULL, 0xaa); cursor->header.unique = 1; cursor->header.width = 128; cursor->header.height = 128; cursor->data_size = 128 * 128 * 4; chunks[0] = create_chunk(0, 1, &cursor->chunk, 0xaa); chunks[0]->next_chunk = to_physical(&cursor->chunk); cursor_cmd.u.set.shape = to_physical(cursor); memset(&red_cursor_cmd, 0xaa, sizeof(red_cursor_cmd)); if (!red_get_cursor_cmd(&mem_info, 0, &red_cursor_cmd, to_physical(&cursor_cmd))) { /* function does not return errors so there should be no data */ assert(red_cursor_cmd.type == QXL_CURSOR_SET); assert(red_cursor_cmd.u.set.position.x == 0); assert(red_cursor_cmd.u.set.position.y == 0); assert(red_cursor_cmd.u.set.shape.data_size == 0); } free(cursor); free(chunks[0]); free(mem_info.mem_slots[0]); free(mem_info.mem_slots); free(surface_mem); return exit_code; }