Files
libucore/include/ucore/mbuf.h
T
2014-05-25 23:07:08 +02:00

213 lines
6.4 KiB
C

#ifndef UC_MBUF_H_
#define UC_MBUF_H_
#include <stdint.h>
#include <stddef.h>
#include "tailq.h"
#ifdef __GNUC__
# define UC_INLINE inline __attribute__((always_inline))
#else
# define UC_INLINE inline
#endif
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];
};
/**
* Concept:
* <--------- allocated ----------->
* <--- len -->
* +--------------------------------+
* |Headroom| Data |Tailroom |
* +--------------------------------+
* ^ ^ ^
* | | |
* | | tail
* | head
* bufstart
*
* Initially when empty, head == tail, and the length is 0.
* Data is added to the 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 message.
* (move head to the right)
* put - Add data to the buffer.
* (move tail to the right)
*/
/** 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)
/** @param mbuf the mbuf to free. (passing NULL is a no-op)*/
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
*
* @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;
}
#undef UC_INLINE
#endif