Files
libucore/include/ucore/mbuf.h
T
2015-05-04 22:57:49 +02:00

218 lines
6.6 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.
*
* @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;
}
#endif