diff --git a/lib/isc/buffer.c b/lib/isc/buffer.c index 8d9873adad..9e2c3bf339 100644 --- a/lib/isc/buffer.c +++ b/lib/isc/buffer.c @@ -120,72 +120,80 @@ isc_buffer_copyregion(isc_buffer_t *b, const isc_region_t *r) { } void -isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dynbuffer, +isc_buffer_allocate(isc_mem_t *mctx, isc_buffer_t **dbufp, unsigned int length) { - REQUIRE(dynbuffer != NULL && *dynbuffer == NULL); + REQUIRE(dbufp != NULL && *dbufp == NULL); - isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(isc_buffer_t)); - unsigned char *bdata = isc_mem_get(mctx, length); + isc_buffer_t *dbuf = isc_mem_get(mctx, sizeof(*dbuf) + length); + uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf); isc_buffer_init(dbuf, bdata, length); - + dbuf->extra = length; dbuf->mctx = mctx; - *dynbuffer = dbuf; + *dbufp = dbuf; } isc_result_t -isc_buffer_reserve(isc_buffer_t *dynbuffer, unsigned int size) { +isc_buffer_reserve(isc_buffer_t *dbuf, unsigned int size) { + REQUIRE(ISC_BUFFER_VALID(dbuf)); + size_t len; + uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf); - REQUIRE(ISC_BUFFER_VALID(dynbuffer)); - - len = dynbuffer->length; - if ((len - dynbuffer->used) >= size) { + len = dbuf->length; + if ((len - dbuf->used) >= size) { return (ISC_R_SUCCESS); } - if (dynbuffer->mctx == NULL) { + if (dbuf->mctx == NULL) { return (ISC_R_NOSPACE); } /* Round to nearest buffer size increment */ - len = size + dynbuffer->used; - len = (len + ISC_BUFFER_INCR - 1 - ((len - 1) % ISC_BUFFER_INCR)); + len = size + dbuf->used; + len = ISC_ALIGN(len, ISC_BUFFER_INCR); /* Cap at UINT_MAX */ if (len > UINT_MAX) { len = UINT_MAX; } - if ((len - dynbuffer->used) < size) { + if ((len - dbuf->used) < size) { return (ISC_R_NOMEMORY); } - dynbuffer->base = isc_mem_reget(dynbuffer->mctx, dynbuffer->base, - dynbuffer->length, len); - dynbuffer->length = (unsigned int)len; + if (dbuf->base == bdata) { + dbuf->base = isc_mem_get(dbuf->mctx, len); + memmove(dbuf->base, bdata, dbuf->used); + } else { + dbuf->base = isc_mem_reget(dbuf->mctx, dbuf->base, dbuf->length, + len); + } + dbuf->length = (unsigned int)len; return (ISC_R_SUCCESS); } void -isc_buffer_free(isc_buffer_t **dynbuffer) { - isc_buffer_t *dbuf; - isc_mem_t *mctx; +isc_buffer_free(isc_buffer_t **dbufp) { + REQUIRE(dbufp != NULL && ISC_BUFFER_VALID(*dbufp)); + REQUIRE((*dbufp)->mctx != NULL); - REQUIRE(dynbuffer != NULL); - REQUIRE(ISC_BUFFER_VALID(*dynbuffer)); - REQUIRE((*dynbuffer)->mctx != NULL); + isc_buffer_t *dbuf = *dbufp; + isc_mem_t *mctx = dbuf->mctx; + uint8_t *bdata = (uint8_t *)dbuf + sizeof(*dbuf); + unsigned int extra = dbuf->extra; - dbuf = *dynbuffer; - *dynbuffer = NULL; /* destroy external reference */ - mctx = dbuf->mctx; + *dbufp = NULL; /* destroy external reference */ dbuf->mctx = NULL; - isc_mem_put(mctx, dbuf->base, dbuf->length); + if (dbuf->base != bdata) { + isc_mem_put(mctx, dbuf->base, dbuf->length); + } + isc_buffer_invalidate(dbuf); - isc_mem_put(mctx, dbuf, sizeof(isc_buffer_t)); + isc_mem_put(mctx, dbuf, sizeof(*dbuf) + extra); } isc_result_t diff --git a/lib/isc/include/isc/buffer.h b/lib/isc/include/isc/buffer.h index 6ce0ba45ce..0929e6a750 100644 --- a/lib/isc/include/isc/buffer.h +++ b/lib/isc/include/isc/buffer.h @@ -128,7 +128,7 @@ ISC_LANG_BEGINDECLS * space in a buffer, we round the allocated buffer length up to the * nearest * multiple of this value. */ -#define ISC_BUFFER_INCR 2048 +#define ISC_BUFFER_INCR 512 /* * The following macros MUST be used only on valid buffers. It is the @@ -177,6 +177,8 @@ struct isc_buffer { unsigned int used; unsigned int current; unsigned int active; + /*! The extra bytes allocated for dynamic buffer */ + unsigned int extra; /*@}*/ /*! linkable */ ISC_LINK(isc_buffer_t) link; @@ -184,6 +186,8 @@ struct isc_buffer { isc_mem_t *mctx; }; +#define ISC_BUFFER_STATIC_SIZE 512 + /*** *** Functions ***/ @@ -509,10 +513,12 @@ static inline void isc_buffer_init(isc_buffer_t *b, void *base, unsigned int length) { ISC_REQUIRE(b != NULL); - *b = (isc_buffer_t){ .base = base, - .length = length, - .magic = ISC_BUFFER_MAGIC }; - ISC_LINK_INIT(b, link); + *b = (isc_buffer_t){ + .base = base, + .length = length, + .link = ISC_LINK_INITIALIZER, + .magic = ISC_BUFFER_MAGIC, + }; } /*! @@ -521,8 +527,10 @@ isc_buffer_init(isc_buffer_t *b, void *base, unsigned int length) { */ static inline void isc_buffer_initnull(isc_buffer_t *b) { - *b = (isc_buffer_t){ .magic = ISC_BUFFER_MAGIC }; - ISC_LINK_INIT(b, link); + *b = (isc_buffer_t){ + .link = ISC_LINK_INITIALIZER, + .magic = ISC_BUFFER_MAGIC, + }; } /*! @@ -560,12 +568,9 @@ isc_buffer_invalidate(isc_buffer_t *b) { ISC_REQUIRE(!ISC_LINK_LINKED(b, link)); ISC_REQUIRE(b->mctx == NULL); - b->magic = 0; - b->base = NULL; - b->length = 0; - b->used = 0; - b->current = 0; - b->active = 0; + *b = (isc_buffer_t){ + .magic = 0, + }; } /*! diff --git a/tests/isc/buffer_test.c b/tests/isc/buffer_test.c index 94ed6f8017..09e1038e46 100644 --- a/tests/isc/buffer_test.c +++ b/tests/isc/buffer_test.c @@ -42,48 +42,44 @@ ISC_RUN_TEST_IMPL(isc_buffer_reserve) { UNUSED(state); b = NULL; - isc_buffer_allocate(mctx, &b, 1024); - assert_int_equal(b->length, 1024); + isc_buffer_allocate(mctx, &b, ISC_BUFFER_INCR); + assert_int_equal(b->length, ISC_BUFFER_INCR); /* - * 1024 bytes should already be available, so this call does + * 512 bytes should already be available, so this call does * nothing. */ - result = isc_buffer_reserve(b, 1024); + result = isc_buffer_reserve(b, 512); assert_int_equal(result, ISC_R_SUCCESS); - assert_true(ISC_BUFFER_VALID(b)); assert_non_null(b); - assert_int_equal(b->length, 1024); + assert_int_equal(b->length, ISC_BUFFER_INCR); /* - * This call should grow it to 2048 bytes as only 1024 bytes are + * This call should grow it to 1536 bytes as only 1024 bytes are * available in the buffer. */ result = isc_buffer_reserve(b, 1025); assert_int_equal(result, ISC_R_SUCCESS); - assert_true(ISC_BUFFER_VALID(b)); assert_non_null(b); - assert_int_equal(b->length, 2048); + assert_int_equal(b->length, 3 * ISC_BUFFER_INCR); /* - * 2048 bytes should already be available, so this call does + * 1536 bytes should already be available, so this call does * nothing. */ - result = isc_buffer_reserve(b, 2000); + result = isc_buffer_reserve(b, 1500); assert_int_equal(result, ISC_R_SUCCESS); - assert_true(ISC_BUFFER_VALID(b)); assert_non_null(b); - assert_int_equal(b->length, 2048); + assert_int_equal(b->length, 3 * ISC_BUFFER_INCR); /* - * This call should grow it to 4096 bytes as only 2048 bytes are + * This call should grow it to 4096 bytes as only 1536 bytes are * available in the buffer. */ - result = isc_buffer_reserve(b, 3000); + result = isc_buffer_reserve(b, 3585); assert_int_equal(result, ISC_R_SUCCESS); - assert_true(ISC_BUFFER_VALID(b)); assert_non_null(b); - assert_int_equal(b->length, 4096); + assert_int_equal(b->length, 8 * ISC_BUFFER_INCR); /* Consume some of the buffer so we can run the next test. */ isc_buffer_add(b, 4096); @@ -93,9 +89,8 @@ ISC_RUN_TEST_IMPL(isc_buffer_reserve) { */ result = isc_buffer_reserve(b, UINT_MAX); assert_int_equal(result, ISC_R_NOMEMORY); - assert_true(ISC_BUFFER_VALID(b)); assert_non_null(b); - assert_int_equal(b->length, 4096); + assert_int_equal(b->length, 8 * ISC_BUFFER_INCR); isc_buffer_free(&b); }