diff --git a/include/grpc/impl/codegen/slice.h b/include/grpc/impl/codegen/slice.h index 11997fcb563..369cee91a8e 100644 --- a/include/grpc/impl/codegen/slice.h +++ b/include/grpc/impl/codegen/slice.h @@ -108,6 +108,10 @@ typedef struct { /** the number of slices allocated in the array. External users (i.e any code * outside grpc core) MUST NOT use this field */ size_t capacity; + /** the index of the first slice who's memory is still owned by this buffer. + * This is only to be used when partially unreffing this slice buffer in + * grpc_slice_buffer_partial_reset_and_unref_internal. */ + size_t idx_of_first_valid_slice; /** the combined length of all slices in the array */ size_t length; /** inlined elements to avoid allocations */ diff --git a/src/core/lib/iomgr/tcp_posix.cc b/src/core/lib/iomgr/tcp_posix.cc index 6b61ed9ec30..016ca87219b 100644 --- a/src/core/lib/iomgr/tcp_posix.cc +++ b/src/core/lib/iomgr/tcp_posix.cc @@ -576,6 +576,8 @@ static bool tcp_flush(grpc_exec_ctx* exec_ctx, grpc_tcp* tcp, if (errno == EAGAIN) { tcp->outgoing_slice_idx = unwind_slice_idx; tcp->outgoing_byte_idx = unwind_byte_idx; + grpc_slice_buffer_partial_reset_and_unref_internal( + exec_ctx, tcp->outgoing_buffer, unwind_slice_idx); return false; } else if (errno == EPIPE) { *error = grpc_error_set_int(GRPC_OS_ERROR(errno, "sendmsg"), diff --git a/src/core/lib/slice/slice_buffer.cc b/src/core/lib/slice/slice_buffer.cc index 5db54dad91e..cd5040fbcb5 100644 --- a/src/core/lib/slice/slice_buffer.cc +++ b/src/core/lib/slice/slice_buffer.cc @@ -62,6 +62,7 @@ void grpc_slice_buffer_init(grpc_slice_buffer* sb) { sb->count = 0; sb->length = 0; sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS; + sb->idx_of_first_valid_slice = 0; sb->base_slices = sb->slices = sb->inlined; } @@ -166,12 +167,26 @@ void grpc_slice_buffer_pop(grpc_slice_buffer* sb) { void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* sb) { size_t i; - for (i = 0; i < sb->count; i++) { + for (i = sb->idx_of_first_valid_slice; i < sb->count; i++) { grpc_slice_unref_internal(exec_ctx, sb->slices[i]); } sb->count = 0; sb->length = 0; + sb->idx_of_first_valid_slice = 0; +} + +void grpc_slice_buffer_partial_reset_and_unref_internal(grpc_exec_ctx* exec_ctx, + grpc_slice_buffer* sb, + size_t idx) { + GPR_ASSERT(idx <= sb->count); + + size_t i; + for (i = sb->idx_of_first_valid_slice; i < idx; i++) { + grpc_slice_unref_internal(exec_ctx, sb->slices[i]); + } + + sb->idx_of_first_valid_slice = idx; } void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) { diff --git a/src/core/lib/slice/slice_internal.h b/src/core/lib/slice/slice_internal.h index 2439fc08267..2c616950d7f 100644 --- a/src/core/lib/slice/slice_internal.h +++ b/src/core/lib/slice/slice_internal.h @@ -32,6 +32,9 @@ grpc_slice grpc_slice_ref_internal(grpc_slice slice); void grpc_slice_unref_internal(grpc_exec_ctx* exec_ctx, grpc_slice slice); void grpc_slice_buffer_reset_and_unref_internal(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* sb); +void grpc_slice_buffer_partial_reset_and_unref_internal(grpc_exec_ctx* exec_ctx, + grpc_slice_buffer* sb, + size_t idx); void grpc_slice_buffer_destroy_internal(grpc_exec_ctx* exec_ctx, grpc_slice_buffer* sb);