From bf9802e565140943e246d833931cc9cf6010c18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 30 Jun 2013 21:42:02 +0200 Subject: [PATCH] First iteration of mbuf, message buffer api --- include/ucore/mbuf.h | 78 +++++++++++++++++ src/mbuf.c | 101 ++++++++++++++++++++++ test/test_mbuf.c | 197 +++++++++++++++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- 4 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 include/ucore/mbuf.h create mode 100644 src/mbuf.c create mode 100644 test/test_mbuf.c diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h new file mode 100644 index 0000000..ebfc8aa --- /dev/null +++ b/include/ucore/mbuf.h @@ -0,0 +1,78 @@ +#ifndef UC_MBUF_H_ +#define UC_MBUF_H_ +#include +#include + +#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 { + struct MBuf *next; + uint8_t *p1; + uint8_t *p2; + uint8_t *p3; + uint8_t *p4; + void *cookie; + uint32_t flags; + uint32_t allocated; + uint8_t *bufstart; + uint8_t *head; + uint8_t *tail; + uint8_t inline_data[0]; +}; + +/* Conventions: + * push - prepend data to the buffer (in the head room part) + * pull - remove data from the beginning of the message. + * put - Add data to the buffer. + */ +struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom); +#define uc_mbuf_new(len) uc_mbuf_new_hr((len), 0) + +struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom); +#define uc_mbuf_new_inline(len) uc_mbuf_new_inline_hr((len), 0) + +void uc_mbuf_free(struct MBuf *mbuf); +struct MBuf *uc_mbuf_copy(struct MBuf *mbuf); + +void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags); +void uc_mbuf_zero(struct MBuf *mbuf); +void uc_mbuf_reset(struct MBuf *mbuf); + +static UC_INLINE uint32_t uc_mbuf_len(struct MBuf *mbuf) +{ + return (uint32_t)(mbuf->tail - mbuf->head); +} + +static UC_INLINE uint32_t uc_mbuf_tailroom(struct MBuf *mbuf) +{ + return mbuf->allocated - (uint32_t)(mbuf->tail - mbuf->bufstart); +} + +static inline uint32_t uc_mbuf_headroom(struct MBuf *mbuf) +{ + return (uint32_t)(mbuf->head - mbuf->bufstart); +} + +uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size); + +uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size); + +uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size); + +struct MBuf *uc_uc_mbuf_new_hr(uint32_t len, uint32_t headroom); +struct MBuf *uc_uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom); + +#undef UC_INLINE + +#endif diff --git a/src/mbuf.c b/src/mbuf.c new file mode 100644 index 0000000..80a551e --- /dev/null +++ b/src/mbuf.c @@ -0,0 +1,101 @@ +#include +#include +#include "ucore/mbuf.h" + +uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size) +{ + uint8_t *data = mbuf->tail; + if (uc_mbuf_tailroom(mbuf) < size) { + return NULL; + } + + mbuf->tail += size; + + return data; +} + +uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size) +{ + if (uc_mbuf_headroom(mbuf) < size) { + return NULL; + } + + mbuf->head -= size; + + return mbuf->head; +} + +uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size) +{ + uint8_t *data = mbuf->head; + if (uc_mbuf_len(mbuf) < size) { + return NULL; + } + + mbuf->head += size; + + return data; +} + + +void uc_mbuf_init(struct MBuf *mbuf, uint8_t *buf, uint32_t len, uint32_t headroom, uint32_t flags) +{ + mbuf->bufstart = buf; + mbuf->next = NULL; + mbuf->p1 = mbuf->p2 = mbuf->p3 = mbuf->p4 = NULL; + mbuf->cookie = NULL; + mbuf->flags = flags; + mbuf->allocated = len + headroom; + mbuf->head = mbuf->bufstart + headroom; + mbuf->tail = mbuf->head; +} + +struct MBuf *uc_mbuf_new_hr(uint32_t len, uint32_t headroom) +{ + struct MBuf *mbuf; + uint8_t *buf; + + mbuf = malloc(sizeof *mbuf); + if (mbuf == NULL) + return mbuf; + + buf = malloc(len + headroom); + if (buf == NULL) { + free(mbuf); + return NULL; + } + + uc_mbuf_init(mbuf, buf, len, headroom, UC_MBUF_FL_MALLOC); + + return mbuf; +} + +struct MBuf *uc_mbuf_new_inline_hr(uint32_t len, uint32_t headroom) +{ + struct MBuf *mbuf; + + mbuf = malloc(sizeof *mbuf + len + headroom); + if (mbuf == NULL) + return mbuf; + + uc_mbuf_init(mbuf, mbuf->inline_data, len, headroom, UC_MBUF_FL_MALLOC_INLINE); + + return mbuf; +} + +void uc_mbuf_free(struct MBuf *mbuf) +{ + if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_BUF)) + free(mbuf->bufstart); + + if (mbuf->flags & (UC_MBUF_FL_MALLOC | UC_MBUF_FL_MALLOC_INLINE)) + free(mbuf); +} + +void uc_mbuf_zero(struct MBuf *mbuf) +{ + memset(mbuf->bufstart, 0, mbuf->allocated); +} + +#undef UC_INLINE + diff --git a/test/test_mbuf.c b/test/test_mbuf.c new file mode 100644 index 0000000..b465110 --- /dev/null +++ b/test/test_mbuf.c @@ -0,0 +1,197 @@ +#include +#include +#include + + +START_TEST (test_mbuf_new) + struct MBuf *mbuf; + + mbuf = uc_mbuf_new(110); + + fail_if(mbuf == NULL); + fail_if(uc_mbuf_len(mbuf) != 0); + fail_if(uc_mbuf_headroom(mbuf) != 0); + fail_if(uc_mbuf_tailroom(mbuf) != 110); + fail_if(mbuf->next != NULL); + fail_if(mbuf->p1 != NULL); + fail_if(mbuf->p2 != NULL); + fail_if(mbuf->p3 != NULL); + fail_if(mbuf->p4 != NULL); + fail_if(mbuf->cookie != NULL); + fail_if(mbuf->head != mbuf->tail); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_new_inline) + struct MBuf *mbuf; + + mbuf = uc_mbuf_new_inline(110); + + fail_if(mbuf == NULL); + fail_if(uc_mbuf_len(mbuf) != 0); + fail_if(uc_mbuf_headroom(mbuf) != 0); + fail_if(uc_mbuf_tailroom(mbuf) != 110); + fail_if(mbuf->next != NULL); + fail_if(mbuf->p1 != NULL); + fail_if(mbuf->p2 != NULL); + fail_if(mbuf->p3 != NULL); + fail_if(mbuf->p4 != NULL); + fail_if(mbuf->cookie != NULL); + fail_if(mbuf->head != mbuf->tail); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_new_headroom) + struct MBuf *mbuf; + + mbuf = uc_mbuf_new_hr(110,20); + + fail_if(mbuf == NULL); + fail_if(uc_mbuf_len(mbuf) != 0); + fail_if(uc_mbuf_headroom(mbuf) != 20); + fail_if(uc_mbuf_tailroom(mbuf) != 110); + fail_if(mbuf->next != NULL); + fail_if(mbuf->p1 != NULL); + fail_if(mbuf->p2 != NULL); + fail_if(mbuf->p3 != NULL); + fail_if(mbuf->p4 != NULL); + fail_if(mbuf->cookie != NULL); + fail_if(mbuf->head != mbuf->tail); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_put) + struct MBuf *mbuf; + uint8_t *data; + + mbuf = uc_mbuf_new_inline(111); + fail_if(mbuf == NULL); + + data = uc_mbuf_put(mbuf, 111); + fail_if(data == NULL); + fail_if(uc_mbuf_len(mbuf) != 111); + fail_if(uc_mbuf_tailroom(mbuf) != 0); + + memset(data, 0, 111); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_put_fail) + struct MBuf *mbuf; + uint8_t *data; + + mbuf = uc_mbuf_new_inline(10); + fail_if(mbuf == NULL); + + data = uc_mbuf_put(mbuf, 11); + fail_if(data != NULL); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_push) + struct MBuf *mbuf; + uint8_t *data; + + mbuf = uc_mbuf_new_hr(10,1); + fail_if(mbuf == NULL); + + data = uc_mbuf_push(mbuf, 1); + fail_if(data == NULL); + fail_if(uc_mbuf_len(mbuf) != 1); + fail_if(uc_mbuf_headroom(mbuf) != 0); + + *data = 0; + + uc_mbuf_free(mbuf); + +END_TEST + + +START_TEST (test_mbuf_push_fail) + struct MBuf *mbuf; + uint8_t *data; + + mbuf = uc_mbuf_new_hr(1,2); + fail_if(mbuf == NULL); + + data = uc_mbuf_push(mbuf, 3); + fail_if(data != NULL); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_pull) + struct MBuf *mbuf; + uint8_t *data1; + uint8_t *data2; + + mbuf = uc_mbuf_new_inline(10); + fail_if(mbuf == NULL); + + data1 = uc_mbuf_put(mbuf, 10); + fail_if(data1 == NULL); + fail_if(uc_mbuf_tailroom(mbuf) != 0); + fail_if(uc_mbuf_len(mbuf) != 10); + + data2 = uc_mbuf_pull(mbuf,10); + fail_if(data2 == NULL); + fail_if(data1 != data2); + fail_if(uc_mbuf_len(mbuf) != 0); + + uc_mbuf_free(mbuf); + +END_TEST + +START_TEST (test_mbuf_pull_fail) + struct MBuf *mbuf; + uint8_t *data1; + uint8_t *data2; + + mbuf = uc_mbuf_new_inline(10); + fail_if(mbuf == NULL); + + data1 = uc_mbuf_put(mbuf, 10); + fail_if(data1 == NULL); + fail_if(uc_mbuf_len(mbuf) != 10); + + data2 = uc_mbuf_pull(mbuf,11); + fail_if(data2 != NULL); + fail_if(uc_mbuf_len(mbuf) != 10); + + + uc_mbuf_free(mbuf); + +END_TEST + + + +Suite *mbuf_suite(void) +{ + Suite *s = suite_create("mbuf"); + TCase *tc = tcase_create("mbuf tests"); + tcase_add_test(tc, test_mbuf_new); + tcase_add_test(tc, test_mbuf_new_inline); + tcase_add_test(tc, test_mbuf_new_headroom); + tcase_add_test(tc, test_mbuf_put); + tcase_add_test(tc, test_mbuf_put_fail); + tcase_add_test(tc, test_mbuf_push); + tcase_add_test(tc, test_mbuf_push_fail); + tcase_add_test(tc, test_mbuf_pull); + tcase_add_test(tc, test_mbuf_pull_fail); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index d85129a..d844221 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -19,6 +19,7 @@ extern Suite *clock_suite(void); extern Suite *seq_suite(void); extern Suite *sat_math_suite(void); extern Suite *timers_suite(void); +extern Suite *mbuf_suite(void); static suite_func suites[] = { bitvec_suite, @@ -33,7 +34,8 @@ static suite_func suites[] = { clock_suite, seq_suite, sat_math_suite, - timers_suite + timers_suite, + mbuf_suite }; int