Line data Source code
1 : /*
2 : *
3 : * Copyright 2015, Google Inc.
4 : * All rights reserved.
5 : *
6 : * Redistribution and use in source and binary forms, with or without
7 : * modification, are permitted provided that the following conditions are
8 : * met:
9 : *
10 : * * Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * * Redistributions in binary form must reproduce the above
13 : * copyright notice, this list of conditions and the following disclaimer
14 : * in the documentation and/or other materials provided with the
15 : * distribution.
16 : * * Neither the name of Google Inc. nor the names of its
17 : * contributors may be used to endorse or promote products derived from
18 : * this software without specific prior written permission.
19 : *
20 : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : *
32 : */
33 :
34 : #include <grpc/support/slice_buffer.h>
35 :
36 : #include <string.h>
37 :
38 : #include <grpc/support/alloc.h>
39 : #include <grpc/support/log.h>
40 : #include <grpc/support/useful.h>
41 :
42 : /* grow a buffer; requires GRPC_SLICE_BUFFER_INLINE_ELEMENTS > 1 */
43 : #define GROW(x) (3 * (x) / 2)
44 :
45 41606559 : static void maybe_embiggen(gpr_slice_buffer *sb) {
46 41606559 : if (sb->count == sb->capacity) {
47 9816 : sb->capacity = GROW(sb->capacity);
48 9816 : GPR_ASSERT(sb->capacity > sb->count);
49 9816 : if (sb->slices == sb->inlined) {
50 3637 : sb->slices = gpr_malloc(sb->capacity * sizeof(gpr_slice));
51 3637 : memcpy(sb->slices, sb->inlined, sb->count * sizeof(gpr_slice));
52 : } else {
53 6179 : sb->slices = gpr_realloc(sb->slices, sb->capacity * sizeof(gpr_slice));
54 : }
55 : }
56 41606559 : }
57 :
58 16750614 : void gpr_slice_buffer_init(gpr_slice_buffer *sb) {
59 16750614 : sb->count = 0;
60 16750614 : sb->length = 0;
61 16750614 : sb->capacity = GRPC_SLICE_BUFFER_INLINE_ELEMENTS;
62 16750614 : sb->slices = sb->inlined;
63 16750614 : }
64 :
65 11324255 : void gpr_slice_buffer_destroy(gpr_slice_buffer *sb) {
66 11324255 : gpr_slice_buffer_reset_and_unref(sb);
67 11325901 : if (sb->slices != sb->inlined) {
68 3637 : gpr_free(sb->slices);
69 : }
70 11325901 : }
71 :
72 19475097 : gpr_uint8 *gpr_slice_buffer_tiny_add(gpr_slice_buffer *sb, size_t n) {
73 : gpr_slice *back;
74 : gpr_uint8 *out;
75 :
76 19475097 : sb->length += n;
77 :
78 19475097 : if (sb->count == 0) goto add_new;
79 19475097 : back = &sb->slices[sb->count - 1];
80 19475097 : if (back->refcount) goto add_new;
81 19429103 : if ((back->data.inlined.length + n) > sizeof(back->data.inlined.bytes))
82 1406798 : goto add_new;
83 18022305 : out = back->data.inlined.bytes + back->data.inlined.length;
84 18022305 : back->data.inlined.length = (gpr_uint8)(back->data.inlined.length + n);
85 18022305 : return out;
86 :
87 : add_new:
88 1452792 : maybe_embiggen(sb);
89 1452694 : back = &sb->slices[sb->count];
90 1452694 : sb->count++;
91 1452694 : back->refcount = NULL;
92 1452694 : back->data.inlined.length = (gpr_uint8)n;
93 1452694 : return back->data.inlined.bytes;
94 : }
95 :
96 37013659 : size_t gpr_slice_buffer_add_indexed(gpr_slice_buffer *sb, gpr_slice s) {
97 37013659 : size_t out = sb->count;
98 37013659 : maybe_embiggen(sb);
99 37082197 : sb->slices[out] = s;
100 37082197 : sb->length += GPR_SLICE_LENGTH(s);
101 37082197 : sb->count = out + 1;
102 37082197 : return out;
103 : }
104 :
105 24288703 : void gpr_slice_buffer_add(gpr_slice_buffer *sb, gpr_slice s) {
106 24288703 : size_t n = sb->count;
107 : /* if both the last slice in the slice buffer and the slice being added
108 : are inlined (that is, that they carry their data inside the slice data
109 : structure), and the back slice is not full, then concatenate directly
110 : into the back slice, preventing many small slices being passed into
111 : writes */
112 24288703 : if (!s.refcount && n) {
113 13405211 : gpr_slice *back = &sb->slices[n - 1];
114 13405211 : if (!back->refcount && back->data.inlined.length < GPR_SLICE_INLINED_SIZE) {
115 12467704 : if (s.data.inlined.length + back->data.inlined.length <=
116 : GPR_SLICE_INLINED_SIZE) {
117 9327927 : memcpy(back->data.inlined.bytes + back->data.inlined.length,
118 9327927 : s.data.inlined.bytes, s.data.inlined.length);
119 9327927 : back->data.inlined.length =
120 9327927 : (gpr_uint8)(back->data.inlined.length + s.data.inlined.length);
121 : } else {
122 3139777 : size_t cp1 = GPR_SLICE_INLINED_SIZE - back->data.inlined.length;
123 3139777 : memcpy(back->data.inlined.bytes + back->data.inlined.length,
124 : s.data.inlined.bytes, cp1);
125 3139777 : back->data.inlined.length = GPR_SLICE_INLINED_SIZE;
126 3139777 : maybe_embiggen(sb);
127 3139759 : back = &sb->slices[n];
128 3139759 : sb->count = n + 1;
129 3139759 : back->refcount = NULL;
130 3139759 : back->data.inlined.length = (gpr_uint8)(s.data.inlined.length - cp1);
131 3139759 : memcpy(back->data.inlined.bytes, s.data.inlined.bytes + cp1,
132 3139759 : s.data.inlined.length - cp1);
133 : }
134 12467686 : sb->length += s.data.inlined.length;
135 36820842 : return; /* early out */
136 : }
137 : }
138 11820999 : gpr_slice_buffer_add_indexed(sb, s);
139 : }
140 :
141 398367 : void gpr_slice_buffer_addn(gpr_slice_buffer *sb, gpr_slice *s, size_t n) {
142 : size_t i;
143 1028826 : for (i = 0; i < n; i++) {
144 630459 : gpr_slice_buffer_add(sb, s[i]);
145 : }
146 398367 : }
147 :
148 26 : void gpr_slice_buffer_pop(gpr_slice_buffer *sb) {
149 26 : if (sb->count != 0) {
150 20 : size_t count = --sb->count;
151 20 : sb->length -= GPR_SLICE_LENGTH(sb->slices[count]);
152 : }
153 26 : }
154 :
155 27734999 : void gpr_slice_buffer_reset_and_unref(gpr_slice_buffer *sb) {
156 : size_t i;
157 :
158 62769865 : for (i = 0; i < sb->count; i++) {
159 34993531 : gpr_slice_unref(sb->slices[i]);
160 : }
161 :
162 27776334 : sb->count = 0;
163 27776334 : sb->length = 0;
164 27776334 : }
165 :
166 15994073 : void gpr_slice_buffer_swap(gpr_slice_buffer *a, gpr_slice_buffer *b) {
167 15994073 : GPR_SWAP(size_t, a->count, b->count);
168 15994073 : GPR_SWAP(size_t, a->capacity, b->capacity);
169 15994073 : GPR_SWAP(size_t, a->length, b->length);
170 :
171 15994073 : if (a->slices == a->inlined) {
172 9621173 : if (b->slices == b->inlined) {
173 : /* swap contents of inlined buffer */
174 : gpr_slice temp[GRPC_SLICE_BUFFER_INLINE_ELEMENTS];
175 6150159 : memcpy(temp, a->slices, b->count * sizeof(gpr_slice));
176 6150159 : memcpy(a->slices, b->slices, a->count * sizeof(gpr_slice));
177 6150159 : memcpy(b->slices, temp, b->count * sizeof(gpr_slice));
178 : } else {
179 : /* a is inlined, b is not - copy a inlined into b, fix pointers */
180 3471014 : a->slices = b->slices;
181 3471014 : b->slices = b->inlined;
182 3471014 : memcpy(b->slices, a->inlined, b->count * sizeof(gpr_slice));
183 : }
184 6372900 : } else if (b->slices == b->inlined) {
185 : /* b is inlined, a is not - copy b inlined int a, fix pointers */
186 3468672 : b->slices = a->slices;
187 3468672 : a->slices = a->inlined;
188 3468672 : memcpy(a->slices, b->inlined, a->count * sizeof(gpr_slice));
189 : } else {
190 : /* no inlining: easy swap */
191 2904228 : GPR_SWAP(gpr_slice *, a->slices, b->slices);
192 : }
193 15994073 : }
194 :
195 2466029 : void gpr_slice_buffer_move_into(gpr_slice_buffer *src, gpr_slice_buffer *dst) {
196 : /* anything to move? */
197 2466029 : if (src->count == 0) {
198 2462349 : return;
199 : }
200 : /* anything in dst? */
201 3680 : if (dst->count == 0) {
202 3680 : gpr_slice_buffer_swap(src, dst);
203 3680 : return;
204 : }
205 : /* both buffers have data - copy, and reset src */
206 0 : gpr_slice_buffer_addn(dst, src->slices, src->count);
207 0 : src->count = 0;
208 0 : src->length = 0;
209 : }
210 :
211 1415918 : void gpr_slice_buffer_trim_end(gpr_slice_buffer *sb, size_t n,
212 : gpr_slice_buffer *garbage) {
213 1415918 : GPR_ASSERT(n <= sb->length);
214 1415918 : sb->length -= n;
215 : for (;;) {
216 2685740 : size_t idx = sb->count - 1;
217 2685740 : gpr_slice slice = sb->slices[idx];
218 2685740 : size_t slice_len = GPR_SLICE_LENGTH(slice);
219 2685740 : if (slice_len > n) {
220 1402536 : sb->slices[idx] = gpr_slice_split_head(&slice, slice_len - n);
221 1402572 : gpr_slice_buffer_add_indexed(garbage, slice);
222 1402570 : return;
223 1283204 : } else if (slice_len == n) {
224 13355 : gpr_slice_buffer_add_indexed(garbage, slice);
225 13355 : sb->count = idx;
226 13355 : return;
227 : } else {
228 1269849 : gpr_slice_buffer_add_indexed(garbage, slice);
229 1269822 : n -= slice_len;
230 1269822 : sb->count = idx;
231 : }
232 1269822 : }
233 : }
|