2
0
mirror of https://github.com/openvswitch/ovs synced 2025-08-31 14:25:26 +00:00

ofpbuf: New function ofpbuf_use_stack().

This new function is useful in a situation where a small stack-allocated
buffer is usually appropriate but occasionally it must be expanded.

Acked-by: Jesse Gross <jesse@nicira.com>
This commit is contained in:
Ben Pfaff
2010-12-23 14:23:41 -08:00
parent f0d3bc8615
commit 31ac1e590b
2 changed files with 84 additions and 17 deletions

View File

@@ -22,32 +22,59 @@
#include "dynamic-string.h"
#include "util.h"
/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
* memory starting at 'base'.
*
* 'base' should ordinarily be the first byte of a region obtained from
* malloc(), but in circumstances where it can be guaranteed that 'b' will
* never need to be expanded or freed, it can be a pointer into arbitrary
* memory. */
void
ofpbuf_use(struct ofpbuf *b, void *base, size_t allocated)
static void
ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
enum ofpbuf_source source)
{
b->base = b->data = base;
b->allocated = allocated;
b->source = source;
b->size = 0;
b->l2 = b->l3 = b->l4 = b->l7 = NULL;
list_poison(&b->list_node);
b->private_p = NULL;
}
/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
* memory starting at 'base'. 'base' should be the first byte of a region
* obtained from malloc(). It will be freed (with free()) if 'b' is resized or
* freed. */
void
ofpbuf_use(struct ofpbuf *b, void *base, size_t allocated)
{
ofpbuf_use__(b, base, allocated, OFPBUF_MALLOC);
}
/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
* memory starting at 'base'. 'base' should point to a buffer on the stack.
* If 'b' is resized, new memory will be allocated with malloc() and 'base'
* will not be freed. This is useful when a small stack-allocated buffer is
* normally appropriate but sometimes it must be expanded.
*
* 'base' should be appropriately aligned. Using an array of uint32_t or
* uint64_t for the buffer is a reasonable way to ensure appropriate alignment
* for 32- or 64-bit data.
*
* (Nothing actually relies on 'base' being allocated on the stack. It could
* be static or malloc()'d memory. But stack space is the most common use
* case.) */
void
ofpbuf_use_stack(struct ofpbuf *b, void *base, size_t allocated)
{
ofpbuf_use__(b, base, allocated, OFPBUF_STACK);
}
/* Initializes 'b' as an ofpbuf whose data starts at 'data' and continues for
* 'size' bytes. This is appropriate for an ofpbuf that will be used to
* inspect existing data, without moving it around or reallocating it, and
* generally without modifying it at all. */
* generally without modifying it at all.
*
* An ofpbuf operation that requires reallocating data will assert-fail if this
* function was used to initialize it. */
void
ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size)
{
ofpbuf_use(b, (void *) data, size);
ofpbuf_use__(b, (void *) data, size, OFPBUF_CONST);
b->size = size;
}
@@ -63,7 +90,7 @@ ofpbuf_init(struct ofpbuf *b, size_t size)
void
ofpbuf_uninit(struct ofpbuf *b)
{
if (b) {
if (b && b->source == OFPBUF_MALLOC) {
free(b->base);
}
}
@@ -176,8 +203,31 @@ ofpbuf_rebase__(struct ofpbuf *b, void *new_base)
static void
ofpbuf_resize_tailroom__(struct ofpbuf *b, size_t new_tailroom)
{
b->allocated = ofpbuf_headroom(b) + b->size + new_tailroom;
ofpbuf_rebase__(b, xrealloc(b->base, b->allocated));
size_t new_allocated;
void *new_base;
new_allocated = ofpbuf_headroom(b) + b->size + new_tailroom;
switch (b->source) {
case OFPBUF_MALLOC:
new_base = xrealloc(b->base, new_allocated);
break;
case OFPBUF_STACK:
new_base = xmalloc(new_allocated);
memcpy(new_base, b->base, MIN(new_allocated, b->allocated));
b->source = OFPBUF_MALLOC;
break;
case OFPBUF_CONST:
NOT_REACHED();
default:
NOT_REACHED();
}
b->allocated = new_allocated;
ofpbuf_rebase__(b, new_base);
}
/* Ensures that 'b' has room for at least 'size' bytes at its tail end,
@@ -198,11 +248,14 @@ ofpbuf_prealloc_headroom(struct ofpbuf *b, size_t size)
}
/* Trims the size of 'b' to fit its actual content, reducing its tailroom to
* 0. Its headroom, if any, is preserved. */
* 0. Its headroom, if any, is preserved.
*
* Buffers not obtained from malloc() are not resized, since that wouldn't save
* any memory. */
void
ofpbuf_trim(struct ofpbuf *b)
{
if (ofpbuf_tailroom(b) > 0) {
if (b->source == OFPBUF_MALLOC && ofpbuf_tailroom(b) > 0) {
ofpbuf_resize_tailroom__(b, 0);
}
}