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 diff --git a/SConstruct b/SConstruct index 695afbe..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', @@ -59,6 +65,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') @@ -80,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() diff --git a/include/ucore/atomic.h b/include/ucore/atomic.h new file mode 100644 index 0000000..5311352 --- /dev/null +++ b/include/ucore/atomic.h @@ -0,0 +1,47 @@ +#ifndef UC_ATOMIC_H_ +#define UC_ATOMIC_H_ + +/** Atomic functions (macros). The ptr argument must be a pointer to + * an integer type. + * For gcc, see http://gcc.gnu.org/onlinedocs/gcc-4.8.1/gcc/_005f_005fsync-Builtins.html + */ + +#ifdef __GNUC__ + +/** + * Atomically add val to *ptr + * @return *ptr before the addition + */ +#define UC_ATOMIC_ADD(ptr, val) __sync_fetch_and_add((ptr), (val)) + +/** + * Atomically subtract val from *ptr + * @return *ptr before the subtraction + */ +#define UC_ATOMIC_SUB(ptr, val) __sync_fetch_and_add((ptr), -(val)) + +/** + * Atomically decrement *ptr + * @return *ptr before the decrement + */ +#define UC_ATOMIC_DEC(ptr) UC_ATOMIC_SUB((ptr), 1) + +/** + * Atomically increment *ptr + * @return *ptr before the increment + */ +#define UC_ATOMIC_INC(ptr) UC_ATOMIC_SUB((ptr), 1) + + +/** + * Atomic Compare-And-Swap. If *ptr is oldval, write newwal to *ptr. + * @return *ptr that was before the operation. + */ +#define UC_ATOMIC_CAS(ptr, oldval, newval) __sync_val_compare_and_swap((ptr), (oldval), (newval)) + +#else +#error "No atomic operations implemented for this compiler" +#endif + + +#endif diff --git a/include/ucore/backtrace.h b/include/ucore/backtrace.h index 0110165..d1c43d5 100644 --- a/include/ucore/backtrace.h +++ b/include/ucore/backtrace.h @@ -1,9 +1,12 @@ #ifndef UC_BACKTRACE_H_ #define UC_BACKTRACE_H_ - -#define UC_BACTRACE_STDERR uc_backtrace_fd(2) #include +#ifdef __cplusplus +extern "C" { +#endif + +#define UC_BACTRACE_STDERR uc_backtrace_fd(2) /** * Print a stacktrace to the given file descriptor. * @@ -21,4 +24,8 @@ void uc_backtrace_fd(int fd); */ void uc_backtrace_buf(char *buf, size_t len); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/ucore/bitvec.h b/include/ucore/bitvec.h index af11d67..acbedaa 100644 --- a/include/ucore/bitvec.h +++ b/include/ucore/bitvec.h @@ -8,7 +8,7 @@ extern "C" { struct UCBitVec { //storage for the bits unsigned long *vec; - //length of the above vec. (Not the number of bits !) + //length in bytes of the above vec. size_t vec_len; }; diff --git a/include/ucore/clock.h b/include/ucore/clock.h index fce2c82..b64c4a9 100644 --- a/include/ucore/clock.h +++ b/include/ucore/clock.h @@ -4,6 +4,9 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif /** * An abstract clock. @@ -110,5 +113,9 @@ void uc_settable_clock_set_tv(struct UCoreSettableClock *uclock, void uc_settable_clock_set(struct UCoreSettableClock *uclock, time_t secs, suseconds_t usecs); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/ucore/iomux.h b/include/ucore/iomux.h index 774b6d2..20a64cb 100644 --- a/include/ucore/iomux.h +++ b/include/ucore/iomux.h @@ -3,6 +3,11 @@ #include "timers.h" +#ifdef __cplusplus +extern "C" { +#endif + + #define MUX_EV_READ (1U << 0x00) #define MUX_EV_WRITE (1U << 0x01) //#define MUX_EV_EXCEPT (1 << 0x02) @@ -38,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); @@ -53,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); @@ -95,10 +111,14 @@ 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); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/ucore/logging.h b/include/ucore/logging.h index f36e1b3..9efa2d6 100644 --- a/include/ucore/logging.h +++ b/include/ucore/logging.h @@ -71,13 +71,15 @@ extern "C" { #endif -/** The log levels defined by ucore logging*/ +/** The log levels defined by ucore logging + * UC_LL_NONE must not be used in logging statements - but + * can be used to suppress all logging for a destination or module*/ enum UC_LOG_LEVEL { - UC_LL_NONE = 0, UC_LL_DEBUG = 1, UC_LL_INFO = 3, UC_LL_WARNING = 5, UC_LL_ERROR = 7, + UC_LL_NONE = 9, }; /** A destination for the logging messages*/ diff --git a/include/ucore/mbuf.h b/include/ucore/mbuf.h new file mode 100644 index 0000000..406f951 --- /dev/null +++ b/include/ucore/mbuf.h @@ -0,0 +1,75 @@ +#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_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); +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); + +#undef UC_INLINE + +#endif diff --git a/include/ucore/mersenne_twister.h b/include/ucore/mersenne_twister.h index 1ff4e6f..f3fb166 100644 --- a/include/ucore/mersenne_twister.h +++ b/include/ucore/mersenne_twister.h @@ -1,6 +1,9 @@ #ifndef UCORE_MERSENNE_TWISTER_H #define UCORE_MERSENNE_TWISTER_H +#ifdef __cplusplus +extern "C" { +#endif /** Context used for the PRNG*/ #define MT_RAND_N 624 @@ -23,5 +26,9 @@ void mtsrand(int seed, MTRand *r); */ unsigned int mtrand(MTRand *r); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/ucore/read_file.h b/include/ucore/read_file.h index e86cc9e..173adc8 100644 --- a/include/ucore/read_file.h +++ b/include/ucore/read_file.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** Read the content of a file. * The returned char* is malloced memory and must be freed by the caller. * The content is terminated by a nul byte, regardless of whether the content @@ -17,4 +21,8 @@ char * uc_read_file(const char *file_name, size_t *length, size_t max); +#ifdef __cplusplus +} +#endif + #endif diff --git a/include/ucore/timers.h b/include/ucore/timers.h index 19c9744..f4769e3 100644 --- a/include/ucore/timers.h +++ b/include/ucore/timers.h @@ -6,6 +6,9 @@ #include #include "rbtree.h" +#ifdef __cplusplus +extern "C" { +#endif struct UCTimer; struct UCTimers; @@ -140,4 +143,8 @@ int uc_timers_run(struct UCTimers *timers); //uc_timers_destroy(struct UCTimers *timers) is currently missing.. +#ifdef __cplusplus +} +#endif + #endif 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 diff --git a/include/ucore/version.h b/include/ucore/version.h index e33a37f..9f9d0b2 100644 --- a/include/ucore/version.h +++ b/include/ucore/version.h @@ -30,6 +30,9 @@ * * @endhtmlonly */ +#ifdef __cplusplus +extern "C" { +#endif /* Major version of the ucore library*/ extern const int ucore_version_major; @@ -46,5 +49,10 @@ extern const char ucore_version_str[]; /** Hostname where the library was built */ extern const char ucore_build_host[]; + +#ifdef __cplusplus +} +#endif + #endif 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); diff --git a/src/iomux_epoll.c b/src/iomux_epoll.c index 21c8898..65a9eaf 100644 --- a/src/iomux_epoll.c +++ b/src/iomux_epoll.c @@ -4,7 +4,7 @@ #include #include #include -#include "ucore/iomux_impl.h" +#include "iomux_impl.h" //epoll (linux specific) IO mux. //We stuff the struct IOMuxFD pointer in the event.data.ptr slot @@ -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_impl.c b/src/iomux_impl.c index 2e47b31..f94e0c9 100644 --- a/src/iomux_impl.c +++ b/src/iomux_impl.c @@ -2,8 +2,8 @@ #include #include #include -#include #include "ucore/clock.h" +#include "iomux_impl.h" //dispatchers for the IOMux implementations */ diff --git a/include/ucore/iomux_impl.h b/src/iomux_impl.h similarity index 96% rename from include/ucore/iomux_impl.h rename to src/iomux_impl.h index 4770810..6c5484a 100644 --- a/include/ucore/iomux_impl.h +++ b/src/iomux_impl.h @@ -1,8 +1,8 @@ #ifndef IO_MUX_IMPL_H_ #define IO_MUX_IMPL_H_ -#include "iomux.h" -#include "timers.h" +#include "ucore/iomux.h" +#include "ucore/timers.h" /** struct for IOMux implementations */ struct IOMux { diff --git a/src/iomux_select.c b/src/iomux_select.c index ebad214..ad39cf9 100644 --- a/src/iomux_select.c +++ b/src/iomux_select.c @@ -5,8 +5,8 @@ #include #include #include -#include "ucore/iomux_impl.h" #include "ucore/utils.h" +#include "iomux_impl.h" #define IOMUX_GROW_CHUNK (32) @@ -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++; } } diff --git a/src/logging.c b/src/logging.c index 0784165..85146e8 100644 --- a/src/logging.c +++ b/src/logging.c @@ -68,17 +68,18 @@ static SLIST_HEAD(, uc_log_destination) g_destinations; static int uc_log_reopen_file(struct uc_log_destination *dest); //Uses enum UC_LOG_LEVEL as index static const char *const g_log_levels[] = { - "NONE", + "UNKNOWN_0", "DEBUG", "UNKNOWN_2", "INFO", "UNKNOWN_4", "WARNING", "UNKNOWN_6", - "ERROR" + "ERROR", + "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]; @@ -104,7 +105,6 @@ static int uc_str_2_ll(const char *str, size_t len) static inline int uc_ll_2_syslog(enum UC_LOG_LEVEL l) { switch(l) { - case UC_LL_NONE: case UC_LL_DEBUG: return LOG_DEBUG; case UC_LL_INFO: @@ -113,6 +113,9 @@ static inline int uc_ll_2_syslog(enum UC_LOG_LEVEL l) return LOG_WARNING; case UC_LL_ERROR: return LOG_ERR; + case UC_LL_NONE: + return LOG_CRIT; //Fishy, but this should never happen + } return LOG_INFO; @@ -544,22 +547,14 @@ void uc_logf(int log_level, int module, int raw, { va_list ap; struct uc_log_destination *dest; - const struct uc_log_module *log_module; va_start(ap, fmt); pthread_mutex_lock(&g_log_lock); - - //Find the module doign the logging, or use the unknown module - - //the latter would indicate a bug somewhere in the application as it should - //always specify a known module - if (module >= 0 && module < g_modules.cnt) - log_module = &g_modules.mods[module]; - else - log_module = &g_unknown_module; //do logging for each destination SLIST_FOREACH(dest, &g_destinations, entry) { + const struct uc_log_module *log_module; va_list apc; int module_log_level; @@ -568,11 +563,16 @@ void uc_logf(int log_level, int module, int raw, if (log_level < dest->log_level) continue; - //individual module level - if (module >= 0 && module < g_modules.cnt) + //Find the module doing the logging, or use the unknown module - + //the latter would indicate a bug somewhere in the application as it should + //always specify a known module + if (module >= 0 && module < g_modules.cnt) { module_log_level = dest->module_settings[module].log_level; - else //application bug. use global/unknown module + log_module = &g_modules.mods[module]; + } else { + log_module = &g_unknown_module; module_log_level = log_module->log_level; + } if (log_level < module_log_level) continue; diff --git a/src/mbuf.c b/src/mbuf.c new file mode 100644 index 0000000..97c1c6e --- /dev/null +++ b/src/mbuf.c @@ -0,0 +1,121 @@ +#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); +} + +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/src/tval.c b/src/tval.c index b2a2eea..a2577e8 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; } @@ -41,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; diff --git a/test/test_logging.c b/test/test_logging.c index d0ad57f..76d1919 100644 --- a/test/test_logging.c +++ b/test/test_logging.c @@ -410,6 +410,64 @@ START_TEST (test_logfile_dest_mask) fail_if(st.st_size != 14*2, "was %ld\n", (long)st.st_size); END_TEST +START_TEST (test_loglevel_module_none) + + struct uc_log_module m = { + .id = 0, + .short_name = "MOD1", + .long_name = "Module 1", + .log_level = UC_LL_NONE, + }; + 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_LOGFR(UC_LL_ERROR, 0, "Lorum ipson %d\n", 1); + + rc = stat(FILE_NAME, &st); + fail_if(rc != 0, "stat failed: %s\n", strerror(errno)); + fail_if(st.st_size != 0, "was %ld\n", (long)st.st_size); +END_TEST + +START_TEST (test_loglevel_dest_none) + + 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_NONE, 1); + fail_if(dest == NULL); + uc_log_add_destination(dest); + + UC_LOGFR(UC_LL_WARNING, 0, "Lorum ipson %d\n", 1); + + rc = stat(FILE_NAME, &st); + fail_if(rc != 0, "stat failed: %s\n", strerror(errno)); + fail_if(st.st_size != 0, "was %ld\n", (long)st.st_size); +END_TEST + Suite *logging_suite(void) { @@ -435,6 +493,9 @@ Suite *logging_suite(void) tcase_add_test(tc2, test_logfile_invalid_file_after_reopen); tcase_add_test(tc1, test_logfile_raw); + tcase_add_test(tc1, test_loglevel_module_none); + tcase_add_test(tc1, test_loglevel_dest_none); + tcase_add_checked_fixture(tc1, logging_rm_files, logging_rm_files); tcase_add_checked_fixture(tc2, logging_setup_subdir, logging_rm_subdir); diff --git a/test/test_mbuf.c b/test/test_mbuf.c new file mode 100644 index 0000000..98b5bdd --- /dev/null +++ b/test/test_mbuf.c @@ -0,0 +1,222 @@ +#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 + +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) +{ + 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); + tcase_add_test(tc, test_mbuf_copy); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_read_file.c b/test/test_read_file.c index 0bb4990..5bef1f4 100644 --- a/test/test_read_file.c +++ b/test/test_read_file.c @@ -91,6 +91,65 @@ 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 + +START_TEST (test_read_file_too_big) + char *content; + const char *filename = "test_read_file_too_big"; + 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 + +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"); @@ -99,6 +158,10 @@ 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); + tcase_add_test(tc, test_read_file_too_big); + tcase_add_test(tc, test_read_file_big); + suite_add_tcase(s, tc); diff --git a/test/test_runner.c b/test/test_runner.c index 37483aa..bf20b6a 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); extern Suite *human_bytesz_suite(void); static suite_func suites[] = { @@ -35,6 +36,7 @@ static suite_func suites[] = { seq_suite, sat_math_suite, timers_suite, + mbuf_suite, human_bytesz_suite };