diff options
author | Florin Coras <fcoras@cisco.com> | 2019-07-02 13:07:37 -0700 |
---|---|---|
committer | Dave Barach <openvpp@barachs.net> | 2019-07-03 11:26:36 +0000 |
commit | eaacce4753c33342a6512039fe4153b15b476fb3 (patch) | |
tree | b7465c6da3970f28db0aca7ab92b12b3c7fbaa5d /src/svm/svm_fifo.c | |
parent | b5ef26d1ed524d1f2f59ffd5546d1c581f4c88a2 (diff) |
svm: fix multi-chunk fifo alloc and add more tests
Type: fix
- make sure that chunks and the rbtree are initialized if fifo segment
allocates multiple chunks for the fifo.
- ensure head/tail chunks are updated on all enqueue/dequeue events,
including when dropping data.
- more unit tests
Also fixes dequeue drop updates of head chunk.
Change-Id: I77f3550bc4e8b4e077f80ea87fe82b83ed013aeb
Signed-off-by: Florin Coras <fcoras@cisco.com>
Diffstat (limited to 'src/svm/svm_fifo.c')
-rw-r--r-- | src/svm/svm_fifo.c | 103 |
1 files changed, 97 insertions, 6 deletions
diff --git a/src/svm/svm_fifo.c b/src/svm/svm_fifo.c index 3d538293c70..56f53a3d339 100644 --- a/src/svm/svm_fifo.c +++ b/src/svm/svm_fifo.c @@ -404,6 +404,31 @@ svm_fifo_init (svm_fifo_t * f, u32 size) f->head_chunk = f->tail_chunk = f->ooo_enq = f->ooo_deq = f->start_chunk; } +void +svm_fifo_init_chunks (svm_fifo_t * f) +{ + svm_fifo_chunk_t *c, *prev; + + if (f->start_chunk->next == f->start_chunk) + return; + + f->flags |= SVM_FIFO_F_MULTI_CHUNK; + rb_tree_init (&f->chunk_lookup); + rb_tree_add2 (&f->chunk_lookup, 0, pointer_to_uword (f->start_chunk)); + + f->start_chunk->start_byte = 0; + prev = f->start_chunk; + c = prev->next; + + while (c != f->start_chunk) + { + c->start_byte = prev->start_byte + prev->length; + rb_tree_add2 (&f->chunk_lookup, c->start_byte, pointer_to_uword (c)); + prev = c; + c = c->next; + } +} + /** * Creates a fifo in the current heap. Fails vs blow up the process */ @@ -559,6 +584,7 @@ svm_fifo_add_chunk (svm_fifo_t * f, svm_fifo_chunk_t * c) * that this is called with the heap where the rbtree's pool is pushed. */ if (!(f->flags & SVM_FIFO_F_MULTI_CHUNK)) { + ASSERT (f->start_chunk->next == f->start_chunk); rb_tree_init (&f->chunk_lookup); rb_tree_add2 (&f->chunk_lookup, 0, pointer_to_uword (f->start_chunk)); f->flags |= SVM_FIFO_F_MULTI_CHUNK; @@ -626,7 +652,7 @@ svm_fifo_collect_chunks (svm_fifo_t * f) void svm_fifo_try_shrink (svm_fifo_t * f, u32 head, u32 tail) { - u32 len_to_shrink = 0, tail_pos, len; + u32 len_to_shrink = 0, tail_pos, len, last_pos; svm_fifo_chunk_t *cur, *prev, *next, *start; tail_pos = tail; @@ -649,13 +675,24 @@ svm_fifo_try_shrink (svm_fifo_t * f, u32 head, u32 tail) * - not wrapped * - last used byte less than start of last chunk */ - if (tail_pos >= head && tail_pos <= f->end_chunk->start_byte) + if (tail_pos >= head && tail_pos < f->end_chunk->start_byte) { /* Lookup the last position not to be removed. Since size still needs - * to be nitems + 1, nitems must fall within the usable space */ - tail_pos = tail_pos > 0 ? tail_pos - 1 : tail_pos; - prev = svm_fifo_find_chunk (f, clib_max (f->nitems, tail_pos)); + * to be nitems + 1, nitems must fall within the usable space. Also, + * first segment is not removable, so tail_pos can be 0. */ + last_pos = tail_pos > 0 ? tail_pos - 1 : tail_pos; + prev = svm_fifo_find_chunk (f, clib_max (f->nitems, last_pos)); next = prev->next; + /* If tail_pos is first position in next, skip the chunk, otherwise, + * we must update the tail and, if fifo size is 0, even the head. + * We should not invalidate the tail for the caller and must not change + * consumer owned variables from code that's typically called by the + * producer */ + if (next->start_byte == tail_pos) + { + prev = next; + next = next->next; + } while (next != f->start_chunk) { cur = next; @@ -790,7 +827,11 @@ svm_fifo_enqueue (svm_fifo_t * f, u32 len, const u8 * src) /* collect out-of-order segments */ if (PREDICT_FALSE (f->ooos_list_head != OOO_SEGMENT_INVALID_INDEX)) - len += ooo_segment_try_collect (f, len, &tail); + { + len += ooo_segment_try_collect (f, len, &tail); + if (!svm_fifo_chunk_includes_pos (f->tail_chunk, tail)) + f->tail_chunk = svm_fifo_find_chunk (f, tail); + } /* store-rel: producer owned index (paired with load-acq in consumer) */ clib_atomic_store_rel_n (&f->tail, tail); @@ -847,6 +888,10 @@ svm_fifo_enqueue_nocopy (svm_fifo_t * f, u32 len) /* load-relaxed: producer owned index */ tail = f->tail; tail = (tail + len) % f->size; + + if (!svm_fifo_chunk_includes_pos (f->tail_chunk, tail)) + f->tail_chunk = svm_fifo_find_chunk (f, tail); + /* store-rel: producer owned index (paired with load-acq in consumer) */ clib_atomic_store_rel_n (&f->tail, tail); } @@ -919,6 +964,9 @@ svm_fifo_dequeue_drop (svm_fifo_t * f, u32 len) /* move head */ head = (head + total_drop_bytes) % f->size; + if (!svm_fifo_chunk_includes_pos (f->head_chunk, head)) + f->head_chunk = svm_fifo_find_chunk (f, head); + /* store-rel: consumer owned index (paired with load-acq in producer) */ clib_atomic_store_rel_n (&f->head, head); @@ -930,6 +978,10 @@ svm_fifo_dequeue_drop_all (svm_fifo_t * f) { /* consumer foreign index */ u32 tail = clib_atomic_load_acq_n (&f->tail); + + if (!svm_fifo_chunk_includes_pos (f->head_chunk, tail)) + f->head_chunk = svm_fifo_find_chunk (f, tail); + /* store-rel: consumer owned index (paired with load-acq in producer) */ clib_atomic_store_rel_n (&f->head, tail); } @@ -1055,6 +1107,45 @@ svm_fifo_del_subscriber (svm_fifo_t * f, u8 subscriber) } } +u8 +svm_fifo_is_sane (svm_fifo_t * f) +{ + if (f->size - 1 != f->nitems && !(f->flags & SVM_FIFO_F_SHRINK)) + return 0; + if (!svm_fifo_chunk_includes_pos (f->head_chunk, f->head)) + return 0; + if (!svm_fifo_chunk_includes_pos (f->tail_chunk, f->tail)) + return 0; + + if (f->start_chunk->next != f->start_chunk) + { + svm_fifo_chunk_t *c, *prev = 0, *tmp; + u32 size = 0; + + if (!(f->flags & SVM_FIFO_F_MULTI_CHUNK)) + return 0; + + c = f->start_chunk; + do + { + tmp = svm_fifo_find_chunk (f, c->start_byte); + if (tmp != c) + return 0; + if (prev && (prev->start_byte + prev->length != c->start_byte)) + return 0; + size += c->length; + prev = c; + c = c->next; + } + while (c != f->start_chunk); + + if (size != f->size) + return 0; + } + + return 1; +} + u8 * format_ooo_segment (u8 * s, va_list * args) { |