230 lines
6.9 KiB
C
230 lines
6.9 KiB
C
#ifndef UC_MBUF_H_
|
|
#define UC_MBUF_H_
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "tailq.h"
|
|
|
|
|
|
/** @file
|
|
* mbuf - A managed message/memory buffer.
|
|
*
|
|
* Concept:
|
|
@verbatim
|
|
<--------- allocated ----------->
|
|
<--- len -->
|
|
+--------------------------------+
|
|
|Headroom| Data |Tailroom |
|
|
+--------------------------------+
|
|
^ ^ ^
|
|
| | |
|
|
| | tail
|
|
| head
|
|
bufstart
|
|
|
|
@endverbatim
|
|
*
|
|
* Initially when empty, head == tail, and the length is 0.
|
|
* Data can be added to the tailroom or the headroom.
|
|
* The data is the memory from (including) head to (excluding) tail.
|
|
*
|
|
* If head == bufstart, there is no headroom
|
|
* if tail points one past the allocated space, there is no
|
|
* tailroom (the buffer is full)
|
|
*
|
|
* Conventions:
|
|
* push - prepend data to the buffer in the head room part
|
|
* (move head to the left)
|
|
* pull - remove data from the beginning of the data
|
|
* (move head to the right)
|
|
* put - Add data to the buffer.
|
|
* (move tail to the right)
|
|
*/
|
|
|
|
/** Flags used internally */
|
|
enum UC_MBUF_FLAGS {
|
|
UC_MBUF_FL_MALLOC = 0x0001, //MBuf and MBuf->bufstart are seperatly malloc'd
|
|
UC_MBUF_FL_MALLOC_BUF = 0x0001, //MBuf is not malloc'd. MBuf->bufstart is malloc'd
|
|
UC_MBUF_FL_MALLOC_INLINE = 0x0002, //MBuf is one big malloc. Can't be resized
|
|
UC_MBUF_FL_STATIC = 0x0004, //MBuf and MBuf->bustart is user controlled. Can't be resized
|
|
};
|
|
|
|
struct MBuf {
|
|
/** linked list entry for keeping the mbufs in a list*/
|
|
struct TailQ entry;
|
|
|
|
/** Pointers the user can use to remember spots in
|
|
* the data. (these must either be NULL pointers or point into
|
|
* something in the buffer*/
|
|
uint8_t *p1;
|
|
uint8_t *p2;
|
|
uint8_t *p3;
|
|
uint8_t *p4;
|
|
/**Arbitary pointer user can associate with the mbuf*/
|
|
void *cookie;
|
|
|
|
/*UC_MBUF_FLAGS. The upper 16 bits can be used by the application */
|
|
uint32_t flags;
|
|
/** Total no of bytes from bufstart*/
|
|
uint32_t allocated;
|
|
/** Start of the buffer*/
|
|
uint8_t *bufstart;
|
|
/** Start of the data in the buffer*/
|
|
uint8_t *head;
|
|
/** End of the buffer (one byte past the data) */
|
|
uint8_t *tail;
|
|
/** Internal data, if we allocate it inline */
|
|
uint8_t inline_data[0];
|
|
};
|
|
|
|
|
|
/** Allocate an mbuf with a length and headroom,
|
|
* the buffer will have the flag UC_MBUF_FL_MALLOC
|
|
* The total length of the buffer will be length+headroom
|
|
*
|
|
* @param len the initial length of the mbuf
|
|
* @param the initial headroom of the mbuf
|
|
* @return NULL if the allocation fails
|
|
*/
|
|
struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom);
|
|
|
|
/** As uc_mbuf_new_hr, but without any headroom*/
|
|
#define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0)
|
|
|
|
|
|
/** Allocate an mbuf with a length and headroom,
|
|
* the buffer will have the flag UC_MBUF_FL_MALLOC_INLINE
|
|
* The total length of the buffer will be length+headroom
|
|
*
|
|
* @param len the initial length of the mbuf
|
|
* @param the initial headroom of the mbuf
|
|
* @return NULL if the allocation fails
|
|
*/
|
|
struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom);
|
|
|
|
/** As uc_mbuf_new_inline_hr, but without any headroom*/
|
|
#define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0)
|
|
|
|
/** Free the memory of an mbuf and its data.
|
|
* If passing in NULL or an mbuf with a UC_MBUF_FL_STATIC flag,
|
|
* no action is taken.
|
|
*
|
|
* @param mbuf the mbuf to free.
|
|
*/
|
|
void uc_mbuf_free(struct MBuf *mbuf);
|
|
|
|
/** Create a new mbuf, with a copy of the data from the given
|
|
* mbuf. The new mbuf will have the same headroom as the old one,
|
|
* but no tailroom.
|
|
*
|
|
* @param mbuf mbuf to copy
|
|
*/
|
|
struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf);
|
|
|
|
/** Initialize an mbuf. This function is mostly used internally,
|
|
* but can be used to e.g. create an mbuf based on a local array
|
|
* (in which case UC_MBUF_FL_STATIC must be set), or other data
|
|
* whose memory is already allocated. * The whole buffer must have len + headroom available data
|
|
*
|
|
* @param mbuf to initialise
|
|
* @param buf start of the buffer
|
|
* @param len length of the buffer (not including the headroom)
|
|
* @param headroom the headroom in the buffer
|
|
* @param flags The appropriate UC_MBUF_FLAGS
|
|
*/
|
|
void uc_mbuf_init(struct MBuf *mbuf, uint8_t *restrict buf, uint32_t len,
|
|
uint32_t headroom, uint32_t flags);
|
|
|
|
/** Zero out all the data in this mbuf, including the headroom and tailroom
|
|
*
|
|
* @param mbuf mbuf to zero out
|
|
*/
|
|
void uc_mbuf_zero(struct MBuf *mbuf);
|
|
|
|
/**
|
|
* @return the length of the data in this mbuf
|
|
*/
|
|
static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf)
|
|
{
|
|
return (uint32_t)(mbuf->tail - mbuf->head);
|
|
}
|
|
|
|
/**
|
|
* @return the length of the tailroom in this mbuf
|
|
*/
|
|
static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf)
|
|
{
|
|
return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart);
|
|
}
|
|
|
|
/**
|
|
* @return the length of the headroom in this mbuf
|
|
*/
|
|
static UC_INLINE uint32_t uc_mbuf_headroom(struct MBuf *mbuf)
|
|
{
|
|
return (uint32_t)(mbuf->head - mbuf->bufstart);
|
|
}
|
|
|
|
|
|
/** Append data data to this buffer
|
|
* The returned pointer points at the end of the current
|
|
* data in the buffer, advancing the tail be size bytes .
|
|
* You need to insert the size bytes at in the returned pointer.
|
|
*
|
|
* @param size bytes to put in the buffer
|
|
* @return NULL if the mbuf does not have room for the given size
|
|
*/
|
|
uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size);
|
|
|
|
/** Prepend data to the buffer. The buffer needs to have enough
|
|
* headroom to allow this.
|
|
* The returned pointer points size bytes in front if the current
|
|
* data in the buffer, retreating the head pointer by size butes
|
|
* You need to insert the size bytes in the returned pointer.
|
|
*
|
|
w* @oaram size bytes to prepend to the buffer
|
|
* @return NULL if the mbuf does not have enough headroom
|
|
*/
|
|
uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size);
|
|
|
|
/** Remove data from the buffer ("read" data from it)
|
|
* The returned pointer is the beginning of the data in the
|
|
* buffer, advancing the head by size bytes.
|
|
*
|
|
* @param size number of bytes to pull
|
|
* @return NULL if the buffer does not have at least size bytes
|
|
**/
|
|
uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size);
|
|
|
|
/** Add more tailroom to an mbuf.
|
|
* Can only be done with mbufs with either
|
|
* UC_MBUF_FL_MALLOC or UC_MBUF_FL_MALLOC_BUF.
|
|
*
|
|
* @param len additional tailroom to add to mbuf
|
|
* @return 0 on success, otherwise failure
|
|
*
|
|
*/
|
|
int uc_mbuf_extend_tailroom(struct MBuf *mbuf, uint32_t len);
|
|
|
|
/** Get a pointer to the data of the buffer
|
|
*
|
|
* @return pointer to the start of the data (head)
|
|
*/
|
|
static UC_INLINE uint8_t *uc_mbuf_head(struct MBuf* mbuf)
|
|
{
|
|
return mbuf->head;
|
|
}
|
|
|
|
/** Add the mbuf at the end of the tailq.
|
|
* This uses the tailQ entry member of the mbuf.
|
|
*/
|
|
void uc_mbuf_enqueue(struct MBuf *mbuf, struct TailQ *head);
|
|
|
|
/** Remove and return the mbuf at the start of the tailq.
|
|
* @return the first mbuf in the queue, or NULL if ti isempty.
|
|
*/
|
|
struct MBuf *uc_mbuf_dequeue(struct TailQ *head);
|
|
|
|
|
|
|
|
#endif
|