From: Willy Tarreau Date: Fri, 18 Oct 2024 15:53:25 +0000 (+0200) Subject: BUILD: buffers: keep b_getblk_nc() and b_peek_varint() in buf.h X-Git-Tag: v3.1-dev11~106 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b5a1fd1fcceaedc1104cd360def5ccf12f22a4e;p=thirdparty%2Fhaproxy.git BUILD: buffers: keep b_getblk_nc() and b_peek_varint() in buf.h Some large functions were moved to buf.c by commit ac66df4e2 ("REORG: buffers: move some of the heavy functions from buf.h to buf.c"). However, as found by Amaury, haring doesn't build anymore. Upon close inspection, b_getblk_nc() isn't that big since it's very much inlinable, and a part of its apparently large size comes from the BUG_ON_HOT() that were implemented. Regarding b_peek_varint(), it doesn't have any dependency and is used only at 4 places in the DNS code, so its loop will not have big impacts, and the rest around can be optimised away by the compiler so it remains relevant to keep it inlined. Also it can serve as a base to deduplicate the code in b_get_varint(). No backport needed. --- diff --git a/include/haproxy/buf.h b/include/haproxy/buf.h index 8238ae40ff..bb0f0b73be 100644 --- a/include/haproxy/buf.h +++ b/include/haproxy/buf.h @@ -35,8 +35,6 @@ size_t b_getblk_ofs(const struct buffer *buf, char *blk, size_t len, size_t offset); size_t b_getblk(const struct buffer *buf, char *blk, size_t len, size_t offset); -size_t b_getblk_nc(const struct buffer *buf, const char **blk1, size_t *len1, - const char **blk2, size_t *len2, size_t ofs, size_t max); size_t b_getdelim(const struct buffer *buf, size_t offset, size_t count, char *str, size_t len, const char *delim, char escape); size_t b_getline(const struct buffer *buf, size_t offset, size_t count, @@ -53,7 +51,6 @@ int b_insert_blk(struct buffer *b, size_t off, const char *blk, size_t len); void __b_put_varint(struct buffer *b, uint64_t v); int b_put_varint(struct buffer *b, uint64_t v); int b_get_varint(struct buffer *b, uint64_t *vptr); -int b_peek_varint(struct buffer *b, size_t ofs, uint64_t *vptr); void bl_deinit(struct bl_elem *head); uint32_t bl_get(struct bl_elem *head, uint32_t idx); @@ -463,6 +460,80 @@ static inline size_t b_force_xfer(struct buffer *dst, struct buffer *src, size_t return ret; } +/* b_getblk_nc() : gets one or two blocks of data at once from a buffer, + * starting from offset after the beginning of its output, and limited to + * no more than bytes. The caller is responsible for ensuring that + * neither nor + exceed the total number of bytes available in + * the buffer. Return values : + * >0 : number of blocks filled (1 or 2). blk1 is always filled before blk2. + * =0 : not enough data available. are left undefined. + * The buffer is left unaffected. Unused buffers are left in an undefined state. + */ +static inline size_t b_getblk_nc(const struct buffer *buf, const char **blk1, size_t *len1, const char **blk2, size_t *len2, size_t ofs, size_t max) +{ + size_t l1; + + BUG_ON_HOT(buf->data > buf->size); + BUG_ON_HOT(ofs > buf->data); + BUG_ON_HOT(ofs + max > buf->data); + + if (!max) + return 0; + + *blk1 = b_peek(buf, ofs); + l1 = b_wrap(buf) - *blk1; + if (l1 < max) { + *len1 = l1; + *len2 = max - l1; + *blk2 = b_orig(buf); + return 2; + } + *len1 = max; + return 1; +} + +/* b_peek_varint(): try to decode a varint from buffer at offset + * relative to head, into value . Returns the number of bytes parsed in + * case of success, or 0 if there were not enough bytes, in which case the + * contents of are not updated. Wrapping is supported. The buffer's head + * will NOT be updated. It is illegal to call this function with greater + * than b->data. + */ +static inline int b_peek_varint(struct buffer *b, size_t ofs, uint64_t *vptr) +{ + const uint8_t *head = (const uint8_t *)b_peek(b, ofs); + const uint8_t *wrap = (const uint8_t *)b_wrap(b); + size_t data = b_data(b) - ofs; + size_t size = b_size(b); + uint64_t v = 0; + int bits = 0; + + BUG_ON_HOT(ofs > b_data(b)); + + if (data != 0 && (*head >= 0xF0)) { + v = *head; + bits += 4; + while (1) { + if (++head == wrap) + head -= size; + data--; + if (!data || !(*head & 0x80)) + break; + v += (uint64_t)*head << bits; + bits += 7; + } + } + + /* last byte */ + if (!data) + return 0; + + v += (uint64_t)*head << bits; + *vptr = v; + data--; + size = b->data - ofs - data; + return size; +} /* diff --git a/src/buf.c b/src/buf.c index b81652ac01..2e07c0bc18 100644 --- a/src/buf.c +++ b/src/buf.c @@ -81,38 +81,6 @@ size_t b_getblk(const struct buffer *buf, char *blk, size_t len, size_t offset) return len; } -/* b_getblk_nc() : gets one or two blocks of data at once from a buffer, - * starting from offset after the beginning of its output, and limited to - * no more than bytes. The caller is responsible for ensuring that - * neither nor + exceed the total number of bytes available in - * the buffer. Return values : - * >0 : number of blocks filled (1 or 2). blk1 is always filled before blk2. - * =0 : not enough data available. are left undefined. - * The buffer is left unaffected. Unused buffers are left in an undefined state. - */ -size_t b_getblk_nc(const struct buffer *buf, const char **blk1, size_t *len1, const char **blk2, size_t *len2, size_t ofs, size_t max) -{ - size_t l1; - - BUG_ON_HOT(buf->data > buf->size); - BUG_ON_HOT(ofs > buf->data); - BUG_ON_HOT(ofs + max > buf->data); - - if (!max) - return 0; - - *blk1 = b_peek(buf, ofs); - l1 = b_wrap(buf) - *blk1; - if (l1 < max) { - *len1 = l1; - *len2 = max - l1; - *blk2 = b_orig(buf); - return 2; - } - *len1 = max; - return 1; -} - /* Locates the longest part of the buffer that is composed exclusively of * characters not in the set, and delimited by one of these characters, * and returns the initial part and the first of such delimiters. A single @@ -688,48 +656,6 @@ int b_get_varint(struct buffer *b, uint64_t *vptr) return size; } -/* b_peek_varint(): try to decode a varint from buffer at offset - * relative to head, into value . Returns the number of bytes parsed in - * case of success, or 0 if there were not enough bytes, in which case the - * contents of are not updated. Wrapping is supported. The buffer's head - * will NOT be updated. It is illegal to call this function with greater - * than b->data. - */ -int b_peek_varint(struct buffer *b, size_t ofs, uint64_t *vptr) -{ - const uint8_t *head = (const uint8_t *)b_peek(b, ofs); - const uint8_t *wrap = (const uint8_t *)b_wrap(b); - size_t data = b_data(b) - ofs; - size_t size = b_size(b); - uint64_t v = 0; - int bits = 0; - - BUG_ON_HOT(ofs > b_data(b)); - - if (data != 0 && (*head >= 0xF0)) { - v = *head; - bits += 4; - while (1) { - if (++head == wrap) - head -= size; - data--; - if (!data || !(*head & 0x80)) - break; - v += (uint64_t)*head << bits; - bits += 7; - } - } - - /* last byte */ - if (!data) - return 0; - - v += (uint64_t)*head << bits; - *vptr = v; - data--; - size = b->data - ofs - data; - return size; -} /* * Buffer List management.