mirror of
https://github.com/openvswitch/ovs
synced 2025-09-01 06:45:17 +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:
85
lib/ofpbuf.c
85
lib/ofpbuf.c
@@ -22,32 +22,59 @@
|
|||||||
#include "dynamic-string.h"
|
#include "dynamic-string.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
/* Initializes 'b' as an empty ofpbuf that contains the 'allocated' bytes of
|
static void
|
||||||
* memory starting at 'base'.
|
ofpbuf_use__(struct ofpbuf *b, void *base, size_t allocated,
|
||||||
*
|
enum ofpbuf_source source)
|
||||||
* '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)
|
|
||||||
{
|
{
|
||||||
b->base = b->data = base;
|
b->base = b->data = base;
|
||||||
b->allocated = allocated;
|
b->allocated = allocated;
|
||||||
|
b->source = source;
|
||||||
b->size = 0;
|
b->size = 0;
|
||||||
b->l2 = b->l3 = b->l4 = b->l7 = NULL;
|
b->l2 = b->l3 = b->l4 = b->l7 = NULL;
|
||||||
list_poison(&b->list_node);
|
list_poison(&b->list_node);
|
||||||
b->private_p = NULL;
|
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
|
/* 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
|
* 'size' bytes. This is appropriate for an ofpbuf that will be used to
|
||||||
* inspect existing data, without moving it around or reallocating it, and
|
* 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
|
void
|
||||||
ofpbuf_use_const(struct ofpbuf *b, const void *data, size_t size)
|
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;
|
b->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -63,7 +90,7 @@ ofpbuf_init(struct ofpbuf *b, size_t size)
|
|||||||
void
|
void
|
||||||
ofpbuf_uninit(struct ofpbuf *b)
|
ofpbuf_uninit(struct ofpbuf *b)
|
||||||
{
|
{
|
||||||
if (b) {
|
if (b && b->source == OFPBUF_MALLOC) {
|
||||||
free(b->base);
|
free(b->base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -176,8 +203,31 @@ ofpbuf_rebase__(struct ofpbuf *b, void *new_base)
|
|||||||
static void
|
static void
|
||||||
ofpbuf_resize_tailroom__(struct ofpbuf *b, size_t new_tailroom)
|
ofpbuf_resize_tailroom__(struct ofpbuf *b, size_t new_tailroom)
|
||||||
{
|
{
|
||||||
b->allocated = ofpbuf_headroom(b) + b->size + new_tailroom;
|
size_t new_allocated;
|
||||||
ofpbuf_rebase__(b, xrealloc(b->base, b->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,
|
/* 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
|
/* 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
|
void
|
||||||
ofpbuf_trim(struct ofpbuf *b)
|
ofpbuf_trim(struct ofpbuf *b)
|
||||||
{
|
{
|
||||||
if (ofpbuf_tailroom(b) > 0) {
|
if (b->source == OFPBUF_MALLOC && ofpbuf_tailroom(b) > 0) {
|
||||||
ofpbuf_resize_tailroom__(b, 0);
|
ofpbuf_resize_tailroom__(b, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
lib/ofpbuf.h
16
lib/ofpbuf.h
@@ -18,17 +18,26 @@
|
|||||||
#define OFPBUF_H 1
|
#define OFPBUF_H 1
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum ofpbuf_source {
|
||||||
|
OFPBUF_MALLOC, /* Obtained via malloc(). */
|
||||||
|
OFPBUF_STACK, /* Stack space or static buffer. */
|
||||||
|
OFPBUF_CONST /* Must not be expanded. */
|
||||||
|
};
|
||||||
|
|
||||||
/* Buffer for holding arbitrary data. An ofpbuf is automatically reallocated
|
/* Buffer for holding arbitrary data. An ofpbuf is automatically reallocated
|
||||||
* as necessary if it grows too large for the available memory. */
|
* as necessary if it grows too large for the available memory. */
|
||||||
struct ofpbuf {
|
struct ofpbuf {
|
||||||
void *base; /* First byte of area malloc()'d area. */
|
void *base; /* First byte of allocated space. */
|
||||||
size_t allocated; /* Number of bytes allocated. */
|
size_t allocated; /* Number of bytes allocated. */
|
||||||
|
enum ofpbuf_source source; /* Source of memory allocated as 'base'. */
|
||||||
|
|
||||||
void *data; /* First byte actually in use. */
|
void *data; /* First byte actually in use. */
|
||||||
size_t size; /* Number of bytes in use. */
|
size_t size; /* Number of bytes in use. */
|
||||||
@@ -42,7 +51,12 @@ struct ofpbuf {
|
|||||||
void *private_p; /* Private pointer for use by owner. */
|
void *private_p; /* Private pointer for use by owner. */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Declares NAME as a SIZE-byte array aligned properly for storing any kind of
|
||||||
|
* data. For use with ofpbuf_use_stack(). */
|
||||||
|
#define OFPBUF_STACK_BUFFER(NAME, SIZE) uint64_t NAME[DIV_ROUND_UP(SIZE, 8)]
|
||||||
|
|
||||||
void ofpbuf_use(struct ofpbuf *, void *, size_t);
|
void ofpbuf_use(struct ofpbuf *, void *, size_t);
|
||||||
|
void ofpbuf_use_stack(struct ofpbuf *, void *, size_t);
|
||||||
void ofpbuf_use_const(struct ofpbuf *, const void *, size_t);
|
void ofpbuf_use_const(struct ofpbuf *, const void *, size_t);
|
||||||
|
|
||||||
void ofpbuf_init(struct ofpbuf *, size_t);
|
void ofpbuf_init(struct ofpbuf *, size_t);
|
||||||
|
Reference in New Issue
Block a user