diff --git a/include/grpc/slice.h b/include/grpc/slice.h index 4dce6da9155..fe6379c867d 100644 --- a/include/grpc/slice.h +++ b/include/grpc/slice.h @@ -124,8 +124,11 @@ GPRAPI grpc_slice grpc_slice_sub_no_ref(grpc_slice s, size_t begin, size_t end); Requires s intialized, split <= s.length */ GPRAPI grpc_slice grpc_slice_split_tail(grpc_slice *s, size_t split); -/* The same as grpc_slice_split_tail, but without altering refcounts */ -GPRAPI grpc_slice grpc_slice_split_tail_no_ref(grpc_slice *s, size_t split); +/* The same as grpc_slice_split_tail, but with an option to skip altering + * refcounts (grpc_slice_split_tail_maybe_ref(..., true) is equivalent to + * grpc_slice_split_tail(...)) */ +GPRAPI grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *s, size_t split, + bool inc_refs); /* Splits s into two: modifies s to be s[split:s.length], and returns a new slice, sharing a refcount with s, that contains s[0:split]. diff --git a/src/core/lib/slice/slice.c b/src/core/lib/slice/slice.c index 8896f1dfd3f..285218837ac 100644 --- a/src/core/lib/slice/slice.c +++ b/src/core/lib/slice/slice.c @@ -312,7 +312,8 @@ grpc_slice grpc_slice_sub(grpc_slice source, size_t begin, size_t end) { return subset; } -grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { +grpc_slice grpc_slice_split_tail_maybe_ref(grpc_slice *source, size_t split, + bool incref) { grpc_slice tail; if (source->refcount == NULL) { @@ -334,9 +335,13 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { tail_length); } else { /* Build the result */ - tail.refcount = source->refcount->sub_refcount; - /* Bump the refcount */ - tail.refcount->vtable->ref(tail.refcount); + if (incref) { + tail.refcount = source->refcount->sub_refcount; + /* Bump the refcount */ + tail.refcount->vtable->ref(tail.refcount); + } else { + tail.refcount = &noop_refcount; + } /* Point into the source array */ tail.data.refcounted.bytes = source->data.refcounted.bytes + split; tail.data.refcounted.length = tail_length; @@ -348,38 +353,8 @@ grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { return tail; } -grpc_slice grpc_slice_split_tail_no_ref(grpc_slice *source, size_t split) { - grpc_slice tail; - - if (source->refcount == NULL) { - /* inlined data, copy it out */ - GPR_ASSERT(source->data.inlined.length >= split); - tail.refcount = NULL; - tail.data.inlined.length = (uint8_t)(source->data.inlined.length - split); - memcpy(tail.data.inlined.bytes, source->data.inlined.bytes + split, - tail.data.inlined.length); - source->data.inlined.length = (uint8_t)split; - } else { - size_t tail_length = source->data.refcounted.length - split; - GPR_ASSERT(source->data.refcounted.length >= split); - if (tail_length < sizeof(tail.data.inlined.bytes)) { - /* Copy out the bytes - it'll be cheaper than refcounting */ - tail.refcount = NULL; - tail.data.inlined.length = (uint8_t)tail_length; - memcpy(tail.data.inlined.bytes, source->data.refcounted.bytes + split, - tail_length); - } else { - /* Build the result */ - tail.refcount = &noop_refcount; - /* Point into the source array */ - tail.data.refcounted.bytes = source->data.refcounted.bytes + split; - tail.data.refcounted.length = tail_length; - } - source->refcount = source->refcount->sub_refcount; - source->data.refcounted.length = split; - } - - return tail; +grpc_slice grpc_slice_split_tail(grpc_slice *source, size_t split) { + return grpc_slice_split_tail_maybe_ref(source, split, true); } grpc_slice grpc_slice_split_head(grpc_slice *source, size_t split) { diff --git a/src/core/lib/slice/slice_buffer.c b/src/core/lib/slice/slice_buffer.c index a13941e5ac8..5a4b434d28c 100644 --- a/src/core/lib/slice/slice_buffer.c +++ b/src/core/lib/slice/slice_buffer.c @@ -253,8 +253,9 @@ void grpc_slice_buffer_move_into(grpc_slice_buffer *src, src->length = 0; } -void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, - grpc_slice_buffer *dst) { +static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst, + bool incref) { GPR_ASSERT(src->length >= n); if (src->length == n) { grpc_slice_buffer_move_into(src, dst); @@ -274,7 +275,8 @@ void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, grpc_slice_buffer_add(dst, slice); break; } else { /* n < slice_len */ - grpc_slice_buffer_undo_take_first(src, grpc_slice_split_tail(&slice, n)); + grpc_slice_buffer_undo_take_first( + src, grpc_slice_split_tail_maybe_ref(&slice, n, incref)); GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); grpc_slice_buffer_add(dst, slice); break; @@ -285,37 +287,14 @@ void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, GPR_ASSERT(src->count > 0); } +void grpc_slice_buffer_move_first(grpc_slice_buffer *src, size_t n, + grpc_slice_buffer *dst) { + slice_buffer_move_first_maybe_ref(src, n, dst, true); +} + void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer *src, size_t n, grpc_slice_buffer *dst) { - GPR_ASSERT(src->length >= n); - if (src->length == n) { - grpc_slice_buffer_move_into(src, dst); - return; - } - - size_t output_len = dst->length + n; - size_t new_input_len = src->length - n; - - while (src->count > 0) { - grpc_slice slice = grpc_slice_buffer_take_first(src); - size_t slice_len = GRPC_SLICE_LENGTH(slice); - if (n > slice_len) { - grpc_slice_buffer_add(dst, slice); - n -= slice_len; - } else if (n == slice_len) { - grpc_slice_buffer_add(dst, slice); - break; - } else { /* n < slice_len */ - grpc_slice_buffer_undo_take_first( - src, grpc_slice_split_tail_no_ref(&slice, n)); - GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n); - grpc_slice_buffer_add(dst, slice); - break; - } - } - GPR_ASSERT(dst->length == output_len); - GPR_ASSERT(src->length == new_input_len); - GPR_ASSERT(src->count > 0); + slice_buffer_move_first_maybe_ref(src, n, dst, false); } void grpc_slice_buffer_move_first_into_buffer(grpc_exec_ctx *exec_ctx,