diff options
author | Yonit Halperin <yhalperi@redhat.com> | 2010-04-09 10:09:47 +0200 |
---|---|---|
committer | Alexander Larsson <alexl@redhat.com> | 2010-04-09 10:11:09 +0200 |
commit | a3700a1bfbb3006b83d8513a5e4c598d6443f2c3 (patch) | |
tree | 041a0e5d67aae0087ff152a4f2e04a689adf9433 /server/glz_encoder_dictionary.c | |
parent | 22d1ac9eb5757ec5a51ec377d3ed31bf520f4ae0 (diff) | |
download | spice-a3700a1bfbb3006b83d8513a5e4c598d6443f2c3.tar.gz spice-a3700a1bfbb3006b83d8513a5e4c598d6443f2c3.tar.xz spice-a3700a1bfbb3006b83d8513a5e4c598d6443f2c3.zip |
server: fix race condition in lz global dictionary, in its image segments list
Diffstat (limited to 'server/glz_encoder_dictionary.c')
-rw-r--r-- | server/glz_encoder_dictionary.c | 55 |
1 files changed, 34 insertions, 21 deletions
diff --git a/server/glz_encoder_dictionary.c b/server/glz_encoder_dictionary.c index 8ea8065f..1a56275b 100644 --- a/server/glz_encoder_dictionary.c +++ b/server/glz_encoder_dictionary.c @@ -332,7 +332,7 @@ static WindowImage *__glz_dictionary_window_alloc_image(SharedDictionary *dict) return ret; } -/* NOTE - it also updates the used_segs_list*/ +/* NOTE - it doesn't update the used_segs list*/ static uint32_t __glz_dictionary_window_alloc_image_seg(SharedDictionary *dict) { uint32_t seg_id; @@ -349,18 +349,6 @@ static uint32_t __glz_dictionary_window_alloc_image_seg(SharedDictionary *dict) seg = dict->window.segs + seg_id; dict->window.free_segs_head = seg->next; - // first segment - if (dict->window.used_segs_tail == NULL_IMAGE_SEG_ID) { - dict->window.used_segs_head = seg_id; - dict->window.used_segs_tail = seg_id; - } else { - int prev_tail = dict->window.used_segs_tail; - dict->window.segs[prev_tail].next = seg_id; - dict->window.used_segs_tail = seg_id; - } - - seg->next = NULL_IMAGE_SEG_ID; - return seg_id; } @@ -467,9 +455,9 @@ static void glz_dictionary_window_remove_head(SharedDictionary *dict, uint32_t e } } -static uint32_t glz_dictionary_window_add_image_seg(SharedDictionary *dict, WindowImage* image, - int size, int stride, - uint8_t *lines, unsigned int num_lines) +static uint32_t glz_dictionary_window_alloc_image_seg(SharedDictionary *dict, WindowImage* image, + int size, int stride, + uint8_t *lines, unsigned int num_lines) { uint32_t seg_id = __glz_dictionary_window_alloc_image_seg(dict); WindowImageSegment *seg = &dict->window.segs[seg_id]; @@ -481,6 +469,8 @@ static uint32_t glz_dictionary_window_add_image_seg(SharedDictionary *dict, Wind seg->pixels_so_far = dict->window.pixels_so_far; dict->window.pixels_so_far += seg->pixels_num; + seg->next = NULL_IMAGE_SEG_ID; + return seg_id; } @@ -492,7 +482,7 @@ static WindowImage *glz_dictionary_window_add_image(SharedDictionary *dict, LzIm { unsigned int num_lines = num_first_lines; unsigned int row; - uint32_t seg_id; + uint32_t seg_id, prev_seg_id; uint8_t* lines = first_lines; // alloc image info,update used head tail, if used_head null - update head WindowImage *image = __glz_dictionary_window_alloc_image(dict); @@ -509,13 +499,16 @@ static WindowImage *glz_dictionary_window_add_image(SharedDictionary *dict, LzIm } for (row = 0;;) { - seg_id = glz_dictionary_window_add_image_seg(dict, image, - image_size * num_lines / image_height, - image_stride, - lines, num_lines); + seg_id = glz_dictionary_window_alloc_image_seg(dict, image, + image_size * num_lines / image_height, + image_stride, + lines, num_lines); if (row == 0) { image->first_seg = seg_id; + } else { + dict->window.segs[prev_seg_id].next = seg_id; } + row += num_lines; if (row < (uint32_t)image_height) { num_lines = dict->cur_usr->more_lines(dict->cur_usr, &lines); @@ -525,6 +518,26 @@ static WindowImage *glz_dictionary_window_add_image(SharedDictionary *dict, LzIm } else { break; } + prev_seg_id = seg_id; + } + + if (dict->window.used_segs_tail == NULL_IMAGE_SEG_ID) { + dict->window.used_segs_head = image->first_seg; + dict->window.used_segs_tail = seg_id; + } else { + int prev_tail = dict->window.used_segs_tail; + + // The used segs may be in use by another thread which is during encoding + // (read-only use - when going over the segs of an image, + // see glz_encode_tmpl::compress). + // Thus, the 'next' field of the list's tail can be accessed only + // after all the new tail's data was set. Note that we are relying on + // an atomic assignment (32 bit varaible). + // For the other thread that may read 'next' of the old tail, NULL_IMAGE_SEG_ID + // is equivalent to a segment with an image id that is different + // from the image id of the tail, so we don't need to further protect this field. + dict->window.segs[prev_tail].next = image->first_seg; + dict->window.used_segs_tail = seg_id; } image->is_alive = TRUE; |