• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  * Copyright 2015 gRPC authors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 #include <grpc/support/port_platform.h>
20 
21 #include <grpc/slice_buffer.h>
22 
23 #include <string.h>
24 
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 
28 #include "src/core/lib/gpr/useful.h"
29 #include "src/core/lib/iomgr/exec_ctx.h"
30 #include "src/core/lib/slice/slice_internal.h"
31 
32 /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
33 #define GROW(x) (3 * (x) / 2)
34 
maybe_embiggen(grpc_slice_buffer * sb)35 static void maybe_embiggen(grpc_slice_buffer* sb) {
36   /* How far away from sb->base_slices is sb->slices pointer */
37   size_t slice_offset = static_cast<size_t>(sb->slices - sb->base_slices);
38   size_t slice_count = sb->count + slice_offset;
39 
40   if (slice_count == sb->capacity) {
41     if (sb->base_slices != sb->slices) {
42       /* Make room by moving elements if there's still space unused */
43       memmove(sb->base_slices, sb->slices, sb->count * sizeof(grpc_slice));
44       sb->slices = sb->base_slices;
45     } else {
46       /* Allocate more memory if no more space is available */
47       sb->capacity = GROW(sb->capacity);
48       GPR_ASSERT(sb->capacity > slice_count);
49       if (sb->base_slices == sb->inlined) {
50         sb->base_slices = static_cast<grpc_slice*>(
51             gpr_malloc(sb->capacity * sizeof(grpc_slice)));
52         memcpy(sb->base_slices, sb->inlined, slice_count * sizeof(grpc_slice));
53       } else {
54         sb->base_slices = static_cast<grpc_slice*>(
55             gpr_realloc(sb->base_slices, sb->capacity * sizeof(grpc_slice)));
56       }
57 
58       sb->slices = sb->base_slices + slice_offset;
59     }
60   }
61 }
62 
grpc_slice_buffer_init(grpc_slice_buffer * sb)63 void grpc_slice_buffer_init(grpc_slice_buffer* sb) {
64   sb->count = 0;
65   sb->length = 0;
66   sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
67   sb->base_slices = sb->slices = sb->inlined;
68 }
69 
grpc_slice_buffer_destroy_internal(grpc_slice_buffer * sb)70 void grpc_slice_buffer_destroy_internal(grpc_slice_buffer* sb) {
71   grpc_slice_buffer_reset_and_unref_internal(sb);
72   if (sb->base_slices != sb->inlined) {
73     gpr_free(sb->base_slices);
74   }
75 }
76 
grpc_slice_buffer_destroy(grpc_slice_buffer * sb)77 void grpc_slice_buffer_destroy(grpc_slice_buffer* sb) {
78   if (grpc_core::ExecCtx::Get() == nullptr) {
79     grpc_core::ExecCtx exec_ctx;
80     grpc_slice_buffer_destroy_internal(sb);
81   } else {
82     grpc_slice_buffer_destroy_internal(sb);
83   }
84 }
85 
grpc_slice_buffer_tiny_add(grpc_slice_buffer * sb,size_t n)86 uint8_t* grpc_slice_buffer_tiny_add(grpc_slice_buffer* sb, size_t n) {
87   grpc_slice* back;
88   uint8_t* out;
89 
90   sb->length += n;
91 
92   if (sb->count == 0) goto add_new;
93   back = &sb->slices[sb->count - 1];
94   if (back->refcount) goto add_new;
95   if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
96     goto add_new;
97   out = back->data.inlined.bytes + back->data.inlined.length;
98   back->data.inlined.length =
99       static_cast<uint8_t>(back->data.inlined.length + n);
100   return out;
101 
102 add_new:
103   maybe_embiggen(sb);
104   back = &sb->slices[sb->count];
105   sb->count++;
106   back->refcount = nullptr;
107   back->data.inlined.length = static_cast<uint8_t>(n);
108   return back->data.inlined.bytes;
109 }
110 
grpc_slice_buffer_add_indexed(grpc_slice_buffer * sb,grpc_slice s)111 size_t grpc_slice_buffer_add_indexed(grpc_slice_buffer* sb, grpc_slice s) {
112   size_t out = sb->count;
113   maybe_embiggen(sb);
114   sb->slices[out] = s;
115   sb->length += GRPC_SLICE_LENGTH(s);
116   sb->count = out + 1;
117   return out;
118 }
119 
grpc_slice_buffer_add(grpc_slice_buffer * sb,grpc_slice s)120 void grpc_slice_buffer_add(grpc_slice_buffer* sb, grpc_slice s) {
121   size_t n = sb->count;
122   /* if both the last slice in the slice buffer and the slice being added
123      are inlined (that is, that they carry their data inside the slice data
124      structure), and the back slice is not full, then concatenate directly
125      into the back slice, preventing many small slices being passed into
126      writes */
127   if (!s.refcount && n) {
128     grpc_slice* back = &sb->slices[n - 1];
129     if (!back->refcount &&
130         back->data.inlined.length < GRPC_SLICE_INLINED_SIZE) {
131       if (s.data.inlined.length + back->data.inlined.length <=
132           GRPC_SLICE_INLINED_SIZE) {
133         memcpy(back->data.inlined.bytes + back->data.inlined.length,
134                s.data.inlined.bytes, s.data.inlined.length);
135         back->data.inlined.length = static_cast<uint8_t>(
136             back->data.inlined.length + s.data.inlined.length);
137       } else {
138         size_t cp1 = GRPC_SLICE_INLINED_SIZE - back->data.inlined.length;
139         memcpy(back->data.inlined.bytes + back->data.inlined.length,
140                s.data.inlined.bytes, cp1);
141         back->data.inlined.length = GRPC_SLICE_INLINED_SIZE;
142         maybe_embiggen(sb);
143         back = &sb->slices[n];
144         sb->count = n + 1;
145         back->refcount = nullptr;
146         back->data.inlined.length =
147             static_cast<uint8_t>(s.data.inlined.length - cp1);
148         memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
149                s.data.inlined.length - cp1);
150       }
151       sb->length += s.data.inlined.length;
152       return; /* early out */
153     }
154   }
155   grpc_slice_buffer_add_indexed(sb, s);
156 }
157 
grpc_slice_buffer_addn(grpc_slice_buffer * sb,grpc_slice * s,size_t n)158 void grpc_slice_buffer_addn(grpc_slice_buffer* sb, grpc_slice* s, size_t n) {
159   size_t i;
160   for (i = 0; i < n; i++) {
161     grpc_slice_buffer_add(sb, s[i]);
162   }
163 }
164 
grpc_slice_buffer_pop(grpc_slice_buffer * sb)165 void grpc_slice_buffer_pop(grpc_slice_buffer* sb) {
166   if (sb->count != 0) {
167     size_t count = --sb->count;
168     sb->length -= GRPC_SLICE_LENGTH(sb->slices[count]);
169   }
170 }
171 
grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer * sb)172 void grpc_slice_buffer_reset_and_unref_internal(grpc_slice_buffer* sb) {
173   size_t i;
174   for (i = 0; i < sb->count; i++) {
175     grpc_slice_unref_internal(sb->slices[i]);
176   }
177 
178   sb->count = 0;
179   sb->length = 0;
180 }
181 
grpc_slice_buffer_reset_and_unref(grpc_slice_buffer * sb)182 void grpc_slice_buffer_reset_and_unref(grpc_slice_buffer* sb) {
183   if (grpc_core::ExecCtx::Get() == nullptr) {
184     grpc_core::ExecCtx exec_ctx;
185     grpc_slice_buffer_reset_and_unref_internal(sb);
186   } else {
187     grpc_slice_buffer_reset_and_unref_internal(sb);
188   }
189 }
190 
grpc_slice_buffer_swap(grpc_slice_buffer * a,grpc_slice_buffer * b)191 void grpc_slice_buffer_swap(grpc_slice_buffer* a, grpc_slice_buffer* b) {
192   size_t a_offset = static_cast<size_t>(a->slices - a->base_slices);
193   size_t b_offset = static_cast<size_t>(b->slices - b->base_slices);
194 
195   size_t a_count = a->count + a_offset;
196   size_t b_count = b->count + b_offset;
197 
198   if (a->base_slices == a->inlined) {
199     if (b->base_slices == b->inlined) {
200       /* swap contents of inlined buffer */
201       grpc_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
202       memcpy(temp, a->base_slices, a_count * sizeof(grpc_slice));
203       memcpy(a->base_slices, b->base_slices, b_count * sizeof(grpc_slice));
204       memcpy(b->base_slices, temp, a_count * sizeof(grpc_slice));
205     } else {
206       /* a is inlined, b is not - copy a inlined into b, fix pointers */
207       a->base_slices = b->base_slices;
208       b->base_slices = b->inlined;
209       memcpy(b->base_slices, a->inlined, a_count * sizeof(grpc_slice));
210     }
211   } else if (b->base_slices == b->inlined) {
212     /* b is inlined, a is not - copy b inlined int a, fix pointers */
213     b->base_slices = a->base_slices;
214     a->base_slices = a->inlined;
215     memcpy(a->base_slices, b->inlined, b_count * sizeof(grpc_slice));
216   } else {
217     /* no inlining: easy swap */
218     GPR_SWAP(grpc_slice*, a->base_slices, b->base_slices);
219   }
220 
221   /* Update the slices pointers (cannot do a GPR_SWAP on slices fields here).
222    * Also note that since the base_slices pointers are already swapped we need
223    * use 'b_offset' for 'a->base_slices' and vice versa */
224   a->slices = a->base_slices + b_offset;
225   b->slices = b->base_slices + a_offset;
226 
227   /* base_slices and slices fields are correctly set. Swap all other fields */
228   GPR_SWAP(size_t, a->count, b->count);
229   GPR_SWAP(size_t, a->capacity, b->capacity);
230   GPR_SWAP(size_t, a->length, b->length);
231 }
232 
grpc_slice_buffer_move_into(grpc_slice_buffer * src,grpc_slice_buffer * dst)233 void grpc_slice_buffer_move_into(grpc_slice_buffer* src,
234                                  grpc_slice_buffer* dst) {
235   /* anything to move? */
236   if (src->count == 0) {
237     return;
238   }
239   /* anything in dst? */
240   if (dst->count == 0) {
241     grpc_slice_buffer_swap(src, dst);
242     return;
243   }
244   /* both buffers have data - copy, and reset src */
245   grpc_slice_buffer_addn(dst, src->slices, src->count);
246   src->count = 0;
247   src->length = 0;
248 }
249 
slice_buffer_move_first_maybe_ref(grpc_slice_buffer * src,size_t n,grpc_slice_buffer * dst,bool incref)250 static void slice_buffer_move_first_maybe_ref(grpc_slice_buffer* src, size_t n,
251                                               grpc_slice_buffer* dst,
252                                               bool incref) {
253   GPR_ASSERT(src->length >= n);
254   if (src->length == n) {
255     grpc_slice_buffer_move_into(src, dst);
256     return;
257   }
258 
259   size_t output_len = dst->length + n;
260   size_t new_input_len = src->length - n;
261 
262   while (src->count > 0) {
263     grpc_slice slice = grpc_slice_buffer_take_first(src);
264     size_t slice_len = GRPC_SLICE_LENGTH(slice);
265     if (n > slice_len) {
266       grpc_slice_buffer_add(dst, slice);
267       n -= slice_len;
268     } else if (n == slice_len) {
269       grpc_slice_buffer_add(dst, slice);
270       break;
271     } else if (incref) { /* n < slice_len */
272       grpc_slice_buffer_undo_take_first(
273           src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_BOTH));
274       GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n);
275       grpc_slice_buffer_add(dst, slice);
276       break;
277     } else { /* n < slice_len */
278       grpc_slice_buffer_undo_take_first(
279           src, grpc_slice_split_tail_maybe_ref(&slice, n, GRPC_SLICE_REF_TAIL));
280       GPR_ASSERT(GRPC_SLICE_LENGTH(slice) == n);
281       grpc_slice_buffer_add_indexed(dst, slice);
282       break;
283     }
284   }
285   GPR_ASSERT(dst->length == output_len);
286   GPR_ASSERT(src->length == new_input_len);
287   GPR_ASSERT(src->count > 0);
288 }
289 
grpc_slice_buffer_move_first(grpc_slice_buffer * src,size_t n,grpc_slice_buffer * dst)290 void grpc_slice_buffer_move_first(grpc_slice_buffer* src, size_t n,
291                                   grpc_slice_buffer* dst) {
292   slice_buffer_move_first_maybe_ref(src, n, dst, true);
293 }
294 
grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer * src,size_t n,grpc_slice_buffer * dst)295 void grpc_slice_buffer_move_first_no_ref(grpc_slice_buffer* src, size_t n,
296                                          grpc_slice_buffer* dst) {
297   slice_buffer_move_first_maybe_ref(src, n, dst, false);
298 }
299 
grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer * src,size_t n,void * dst)300 void grpc_slice_buffer_move_first_into_buffer(grpc_slice_buffer* src, size_t n,
301                                               void* dst) {
302   char* dstp = static_cast<char*>(dst);
303   GPR_ASSERT(src->length >= n);
304 
305   while (n > 0) {
306     grpc_slice slice = grpc_slice_buffer_take_first(src);
307     size_t slice_len = GRPC_SLICE_LENGTH(slice);
308     if (slice_len > n) {
309       memcpy(dstp, GRPC_SLICE_START_PTR(slice), n);
310       grpc_slice_buffer_undo_take_first(
311           src, grpc_slice_sub_no_ref(slice, n, slice_len));
312       n = 0;
313     } else if (slice_len == n) {
314       memcpy(dstp, GRPC_SLICE_START_PTR(slice), n);
315       grpc_slice_unref_internal(slice);
316       n = 0;
317     } else {
318       memcpy(dstp, GRPC_SLICE_START_PTR(slice), slice_len);
319       dstp += slice_len;
320       n -= slice_len;
321       grpc_slice_unref_internal(slice);
322     }
323   }
324 }
325 
grpc_slice_buffer_trim_end(grpc_slice_buffer * sb,size_t n,grpc_slice_buffer * garbage)326 void grpc_slice_buffer_trim_end(grpc_slice_buffer* sb, size_t n,
327                                 grpc_slice_buffer* garbage) {
328   GPR_ASSERT(n <= sb->length);
329   sb->length -= n;
330   for (;;) {
331     size_t idx = sb->count - 1;
332     grpc_slice slice = sb->slices[idx];
333     size_t slice_len = GRPC_SLICE_LENGTH(slice);
334     if (slice_len > n) {
335       sb->slices[idx] = grpc_slice_split_head(&slice, slice_len - n);
336       if (garbage) {
337         grpc_slice_buffer_add_indexed(garbage, slice);
338       } else {
339         grpc_slice_unref_internal(slice);
340       }
341       return;
342     } else if (slice_len == n) {
343       if (garbage) {
344         grpc_slice_buffer_add_indexed(garbage, slice);
345       } else {
346         grpc_slice_unref_internal(slice);
347       }
348       sb->count = idx;
349       return;
350     } else {
351       if (garbage) {
352         grpc_slice_buffer_add_indexed(garbage, slice);
353       } else {
354         grpc_slice_unref_internal(slice);
355       }
356       n -= slice_len;
357       sb->count = idx;
358     }
359   }
360 }
361 
grpc_slice_buffer_take_first(grpc_slice_buffer * sb)362 grpc_slice grpc_slice_buffer_take_first(grpc_slice_buffer* sb) {
363   grpc_slice slice;
364   GPR_ASSERT(sb->count > 0);
365   slice = sb->slices[0];
366   sb->slices++;
367   sb->count--;
368   sb->length -= GRPC_SLICE_LENGTH(slice);
369 
370   return slice;
371 }
372 
grpc_slice_buffer_undo_take_first(grpc_slice_buffer * sb,grpc_slice slice)373 void grpc_slice_buffer_undo_take_first(grpc_slice_buffer* sb,
374                                        grpc_slice slice) {
375   sb->slices--;
376   sb->slices[0] = slice;
377   sb->count++;
378   sb->length += GRPC_SLICE_LENGTH(slice);
379 }
380