Line data Source code
1 : #ifndef HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
2 : #define HEADER_fd_src_waltz_h2_fd_h2_rbuf_h
3 :
4 : /* fd_h2_rbuf.h provides a byte oriented unaligend ring buffer. */
5 :
6 : #include "fd_h2_base.h"
7 : #include "../../util/log/fd_log.h"
8 :
9 : struct fd_h2_rbuf {
10 : uchar * buf0; /* points to first byte of buffer */
11 : uchar * buf1; /* points one past last byte of buffer */
12 : uchar * lo; /* in [buf0,buf1) */
13 : uchar * hi; /* in [buf0,buf1) */
14 : ulong lo_off;
15 : ulong hi_off;
16 : ulong bufsz;
17 : };
18 :
19 : FD_PROTOTYPES_BEGIN
20 :
21 : /* fd_h2_rbuf_init initializes an h2_rbuf backed by the given buffer.
22 : On return, h2_rbuf has a read-write interested in buf. bufsz has no
23 : alignment requirements. */
24 :
25 : static inline fd_h2_rbuf_t *
26 : fd_h2_rbuf_init( fd_h2_rbuf_t * rbuf,
27 : void * buf,
28 282 : ulong bufsz ) {
29 282 : *rbuf = (fd_h2_rbuf_t) {
30 282 : .buf0 = (uchar *)buf,
31 282 : .buf1 = (uchar *)buf+bufsz,
32 282 : .lo = (uchar *)buf,
33 282 : .hi = (uchar *)buf,
34 282 : .bufsz = bufsz
35 282 : };
36 282 : return rbuf;
37 282 : }
38 :
39 : /* fd_h2_rbuf_used_sz returns the number of unconsumed bytes in rbuf. */
40 :
41 : FD_FN_PURE static inline ulong
42 500627163 : fd_h2_rbuf_used_sz( fd_h2_rbuf_t const * rbuf ) {
43 500627163 : return rbuf->hi_off - rbuf->lo_off;
44 500627163 : }
45 :
46 : /* fd_h2_rbuf_free_sz returns the number of bytes that can be appended
47 : using fd_h2_rbuf_push. */
48 :
49 : FD_FN_PURE static inline ulong
50 247502892 : fd_h2_rbuf_free_sz( fd_h2_rbuf_t const * rbuf ) {
51 247502892 : long used = (long)fd_h2_rbuf_used_sz( rbuf );
52 247502892 : return (ulong)fd_long_max( 0L, rbuf->buf1 - rbuf->buf0 - used );
53 247502892 : }
54 :
55 : /* fd_h2_rbuf_validate_private validates invariants of rbuf. */
56 : static void
57 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf );
58 :
59 : /* fd_h2_rbuf_push appends a series of newly received bytes into rbuf.
60 : Returns chunk_sz.
61 :
62 : WARNING: The caller must not pass a chunk_sz larger than
63 : fd_h2_rbuf_free_sz bytes. */
64 :
65 : static inline void
66 : fd_h2_rbuf_push( fd_h2_rbuf_t * rbuf,
67 : void const * chunk,
68 7502367 : ulong chunk_sz ) {
69 : #ifdef FD_H2_USE_HANDHOLDING
70 : FD_TEST( chunk_sz<=fd_h2_rbuf_free_sz( rbuf ) );
71 : #endif
72 7502367 : uchar * buf0 = rbuf->buf0;
73 7502367 : uchar * buf1 = rbuf->buf1;
74 7502367 : uchar * lo = rbuf->lo;
75 7502367 : uchar * hi = rbuf->hi;
76 7502367 : rbuf->hi_off += chunk_sz;
77 :
78 7502367 : if( FD_UNLIKELY( hi+chunk_sz > rbuf->buf1 ) ) {
79 : /* Split copy */
80 1774620 : if( FD_UNLIKELY( lo>hi ) ) {
81 0 : FD_LOG_CRIT(( "rbuf overflow: buf_sz=%lu lo=%ld hi=%ld chunk_sz=%lu",
82 0 : rbuf->bufsz, rbuf->lo-buf0, rbuf->hi-buf0, chunk_sz ));
83 0 : }
84 1774620 : ulong part1 = (ulong)( buf1-hi );
85 1774620 : ulong part2 = (ulong)( chunk_sz-part1 );
86 1774620 : fd_memcpy( hi, chunk, part1 );
87 1774620 : fd_memcpy( buf0, (void *)( (ulong)chunk+part1 ), part2 );
88 1774620 : rbuf->hi = buf0+part2;
89 1774620 : fd_h2_rbuf_validate_private( rbuf );
90 1774620 : return;
91 1774620 : }
92 :
93 : /* One-shot copy */
94 5727747 : uchar * new_hi = hi+chunk_sz;
95 5727747 : if( new_hi==buf1 ) new_hi = buf0;
96 5727747 : fd_memcpy( hi, chunk, chunk_sz );
97 5727747 : rbuf->hi = new_hi;
98 5727747 : fd_h2_rbuf_validate_private( rbuf );
99 5727747 : return;
100 7502367 : }
101 :
102 : /* fd_h2_rbuf_peek_used returns a pointer to the first contiguous
103 : fragment of unconsumed data. *sz is set to the number of contiguous
104 : bytes starting at rbuf->lo. *split_sz is set to the number of bytes
105 : that are unconsumed, but in a separate fragment. The caller may
106 : mangle bytes in [retval,retval+sz) if it consumes these bytes
107 : immediately afterwards. */
108 :
109 : static inline uchar *
110 : fd_h2_rbuf_peek_used( fd_h2_rbuf_t * rbuf,
111 : ulong * sz,
112 73123704 : ulong * split_sz ) {
113 73123704 : ulong used_sz = fd_h2_rbuf_used_sz( rbuf );
114 73123704 : uchar * buf0 = rbuf->buf0;
115 73123704 : uchar * buf1 = rbuf->buf1;
116 73123704 : uchar * lo = rbuf->lo;
117 73123704 : uchar * hi = rbuf->hi;
118 73123704 : uchar * end = lo+used_sz;
119 : /* FIXME make this branchless */
120 73123704 : if( end<=buf1 ) {
121 37615812 : *sz = (ulong)( used_sz );
122 37615812 : *split_sz = 0UL;
123 37615812 : } else {
124 35507892 : *sz = (ulong)( buf1 - lo );
125 35507892 : *split_sz = (ulong)( hi - buf0 );
126 35507892 : }
127 73123704 : return lo;
128 73123704 : }
129 :
130 : /* fd_h2_rbuf_peek_free is like fd_h2_rbuf_peek_used, but refers to the
131 : free region. */
132 :
133 : static inline uchar *
134 : fd_h2_rbuf_peek_free( fd_h2_rbuf_t * rbuf,
135 : ulong * sz,
136 60000018 : ulong * split_sz ) {
137 60000018 : ulong free_sz = fd_h2_rbuf_free_sz( rbuf );
138 60000018 : uchar * buf0 = rbuf->buf0;
139 60000018 : uchar * buf1 = rbuf->buf1;
140 60000018 : uchar * lo = rbuf->lo;
141 60000018 : uchar * hi = rbuf->hi;
142 60000018 : uchar * end = hi+free_sz;
143 : /* FIXME make this branchless */
144 60000018 : if( end<=buf1 ) {
145 30880788 : *sz = (ulong)( free_sz );
146 30880788 : *split_sz = 0UL;
147 30880788 : } else {
148 29119230 : *sz = (ulong)( buf1 - hi );
149 29119230 : *split_sz = (ulong)( lo - buf0 );
150 29119230 : }
151 60000018 : return hi;
152 60000018 : }
153 :
154 : /* fd_h2_rbuf_skip frees n bytes from rbuf. Freeing more bytes than
155 : returned by fd_h2_rbuf_used_sz corrupts the buffer state. */
156 :
157 : static inline void
158 : fd_h2_rbuf_skip( fd_h2_rbuf_t * rbuf,
159 13123764 : ulong n ) {
160 13123764 : uchar * lo = rbuf->lo;
161 13123764 : ulong bufsz = rbuf->bufsz;
162 13123764 : uchar * buf1 = rbuf->buf1;
163 13123764 : rbuf->lo_off += n;
164 13123764 : lo += n;
165 13123764 : if( FD_UNLIKELY( lo>=buf1 ) ) {
166 3284448 : lo -= bufsz;
167 3284448 : }
168 13123764 : rbuf->lo = lo;
169 13123764 : fd_h2_rbuf_validate_private( rbuf );
170 13123764 : }
171 :
172 : /* fd_h2_rbuf_alloc marks the next n free bytes as used. */
173 :
174 : static inline void
175 : fd_h2_rbuf_alloc( fd_h2_rbuf_t * rbuf,
176 0 : ulong n ) {
177 0 : uchar * hi = rbuf->hi;
178 0 : ulong bufsz = rbuf->bufsz;
179 0 : uchar * buf1 = rbuf->buf1;
180 0 : rbuf->hi_off += n;
181 0 : hi += n;
182 0 : if( FD_UNLIKELY( hi>=buf1 ) ) {
183 0 : hi -= bufsz;
184 0 : }
185 0 : rbuf->hi = hi;
186 0 : fd_h2_rbuf_validate_private( rbuf );
187 0 : }
188 :
189 : /* fd_h2_rbuf_pop consumes n bytes from rbuf. n is the number of bytes
190 : to consume. n is assumed to be <= fd_h2_rbuf_used(rbuf). scratch
191 : points to scratch memory with space for n bytes.
192 :
193 : If the bytes are available contiguously in rbuf, returns a pointer to
194 : them. Otherwise, the bytes are copied into scratch. The returned
195 : pointer is valid until the next mutating rbuf operation. */
196 :
197 : static inline uchar *
198 : fd_h2_rbuf_pop( fd_h2_rbuf_t * rbuf,
199 : uchar * scratch,
200 1872021 : ulong n ) {
201 : #ifdef FD_H2_USE_HANDHOLDING
202 : FD_TEST( n<=fd_h2_rbuf_used_sz( rbuf ) );
203 : #endif
204 1872021 : uchar * lo = rbuf->lo;
205 1872021 : uchar * buf0 = rbuf->buf0;
206 1872021 : uchar * buf1 = rbuf->buf1;
207 1872021 : ulong bufsz = rbuf->bufsz;
208 1872021 : uchar * ret = lo;
209 1872021 : rbuf->lo_off += n;
210 1872021 : uchar * end = lo+n;
211 1872021 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
212 466122 : end -= bufsz;
213 466122 : }
214 1872021 : if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
215 441582 : ulong part0 = (ulong)( buf1-lo );
216 441582 : ulong part1 = n-part0;
217 441582 : fd_memcpy( scratch, lo, part0 );
218 441582 : fd_memcpy( scratch+part0, buf0, part1 );
219 441582 : ret = scratch;
220 441582 : }
221 1872021 : rbuf->lo = end;
222 1872021 : fd_h2_rbuf_validate_private( rbuf );
223 1872021 : return ret;
224 1872021 : }
225 :
226 : static inline void
227 : fd_h2_rbuf_pop_copy( fd_h2_rbuf_t * rbuf,
228 : void * out,
229 186 : ulong n ) {
230 : #ifdef FD_H2_USE_HANDHOLDING
231 : FD_TEST( n<=fd_h2_rbuf_used_sz( rbuf ) );
232 : #endif
233 186 : uchar * lo = rbuf->lo;
234 186 : uchar * buf0 = rbuf->buf0;
235 186 : uchar * buf1 = rbuf->buf1;
236 186 : ulong bufsz = rbuf->bufsz;
237 186 : rbuf->lo_off += n;
238 186 : uchar * end = lo+n;
239 186 : if( FD_UNLIKELY( (lo+n)>=buf1 ) ) {
240 3 : end -= bufsz;
241 3 : }
242 186 : if( FD_UNLIKELY( (lo+n)>buf1 ) ) {
243 0 : ulong part0 = (ulong)( buf1-lo );
244 0 : ulong part1 = n-part0;
245 0 : fd_memcpy( out, lo, part0 );
246 0 : fd_memcpy( (void *)( (ulong)out+part0 ), buf0, part1 );
247 186 : } else {
248 186 : fd_memcpy( out, lo, n );
249 186 : }
250 186 : rbuf->lo = end;
251 186 : fd_h2_rbuf_validate_private( rbuf );
252 186 : }
253 :
254 : FD_FN_PURE static inline int
255 108 : fd_h2_rbuf_is_empty( fd_h2_rbuf_t const * rbuf ) {
256 108 : return rbuf->lo_off==rbuf->hi_off;
257 108 : }
258 :
259 : static void
260 22498338 : fd_h2_rbuf_validate_private( fd_h2_rbuf_t * rbuf ) {
261 22498338 : #ifndef FD_H2_USE_HANDHOLDING
262 22498338 : (void)rbuf;
263 22498338 : #endif
264 : #ifdef FD_H2_USE_HANDHOLDING
265 : ulong used = fd_h2_rbuf_used_sz( rbuf );
266 : ulong free = fd_h2_rbuf_free_sz( rbuf );
267 :
268 : if( !( used <= rbuf->bufsz ) ) {
269 : FD_LOG_NOTICE(( "used <= rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
270 : }
271 : if( !( free <= rbuf->bufsz ) ) {
272 : FD_LOG_NOTICE(( "free <= rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
273 : }
274 : if( !( used + free == rbuf->bufsz ) ) {
275 : FD_LOG_NOTICE(( "used + free == rbuf->bufsz failed: rbuf %p used %lu free %lu bufsz %lu", (void *)rbuf, used, free, rbuf->bufsz ));
276 : }
277 : FD_TEST( used <= rbuf->bufsz );
278 : FD_TEST( free <= rbuf->bufsz );
279 : FD_TEST( used + free == rbuf->bufsz );
280 :
281 : ulong used0, used1;
282 : uchar * used_p = fd_h2_rbuf_peek_used( rbuf, &used0, &used1 );
283 : FD_TEST( used_p == rbuf->lo );
284 : FD_TEST( used0 + used1 == used );
285 :
286 : ulong free0, free1;
287 : uchar * free_p = fd_h2_rbuf_peek_free( rbuf, &free0, &free1 );
288 : FD_TEST( free_p == rbuf->hi );
289 : FD_TEST( free0 + free1 == free );
290 : #endif /* FD_H2_USE_HANDHOLDING */
291 22498338 : }
292 :
293 : FD_PROTOTYPES_END
294 :
295 : #endif /* HEADER_fd_src_waltz_h2_fd_h2_rbuf_h */
|