From 9b7db5440e4b5fdcc0efb1372563db88191a7c79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 27 Jun 2013 20:58:07 +0200 Subject: [PATCH 01/45] Allow CC shell environment to override compiler --- SConstruct | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/SConstruct b/SConstruct index 695afbe..d32cd4d 100644 --- a/SConstruct +++ b/SConstruct @@ -59,6 +59,11 @@ def InstallPerm(env, dest, files, perm): env = Environment(tools = ['default', 'textfile']) + +#allow shell environment to override compiler +if os.environ.has_key('CC'): + env['CC'] = os.environ['CC'] + env.AddMethod(InstallPerm) Export('env', 'build_type', 'prefix', 'version_info', 'test_xml') From a8dcf6edff957af8db4a5c4dd203618cd34cec50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 27 Jun 2013 20:58:23 +0200 Subject: [PATCH 02/45] Get rid of inline warning from clang --- src/logging.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/logging.c b/src/logging.c index cdf086a..85146e8 100644 --- a/src/logging.c +++ b/src/logging.c @@ -79,7 +79,7 @@ static const char *const g_log_levels[] = { "NONE" }; -inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l) +const char *uc_ll_2_str(enum UC_LOG_LEVEL l) { if (l < ARRAY_SIZE(g_log_levels)) { return g_log_levels[l]; From 1e0e840ee5ddd92f6e8ec3fb9bb5a4e995043649 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 27 Jun 2013 20:58:43 +0200 Subject: [PATCH 03/45] Get rid of aligment warning on CONTAINER_OF in clang --- include/ucore/utils.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/include/ucore/utils.h b/include/ucore/utils.h index 9d1e86c..aad8379 100644 --- a/include/ucore/utils.h +++ b/include/ucore/utils.h @@ -48,12 +48,14 @@ //struct foo *f = CONTAINER_OF(p, struct foo, zap); #define CONTAINER_OF(ptr, type, member) ({ \ typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (unsigned char *)__mptr - offsetof(type, member) ); }) + (type *)((void *)(unsigned char *)__mptr - offsetof(type, member) ); }) + +//the void* cast is to suppress alignment warnings //Same as CONTAINER_OF, but for a const pointer to avoid gcc warnings.. #define CONST_CONTAINER_OF(ptr, type, member) ({ \ const typeof( ((const type *)0)->member ) *__mptr = (ptr); \ - (const type *)( (const unsigned char *)__mptr - offsetof(const type, member) ); }) + (const type *)((const void *)(const unsigned char *)__mptr - offsetof(const type, member) ); }) /** Align a value. * @param val value to align From 89232426e05e8593a7402b7d3eba6ed472c8e198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 30 Jun 2013 14:34:19 +0200 Subject: [PATCH 04/45] Properly use return value of select to count the number of events --- src/iomux_epoll.c | 2 +- src/iomux_select.c | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/iomux_epoll.c b/src/iomux_epoll.c index 22f964b..65a9eaf 100644 --- a/src/iomux_epoll.c +++ b/src/iomux_epoll.c @@ -183,7 +183,7 @@ again: fd->callback(mux_, fd, events); //be sure not to use fd after the callback, it might been removed. - mux->pending_events[i].data.ptr = NULL; + mux->pending_events[i].data.ptr = NULL; //clear from pending list event_cnt++; } diff --git a/src/iomux_select.c b/src/iomux_select.c index 8b67414..ad39cf9 100644 --- a/src/iomux_select.c +++ b/src/iomux_select.c @@ -168,17 +168,18 @@ again: } if (FD_ISSET(mux->descriptors[i]->fd, &read_set)) { + rc--; events |= MUX_EV_READ; } if (FD_ISSET(mux->descriptors[i]->fd, &write_set)) { + rc--; events |= MUX_EV_WRITE; } if (events) { assert(mux->descriptors[i]->callback != NULL); mux->descriptors[i]->callback(mux_, mux->descriptors[i], events); - rc--; event_cnt++; } } 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 05/45] 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 From 764dfc563c82f73b24ad6546860d92183e9cfa05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 1 Jul 2013 23:00:19 +0200 Subject: [PATCH 06/45] Don't trt yo be smart with the comma operator --- src/tval.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tval.c b/src/tval.c index b2a2eea..4218742 100644 --- a/src/tval.c +++ b/src/tval.c @@ -6,8 +6,10 @@ uc_tvadd(struct timeval *dst, const struct timeval *a, const struct timeval *b) dst->tv_sec = a->tv_sec + b->tv_sec; dst->tv_usec = a->tv_usec + b->tv_usec; - if (dst->tv_usec >= 1000000) - dst->tv_sec++, dst->tv_usec -= 1000000; + if (dst->tv_usec >= 1000000) { + dst->tv_sec++; + dst->tv_usec -= 1000000; + } return dst; } @@ -18,8 +20,10 @@ uc_tvsub(struct timeval *dst, const struct timeval *a, const struct timeval *b) dst->tv_sec = a->tv_sec - b->tv_sec; dst->tv_usec = a->tv_usec - b->tv_usec; - if (dst->tv_usec < 0) - dst->tv_sec--, dst->tv_usec += 1000000; + if (dst->tv_usec < 0) { + dst->tv_sec--; + dst->tv_usec += 1000000; + } return dst; } From 6d77b78b41c3cfd5bd95e529e4aed2272aee5883 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 1 Jul 2013 23:02:24 +0200 Subject: [PATCH 07/45] use unsigned long long for uc_ms2tv() --- src/tval.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tval.c b/src/tval.c index 4218742..a2577e8 100644 --- a/src/tval.c +++ b/src/tval.c @@ -45,7 +45,7 @@ uc_tvcmp(const struct timeval *a, const struct timeval *b) } struct timeval * -uc_to2tv(struct timeval *dst, unsigned long ms) +uc_ms2tv(struct timeval *dst, unsigned long long ms) { dst->tv_sec = ms / 1000; dst->tv_usec = ms % 1000 * 1000; From d8376338faedc3a36bea3355c1c1d1f93bee2c46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 2 Jul 2013 21:21:27 +0200 Subject: [PATCH 08/45] Improve doxygen comments --- include/ucore/iomux.h | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/include/ucore/iomux.h b/include/ucore/iomux.h index 7f8c2f7..20a64cb 100644 --- a/include/ucore/iomux.h +++ b/include/ucore/iomux.h @@ -43,6 +43,9 @@ struct IOMuxFD { }; /** Creates a new IOMux. + * + * @param type the underlying implementation to use @see IOMUX_TYPE + * @return Newly allocated IOMux. NULL if memory allocation fails. */ struct IOMux *iomux_create(enum IOMUX_TYPE type); @@ -58,19 +61,27 @@ struct IOMux *iomux_create_ex(enum IOMUX_TYPE type, struct UCoreClock *uclock); void iomux_delete(struct IOMux *mux); /** Runs the event loop of the mux - * returns if the number of file descriptors and timers are 0 or + * + * @return if the number of file descriptors and timers are 0 or * an error occurs */ int iomux_run(struct IOMux *mux); -/* Adds a file descriptor to the watch set, - * returns 0 on success, an errno value on error */ +/* Adds a file descriptor to the watch set. + * The file descriptor integer value must reside in only + * one struct IOMuxFD. Adding e.g. the same file descriptor + * in 2 different struct IOMuxFD, one for read events and one for + * write events is not supported. + * + * @return 0 on success, an errno value on error + */ int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd); /** Removes the file descriptor*/ int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd); /** Updates the events to watch for in fd->what - * returns 0 on success, an errno value on error */ + * @return 0 on success, an errno value on error + */ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd); @@ -100,7 +111,7 @@ int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd); iomux_update_events((mux), (fd));\ }) -/** Returns a UCTimer instance tied to this mux. +/** @return a UCTimer instance tied to this mux. * Used to schedule timers within this mux. */ struct UCTimers *iomux_get_timers(struct IOMux *mux); From bc65b3c421f9843fe9abec830b18ee46ca8aa74b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 2 Jul 2013 21:22:03 +0200 Subject: [PATCH 09/45] Check for backtrace_fd returning NULL --- src/backtrace.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/backtrace.c b/src/backtrace.c index 58e1fb2..69885b5 100644 --- a/src/backtrace.c +++ b/src/backtrace.c @@ -35,16 +35,18 @@ void uc_backtrace_buf(char *buf, size_t len) buf[0] = 0; lines = backtrace_symbols(buffer, ptrs); - for (i = 1; i < ptrs; i++) { + if (lines != NULL) { + for (i = 1; i < ptrs; i++) { - int rc = snprintf(buf, remaining, "%s\n", lines[i]); - - if (rc <= 0 || (size_t)rc >= remaining) { - break; + int rc = snprintf(buf, remaining, "%s\n", lines[i]); + + if (rc <= 0 || (size_t)rc >= remaining) { + break; + } + + remaining -= rc; + buf += rc; } - - remaining -= rc; - buf += rc; } free(lines); From 65c32810cb7f46b63b0bfbc7ad38257f399e3360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Tue, 2 Jul 2013 21:22:38 +0200 Subject: [PATCH 10/45] Add test for uc_mbuf-copy_data --- include/ucore/mbuf.h | 5 +---- src/mbuf.c | 22 +++++++++++++++++++++- test/test_mbuf.c | 25 +++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 5 deletions(-) diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h index ebfc8aa..406f951 100644 --- a/include/ucore/mbuf.h +++ b/include/ucore/mbuf.h @@ -43,7 +43,7 @@ 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); +struct MBuf *uc_mbuf_copy_data(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); @@ -70,9 +70,6 @@ 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 index 80a551e..97c1c6e 100644 --- a/src/mbuf.c +++ b/src/mbuf.c @@ -5,6 +5,7 @@ uint8_t *uc_mbuf_put(struct MBuf *mbuf, uint32_t size) { uint8_t *data = mbuf->tail; + if (uc_mbuf_tailroom(mbuf) < size) { return NULL; } @@ -28,6 +29,7 @@ uint8_t *uc_mbuf_push(struct MBuf *mbuf, uint32_t size) uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t size) { uint8_t *data = mbuf->head; + if (uc_mbuf_len(mbuf) < size) { return NULL; } @@ -37,7 +39,6 @@ uint8_t *uc_mbuf_pull(struct MBuf *mbuf, uint32_t 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; @@ -97,5 +98,24 @@ void uc_mbuf_zero(struct MBuf *mbuf) memset(mbuf->bufstart, 0, mbuf->allocated); } +struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf) +{ + uint32_t len; + struct MBuf *copy; + uint8_t *data; + + len = uc_mbuf_len(mbuf); + + copy = uc_mbuf_new_hr(len, uc_mbuf_headroom(mbuf)); + if (copy == NULL) { + return NULL; + } + + data = uc_mbuf_put(copy, len); + memcpy(data, mbuf->head, len); + + return copy; +} + #undef UC_INLINE diff --git a/test/test_mbuf.c b/test/test_mbuf.c index b465110..98b5bdd 100644 --- a/test/test_mbuf.c +++ b/test/test_mbuf.c @@ -174,6 +174,30 @@ START_TEST (test_mbuf_pull_fail) END_TEST +START_TEST (test_mbuf_copy) + struct MBuf *mbuf; + uint8_t *data1; + struct MBuf *copy; + + mbuf = uc_mbuf_new_inline_hr(10,5); + fail_if(mbuf == NULL); + + data1 = uc_mbuf_put(mbuf, 10); + fail_if(data1 == NULL); + + strcpy((char*)data1, "123456789"); + + copy = uc_mbuf_copy_data(mbuf); + fail_if(copy == NULL); + fail_if(uc_mbuf_len(copy) != 10); + fail_if(uc_mbuf_headroom(copy) != 5); + fail_if(memcmp(mbuf->head, copy->head, 10) != 0); + + uc_mbuf_free(mbuf); + uc_mbuf_free(copy); + +END_TEST + Suite *mbuf_suite(void) @@ -189,6 +213,7 @@ Suite *mbuf_suite(void) tcase_add_test(tc, test_mbuf_push_fail); tcase_add_test(tc, test_mbuf_pull); tcase_add_test(tc, test_mbuf_pull_fail); + tcase_add_test(tc, test_mbuf_copy); suite_add_tcase(s, tc); From 4304e013432eff6b643bb61299356a225c834410 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jul 2013 20:45:39 +0200 Subject: [PATCH 11/45] Add --coverage option to SConstruct file to build with gcov coverage support --- SConstruct | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/SConstruct b/SConstruct index d32cd4d..7b7f1c4 100644 --- a/SConstruct +++ b/SConstruct @@ -36,6 +36,12 @@ AddOption('--test_xml', help='Create a result.xml when running the testsuite' ) +AddOption('--coverage', + dest='coverage', + action='store_true', + help='Build with coverage (gcov) support' +) + AddOption('--stack-protection', dest = 'stack_protection', action='store_true', @@ -85,6 +91,9 @@ if GetOption('stack_protection'): env.Append(CFLAGS = ['-fstack-protector', '--param=ssp-buffer-size=4']) env.Append(CPPDEFINES = ['_FORTIFY_SOURCE=2']) +if GetOption('coverage'): + env.Append(CFLAGS = ['--coverage']) + env.Append(LINKFLAGS = ['--coverage']) #put all .sconsign files in one place env.SConsignFile() From c68ba458464f16334c033438411cfae0464f09b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 6 Jul 2013 20:47:37 +0200 Subject: [PATCH 12/45] Build doxygen docs from include/ dir instead of src/ --- Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doxyfile b/Doxyfile index dab44b8..2f3d864 100644 --- a/Doxyfile +++ b/Doxyfile @@ -655,7 +655,7 @@ WARN_LOGFILE = # directories like "/usr/src/myproject". Separate the files or directories # with spaces. -INPUT = src +INPUT = include # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is From 8200aaab217cb2893ffd1cfab3a9c67807a25835 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 6 Jul 2013 21:15:51 +0200 Subject: [PATCH 13/45] Add a test case for reading /dev/null --- test/test_read_file.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_read_file.c b/test/test_read_file.c index 0bb4990..0f93205 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -91,6 +91,17 @@ START_TEST (test_read_file_boundary) free(content); END_TEST +START_TEST (test_read_file_devnull) + char *content; + size_t len = 123; + + content = uc_read_file("/dev/null", &len, 1024); + fail_if(content == NULL); + fail_if(len != 0); + free(content); + +END_TEST + Suite *read_file_suite(void) { Suite *s = suite_create("read_file"); @@ -99,6 +110,8 @@ Suite *read_file_suite(void) tcase_add_test(tc, test_read_file_simple); tcase_add_test(tc, test_read_file_greater_than_max); tcase_add_test(tc, test_read_file_boundary); + tcase_add_test(tc, test_read_file_devnull); + suite_add_tcase(s, tc); From 42155cae39f5e127e998499c4b29bf739086fa50 Mon Sep 17 00:00:00 2001 From: root Date: Sat, 6 Jul 2013 22:18:09 +0200 Subject: [PATCH 14/45] Add another test for mroe coverage --- test/test_read_file.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/test/test_read_file.c b/test/test_read_file.c index 0f93205..90e2ff8 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -102,6 +102,28 @@ START_TEST (test_read_file_devnull) END_TEST +START_TEST (test_read_file_too_big) + char *content; + const char *filename = "test_read_file_simple"; + size_t len; + ssize_t rc; + + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); + fail_if(fd == -1); + + rc = write(fd, "hello", 5); + fail_if(rc != 5, "rc was %ld", (long)rc); + + close(fd); + + content = uc_read_file(filename, &len, 4); + + fail_if(errno != EMSGSIZE); + fail_if(content != NULL); + + unlink(filename); +END_TEST + Suite *read_file_suite(void) { Suite *s = suite_create("read_file"); @@ -111,6 +133,7 @@ Suite *read_file_suite(void) tcase_add_test(tc, test_read_file_greater_than_max); tcase_add_test(tc, test_read_file_boundary); tcase_add_test(tc, test_read_file_devnull); + tcase_add_test(tc, test_read_file_too_big); suite_add_tcase(s, tc); From 24bf90b7e450ab6b256209177463980399af6c7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sat, 6 Jul 2013 22:25:06 +0200 Subject: [PATCH 15/45] Another test for more coverage --- test/test_read_file.c | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/test/test_read_file.c b/test/test_read_file.c index 90e2ff8..5bef1f4 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -104,7 +104,7 @@ END_TEST START_TEST (test_read_file_too_big) char *content; - const char *filename = "test_read_file_simple"; + const char *filename = "test_read_file_too_big"; size_t len; ssize_t rc; @@ -124,6 +124,32 @@ START_TEST (test_read_file_too_big) unlink(filename); END_TEST +START_TEST (test_read_file_big) + char *content; + const char *filename = "test_read_file_big"; + char buf[4096 * 16]; + size_t len; + ssize_t rc; + + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); + fail_if(fd == -1); + memset(buf, 'a', sizeof buf); + + rc = write(fd, buf, sizeof buf); + fail_if(rc != sizeof buf, "rc was %ld", (long)rc); + + close(fd); + + content = uc_read_file(filename, &len, 4096*16); + fail_if(content == NULL); + fail_if(len != sizeof buf); + fail_if(memcmp(content, buf, sizeof buf) != 0); + + free(content); + + unlink(filename); +END_TEST + Suite *read_file_suite(void) { Suite *s = suite_create("read_file"); @@ -134,6 +160,7 @@ Suite *read_file_suite(void) tcase_add_test(tc, test_read_file_boundary); tcase_add_test(tc, test_read_file_devnull); tcase_add_test(tc, test_read_file_too_big); + tcase_add_test(tc, test_read_file_big); suite_add_tcase(s, tc); From 16516d94b614b496ef32346fc8770ccc0fc02afc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 03:17:34 +0200 Subject: [PATCH 16/45] Add test for human_bytesz --- test/test_human_bytesz.c | 84 ++++++++++++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- 2 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 test/test_human_bytesz.c diff --git a/test/test_human_bytesz.c b/test/test_human_bytesz.c new file mode 100644 index 0000000..86da611 --- /dev/null +++ b/test/test_human_bytesz.c @@ -0,0 +1,84 @@ +#include +#include + + +START_TEST (test_human_bytesz_bytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(999, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "999 b"); +END_TEST + +START_TEST (test_human_bytesz_bytes_0) + char result[128]; + char *rc; + + rc = uc_human_bytesz(0, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "0 b"); +END_TEST + +START_TEST (test_human_bytesz_kilobytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(64000, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "64.00 kB"); +END_TEST + +START_TEST (test_human_bytesz_megabytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(6409000, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "6.41 MB"); +END_TEST + +START_TEST (test_human_bytesz_gigabytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(126999400000, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "127.00 GB"); +END_TEST + +START_TEST (test_human_bytesz_terrabytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(12453400030000, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "12.45 TB"); +END_TEST + +START_TEST (test_human_bytesz_petabytes) + char result[128]; + char *rc; + + rc = uc_human_bytesz(~0LL, result, sizeof result); + fail_if(rc == NULL); + ck_assert_str_eq(result, "18446.74 PB"); +END_TEST + + +Suite *human_bytesz_suite(void) +{ + Suite *s = suite_create("human_bytesz"); + TCase *tc = tcase_create("human_bytesz tests"); + tcase_add_test(tc, test_human_bytesz_bytes); + tcase_add_test(tc, test_human_bytesz_bytes_0); + tcase_add_test(tc, test_human_bytesz_kilobytes); + tcase_add_test(tc, test_human_bytesz_megabytes); + tcase_add_test(tc, test_human_bytesz_terrabytes); + tcase_add_test(tc, test_human_bytesz_petabytes); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index d85129a..37483aa 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 *human_bytesz_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, + human_bytesz_suite }; int From f177d2149ef1d76d5f3e9cf7ee037d7e5a9937f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 03:22:00 +0200 Subject: [PATCH 17/45] Missed a test case --- test/test_human_bytesz.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_human_bytesz.c b/test/test_human_bytesz.c index 86da611..c3819d9 100644 --- a/test/test_human_bytesz.c +++ b/test/test_human_bytesz.c @@ -74,6 +74,7 @@ Suite *human_bytesz_suite(void) tcase_add_test(tc, test_human_bytesz_bytes_0); tcase_add_test(tc, test_human_bytesz_kilobytes); tcase_add_test(tc, test_human_bytesz_megabytes); + tcase_add_test(tc, test_human_bytesz_gigabytes); tcase_add_test(tc, test_human_bytesz_terrabytes); tcase_add_test(tc, test_human_bytesz_petabytes); From 8c42c26e6ab51ddcc9b0c5a19730397093c31750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:03:33 +0200 Subject: [PATCH 18/45] Another mbuf test case for a static buffer --- test/test_mbuf.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/test/test_mbuf.c b/test/test_mbuf.c index 98b5bdd..87951d1 100644 --- a/test/test_mbuf.c +++ b/test/test_mbuf.c @@ -198,6 +198,29 @@ START_TEST (test_mbuf_copy) END_TEST +START_TEST (test_mbuf_static) + + uint8_t data[1024]; + struct MBuf mbuf; + + uc_mbuf_init(&mbuf, data, 1000, 24, UC_MBUF_FL_STATIC); + + fail_if(uc_mbuf_len(&mbuf) != 0); + fail_if(uc_mbuf_headroom(&mbuf) != 24); + fail_if(uc_mbuf_tailroom(&mbuf) != 1000); + 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); + fail_if(mbuf.head != &data[24]); + + uc_mbuf_free(&mbuf); + +END_TEST + Suite *mbuf_suite(void) @@ -214,6 +237,7 @@ Suite *mbuf_suite(void) tcase_add_test(tc, test_mbuf_pull); tcase_add_test(tc, test_mbuf_pull_fail); tcase_add_test(tc, test_mbuf_copy); + tcase_add_test(tc, test_mbuf_static); suite_add_tcase(s, tc); From 6f209912ae1f77b5ead4e4d64a28ce81711aa1b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:22:21 +0200 Subject: [PATCH 19/45] Test for mbuf_zero, for more coverage --- test/test_mbuf.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test/test_mbuf.c b/test/test_mbuf.c index 87951d1..dfe8577 100644 --- a/test/test_mbuf.c +++ b/test/test_mbuf.c @@ -198,6 +198,25 @@ START_TEST (test_mbuf_copy) END_TEST +START_TEST (test_mbuf_zero) + struct MBuf *mbuf; + uint8_t *data1; + + mbuf = uc_mbuf_new_inline(10); + fail_if(mbuf == NULL); + + data1 = uc_mbuf_put(mbuf, 10); + fail_if(data1 == NULL); + + strcpy((char*)data1, "123456789"); + uc_mbuf_zero(mbuf); + + fail_if(memcmp(mbuf->head, "\0\0\0\0\0\0\0\0\0\0", 10) != 0); + + uc_mbuf_free(mbuf); + +END_TEST + START_TEST (test_mbuf_static) uint8_t data[1024]; @@ -237,6 +256,7 @@ Suite *mbuf_suite(void) tcase_add_test(tc, test_mbuf_pull); tcase_add_test(tc, test_mbuf_pull_fail); tcase_add_test(tc, test_mbuf_copy); + tcase_add_test(tc, test_mbuf_zero); tcase_add_test(tc, test_mbuf_static); suite_add_tcase(s, tc); From 7706c7404d611688c369952e110ffdfae9cf1553 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:22:49 +0200 Subject: [PATCH 20/45] Ad dscript to gerneate html coverage report using the lcov tool --- .gitignore | 1 + gencoverage.sh | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100755 gencoverage.sh diff --git a/.gitignore b/.gitignore index fe17ed5..d001440 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ build/ tags doc/ log_subdir/ +coverage/ diff --git a/gencoverage.sh b/gencoverage.sh new file mode 100755 index 0000000..2c8a12a --- /dev/null +++ b/gencoverage.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +scons --coverage test +mkdir -p coverage && cd coverage +lcov -c -d ../build/src/ -o lcov.trace +genhtml lcov.trace From 53dd99d32b00de83d62bc107b89b230e3be77ad2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:31:47 +0200 Subject: [PATCH 21/45] Add another timer test case for more coverage --- test/test_timers.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/test/test_timers.c b/test/test_timers.c index a563cd4..d0e81aa 100644 --- a/test/test_timers.c +++ b/test/test_timers.c @@ -160,6 +160,47 @@ START_TEST (test_timers_remove_from_callback) END_TEST +START_TEST (test_timers_add_remove) + struct UCoreSettableClock clk; + struct TimerTest tt; + struct UCTimers timers; + struct UCTimer timer1; + struct UCTimer timer2; + struct UCTimer timer3; + struct UCTimer timer4; + struct timeval first; + + common_init(&clk, &tt, &timers, &timer1); + memset(&timer2, 0, sizeof timer2); + memset(&timer3, 0, sizeof timer2); + memset(&timer4, 0, sizeof timer2); + + timer1.callback = timer_test_cb_add; + timer2.callback = timer_test_cb_add; + timer3.callback = timer_test_cb_add; + timer4.callback = timer_test_cb_add; + + uc_timers_add(&timers, &timer1, 10, 0); + uc_timers_add(&timers, &timer2, 5 , 0); + uc_timers_add(&timers, &timer3, 15, 1); + uc_timers_add(&timers, &timer4, 15, 1); + + fail_if(uc_timers_first(&timers, &first) != 0); + fail_if(first.tv_sec != TEST_TIMER_START + 5); + fail_if(first.tv_usec != 0); + + fail_if(uc_timers_count(&timers) != 4); + + uc_timers_remove(&timers, &timer1); + uc_timers_remove(&timers, &timer2); + uc_timers_remove(&timers, &timer3); + uc_timers_remove(&timers, &timer4); + + fail_if(uc_timers_count(&timers) != 0); + fail_if(uc_timers_first(&timers, &first) == 0); + +END_TEST + Suite *timers_suite(void) { @@ -168,6 +209,7 @@ Suite *timers_suite(void) tcase_add_test(tc, test_timers_simple); tcase_add_test(tc, test_timers_add_from_callback); tcase_add_test(tc, test_timers_remove_from_callback); + tcase_add_test(tc, test_timers_add_remove); suite_add_tcase(s, tc); From ec9a53b3a6beff98803f721b5eb76c0f58f91edb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:35:23 +0200 Subject: [PATCH 22/45] Free the allocated bitvec in test --- test/test_bitvec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/test_bitvec.c b/test/test_bitvec.c index 629c241..3805ebb 100644 --- a/test/test_bitvec.c +++ b/test/test_bitvec.c @@ -66,6 +66,8 @@ START_TEST (test_bitvec_setall_clearall) for (i = 0; i < sizeof(unsigned long) * 8; i++) fail_if(uc_bv_get_bit(v, i) != 0 , "bit %zu is not 0", i); + uc_bv_free(v); + END_TEST Suite *bitvec_suite(void) From 648f963763d70fe68e4b72a25c9bb8c2d647d66b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:42:19 +0200 Subject: [PATCH 23/45] make output filename libucore.info --- gencoverage.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/gencoverage.sh b/gencoverage.sh index 2c8a12a..f98f0b7 100755 --- a/gencoverage.sh +++ b/gencoverage.sh @@ -2,5 +2,5 @@ scons --coverage test mkdir -p coverage && cd coverage -lcov -c -d ../build/src/ -o lcov.trace -genhtml lcov.trace +lcov -c -d ../build/src/ -o libucore.info +genhtml libucore.info From 3c5688ad54100c4314631b6895c360c6e2cb5825 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 19:44:51 +0200 Subject: [PATCH 24/45] Add testcase for lowercase hex --- test/test_hex.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/test_hex.c b/test/test_hex.c index 87ca984..39250c9 100644 --- a/test/test_hex.c +++ b/test/test_hex.c @@ -164,6 +164,18 @@ START_TEST (test_uc_hex_encode_delim_zero_len) END_TEST +START_TEST (test_uc_hex_decode_lowercase) + char hex[] = "1f"; + uint8_t binary[2] = {0x11,0x22}; + uint8_t *res; + + res = uc_hex_decode(hex, 2, binary); + + fail_if(binary[0] != 0x1f); + fail_if(binary[1] != 0x22); + fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res); + +END_TEST Suite *hex_suite(void) { Suite *s = suite_create("hex"); @@ -185,6 +197,8 @@ Suite *hex_suite(void) tcase_add_test(tc, test_uc_hex_decode_invalid); tcase_add_test(tc, test_uc_hex_decode_empty_string); + tcase_add_test(tc, test_uc_hex_decode_lowercase); + suite_add_tcase(s, tc); From 2bd5f9f5b9b7d63537c36f55d44250a56309e806 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 22:10:41 +0200 Subject: [PATCH 25/45] Add DBuf , buffer API --- include/ucore/dbuf.h | 121 +++++++++++++++++++++++++++++++++++++++++++ src/dbuf.c | 111 +++++++++++++++++++++++++++++++++++++++ test/test_dbuf.c | 84 ++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- 4 files changed, 319 insertions(+), 1 deletion(-) create mode 100644 include/ucore/dbuf.h create mode 100644 src/dbuf.c create mode 100644 test/test_dbuf.c diff --git a/include/ucore/dbuf.h b/include/ucore/dbuf.h new file mode 100644 index 0000000..4aa71ab --- /dev/null +++ b/include/ucore/dbuf.h @@ -0,0 +1,121 @@ +#ifndef dbuf_H_ +#define dbuf_H_ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * dbuf is a generic buffer that will grow automatically. + * call buf_ensure() to reserve space, and don't write more data + * than you told buf_ensure() to reserve. + * + * You write data to buf->end + * When finished writing data + * you call dbuf_added/( with the no. of bytes you've added. + * + * You read data from buf->start, the buffer has dbuf_len() bytes of data + * When you've read and processed the data, call dbuf_take() + * to indicate you're done with the data. + * + * typically(but add error checking) + * DBuf buf; + * dbuf_init(&buf,4096); + * for(;;) { + * dbuf_ensure(buf,4096); + * size_t len = fread(buf,4096,1,f); + * dbuf_added(&buf,len); + * char *end; + * while((end = memchr(buf.start,'\n',dbuf_len(&dbuf))) != NULL) { //look for a newline + * ++end; + * int linelen = end - buf.start; + * process_line(buf.start,linelen); + * dbuf_take(&dbuf,linelen); + * } + * } + */ +typedef struct DBuf DBuf; +struct DBuf { + /** Start of user data */ + unsigned char *start; + /** end of user data */ + unsigned char *end; + /** Start of underlying buffer. Internal use.*/ + unsigned char *bufstart; + /** end of underlying buffer. Internal use.*/ + unsigned char *bufend; +}; +/** free the internals of a DBuf, does not free buf itself. + * Does nothing if buf == NULL + * @param buf buffer to free + */ +void uc_dbuf_free(DBuf *buf); + +/** Initialixe a dbuf. +* +* @param buf buffer to initialize +* @return 0 on success +*/ +int uc_dbuf_init(DBuf *buf,size_t initlen); + +/** Get length of user data in the buffer + * + * @param buf buffer to get length of + * @return length of the user data + */ +size_t uc_dbuf_len(DBuf *buf); + +/** Allocated size of the buffer + * + * @buf buffer to get allocated length of + * @return allocated length of the underlying buffer + */ +size_t uc_dbuf_buflen(DBuf *buf); + +/** Get remaining space in the buffer + * @param buf buffer + * @return remaining space (after buf->end) in the buffer + */ +size_t uc_dbuf_remaining(DBuf *buf); + +/** ensure the buffer can hold 'capacity' no of bytes, + * + * @param buffer + * @param capacity ensure there is room for capacity bytes after buf->end + * @retun 0 on success + */ +int uc_dbuf_ensure(DBuf *buf,size_t capacity); + +/** trim the buffer to hold no more space than needed. + * @param buf buffer to trum + */ +void uc_dbuf_trim(DBuf *buf); + +/** Indicate you've taken 'len' bytes out of the buffer. + * Advances buf->start by len bytes + * This may re-set buf->start and buf->end if e.g. all data + * is taken out of the buffer. + * + * @param buf buffer + * @param len length that was taken out of the buffer + * @return 0 on success. Non-zero if @len is larger than the bufer capacity + */ +int uc_dbuf_take(DBuf *buf,size_t len); + +/** indicate you've added 'len' bytes to the buffer + * Advances buf->end by @len bytes + * User must always make sure (e.g. by using uc_dbuf_ensure) + * that the buffer has the capacity to add @len bytes + * + * @param buf buffer + * @param len length that was added to the buffer. + */ +void uc_dbuf_added(DBuf *buf,size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/dbuf.c b/src/dbuf.c new file mode 100644 index 0000000..ff03328 --- /dev/null +++ b/src/dbuf.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include "ucore/dbuf.h" + +void +uc_dbuf_free(DBuf *buf) +{ + if(buf != NULL) + free(buf->bufstart); + +} + +int +uc_dbuf_init(DBuf *buf,size_t initlen) +{ + unsigned char *tmp = malloc(initlen); + if(tmp == NULL) + return -1; + buf->start = buf->bufstart = buf->end = tmp; + buf->bufend = tmp + initlen; + + return 0; +} + +size_t +uc_dbuf_len(DBuf *buf) +{ + return buf->end - buf->start; +} + +size_t +uc_dbuf_buflen(DBuf *buf) +{ + return buf->bufend - buf->bufstart; +} + +size_t +uc_dbuf_remaining(DBuf *buf) +{ + return buf->bufend - buf->end; +} + +int +uc_dbuf_ensure(DBuf *buf,size_t capacity) +{ + size_t sz,remaining,len; + + remaining = uc_dbuf_remaining(buf); + if(remaining >= capacity) + return 0; + len = uc_dbuf_len(buf); + sz = buf->start - buf->bufstart; + memmove(buf->bufstart,buf->start,len); + if(sz + remaining < capacity) { + size_t newlen = uc_dbuf_buflen(buf) + capacity; + void *tmp = realloc(buf->bufstart,newlen); + if(tmp == NULL) + return 1; + buf->bufstart = tmp; + buf->bufend = buf->bufstart + newlen; + + } + buf->start = buf->bufstart; + buf->end = buf->start + len; + + return 0; +} + +void +uc_dbuf_trim(DBuf *buf) +{ + size_t len = uc_dbuf_len(buf); + void *tmp; + + if(len == 0) + return; + + memmove(buf->bufstart,buf->start,len); + + tmp = realloc(buf->bufstart,len); + if(tmp != NULL) + buf->bufstart = tmp; + + buf->start = buf->bufstart; + buf->bufend = buf->end = buf->bufstart + len; +} + +int +uc_dbuf_take(DBuf *buf,size_t len) +{ + size_t buflen = uc_dbuf_len(buf); + + if(len == buflen) { + buf->start = buf->end = buf->bufstart; + } else if (len < buflen) { + buf->start = buf->start + len; + } else { + //should maybe assert. This is a serious offence + return 1; + } + + return 0; +} + +void +uc_dbuf_added(DBuf *buf,size_t len) +{ + assert(len <= uc_dbuf_remaining(buf)); + buf->end +=len; +} diff --git a/test/test_dbuf.c b/test/test_dbuf.c new file mode 100644 index 0000000..6214efa --- /dev/null +++ b/test/test_dbuf.c @@ -0,0 +1,84 @@ +#include +#include +#include + + +START_TEST (test_dbuf) + DBuf buf; + int rc; + + rc = uc_dbuf_init(&buf, 10); + + fail_if(rc != 0); + fail_if(uc_dbuf_buflen(&buf) != 10); + fail_if(uc_dbuf_remaining(&buf) != 10); + + strcpy((char *)buf.end, "12345679"); + uc_dbuf_added(&buf, 10); + fail_if(uc_dbuf_len(&buf) != 10); + fail_if(uc_dbuf_remaining(&buf) != 0); + + rc = uc_dbuf_ensure(&buf, 110); + fail_if(rc != 0); + fail_if(uc_dbuf_remaining(&buf) != 110); + fail_if(uc_dbuf_buflen(&buf) != 120); + + rc = uc_dbuf_ensure(&buf, 5); + fail_if(rc != 0); + strcpy((char *)buf.end, "ABCD"); + uc_dbuf_added(&buf, 5); + uc_dbuf_take(&buf, 10); + fail_if(uc_dbuf_remaining(&buf) != 105); + fail_if(uc_dbuf_len(&buf) != 5); + ck_assert_str_eq((char *)buf.start, "ABCD"); + + uc_dbuf_take(&buf, 5); + + fail_if(uc_dbuf_remaining(&buf) != 120); + fail_if(uc_dbuf_buflen(&buf) != 120); + fail_if(uc_dbuf_len(&buf) != 0); + + strcpy((char *)buf.end, "EFGH"); + uc_dbuf_added(&buf, 5); + uc_dbuf_trim(&buf); + fail_if(uc_dbuf_buflen(&buf) != 5); + fail_if(uc_dbuf_len(&buf) != 5); + + uc_dbuf_free(&buf); +END_TEST + +START_TEST (test_dbuf_take_fail) + DBuf buf; + int rc; + + rc = uc_dbuf_init(&buf, 10); + + fail_if(rc != 0); + fail_if(uc_dbuf_buflen(&buf) != 10); + fail_if(uc_dbuf_remaining(&buf) != 10); + + strcpy((char *)buf.end, "12345679"); + uc_dbuf_added(&buf, 10); + fail_if(uc_dbuf_len(&buf) != 10); + fail_if(uc_dbuf_remaining(&buf) != 0); + + rc = uc_dbuf_take(&buf, 11); + fail_if(rc == 0); + + uc_dbuf_free(&buf); +END_TEST + + + +Suite *dbuf_suite(void) +{ + Suite *s = suite_create("dbuf"); + TCase *tc = tcase_create("dbuf tests"); + tcase_add_test(tc, test_dbuf); + tcase_add_test(tc, test_dbuf_take_fail); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_runner.c b/test/test_runner.c index bf20b6a..2ab0db3 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -21,6 +21,7 @@ extern Suite *sat_math_suite(void); extern Suite *timers_suite(void); extern Suite *mbuf_suite(void); extern Suite *human_bytesz_suite(void); +extern Suite *dbuf_suite(void); static suite_func suites[] = { bitvec_suite, @@ -37,7 +38,8 @@ static suite_func suites[] = { sat_math_suite, timers_suite, mbuf_suite, - human_bytesz_suite + human_bytesz_suite, + dbuf_suite }; int From bc3a5ba2caa1f3062dd61138e9810ddde62d8d38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 22:11:00 +0200 Subject: [PATCH 26/45] Print out URL to local coverage test results --- gencoverage.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gencoverage.sh b/gencoverage.sh index f98f0b7..bc73696 100755 --- a/gencoverage.sh +++ b/gencoverage.sh @@ -4,3 +4,5 @@ scons --coverage test mkdir -p coverage && cd coverage lcov -c -d ../build/src/ -o libucore.info genhtml libucore.info + +echo "Test report available at file:///$(pwd)/index.html" From 1d01e6dc7ea9fddb739a876b92dc808d7db249c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 22:14:56 +0200 Subject: [PATCH 27/45] INdent properly --- src/dbuf.c | 115 ++++++++++++++++++++++++++--------------------------- 1 file changed, 57 insertions(+), 58 deletions(-) diff --git a/src/dbuf.c b/src/dbuf.c index ff03328..8cf6c80 100644 --- a/src/dbuf.c +++ b/src/dbuf.c @@ -6,106 +6,105 @@ void uc_dbuf_free(DBuf *buf) { - if(buf != NULL) - free(buf->bufstart); - + if (buf != NULL) + free(buf->bufstart); } -int -uc_dbuf_init(DBuf *buf,size_t initlen) +int +uc_dbuf_init(DBuf *buf, size_t initlen) { - unsigned char *tmp = malloc(initlen); - if(tmp == NULL) - return -1; - buf->start = buf->bufstart = buf->end = tmp; - buf->bufend = tmp + initlen; + unsigned char *tmp = malloc(initlen); + if (tmp == NULL) + return -1; + buf->start = buf->bufstart = buf->end = tmp; + buf->bufend = tmp + initlen; - return 0; + return 0; } -size_t +size_t uc_dbuf_len(DBuf *buf) { - return buf->end - buf->start; + return buf->end - buf->start; } -size_t +size_t uc_dbuf_buflen(DBuf *buf) { - return buf->bufend - buf->bufstart; + return buf->bufend - buf->bufstart; } size_t uc_dbuf_remaining(DBuf *buf) { - return buf->bufend - buf->end; + return buf->bufend - buf->end; } int -uc_dbuf_ensure(DBuf *buf,size_t capacity) +uc_dbuf_ensure(DBuf *buf, size_t capacity) { - size_t sz,remaining,len; - - remaining = uc_dbuf_remaining(buf); - if(remaining >= capacity) - return 0; - len = uc_dbuf_len(buf); - sz = buf->start - buf->bufstart; - memmove(buf->bufstart,buf->start,len); - if(sz + remaining < capacity) { - size_t newlen = uc_dbuf_buflen(buf) + capacity; - void *tmp = realloc(buf->bufstart,newlen); - if(tmp == NULL) - return 1; - buf->bufstart = tmp; - buf->bufend = buf->bufstart + newlen; + size_t sz, remaining, len; - } - buf->start = buf->bufstart; - buf->end = buf->start + len; - - return 0; + remaining = uc_dbuf_remaining(buf); + if (remaining >= capacity) + return 0; + len = uc_dbuf_len(buf); + sz = buf->start - buf->bufstart; + memmove(buf->bufstart, buf->start, len); + if (sz + remaining < capacity) { + size_t newlen = uc_dbuf_buflen(buf) + capacity; + void *tmp = realloc(buf->bufstart, newlen); + if (tmp == NULL) + return 1; + buf->bufstart = tmp; + buf->bufend = buf->bufstart + newlen; + + } + buf->start = buf->bufstart; + buf->end = buf->start + len; + + return 0; } void uc_dbuf_trim(DBuf *buf) { - size_t len = uc_dbuf_len(buf); - void *tmp; + size_t len = uc_dbuf_len(buf); + void *tmp; - if(len == 0) - return; + if (len == 0) + return; - memmove(buf->bufstart,buf->start,len); + memmove(buf->bufstart, buf->start, len); - tmp = realloc(buf->bufstart,len); - if(tmp != NULL) - buf->bufstart = tmp; + tmp = realloc(buf->bufstart, len); + if (tmp != NULL) + buf->bufstart = tmp; - buf->start = buf->bufstart; - buf->bufend = buf->end = buf->bufstart + len; + buf->start = buf->bufstart; + buf->bufend = buf->end = buf->bufstart + len; } -int -uc_dbuf_take(DBuf *buf,size_t len) +int +uc_dbuf_take(DBuf *buf, size_t len) { - size_t buflen = uc_dbuf_len(buf); + size_t buflen = uc_dbuf_len(buf); - if(len == buflen) { - buf->start = buf->end = buf->bufstart; - } else if (len < buflen) { - buf->start = buf->start + len; + if (len == buflen) { + buf->start = buf->end = buf->bufstart; + } else if (len < buflen) { + buf->start = buf->start + len; } else { //should maybe assert. This is a serious offence - return 1; + return 1; } - return 0; + return 0; } void -uc_dbuf_added(DBuf *buf,size_t len) +uc_dbuf_added(DBuf *buf, size_t len) { assert(len <= uc_dbuf_remaining(buf)); - buf->end +=len; + buf->end += len; } From e1f16b36030ddf8ffeccc602827f0f715a5439a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Sun, 7 Jul 2013 22:28:41 +0200 Subject: [PATCH 28/45] Correct spelling mistakes in comments --- include/ucore/dbuf.h | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/include/ucore/dbuf.h b/include/ucore/dbuf.h index 4aa71ab..c3c841c 100644 --- a/include/ucore/dbuf.h +++ b/include/ucore/dbuf.h @@ -20,6 +20,7 @@ extern "C" { * to indicate you're done with the data. * * typically(but add error checking) + * @code * DBuf buf; * dbuf_init(&buf,4096); * for(;;) { @@ -34,27 +35,30 @@ extern "C" { * dbuf_take(&dbuf,linelen); * } * } + * @endcode */ typedef struct DBuf DBuf; struct DBuf { /** Start of user data */ unsigned char *start; - /** end of user data */ + /** End of user data */ unsigned char *end; /** Start of underlying buffer. Internal use.*/ unsigned char *bufstart; - /** end of underlying buffer. Internal use.*/ + /** End of underlying buffer. Internal use.*/ unsigned char *bufend; }; -/** free the internals of a DBuf, does not free buf itself. +/** Free the internals of a DBuf, does not free buf itself. * Does nothing if buf == NULL + * * @param buf buffer to free */ void uc_dbuf_free(DBuf *buf); -/** Initialixe a dbuf. +/** Initialize a dbuf. * * @param buf buffer to initialize +* @param initlen inital capacity of the buffer * @return 0 on success */ int uc_dbuf_init(DBuf *buf,size_t initlen); @@ -68,12 +72,13 @@ size_t uc_dbuf_len(DBuf *buf); /** Allocated size of the buffer * - * @buf buffer to get allocated length of + * @param buf buffer to get allocated length of * @return allocated length of the underlying buffer */ size_t uc_dbuf_buflen(DBuf *buf); /** Get remaining space in the buffer + * * @param buf buffer * @return remaining space (after buf->end) in the buffer */ @@ -81,13 +86,14 @@ size_t uc_dbuf_remaining(DBuf *buf); /** ensure the buffer can hold 'capacity' no of bytes, * - * @param buffer + * @param buf buffer * @param capacity ensure there is room for capacity bytes after buf->end - * @retun 0 on success + * @return 0 on success */ int uc_dbuf_ensure(DBuf *buf,size_t capacity); -/** trim the buffer to hold no more space than needed. +/** Trim the buffer to hold no more space than needed. + * * @param buf buffer to trum */ void uc_dbuf_trim(DBuf *buf); @@ -99,12 +105,12 @@ void uc_dbuf_trim(DBuf *buf); * * @param buf buffer * @param len length that was taken out of the buffer - * @return 0 on success. Non-zero if @len is larger than the bufer capacity + * @return 0 on success. Non-zero if len is larger than the bufer capacity */ int uc_dbuf_take(DBuf *buf,size_t len); -/** indicate you've added 'len' bytes to the buffer - * Advances buf->end by @len bytes +/** Indicate you've added 'len' bytes to the buffer + * Advances buf->end by len bytes * User must always make sure (e.g. by using uc_dbuf_ensure) * that the buffer has the capacity to add @len bytes * From b475fae56b7d795e82b3d0eb28b77afbbb9d8dba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Mon, 8 Jul 2013 22:15:56 +0200 Subject: [PATCH 29/45] Add uc_set_tcp_keepalive_cfg too set keepalive options --- include/ucore/fd_utils.h | 38 +++++++++++++++++++++++++------ src/fd_utils.c | 48 +++++++++++++++++++++++++++++++++------- 2 files changed, 71 insertions(+), 15 deletions(-) diff --git a/include/ucore/fd_utils.h b/include/ucore/fd_utils.h index c2145bc..9c8d178 100644 --- a/include/ucore/fd_utils.h +++ b/include/ucore/fd_utils.h @@ -10,42 +10,66 @@ extern "C" { * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_nonblocking(int fd); +int uc_set_nonblocking(int fd); /** * set the file descriptor to blocking * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_blocking(int fd); +int uc_set_blocking(int fd); /** * set the socket file descriptor to SO_REUSEADDR * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_reuseaddr(int sockfd); +int uc_set_reuseaddr(int sockfd); /** * enable TCP keepalive on the socket * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_tcp_keepalive(int sockfd); +int uc_set_tcp_keepalive(int sockfd); + +struct UCKeepConfig { + /** The maximum number of keepalive probes TCP should + * send before dropping the connection. (TCP_KEEPCNT socket option) + */ + int keepcnt; + /** The time (in seconds) the connection needs to remain + * idle before TCP starts sending keepalive probes (TCP_KEEPIDLE socket option) + */ + int keepidle; + /** The time (in seconds) between individual keepalive probes. + * (TCP_KEEPINTVL socket option) + */ + int keepintvl; +}; + +/** Set the keepalive options on the socket +* This also enables TCP keepalive on the socket +* +* @param fd file descriptor +* @param fd file descriptor +* @return 0 on success -1 on failure +*/ +int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg); /** * Set the socket send timeout, in miliseconds * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_send_timeout(int sockfd,long timeoutms); +int uc_set_send_timeout(int sockfd,long timeoutms); /** * Set the socket receive timeout, in miliseconds * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_receive_timeout(int sockfd,long timeoutms); +int uc_set_receive_timeout(int sockfd,long timeoutms); /* * Set the IP DSCP (differnetiated services code point) header value @@ -53,7 +77,7 @@ int set_receive_timeout(int sockfd,long timeoutms); * @param fd file descriptor * @return 0 on success -1 on failure */ -int set_ip_dscp(int fd, unsigned int dscp); +int uc_set_ip_dscp(int fd, unsigned int dscp); #ifdef __cplusplus diff --git a/src/fd_utils.c b/src/fd_utils.c index 9e7d539..20c158d 100644 --- a/src/fd_utils.c +++ b/src/fd_utils.c @@ -2,11 +2,12 @@ #include #include #include +#include #include #include #include "ucore/fd_utils.h" -int set_nonblocking(int fd) +int uc_set_nonblocking(int fd) { int flags = fcntl(fd,F_GETFL,NULL); if(flags < 0 ) { @@ -15,7 +16,7 @@ int set_nonblocking(int fd) return fcntl(fd,F_SETFL,flags | O_NONBLOCK); } -int set_blocking(int fd) +int uc_set_blocking(int fd) { int flags = fcntl(fd,F_GETFL,NULL); if(flags < 0 ) { @@ -25,35 +26,66 @@ int set_blocking(int fd) return fcntl(fd,F_SETFL,flags&~O_NONBLOCK); } -int set_reuseaddr(int sockfd) +int uc_set_reuseaddr(int sockfd) { int opt = 1; return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); } -int set_tcp_keepalive(int sockfd) +int uc_set_tcp_keepalive(int sockfd) { int optval = 1; + return setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)); } +int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg) +{ + int rc; -int set_send_timeout(int sockfd,long timeoutms) + //first turn on keepalive + rc = uc_set_tcp_keepalive(sockfd); + if (rc != 0) { + return rc; + } + + //set the keepalive options + + rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepcnt, sizeof cfg->keepcnt); + if (rc != 0) { + return rc; + } + + rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepidle, sizeof cfg->keepintvl); + if (rc != 0) { + return rc; + } + + rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepintvl, sizeof cfg->keepintvl); + if (rc != 0) { + return rc; + } + + return 0; +} + + +int uc_set_send_timeout(int sockfd,long timeoutms) { struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000}; return setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &so_sndtimeo, sizeof(so_sndtimeo)); } -int set_receive_timeout(int sockfd,long timeoutms) +int uc_set_receive_timeout(int sockfd,long timeoutms) { struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000}; return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &so_sndtimeo, sizeof(so_sndtimeo)); } -int -set_ip_dscp(int fd, unsigned int dscp) { + +int uc_set_ip_dscp(int fd, unsigned int dscp) { int val; if (dscp > 63) { From b6bd7fcaa6549a7b9dac4410a2c5bc01035c2b2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jul 2013 20:27:31 +0200 Subject: [PATCH 30/45] Don't memmove the buffer content unless it's needed --- src/dbuf.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dbuf.c b/src/dbuf.c index 8cf6c80..c5cd1ce 100644 --- a/src/dbuf.c +++ b/src/dbuf.c @@ -50,7 +50,10 @@ uc_dbuf_ensure(DBuf *buf, size_t capacity) return 0; len = uc_dbuf_len(buf); sz = buf->start - buf->bufstart; - memmove(buf->bufstart, buf->start, len); + + if (buf->bufstart != buf->start) + memmove(buf->bufstart, buf->start, len); + if (sz + remaining < capacity) { size_t newlen = uc_dbuf_buflen(buf) + capacity; void *tmp = realloc(buf->bufstart, newlen); @@ -75,7 +78,8 @@ uc_dbuf_trim(DBuf *buf) if (len == 0) return; - memmove(buf->bufstart, buf->start, len); + if (buf->bufstart != buf->start) + memmove(buf->bufstart, buf->start, len); tmp = realloc(buf->bufstart, len); if (tmp != NULL) From 1281533884c9c2cc708d9de010c0c05f880f672b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jul 2013 20:36:17 +0200 Subject: [PATCH 31/45] Add test to conver memmove cases now that memmove arn't always performed --- test/test_dbuf.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/test_dbuf.c b/test/test_dbuf.c index 6214efa..fbeed99 100644 --- a/test/test_dbuf.c +++ b/test/test_dbuf.c @@ -44,6 +44,19 @@ START_TEST (test_dbuf) fail_if(uc_dbuf_buflen(&buf) != 5); fail_if(uc_dbuf_len(&buf) != 5); + uc_dbuf_take(&buf, 1); + rc = uc_dbuf_ensure(&buf, 10); + fail_if(rc != 0); + ck_assert_str_eq((char *)buf.start, "FGH"); + + uc_dbuf_take(&buf, 1); + uc_dbuf_trim(&buf); + ck_assert_str_eq((char *)buf.start, "GH"); + fail_if(uc_dbuf_buflen(&buf) != 3); + fail_if(uc_dbuf_len(&buf) != 3); + + + uc_dbuf_free(&buf); END_TEST From c7d897c0803e96daf1c6b153c97ffbb5552851a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jul 2013 20:40:46 +0200 Subject: [PATCH 32/45] Enable some asserts for impossible conditions --- src/timers.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/timers.c b/src/timers.c index b89381b..7db0cc2 100644 --- a/src/timers.c +++ b/src/timers.c @@ -19,11 +19,11 @@ static int timers_cmp(const RBNode *a_, const RBNode *b_) } else if (a->seq > b->seq) { return 1; } else { //should never happen - //assert(0); + assert(0); return 0; } } - //assert(0); + assert(0); return 0; //silence compiler } @@ -56,8 +56,10 @@ void uc_timers_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int struct timeval tmp; assert(timer->callback != NULL); - if (timer->callback == NULL) //must be set. + if (timer->callback == NULL) { //must be set. + assert(timer->callback != NULL); return; + } tmp.tv_sec = sec; tmp.tv_usec = usec; From 6e3585e77ced752036d1dd3ce2aa64a9e07eca5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jul 2013 20:42:05 +0200 Subject: [PATCH 33/45] Remove a redundant assert.. --- src/timers.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/timers.c b/src/timers.c index 7db0cc2..ed399dc 100644 --- a/src/timers.c +++ b/src/timers.c @@ -57,7 +57,6 @@ void uc_timers_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int assert(timer->callback != NULL); if (timer->callback == NULL) { //must be set. - assert(timer->callback != NULL); return; } From 7a968ee77ac501d98900acf1e13c67aedce37d2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 12 Jul 2013 21:13:22 +0200 Subject: [PATCH 34/45] Nuke the base64 code. It was wrong --- include/ucore/string.h | 4 ---- src/base64_dec.c | 52 ------------------------------------------ src/base64_enc.c | 43 ---------------------------------- test/test_runner.c | 2 +- 4 files changed, 1 insertion(+), 100 deletions(-) delete mode 100644 src/base64_dec.c delete mode 100644 src/base64_enc.c diff --git a/include/ucore/string.h b/include/ucore/string.h index 56eaf73..9b09103 100644 --- a/include/ucore/string.h +++ b/include/ucore/string.h @@ -9,10 +9,6 @@ extern "C" { #endif -size_t -uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result); -size_t -uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result); char* uc_hex_encode(const uint8_t *in, size_t len, char *out); diff --git a/src/base64_dec.c b/src/base64_dec.c deleted file mode 100644 index 5ac2e98..0000000 --- a/src/base64_dec.c +++ /dev/null @@ -1,52 +0,0 @@ -#include -#include "ucore/string.h" - -static const uint8_t basecode[128] = -{ - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, - 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, - 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff -}; - -#define deccode(c) ((c > 127) ? 0xff : basecode[(c)]) - -size_t -uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result) -{ - size_t i = 0, j = 0, pad; - uint8_t c[4]; - - while ((i + 3) < len) { - - pad = 0; - c[0] = deccode(data[i ]); pad += (c[0] == 0xff); - c[1] = deccode(data[i+1]); pad += (c[1] == 0xff); - c[2] = deccode(data[i+2]); pad += (c[2] == 0xff); - c[3] = deccode(data[i+3]); pad += (c[3] == 0xff); - switch (pad) { - case 1: - result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); - result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2); - result[j] = (c[2] & 0x03) << 6; - break; - case 2: - result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); - result[j] = (c[1] & 0x0f) << 4; - break; - default: - result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); - result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2); - result[j++] = ((c[2] & 0x03) << 6) | (c[3] & 0x3f); - } - - i += 4; - } - - return j; -} - diff --git a/src/base64_enc.c b/src/base64_enc.c deleted file mode 100644 index bc8126e..0000000 --- a/src/base64_enc.c +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include -#include "ucore/string.h" - -static const char basecode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -#define PAD '=' - -size_t -uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result) -{ - - size_t i = 0, j = 0; - size_t pad; - - - while (i < len) { - pad = 3 - (len - i); - switch(pad) { - case 2: - result[j] = basecode[data[i]>>2]; - result[j+1] = basecode[(data[i] & 0x03) << 4]; - result[j+2] = PAD; - result[j+3] = PAD; - break; - case 3: - result[j ] = basecode[data[i]>>2]; - result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)]; - result[j+2] = basecode[(data[i+1] & 0x0f) << 2]; - result[j+3] = PAD; - break; - default: - result[j ] = basecode[data[i]>>2]; - result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)]; - result[j+2] = basecode[((data[i+1] & 0x0f) << 2) | ((data[i+2] & 0xc0) >> 6)]; - result[j+3] = basecode[data[i+2] & 0x3f]; - break; - } - j += 4; - i += 3; - } - - return j; -} diff --git a/test/test_runner.c b/test/test_runner.c index 2ab0db3..d3440c5 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -39,7 +39,7 @@ static suite_func suites[] = { timers_suite, mbuf_suite, human_bytesz_suite, - dbuf_suite + dbuf_suite, }; int From ea0accdadfa7974055b0398e08f05ec427d2a0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 17 Jul 2013 19:51:09 +0200 Subject: [PATCH 35/45] Fix indent --- src/fd_utils.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fd_utils.c b/src/fd_utils.c index 20c158d..a3e65c8 100644 --- a/src/fd_utils.c +++ b/src/fd_utils.c @@ -10,9 +10,11 @@ int uc_set_nonblocking(int fd) { int flags = fcntl(fd,F_GETFL,NULL); + if(flags < 0 ) { return flags; } + return fcntl(fd,F_SETFL,flags | O_NONBLOCK); } @@ -30,7 +32,6 @@ int uc_set_reuseaddr(int sockfd) { int opt = 1; return setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&opt, sizeof(opt)); - } int uc_set_tcp_keepalive(int sockfd) @@ -51,7 +52,6 @@ int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg) } //set the keepalive options - rc = setsockopt(sockfd, SOL_TCP, TCP_KEEPCNT, &cfg->keepcnt, sizeof cfg->keepcnt); if (rc != 0) { return rc; @@ -70,7 +70,6 @@ int uc_set_tcp_keepalive_cfg(int sockfd, const struct UCKeepConfig *cfg) return 0; } - int uc_set_send_timeout(int sockfd,long timeoutms) { struct timeval so_sndtimeo = {timeoutms/1000,(timeoutms%1000)*1000}; @@ -85,15 +84,18 @@ int uc_set_receive_timeout(int sockfd,long timeoutms) return setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &so_sndtimeo, sizeof(so_sndtimeo)); } -int uc_set_ip_dscp(int fd, unsigned int dscp) { +int uc_set_ip_dscp(int fd, unsigned int dscp) +{ int val; + //only 6 bits for dscp if (dscp > 63) { errno = EINVAL; return -1; } val = dscp << 2; + return setsockopt(fd, IPPROTO_IP, IP_TOS, &val, sizeof val); } From 69b7cfc38f8deebfe84193e2790b9f537328568f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 17 Jul 2013 23:26:35 +0200 Subject: [PATCH 36/45] Remove unneeded #undef --- src/mbuf.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mbuf.c b/src/mbuf.c index 97c1c6e..6d735ab 100644 --- a/src/mbuf.c +++ b/src/mbuf.c @@ -117,5 +117,3 @@ struct MBuf *uc_mbuf_copy_data(struct MBuf *mbuf) return copy; } -#undef UC_INLINE - From 6809a68060348f114d774e4b3087846cfed7b051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 18 Jul 2013 00:04:38 +0200 Subject: [PATCH 37/45] Add tests for uc_sprintb/c/s/ll --- test/test_runner.c | 2 + test/test_sprintb.c | 97 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 test/test_sprintb.c diff --git a/test/test_runner.c b/test/test_runner.c index d3440c5..56af24a 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -22,6 +22,7 @@ extern Suite *timers_suite(void); extern Suite *mbuf_suite(void); extern Suite *human_bytesz_suite(void); extern Suite *dbuf_suite(void); +extern Suite *sprintb_suite(void); static suite_func suites[] = { bitvec_suite, @@ -40,6 +41,7 @@ static suite_func suites[] = { mbuf_suite, human_bytesz_suite, dbuf_suite, + sprintb_suite }; int diff --git a/test/test_sprintb.c b/test/test_sprintb.c new file mode 100644 index 0000000..0a1f782 --- /dev/null +++ b/test/test_sprintb.c @@ -0,0 +1,97 @@ +#include +#include +#include + +//Note these tests assume +// char 8 bit +// short 16 bit +// int 32 bit +// long long 64 bit + +START_TEST (test_sprintb) + char result[128]; + char *rc; + + rc = uc_sprintb(result, 0); + ck_assert_str_eq(rc, "00000000000000000000000000000000"); + + rc = uc_sprintb(result, UINT_MAX); + ck_assert_str_eq(rc, "11111111111111111111111111111111"); + + rc = uc_sprintb(result, 0xE0A14341); + ck_assert_str_eq(rc, "11100000101000010100001101000001"); + + rc = uc_sprintb(result, 1); + ck_assert_str_eq(rc, "00000000000000000000000000000001"); + +END_TEST + +START_TEST (test_sprintbc) + char result[128]; + char *rc; + + rc = uc_sprintbc(result, 0); + ck_assert_str_eq(rc, "00000000"); + + rc = uc_sprintbc(result, UCHAR_MAX); + ck_assert_str_eq(rc, "11111111"); + + rc = uc_sprintbc(result, 0xE1); + ck_assert_str_eq(rc, "11100001"); + + rc = uc_sprintbc(result, 1); + ck_assert_str_eq(rc, "00000001"); + +END_TEST + +START_TEST (test_sprintbs) + char result[128]; + char *rc; + + rc = uc_sprintbs(result, 0); + ck_assert_str_eq(rc, "0000000000000000"); + + rc = uc_sprintbs(result, USHRT_MAX); + ck_assert_str_eq(rc, "1111111111111111"); + + rc = uc_sprintbs(result, 0xE0A1); + ck_assert_str_eq(rc, "1110000010100001"); + + rc = uc_sprintbs(result, 1); + ck_assert_str_eq(rc, "0000000000000001"); + +END_TEST + +START_TEST (test_sprintbll) + char result[128]; + char *rc; + + rc = uc_sprintbll(result, 0); + ck_assert_str_eq(rc, "0000000000000000000000000000000000000000000000000000000000000000"); + + rc = uc_sprintbll(result, ULLONG_MAX); + ck_assert_str_eq(rc, "1111111111111111111111111111111111111111111111111111111111111111"); + + rc = uc_sprintbll(result, 0xE0A14341E0A14341ULL); + ck_assert_str_eq(rc, "1110000010100001010000110100000111100000101000010100001101000001"); + + rc = uc_sprintbll(result, 1); + ck_assert_str_eq(rc, "0000000000000000000000000000000000000000000000000000000000000001"); + +END_TEST + +Suite *sprintb_suite(void) +{ + Suite *s = suite_create("sprintb"); + TCase *tc = tcase_create("sprintb tests"); + + tcase_add_test(tc, test_sprintb); + tcase_add_test(tc, test_sprintbc); + tcase_add_test(tc, test_sprintbs); + tcase_add_test(tc, test_sprintbll); + + suite_add_tcase(s, tc); + + return s; +} + From 679b4b12e50e6463c3b3664b84381e0ec13297b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 19 Jul 2013 20:53:36 +0200 Subject: [PATCH 38/45] Fix UC_ATOMIC_ADD --- include/ucore/atomic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ucore/atomic.h b/include/ucore/atomic.h index 5311352..a3b4a67 100644 --- a/include/ucore/atomic.h +++ b/include/ucore/atomic.h @@ -30,7 +30,7 @@ * Atomically increment *ptr * @return *ptr before the increment */ -#define UC_ATOMIC_INC(ptr) UC_ATOMIC_SUB((ptr), 1) +#define UC_ATOMIC_INC(ptr) UC_ATOMIC_ADD((ptr), 1) /** From 13108f1f4837d89ca0c70f07b78ae38a1545f226 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 31 Jul 2013 03:37:50 +0200 Subject: [PATCH 39/45] Add doxygen groups --- include/ucore/clock.h | 6 +++++- include/ucore/iomux.h | 32 +++++++++++++++++++++++++++++--- include/ucore/saturating_math.h | 9 ++++++--- include/ucore/timers.h | 6 ++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/include/ucore/clock.h b/include/ucore/clock.h index b64c4a9..7014c63 100644 --- a/include/ucore/clock.h +++ b/include/ucore/clock.h @@ -3,7 +3,10 @@ #include #include - +/** @addtogroup Timers + * @{ + * Clock abstractions + */ #ifdef __cplusplus extern "C" { #endif @@ -117,5 +120,6 @@ void uc_settable_clock_set(struct UCoreSettableClock *uclock, } #endif +/** @} (addtogroup) */ #endif diff --git a/include/ucore/iomux.h b/include/ucore/iomux.h index 20a64cb..78e4ccd 100644 --- a/include/ucore/iomux.h +++ b/include/ucore/iomux.h @@ -2,7 +2,18 @@ #define IO_MUX_H_ #include "timers.h" - +/** @addtogroup IOMux + * @{ + * The IOMux is an I/O multiplexer, implementing a main eventloop. + * The event loop can be used to register callbacks for activity on + * file descriptors such as sockets and pips, and for timers. + * + * The IOMux is backed either by the select() system call, or the epoll + * facility on Linux. Several IOMuxes can run in different threads concurrently, + * but note that the IOMux itself is not thread safe so operations in one thread + * cannot work on an IOMux running in another thread. + * + * */ #ifdef __cplusplus extern "C" { #endif @@ -22,9 +33,20 @@ enum IOMUX_TYPE { IOMUX_TYPE_EPOLL }; -/** Opaque struct */ +/** The IOMux used to issue mux operations. This is to be treated as an opaque + * handle. Use iomux_create() or iomux_create_ex() to create an IOMux, register + * callbakcs, and call iomux_run() to process the events + */ struct IOMux; + struct IOMuxFD; + +/** Callback function used in struct IOMuxFD + * @param mux the mux that issued the callback. + * @param fd the file desciptor structure. + * @param event A bitmask of the MUX_EV_XX values. Both a read and a write event + * might be signalled in the same callback + */ typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event); /** Represents a watched file descriptor */ @@ -76,7 +98,10 @@ int iomux_run(struct IOMux *mux); */ int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd); -/** Removes the file descriptor*/ +/** Removes the file descriptor + * + * @return 0 on success, an errno value on error + */ int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd); /** Updates the events to watch for in fd->what @@ -120,5 +145,6 @@ struct UCTimers *iomux_get_timers(struct IOMux *mux); } #endif +/** @} (addtogroup)*/ #endif diff --git a/include/ucore/saturating_math.h b/include/ucore/saturating_math.h index f870222..e10539d 100644 --- a/include/ucore/saturating_math.h +++ b/include/ucore/saturating_math.h @@ -1,8 +1,11 @@ #include -/** Implementation of saturated operation on uintaa_t. - * Opaerations are clamped betweehn 0 and UINTaa_MAa instead of - * wrapping around*/ +/** Implementation of saturated operation on uintxx_t. + * + * Operations are clamped between 0 and UINTxx_MAX instead of + * wrapping around. + * + * multiplication, subtraction and addition operations are provided.*/ #define UC_SAT_ADD(a, b, type, max_val)\ ((type)((a) + (b)) >= (a) ? (a) + (b) : (max_val)) diff --git a/include/ucore/timers.h b/include/ucore/timers.h index f4769e3..6aa34b5 100644 --- a/include/ucore/timers.h +++ b/include/ucore/timers.h @@ -6,6 +6,11 @@ #include #include "rbtree.h" +/** @addtogroup Timers + * @{ + * Timer management for managing timeouts + */ + #ifdef __cplusplus extern "C" { #endif @@ -147,4 +152,5 @@ int uc_timers_run(struct UCTimers *timers); } #endif +/** @{ (addtogroup) */ #endif From 110c843d9dd1d47a37f5f041c9ae048db76b2cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 28 Aug 2013 23:25:02 +0200 Subject: [PATCH 40/45] Add supervisor --- include/ucore/supervisor.h | 22 +++++ src/supervisor.c | 194 +++++++++++++++++++++++++++++++++++++ 2 files changed, 216 insertions(+) create mode 100644 include/ucore/supervisor.h create mode 100644 src/supervisor.c diff --git a/include/ucore/supervisor.h b/include/ucore/supervisor.h new file mode 100644 index 0000000..b33aa2b --- /dev/null +++ b/include/ucore/supervisor.h @@ -0,0 +1,22 @@ +#ifndef UCORE_SUPERVISOR_H_ +#define UCORE_SUPERVISOR_H_ + +/** Supervises this process - restart if it dies. + * + * The program should call supervise() at a pristine state (all relevant file descriptors closed, etc). + * supervise() will return 0 if all is ok, and the program can continue.(returning != 0 means + * the supervisor couldn't start, and the calling process must exit) + * + * This will run the actual process as a child process. If that child process dies by any means, + * supervise will create another child process, where supervise() returns 0 again. + * + * To kill the supervisor process and the supervised process, send SIGERM/SIGHUP/SIGINT to the + * parent supervisor process. + * Sending SIGUSR1 to the parent supervisor process will terminate the current child process and + * restart it. + * + * The supervised child process must exit if it recieves a SIGTERM + * @return 0 on success, non-zero on failure (e.g. fork() fails)*/ +int uc_supervise(void); + +#endif diff --git a/src/supervisor.c b/src/supervisor.c new file mode 100644 index 0000000..c59bc91 --- /dev/null +++ b/src/supervisor.c @@ -0,0 +1,194 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#define CLEAN_EXIT 11 +#define BAD_EXIT 22 +#define RESTART 33 + +//seconds to wait before restarting the process +#define RESTART_GRACE 1 + +static volatile sig_atomic_t restart_flag = 0; +static volatile sig_atomic_t exit_flag = 0; + +static void restart_handler(int sig) +{ + (void)sig; + restart_flag = 1; +} + +static void exit_handler(int sig) +{ + (void)sig; + exit_flag = 1; +} + +static void kill_supervised_process(pid_t pid) +{ + kill(pid, SIGTERM); + /* Todo.. verify we killed it, otherwise take more + * desperate measures*/ +} + +static int watch(pid_t pid) +{ + int status; + pid_t rc; + +restart: + rc = waitpid(pid, &status, 0); + if (rc == -1 && errno == EINTR) { + if (restart_flag) { + restart_flag = 0; + kill_supervised_process(pid); + /* next waitpid should notify us of the death and + * we'll restart the process */ + goto restart; + } else if (exit_flag) { + exit_flag = 0; + return CLEAN_EXIT; + } + + goto restart; + + } else if (rc == -1) { + return BAD_EXIT; + } + + if (WIFSIGNALED(status)) { + syslog(LOG_ERR, "supervised process(pid %ld) exited cause of signal %d, status = 0x%X", (long)pid, WTERMSIG(status), status); + return RESTART; + } else if (WIFEXITED(status)) { + syslog(LOG_ERR, "supervised process(pid %ld) exited with code %d, status = 0x%X", (long)pid, WTERMSIG(status), status); + return RESTART; + } + + /* Ok, can we ever get here ? */ + + syslog(LOG_ERR, "waitpid of supervised process(pid %ld) status = 0x%X", (long)pid, status); + if (kill(pid, 0) == 0) { + syslog(LOG_ERR, "supervised process(pid %ld) seems to still be alive, not restarting", (long)pid); + goto restart; + } + + return RESTART; +} + +static struct sigaction orig_usr1_sa; +static struct sigaction orig_term_sa; +static struct sigaction orig_hup_sa; +static struct sigaction orig_int_sa; + +static void restore_signal_handlers(void) +{ + sigaction(SIGUSR1, &orig_usr1_sa, NULL); + sigaction(SIGTERM, &orig_term_sa, NULL); + sigaction(SIGHUP, &orig_hup_sa, NULL); + sigaction(SIGINT, &orig_int_sa, NULL); +} + +static void install_signal_handlers(void) +{ + struct sigaction act; + memset(&act, 0, sizeof act); + + act.sa_handler = restart_handler; + sigaction(SIGUSR1, &act, &orig_usr1_sa); + + act.sa_handler = exit_handler; + sigaction(SIGTERM, &act, &orig_term_sa); + sigaction(SIGHUP, &act, &orig_hup_sa); + sigaction(SIGINT, &act, &orig_int_sa); +} + +/** Supervises this process - restart if it dies. + * + * The program should call supervise() at a pristine state (all relevant file descriptors closed, etc). + * supervise() will return 0 if all is ok, and the program can continue.(returning != 0 means + * the supervisor couldn't start, and the calling process must exit) + * + * This will run the actual process as a child process. If that child process dies by any means, + * supervise will create another child process, where supervise() returns 0 again. + * + * To kill the supervisor process and the supervised process, send SIGERM/SIGHUP/SIGINT to the + * parent supervisor process. + * Sending SIGUSR1 to the parent supervisor process will terminate the current child process and + * restart it. + * + * The supervised child process must exit if it recieves a SIGTERM */ +int uc_supervise(void) +{ + pid_t pid; + + pid = fork(); + if (pid == -1) { + syslog(LOG_ERR, "Cannot create supervisor : %s", strerror(errno)); + return -1; + } else if (pid == 0) { + return 0; + } + + //close_files(); + install_signal_handlers(); + + syslog(LOG_INFO, "Supervising pid %ld", (long)pid); + + for (;;) { + int cmd = watch(pid); + switch (cmd) { + + case CLEAN_EXIT: + syslog(LOG_INFO, "Terminating supervised pid %lu", (unsigned long)pid); + kill_supervised_process(pid); + wait(NULL); + syslog(LOG_INFO, "Exiting"); + exit(0); + break; + + case BAD_EXIT: + syslog(LOG_ERR, "watch() error, exiting"); + exit(55); + break; + + case RESTART: { + pid_t new_pid = -1; + + while (new_pid == -1) { + sleep(RESTART_GRACE); + syslog(LOG_INFO, "Restarting supervised pid %lu", (unsigned long)pid); + closelog(); + new_pid = fork(); + if (new_pid == -1) { + syslog(LOG_INFO, "Cannot restart. %s", strerror(errno)); + } else if (new_pid == 0) { //return so the original process continues + restore_signal_handlers(); + return 0; + } + } + + pid = new_pid; + syslog(LOG_INFO, "Supervising new pid %lu", (unsigned long)new_pid); + } + + break; + + default: + exit(38); + break; + } + + } + + return 0x76; +} + + From 1a85dd32316bf21114a144afcb379d0012b1264e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 28 Aug 2013 23:30:37 +0200 Subject: [PATCH 41/45] Remove comments that was moved to .h file, rename goto label.. --- src/supervisor.c | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/supervisor.c b/src/supervisor.c index c59bc91..1a89a39 100644 --- a/src/supervisor.c +++ b/src/supervisor.c @@ -44,7 +44,7 @@ static int watch(pid_t pid) int status; pid_t rc; -restart: +again: rc = waitpid(pid, &status, 0); if (rc == -1 && errno == EINTR) { if (restart_flag) { @@ -52,13 +52,13 @@ restart: kill_supervised_process(pid); /* next waitpid should notify us of the death and * we'll restart the process */ - goto restart; + goto again; } else if (exit_flag) { exit_flag = 0; return CLEAN_EXIT; } - goto restart; + goto again; } else if (rc == -1) { return BAD_EXIT; @@ -110,21 +110,7 @@ static void install_signal_handlers(void) sigaction(SIGINT, &act, &orig_int_sa); } -/** Supervises this process - restart if it dies. - * - * The program should call supervise() at a pristine state (all relevant file descriptors closed, etc). - * supervise() will return 0 if all is ok, and the program can continue.(returning != 0 means - * the supervisor couldn't start, and the calling process must exit) - * - * This will run the actual process as a child process. If that child process dies by any means, - * supervise will create another child process, where supervise() returns 0 again. - * - * To kill the supervisor process and the supervised process, send SIGERM/SIGHUP/SIGINT to the - * parent supervisor process. - * Sending SIGUSR1 to the parent supervisor process will terminate the current child process and - * restart it. - * - * The supervised child process must exit if it recieves a SIGTERM */ +//See notes in supervisor.h int uc_supervise(void) { pid_t pid; From a5b8d53177f42b222816a3f7a34641919634c07b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Fri, 30 Aug 2013 19:34:33 +0200 Subject: [PATCH 42/45] Fix goto label --- src/supervisor.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/supervisor.c b/src/supervisor.c index 1a89a39..b5f41d8 100644 --- a/src/supervisor.c +++ b/src/supervisor.c @@ -77,7 +77,7 @@ again: syslog(LOG_ERR, "waitpid of supervised process(pid %ld) status = 0x%X", (long)pid, status); if (kill(pid, 0) == 0) { syslog(LOG_ERR, "supervised process(pid %ld) seems to still be alive, not restarting", (long)pid); - goto restart; + goto again; } return RESTART; From 216dfe879dda0f8367b504638b7ed45d4d1a8171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 4 Sep 2013 18:10:26 +0200 Subject: [PATCH 43/45] Added string vector(argv like) functions --- include/ucore/strvec.h | 90 ++++++++++++++++++++++++++++++++++ src/strvec.c | 107 +++++++++++++++++++++++++++++++++++++++++ test/test_runner.c | 4 +- test/test_strv.c | 91 +++++++++++++++++++++++++++++++++++ 4 files changed, 291 insertions(+), 1 deletion(-) create mode 100644 include/ucore/strvec.h create mode 100644 src/strvec.c create mode 100644 test/test_strv.c diff --git a/include/ucore/strvec.h b/include/ucore/strvec.h new file mode 100644 index 0000000..3789d78 --- /dev/null +++ b/include/ucore/strvec.h @@ -0,0 +1,90 @@ +#include + +#ifndef UC_STRVEC_H_ +#define UC_STRVEC_H_ + +#ifdef __cplusplus +extern "C" { +#endif +/** A Vector of strings.*/ +struct UCStrv +{ + /** number of strings */ + size_t cnt; + /** allocated room in strings (internal use) */ + size_t allocated; + /** Array of strings */ + char **strings; +}; + +/** Initialize a UCStrv + * + * @param strv + */ +void uc_strv_init(struct UCStrv *strv); + +/** + * Grow the UCStrv so it can hold n more items + * + * @param strv UCStrv to grow + * @param cnt expand strvec to hold this cnt more items + * @return 0 on success, otherwise failure + **/ +int uc_strv_grow(struct UCStrv *strv, size_t cnt); + +/** + * Expand the UCStrv to hold 1 more item + * + * @param strv UCStrv to expand + * @return 0 on success, otherwise failure + **/ +int uc_strv_expand(struct UCStrv *strv); + +/** + * Append a string to the UCStrv, the string will be copied in + * + * @param strv UCStrv to append to + * @param str String to append, the string will be copied. + * @return 0 on success, otherwise failure + **/ +int uc_strv_append(struct UCStrv *strv, const char *str); + +/** + * Append a string to the strvec, nocopy variang. + * The string shold be dynamically allocated, as + * destroying the UCStrv will free() all items. + * + * @param strv UCStrv to add to + * @param str the string to append + * @return 0 on success, otherwise failure + **/ +int uc_strv_append_nocopy(struct UCStrv *strv, char *str); + +/** + * Append a NULL pointer to the UCStrv, (cnt is not increased, + * so another _appended item will overwrite this NULL terminator) + * + * @param strv UCStrv to append to + * @return 0 on success, otherwise failure + **/ +int uc_strv_null_terminate(struct UCStrv *strv); + +/** + * free all strings in this UCStrv, cnt will be 0 after this + * @param strv UCStrv to clear + */ +void uc_strv_clear(struct UCStrv *strv); + +/** + * free all elements as well as the underlying array, the UCStrv is + * unusable after this call + * + * @param strv UCStrv to destroy + */ +void uc_strv_destroy(struct UCStrv *strv); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/strvec.c b/src/strvec.c new file mode 100644 index 0000000..079cbdd --- /dev/null +++ b/src/strvec.c @@ -0,0 +1,107 @@ +#include +#include +#include "ucore/strvec.h" + +void uc_strv_init(struct UCStrv *strv) +{ + strv->cnt = 0; + strv->allocated = 0; + strv->strings = NULL; +} + +int uc_strv_grow(struct UCStrv *strv, size_t cnt) +{ + + size_t allocate = strv->allocated + cnt; + void *tmp = realloc(strv->strings, sizeof *strv->strings * allocate); + + if (tmp == NULL) { + return -1; + } + strv->strings = tmp; + strv->allocated = allocate; + + return 0; +} + +int uc_strv_expand(struct UCStrv *strv) +{ + int rc = 0; + + if (strv->cnt >= strv->allocated) { + rc = uc_strv_grow(strv, 1); + } + + return rc; +} + +int uc_strv_append(struct UCStrv *strv, const char *str) +{ + int rc; + char *dup; + + rc = uc_strv_expand(strv); + if (rc != 0) { + return rc; + } + + dup = strdup(str); + if (dup == NULL) { + return -2; + } + + strv->strings[strv->cnt] = dup; + strv->cnt++; + + return 0; +} + +int uc_strv_append_nocopy(struct UCStrv *strv, char *str) +{ + int rc; + rc = uc_strv_expand(strv); + + if (rc != 0) { + return rc; + } + + strv->strings[strv->cnt] = str; + strv->cnt++; + + return 0; +} + +int uc_strv_null_terminate(struct UCStrv *strv) +{ + int rc; + + rc = uc_strv_expand(strv); + if (rc != 0) { + return rc; + } + + strv->strings[strv->cnt] = NULL; + strv->cnt++; + + return 0; +} + +void uc_strv_clear(struct UCStrv *strv) +{ + size_t i; + + for (i = 0; i < strv->cnt; i++) { + free(strv->strings[i]); + strv->strings[i] = NULL; + } + + strv->cnt = 0; +} + +void uc_strv_destroy(struct UCStrv *strv) +{ + uc_strv_clear(strv); + free(strv->strings); + strv->strings = NULL; +} + diff --git a/test/test_runner.c b/test/test_runner.c index 56af24a..3c38f59 100644 --- a/test/test_runner.c +++ b/test/test_runner.c @@ -23,6 +23,7 @@ extern Suite *mbuf_suite(void); extern Suite *human_bytesz_suite(void); extern Suite *dbuf_suite(void); extern Suite *sprintb_suite(void); +extern Suite *strv_suite(void); static suite_func suites[] = { bitvec_suite, @@ -41,7 +42,8 @@ static suite_func suites[] = { mbuf_suite, human_bytesz_suite, dbuf_suite, - sprintb_suite + sprintb_suite, + strv_suite }; int diff --git a/test/test_strv.c b/test/test_strv.c new file mode 100644 index 0000000..d9745b2 --- /dev/null +++ b/test/test_strv.c @@ -0,0 +1,91 @@ +#include +#include +#include + + +START_TEST (test_strv_append) + struct UCStrv strv; + int rc; + + uc_strv_init(&strv); + + rc = uc_strv_append(&strv, "string"); + fail_if(rc != 0); + fail_if(strv.cnt != 1); + ck_assert_str_eq("string", strv.strings[0]); + + rc = uc_strv_append(&strv, "string2"); + fail_if(rc != 0); + fail_if(strv.cnt != 2); + ck_assert_str_eq("string2", strv.strings[1]); + + uc_strv_destroy(&strv); + +END_TEST + +START_TEST (test_strv_clear) + struct UCStrv strv; + int rc; + + uc_strv_init(&strv); + + rc = uc_strv_append(&strv, "string"); + fail_if(rc != 0); + fail_if(strv.cnt != 1); + + uc_strv_clear(&strv); + fail_if(strv.cnt != 0); + uc_strv_destroy(&strv); + +END_TEST + +START_TEST (test_strv_nocopy) + struct UCStrv strv; + char *str = strdup("string"); + int rc; + + uc_strv_init(&strv); + + rc = uc_strv_append_nocopy(&strv, str); + fail_if(rc != 0); + fail_if(strv.cnt != 1); + fail_if(strv.strings[0] != str); + + uc_strv_destroy(&strv); + +END_TEST + +START_TEST (test_strv_null_terminate) + struct UCStrv strv; + int rc; + + uc_strv_init(&strv); + + rc = uc_strv_append(&strv, "string"); + fail_if(rc != 0); + fail_if(strv.cnt != 1); + + rc = uc_strv_null_terminate(&strv); + fail_if(rc != 0); + fail_if(strv.strings[strv.cnt] != NULL); + + uc_strv_destroy(&strv); + +END_TEST + + +Suite *strv_suite(void) +{ + Suite *s = suite_create("strvec"); + TCase *tc = tcase_create("strvec"); + + tcase_add_test(tc, test_strv_append); + tcase_add_test(tc, test_strv_clear); + tcase_add_test(tc, test_strv_nocopy); + tcase_add_test(tc, test_strv_null_terminate); + + suite_add_tcase(s, tc); + + return s; +} + From 1deb2bcce148c4744abf281baf72d57e99a8734a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 4 Sep 2013 18:15:08 +0200 Subject: [PATCH 44/45] Test adding a destination twice --- test/test_logging.c | 1 + 1 file changed, 1 insertion(+) diff --git a/test/test_logging.c b/test/test_logging.c index 76d1919..142f565 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -50,6 +50,7 @@ START_TEST (test_logfile_location) dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); fail_if(dest == NULL); uc_log_add_destination(dest); + uc_log_add_destination(dest); //adding this twice should do nothing UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n"); From 88a20409cf2d76f4150e9cd7a08dd2544df9bbba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Wed, 4 Sep 2013 18:33:40 +0200 Subject: [PATCH 45/45] Test removing a destination --- test/test_logging.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/test/test_logging.c b/test/test_logging.c index 142f565..ea42309 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -63,6 +63,54 @@ START_TEST (test_logfile_location) fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size); END_TEST +START_TEST (test_logfile_delete_destination) + + struct uc_log_module m = { + .id = 0, + .short_name = "MOD1", + .long_name = "Module 1", + .log_level = UC_LL_DEBUG, + }; + struct uc_log_modules mods = { + .mods = &m, + .cnt = 1, + }; + struct stat st; + struct uc_log_destination *dest; + int rc; + + uc_log_init(&mods); + + dest = uc_log_new_file(FILE_NAME, UC_LL_DEBUG, 1); + fail_if(dest == NULL); + uc_log_add_destination(dest); + uc_log_add_destination(dest); //adding this twice should do nothing + + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n"); + UC_LOGF(UC_LL_INFO, 0, "Lorum ipson 3\n"); + UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson 4\n"); + UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5\n"); + + rc = stat(FILE_NAME, &st); + fail_if(rc != 0, "stat failed: %s\n", strerror(errno)); + fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size); + + uc_log_delete_destination(dest); + + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson %d\n", 1); + UC_LOGF(UC_LL_DEBUG, 0, "Lorum ipson 2\n"); + UC_LOGF(UC_LL_INFO, 0, "Lorum ipson 3\n"); + UC_LOGF(UC_LL_WARNING, 0, "Lorum ipson 4\n"); + UC_LOGF(UC_LL_ERROR, 0, "Lorum ipson 5\n"); + + //since we deleted destinatiion, no more logging should appear in the file + rc = stat(FILE_NAME, &st); + fail_if(rc != 0, "stat failed: %s\n", strerror(errno)); + fail_if(st.st_size != 380, "was %ld\n", (long)st.st_size); + +END_TEST + START_TEST (test_logfile_no_location) struct uc_log_module m = { @@ -477,6 +525,7 @@ Suite *logging_suite(void) TCase *tc2 = tcase_create("ucore_logging2"); tcase_add_test(tc1, test_logfile_location); + tcase_add_test(tc1, test_logfile_delete_destination); tcase_add_test(tc1, test_logfile_no_location); tcase_add_test(tc1, test_logfile_loglevel_surpressed_dest); tcase_add_test(tc1, test_logfile_loglevel_surpressed_module);