From 4dca24953f049b0fb84fbf0b59a014655e7efbce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nils=20O=2E=20Sel=C3=A5sdal?= Date: Thu, 15 Nov 2012 17:30:40 +0100 Subject: [PATCH] readd include dir --- include/SConscript | 16 + include/iomux.h | 97 ++++ include/iomux_impl.h | 47 ++ include/tree.h | 741 +++++++++++++++++++++++++++++++ include/ucore_backtrace.h | 8 + include/ucore_bitvec.h | 81 ++++ include/ucore_buffer.h | 83 ++++ include/ucore_hash.h | 39 ++ include/ucore_heapsort.h | 21 + include/ucore_logging.h | 252 +++++++++++ include/ucore_math.h | 39 ++ include/ucore_mersenne_twister.h | 27 ++ include/ucore_pack.h | 257 +++++++++++ include/ucore_rbtree.h | 42 ++ include/ucore_read_file.h | 20 + include/ucore_salloc.h | 70 +++ include/ucore_seq.h | 21 + include/ucore_string.h | 60 +++ include/ucore_threadqueue.h | 248 +++++++++++ include/ucore_timers.h | 63 +++ include/ucore_utils.h | 55 +++ include/ucore_version.c.in | 7 + include/ucore_version.h | 47 ++ 23 files changed, 2341 insertions(+) create mode 100644 include/SConscript create mode 100644 include/iomux.h create mode 100644 include/iomux_impl.h create mode 100644 include/tree.h create mode 100644 include/ucore_backtrace.h create mode 100644 include/ucore_bitvec.h create mode 100644 include/ucore_buffer.h create mode 100644 include/ucore_hash.h create mode 100644 include/ucore_heapsort.h create mode 100644 include/ucore_logging.h create mode 100644 include/ucore_math.h create mode 100644 include/ucore_mersenne_twister.h create mode 100644 include/ucore_pack.h create mode 100644 include/ucore_rbtree.h create mode 100644 include/ucore_read_file.h create mode 100644 include/ucore_salloc.h create mode 100644 include/ucore_seq.h create mode 100644 include/ucore_string.h create mode 100644 include/ucore_threadqueue.h create mode 100644 include/ucore_timers.h create mode 100644 include/ucore_utils.h create mode 100644 include/ucore_version.c.in create mode 100644 include/ucore_version.h diff --git a/include/SConscript b/include/SConscript new file mode 100644 index 0000000..5c5faf2 --- /dev/null +++ b/include/SConscript @@ -0,0 +1,16 @@ +import os +Import('env', 'build_type', 'prefix', 'version_info') + +ucore_env = env.Clone() + +#substitute @version_xx@ strings +subst_version_info = dict(('@' + key + '@', version_info[key]) for key in version_info) +ucore_env.Substfile('ucore_version.c.in', SUBST_DICT = subst_version_info) + +headers = ucore_env.Glob('*.h') + +#install targets + +ucore_env.Alias('install', + ucore_env.InstallPerm(os.path.join(prefix, 'include', 'ucore'), headers, 0644)) + diff --git a/include/iomux.h b/include/iomux.h new file mode 100644 index 0000000..a065afe --- /dev/null +++ b/include/iomux.h @@ -0,0 +1,97 @@ +#ifndef IO_MUX_H_ +#define IO_MUX_H_ + +#include "ucore_timers.h" + +#define MUX_EV_READ (1 << 0x00) +#define MUX_EV_WRITE (1 << 0x01) +//#define MUX_EV_EXCEPT (1 << 0x02) +#define MUX_EV_MASK (MUX_EV_READ | MUX_EV_WRITE ) + +/** + * mux implementation to use +*/ +enum IOMUX_TYPE { + IOMUX_TYPE_DEFAULT = 0, + IOMUX_TYPE_SELECT, + IOMUX_TYPE_EPOLL +}; + +/** Opaque struct */ +struct IOMux; +struct IOMuxFD; +typedef void (*iomux_cb)(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event); + +/** Represents a watched file descriptor */ +struct IOMuxFD { + /** The file descriptor */ + int fd; + /** The events to watch for, MUX_EV_XX mask */ + unsigned int what; + /** callback to call on an event */ + iomux_cb callback; + /** values available to the caller. These will bbe passed + * back on the callback */ + void *cookie_ptr; + int cookie_int; + int cookie_int2; +}; + +/** Creates a new IOMux. + */ +struct IOMux *iomux_create(enum IOMUX_TYPE type); + +/** Deletes the IOMux and frees its resources. + * Can not be called from within a callback */ +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 + * 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 */ +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 */ +int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd); + + +/** + * Convenience macro for setting the new event + */ +#define iomux_set_event(mux, fd, what)\ +({\ + (fd)->what = (what);\ + iomux_update_events((mux), (fd));\ +}) + +/** + * Convenience macro for clearing the new event + */ +#define iomux_clear_event(mux, fd, what)\ +({\ + (fd)->what &= ~(what);\ + iomux_update_events((mux), (fd));\ +}) +/** + * Convenience macro for adding the new event to the existing events + */ +#define iomux_add_event(mux, fd, what)\ +({\ + (fd)->what &= (what);\ + iomux_update_events((mux), (fd));\ +}) + +/** Returns a UCTimer instance tied to this mux. + * Used to schedule timers within this mux. + */ +struct UCTimers *iomux_get_timers(struct IOMux *mux); + +#endif + diff --git a/include/iomux_impl.h b/include/iomux_impl.h new file mode 100644 index 0000000..ef65ad7 --- /dev/null +++ b/include/iomux_impl.h @@ -0,0 +1,47 @@ +#ifndef IO_MUX_IMPL_H_ +#define IO_MUX_IMPL_H_ + +#include "iomux.h" +#include "ucore_timers.h" +/** struct for IOMux implementations */ +struct IOMux { + + /* TImer instance */ + struct UCTimers timers; + + /* Current time. Updated before calling run_impl, and updated + * by iomux_timers_run + */ + struct timeval now; + + /* Used by mux implementations to hold their own data/instance */ + void *instance; + + /** Run one iteration of the mux. + * The mux implementation must honor the timeout, if given. + * The mux implementation must call iomux_timers_run after the + * polling has occured (or if it's polling times out) + * + * @param mux The IOMux instance + * @param timeout absolute time of a timeout - after which timers should run. + * If timeout is NULL, no timeout should be set on the poll. + */ + int (*run_impl)(struct IOMux *mux, struct timeval *timeout); + + /* Deallocate the instance specific part of the IOMux */ + void (*delete_impl)(struct IOMux *mux); + + /** Register an IOMuxFD for events*/ + int (*register_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd); + /** Unregister an IOMuxFD */ + int (*unregister_fd_impl)(struct IOMux *mux, struct IOMuxFD *fd); + /** Update an IOMuxFD (due to its events ('what') has changed*/ + int (*update_events_impl)(struct IOMux *mux, struct IOMuxFD *fd); +}; + +int iomux_select_init(struct IOMux *mux); +int iomux_epoll_init(struct IOMux *mux); +int iomux_timers_run(struct IOMux *mux); + +#endif + diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000..d044f98 --- /dev/null +++ b/include/tree.h @@ -0,0 +1,741 @@ +/* $NetBSD: tree.h,v 1.16 2008/03/21 13:07:15 ad Exp $ */ +/* $OpenBSD: tree.h,v 1.7 2002/10/17 21:51:54 art Exp $ */ +/* + * Copyright 2002 Niels Provos + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYS_TREE_H_ +#define _SYS_TREE_H_ + +/* + * This file defines data structures for different types of trees: + * splay trees and red-black trees. + * + * A splay tree is a self-organizing data structure. Every operation + * on the tree causes a splay to happen. The splay moves the requested + * node to the root of the tree and partly rebalances it. + * + * This has the benefit that request locality causes faster lookups as + * the requested nodes move to the top of the tree. On the other hand, + * every lookup causes memory writes. + * + * The Balance Theorem bounds the total access time for m operations + * and n inserts on an initially empty tree as O((m + n)lg n). The + * amortized cost for a sequence of m accesses to a splay tree is O(lg n); + * + * A red-black tree is a binary search tree with the node color as an + * extra attribute. It fulfills a set of conditions: + * - every search path from the root to a leaf consists of the + * same number of black nodes, + * - each red node (except for the root) has a black parent, + * - each leaf node is black. + * + * Every operation on a red-black tree is bounded as O(lg n). + * The maximum height of a red-black tree is 2lg (n+1). + */ + +#define SPLAY_HEAD(name, type) \ +struct name { \ + struct type *sph_root; /* root of the tree */ \ +} + +#define SPLAY_INITIALIZER(root) \ + { NULL } + +#define SPLAY_INIT(root) do { \ + (root)->sph_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ENTRY(type) \ +struct { \ + struct type *spe_left; /* left element */ \ + struct type *spe_right; /* right element */ \ +} + +#define SPLAY_LEFT(elm, field) (elm)->field.spe_left +#define SPLAY_RIGHT(elm, field) (elm)->field.spe_right +#define SPLAY_ROOT(head) (head)->sph_root +#define SPLAY_EMPTY(head) (SPLAY_ROOT(head) == NULL) + +/* SPLAY_ROTATE_{LEFT,RIGHT} expect that tmp hold SPLAY_{RIGHT,LEFT} */ +#define SPLAY_ROTATE_RIGHT(head, tmp, field) do { \ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(tmp, field); \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ROTATE_LEFT(head, tmp, field) do { \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(tmp, field); \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + (head)->sph_root = tmp; \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKLEFT(head, tmp, field) do { \ + SPLAY_LEFT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_LINKRIGHT(head, tmp, field) do { \ + SPLAY_RIGHT(tmp, field) = (head)->sph_root; \ + tmp = (head)->sph_root; \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field); \ +} while (/*CONSTCOND*/ 0) + +#define SPLAY_ASSEMBLE(head, node, left, right, field) do { \ + SPLAY_RIGHT(left, field) = SPLAY_LEFT((head)->sph_root, field); \ + SPLAY_LEFT(right, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT((head)->sph_root, field) = SPLAY_RIGHT(node, field); \ + SPLAY_RIGHT((head)->sph_root, field) = SPLAY_LEFT(node, field); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ + +#define SPLAY_PROTOTYPE(name, type, field, cmp) \ +void name##_SPLAY(struct name *, struct type *); \ +void name##_SPLAY_MINMAX(struct name *, int); \ +struct type *name##_SPLAY_INSERT(struct name *, struct type *); \ +struct type *name##_SPLAY_REMOVE(struct name *, struct type *); \ + \ +/* Finds the node with the same key as elm */ \ +static __inline struct type * \ +name##_SPLAY_FIND(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) \ + return(NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) \ + return (head->sph_root); \ + return (NULL); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_NEXT(struct name *head, struct type *elm) \ +{ \ + name##_SPLAY(head, elm); \ + if (SPLAY_RIGHT(elm, field) != NULL) { \ + elm = SPLAY_RIGHT(elm, field); \ + while (SPLAY_LEFT(elm, field) != NULL) { \ + elm = SPLAY_LEFT(elm, field); \ + } \ + } else \ + elm = NULL; \ + return (elm); \ +} \ + \ +static __inline struct type * \ +name##_SPLAY_MIN_MAX(struct name *head, int val) \ +{ \ + name##_SPLAY_MINMAX(head, val); \ + return (SPLAY_ROOT(head)); \ +} + +/* Main splay operation. + * Moves node close to the key of elm to top + */ +#define SPLAY_GENERATE(name, type, field, cmp) \ +struct type * \ +name##_SPLAY_INSERT(struct name *head, struct type *elm) \ +{ \ + if (SPLAY_EMPTY(head)) { \ + SPLAY_LEFT(elm, field) = SPLAY_RIGHT(elm, field) = NULL; \ + } else { \ + int __comp; \ + name##_SPLAY(head, elm); \ + __comp = (cmp)(elm, (head)->sph_root); \ + if(__comp < 0) { \ + SPLAY_LEFT(elm, field) = SPLAY_LEFT((head)->sph_root, field);\ + SPLAY_RIGHT(elm, field) = (head)->sph_root; \ + SPLAY_LEFT((head)->sph_root, field) = NULL; \ + } else if (__comp > 0) { \ + SPLAY_RIGHT(elm, field) = SPLAY_RIGHT((head)->sph_root, field);\ + SPLAY_LEFT(elm, field) = (head)->sph_root; \ + SPLAY_RIGHT((head)->sph_root, field) = NULL; \ + } else \ + return ((head)->sph_root); \ + } \ + (head)->sph_root = (elm); \ + return (NULL); \ +} \ + \ +struct type * \ +name##_SPLAY_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *__tmp; \ + if (SPLAY_EMPTY(head)) \ + return (NULL); \ + name##_SPLAY(head, elm); \ + if ((cmp)(elm, (head)->sph_root) == 0) { \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL) { \ + (head)->sph_root = SPLAY_RIGHT((head)->sph_root, field);\ + } else { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + (head)->sph_root = SPLAY_LEFT((head)->sph_root, field);\ + name##_SPLAY(head, elm); \ + SPLAY_RIGHT((head)->sph_root, field) = __tmp; \ + } \ + return (elm); \ + } \ + return (NULL); \ +} \ + \ +void \ +name##_SPLAY(struct name *head, struct type *elm) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ + int __comp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while ((__comp = (cmp)(elm, (head)->sph_root)) != 0) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if ((cmp)(elm, __tmp) > 0){ \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} \ + \ +/* Splay with either the minimum or the maximum element \ + * Used to find minimum or maximum element in tree. \ + */ \ +void name##_SPLAY_MINMAX(struct name *head, int __comp) \ +{ \ + struct type __node, *__left, *__right, *__tmp; \ +\ + SPLAY_LEFT(&__node, field) = SPLAY_RIGHT(&__node, field) = NULL;\ + __left = __right = &__node; \ +\ + while (1) { \ + if (__comp < 0) { \ + __tmp = SPLAY_LEFT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp < 0){ \ + SPLAY_ROTATE_RIGHT(head, __tmp, field); \ + if (SPLAY_LEFT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKLEFT(head, __right, field); \ + } else if (__comp > 0) { \ + __tmp = SPLAY_RIGHT((head)->sph_root, field); \ + if (__tmp == NULL) \ + break; \ + if (__comp > 0) { \ + SPLAY_ROTATE_LEFT(head, __tmp, field); \ + if (SPLAY_RIGHT((head)->sph_root, field) == NULL)\ + break; \ + } \ + SPLAY_LINKRIGHT(head, __left, field); \ + } \ + } \ + SPLAY_ASSEMBLE(head, &__node, __left, __right, field); \ +} + +#define SPLAY_NEGINF -1 +#define SPLAY_INF 1 + +#define SPLAY_INSERT(name, x, y) name##_SPLAY_INSERT(x, y) +#define SPLAY_REMOVE(name, x, y) name##_SPLAY_REMOVE(x, y) +#define SPLAY_FIND(name, x, y) name##_SPLAY_FIND(x, y) +#define SPLAY_NEXT(name, x, y) name##_SPLAY_NEXT(x, y) +#define SPLAY_MIN(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_NEGINF)) +#define SPLAY_MAX(name, x) (SPLAY_EMPTY(x) ? NULL \ + : name##_SPLAY_MIN_MAX(x, SPLAY_INF)) + +#define SPLAY_FOREACH(x, name, head) \ + for ((x) = SPLAY_MIN(name, head); \ + (x) != NULL; \ + (x) = SPLAY_NEXT(name, head, x)) + +/* Macros that define a red-black tree */ +#define RB_HEAD(name, type) \ +struct name { \ + struct type *rbh_root; /* root of the tree */ \ +} + +#define RB_INITIALIZER(root) \ + { NULL } + +#define RB_INIT(root) do { \ + (root)->rbh_root = NULL; \ +} while (/*CONSTCOND*/ 0) + +#define RB_BLACK 0 +#define RB_RED 1 +#define RB_ENTRY(type) \ +struct { \ + struct type *rbe_left; /* left element */ \ + struct type *rbe_right; /* right element */ \ + struct type *rbe_parent; /* parent element */ \ + int rbe_color; /* node color */ \ +} + +#define RB_LEFT(elm, field) (elm)->field.rbe_left +#define RB_RIGHT(elm, field) (elm)->field.rbe_right +#define RB_PARENT(elm, field) (elm)->field.rbe_parent +#define RB_COLOR(elm, field) (elm)->field.rbe_color +#define RB_ROOT(head) (head)->rbh_root +#define RB_EMPTY(head) (RB_ROOT(head) == NULL) + +#define RB_SET(elm, parent, field) do { \ + RB_PARENT(elm, field) = parent; \ + RB_LEFT(elm, field) = RB_RIGHT(elm, field) = NULL; \ + RB_COLOR(elm, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#define RB_SET_BLACKRED(black, red, field) do { \ + RB_COLOR(black, field) = RB_BLACK; \ + RB_COLOR(red, field) = RB_RED; \ +} while (/*CONSTCOND*/ 0) + +#ifndef RB_AUGMENT +#define RB_AUGMENT(x) (void)(x) +#endif + +#define RB_ROTATE_LEFT(head, elm, tmp, field) do { \ + (tmp) = RB_RIGHT(elm, field); \ + if ((RB_RIGHT(elm, field) = RB_LEFT(tmp, field)) != NULL) { \ + RB_PARENT(RB_LEFT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_LEFT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +#define RB_ROTATE_RIGHT(head, elm, tmp, field) do { \ + (tmp) = RB_LEFT(elm, field); \ + if ((RB_LEFT(elm, field) = RB_RIGHT(tmp, field)) != NULL) { \ + RB_PARENT(RB_RIGHT(tmp, field), field) = (elm); \ + } \ + RB_AUGMENT(elm); \ + if ((RB_PARENT(tmp, field) = RB_PARENT(elm, field)) != NULL) { \ + if ((elm) == RB_LEFT(RB_PARENT(elm, field), field)) \ + RB_LEFT(RB_PARENT(elm, field), field) = (tmp); \ + else \ + RB_RIGHT(RB_PARENT(elm, field), field) = (tmp); \ + } else \ + (head)->rbh_root = (tmp); \ + RB_RIGHT(tmp, field) = (elm); \ + RB_PARENT(elm, field) = (tmp); \ + RB_AUGMENT(tmp); \ + if ((RB_PARENT(tmp, field))) \ + RB_AUGMENT(RB_PARENT(tmp, field)); \ +} while (/*CONSTCOND*/ 0) + +/* Generates prototypes and inline functions */ +#define RB_PROTOTYPE(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp,) +#define RB_PROTOTYPE_STATIC(name, type, field, cmp) \ + RB_PROTOTYPE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_PROTOTYPE_INTERNAL(name, type, field, cmp, attr) \ +attr void name##_RB_INSERT_COLOR(struct name *, struct type *); \ +attr void name##_RB_REMOVE_COLOR(struct name *, struct type *, struct type *);\ +attr struct type *name##_RB_REMOVE(struct name *, struct type *); \ +attr struct type *name##_RB_INSERT(struct name *, struct type *); \ +attr struct type *name##_RB_FIND(struct name *, struct type *); \ +attr struct type *name##_RB_NFIND(struct name *, struct type *); \ +attr struct type *name##_RB_NEXT(struct type *); \ +attr struct type *name##_RB_PREV(struct type *); \ +attr struct type *name##_RB_MINMAX(struct name *, int); \ + \ + +/* Main rb operation. + * Moves node close to the key of elm to top + */ +#define RB_GENERATE(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp,) +#define RB_GENERATE_STATIC(name, type, field, cmp) \ + RB_GENERATE_INTERNAL(name, type, field, cmp, __unused static) +#define RB_GENERATE_INTERNAL(name, type, field, cmp, attr) \ +attr void \ +name##_RB_INSERT_COLOR(struct name *head, struct type *elm) \ +{ \ + struct type *parent, *gparent, *tmp; \ + while ((parent = RB_PARENT(elm, field)) != NULL && \ + RB_COLOR(parent, field) == RB_RED) { \ + gparent = RB_PARENT(parent, field); \ + if (parent == RB_LEFT(gparent, field)) { \ + tmp = RB_RIGHT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_RIGHT(parent, field) == elm) { \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_RIGHT(head, gparent, tmp, field); \ + } else { \ + tmp = RB_LEFT(gparent, field); \ + if (tmp && RB_COLOR(tmp, field) == RB_RED) { \ + RB_COLOR(tmp, field) = RB_BLACK; \ + RB_SET_BLACKRED(parent, gparent, field);\ + elm = gparent; \ + continue; \ + } \ + if (RB_LEFT(parent, field) == elm) { \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = parent; \ + parent = elm; \ + elm = tmp; \ + } \ + RB_SET_BLACKRED(parent, gparent, field); \ + RB_ROTATE_LEFT(head, gparent, tmp, field); \ + } \ + } \ + RB_COLOR(head->rbh_root, field) = RB_BLACK; \ +} \ + \ +attr void \ +name##_RB_REMOVE_COLOR(struct name *head, struct type *parent, struct type *elm) \ +{ \ + struct type *tmp; \ + while ((elm == NULL || RB_COLOR(elm, field) == RB_BLACK) && \ + elm != RB_ROOT(head)) { \ + if (RB_LEFT(parent, field) == elm) { \ + tmp = RB_RIGHT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK) {\ + struct type *oleft; \ + if ((oleft = RB_LEFT(tmp, field)) \ + != NULL) \ + RB_COLOR(oleft, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_RIGHT(head, tmp, oleft, field);\ + tmp = RB_RIGHT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_RIGHT(tmp, field)) \ + RB_COLOR(RB_RIGHT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_LEFT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } else { \ + tmp = RB_LEFT(parent, field); \ + if (RB_COLOR(tmp, field) == RB_RED) { \ + RB_SET_BLACKRED(tmp, parent, field); \ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + if ((RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) &&\ + (RB_RIGHT(tmp, field) == NULL || \ + RB_COLOR(RB_RIGHT(tmp, field), field) == RB_BLACK)) {\ + RB_COLOR(tmp, field) = RB_RED; \ + elm = parent; \ + parent = RB_PARENT(elm, field); \ + } else { \ + if (RB_LEFT(tmp, field) == NULL || \ + RB_COLOR(RB_LEFT(tmp, field), field) == RB_BLACK) {\ + struct type *oright; \ + if ((oright = RB_RIGHT(tmp, field)) \ + != NULL) \ + RB_COLOR(oright, field) = RB_BLACK;\ + RB_COLOR(tmp, field) = RB_RED; \ + RB_ROTATE_LEFT(head, tmp, oright, field);\ + tmp = RB_LEFT(parent, field); \ + } \ + RB_COLOR(tmp, field) = RB_COLOR(parent, field);\ + RB_COLOR(parent, field) = RB_BLACK; \ + if (RB_LEFT(tmp, field)) \ + RB_COLOR(RB_LEFT(tmp, field), field) = RB_BLACK;\ + RB_ROTATE_RIGHT(head, parent, tmp, field);\ + elm = RB_ROOT(head); \ + break; \ + } \ + } \ + } \ + if (elm) \ + RB_COLOR(elm, field) = RB_BLACK; \ +} \ + \ +attr struct type * \ +name##_RB_REMOVE(struct name *head, struct type *elm) \ +{ \ + struct type *child, *parent, *old = elm; \ + int color; \ + if (RB_LEFT(elm, field) == NULL) \ + child = RB_RIGHT(elm, field); \ + else if (RB_RIGHT(elm, field) == NULL) \ + child = RB_LEFT(elm, field); \ + else { \ + struct type *left; \ + elm = RB_RIGHT(elm, field); \ + while ((left = RB_LEFT(elm, field)) != NULL) \ + elm = left; \ + child = RB_RIGHT(elm, field); \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ + if (RB_PARENT(elm, field) == old) \ + parent = elm; \ + (elm)->field = (old)->field; \ + if (RB_PARENT(old, field)) { \ + if (RB_LEFT(RB_PARENT(old, field), field) == old)\ + RB_LEFT(RB_PARENT(old, field), field) = elm;\ + else \ + RB_RIGHT(RB_PARENT(old, field), field) = elm;\ + RB_AUGMENT(RB_PARENT(old, field)); \ + } else \ + RB_ROOT(head) = elm; \ + RB_PARENT(RB_LEFT(old, field), field) = elm; \ + if (RB_RIGHT(old, field)) \ + RB_PARENT(RB_RIGHT(old, field), field) = elm; \ + if (parent) { \ + left = parent; \ + do { \ + RB_AUGMENT(left); \ + } while ((left = RB_PARENT(left, field)) != NULL); \ + } \ + goto color; \ + } \ + parent = RB_PARENT(elm, field); \ + color = RB_COLOR(elm, field); \ + if (child) \ + RB_PARENT(child, field) = parent; \ + if (parent) { \ + if (RB_LEFT(parent, field) == elm) \ + RB_LEFT(parent, field) = child; \ + else \ + RB_RIGHT(parent, field) = child; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = child; \ +color: \ + if (color == RB_BLACK) \ + name##_RB_REMOVE_COLOR(head, parent, child); \ + return (old); \ +} \ + \ +/* Inserts a node into the RB tree */ \ +attr struct type * \ +name##_RB_INSERT(struct name *head, struct type *elm) \ +{ \ + struct type *tmp; \ + struct type *parent = NULL; \ + int comp = 0; \ + tmp = RB_ROOT(head); \ + while (tmp) { \ + parent = tmp; \ + comp = (cmp)(elm, parent); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + RB_SET(elm, parent, field); \ + if (parent != NULL) { \ + if (comp < 0) \ + RB_LEFT(parent, field) = elm; \ + else \ + RB_RIGHT(parent, field) = elm; \ + RB_AUGMENT(parent); \ + } else \ + RB_ROOT(head) = elm; \ + name##_RB_INSERT_COLOR(head, elm); \ + return (NULL); \ +} \ + \ +/* Finds the node with the same key as elm */ \ +attr struct type * \ +name##_RB_FIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) \ + tmp = RB_LEFT(tmp, field); \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (NULL); \ +} \ + \ +/* Finds the first node greater than or equal to the search key */ \ +attr struct type * \ +name##_RB_NFIND(struct name *head, struct type *elm) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *res = NULL; \ + int comp; \ + while (tmp) { \ + comp = cmp(elm, tmp); \ + if (comp < 0) { \ + res = tmp; \ + tmp = RB_LEFT(tmp, field); \ + } \ + else if (comp > 0) \ + tmp = RB_RIGHT(tmp, field); \ + else \ + return (tmp); \ + } \ + return (res); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_NEXT(struct type *elm) \ +{ \ + if (RB_RIGHT(elm, field)) { \ + elm = RB_RIGHT(elm, field); \ + while (RB_LEFT(elm, field)) \ + elm = RB_LEFT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +/* ARGSUSED */ \ +attr struct type * \ +name##_RB_PREV(struct type *elm) \ +{ \ + if (RB_LEFT(elm, field)) { \ + elm = RB_LEFT(elm, field); \ + while (RB_RIGHT(elm, field)) \ + elm = RB_RIGHT(elm, field); \ + } else { \ + if (RB_PARENT(elm, field) && \ + (elm == RB_RIGHT(RB_PARENT(elm, field), field))) \ + elm = RB_PARENT(elm, field); \ + else { \ + while (RB_PARENT(elm, field) && \ + (elm == RB_LEFT(RB_PARENT(elm, field), field)))\ + elm = RB_PARENT(elm, field); \ + elm = RB_PARENT(elm, field); \ + } \ + } \ + return (elm); \ +} \ + \ +attr struct type * \ +name##_RB_MINMAX(struct name *head, int val) \ +{ \ + struct type *tmp = RB_ROOT(head); \ + struct type *parent = NULL; \ + while (tmp) { \ + parent = tmp; \ + if (val < 0) \ + tmp = RB_LEFT(tmp, field); \ + else \ + tmp = RB_RIGHT(tmp, field); \ + } \ + return (parent); \ +} + +#define RB_NEGINF -1 +#define RB_INF 1 + +#define RB_INSERT(name, x, y) name##_RB_INSERT(x, y) +#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) +#define RB_FIND(name, x, y) name##_RB_FIND(x, y) +#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) +#define RB_NEXT(name, x, y) name##_RB_NEXT(y) +#define RB_PREV(name, x, y) name##_RB_PREV(y) +#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) +#define RB_MAX(name, x) name##_RB_MINMAX(x, RB_INF) + +#define RB_FOREACH(x, name, head) \ + for ((x) = RB_MIN(name, head); \ + (x) != NULL; \ + (x) = name##_RB_NEXT(x)) + +#define RB_FOREACH_REVERSE(x, name, head) \ + for ((x) = RB_MAX(name, head); \ + (x) != NULL; \ + (x) = name##_RB_PREV(x)) + +#endif /* _SYS_TREE_H_ */ diff --git a/include/ucore_backtrace.h b/include/ucore_backtrace.h new file mode 100644 index 0000000..7de6b72 --- /dev/null +++ b/include/ucore_backtrace.h @@ -0,0 +1,8 @@ +#ifndef UC_BACKTRACE_H_ +#define UC_BACKTRACE_H_ + +#define UC_BACTRACE_STDERR uc_backtrace_fd(3) + +void uc_backtrace_fd(int fd); + +#endif diff --git a/include/ucore_bitvec.h b/include/ucore_bitvec.h new file mode 100644 index 0000000..7a88f30 --- /dev/null +++ b/include/ucore_bitvec.h @@ -0,0 +1,81 @@ +#ifndef BITEVEC_H_ +#define BITEVEC_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +struct bitvec { + //storage for the bits + unsigned long *vec; + //length of the above vec. (Not the number of bits !) + size_t vec_len; +}; + +/** + * Evaluates the length required for a bitvec to store nbit bits. + */ +#define BITVEC_VEC_LEN(nbits) ((nbits/(sizeof(unsigned long)*CHAR_BIT)) + (nbits % (sizeof(unsigned long)*CHAR_BIT) == 0 ? 0 : 1)) + +/** + * Use as : + * unsigned long v[10]; + * struct bitvec v = BITVEC_STATIC_INIT(v); + */ +#define BITVEC_STATIC_INIT(vec_data)\ +{\ +vec_data,\ +sizeof vec_data/sizeof vec_data[0]} + + +/** + * Returns a newly malloced bitvec, capable of storing at least nbits bits + * All bits are initially zero. + * + */ +struct bitvec *bitvec_new(size_t nbits); + +/** free a bitvec previously allocated by bitvec_new + */ +void bitvec_free(struct bitvec *v); + +//Note that accessing a bit beyond the nbits originally initialized +//for the given bitvec is undedefined + +/** Sets bit no. b */ +void set_bit(struct bitvec *v,int b); + +/** Clears bit no. b*/ +void clear_bit(struct bitvec *v,int b); + +/** Gets the current value (0 or 1) of bit no. b*/ +int get_bit(const struct bitvec *v,int b); + +/** Sets all bits to zero */ +void clear_all(struct bitvec *v); + +/** Sets all bits to one */ +void set_all(struct bitvec *v); + +/** Initialize bits from a array of ints, each array element maps to one bit. + * The bits are initialized from the int array so zero maps to zero and non-zero maps to one. + * e..g to set the 5 first bits, to 01110: + * int a[] = {0,1,1,1,0}; + * set_bits_from_array(v,a,5); + * */ +void set_bits_from_array(struct bitvec *v,char *array,size_t array_len); + +// The _s ("secure") versions does boundary checking and assert() if they +// try to access a bit out of bounds. + +void set_bit_s(struct bitvec *v,int b); + +void clear_bit_s(struct bitvec *v,int b); + +int get_bit_s(const struct bitvec *v,int b); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ucore_buffer.h b/include/ucore_buffer.h new file mode 100644 index 0000000..0af5a58 --- /dev/null +++ b/include/ucore_buffer.h @@ -0,0 +1,83 @@ +#ifndef UCORE_BUFFER_H_ +#define UCORE_BUFFER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + +/** A GBuf is a growing reference counted buffer. + * The buffer is dynamically allocated, and can grow + * as you append data to it. Reference counting takes care + * of automatically freeing the GBuf and its buffer when it + * reaches 0 + */ +typedef struct GBuf GBuf; +struct GBuf { + /** Allocated buffer length.*/ + size_t len; + /** Used space in the buffer */ + size_t used; + /** Reference count */ + size_t ref_cnt; + /** The data */ + void *buf; +}; + +/** Allocatea new GBuf. + * + * @param initsz Intial capacity of the GBuf + * @return New GBuf, or NULL if allocation fails, + * The returned GBuf will have ref_cnt=1 + */ +GBuf* uc_new_gbuf(size_t initsz); + +/** Increment the reference count of the GBuf. + * + * @param buf Bufffer + */ +void uc_gbuf_ref(GBuf *buf); + +/** Decrement the reference count of the GBuf, free it if ref_cnt reaches 0 + * + * @param buf Bufffer + */ +void uc_gbuf_unref(GBuf *buf); + +/** Append data to the GBuf. + * Data is coped into the buffer, starting at &buf->data[used] + * The GBuf automatically grows if needed. + * + * @param buf buffer to append to + * @param data data to copy to the GBuf + * @param len length of @data to copy + * @return 0 on success, -1 on failure when allocation fails if he buffer + * needs to grow + */ +int uc_gbuf_append(GBuf *buf,void *data,size_t len); + +/** Expand the capacity of the GBuf. + * + * @param buf buffer to grow + * @return 0 on success, -1 on failure when allocation fails + */ +int uc_gbuf_grow(GBuf *buf, size_t addlen); + +/** Remaining unised space of the GBuf. + * @param buff buffer + * @return length of unused space + */ +size_t uc_gbuf_remaining(const GBuf *buf) +{ + return buf->len - buf->used; +} + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/include/ucore_hash.h b/include/ucore_hash.h new file mode 100644 index 0000000..6c0c3d0 --- /dev/null +++ b/include/ucore_hash.h @@ -0,0 +1,39 @@ +#ifndef UCORE_HASH_H_ +#define UCORE_HASH_H_ +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t +uc_crc32(const uint8_t *buf, size_t len); + +uint32_t +uc_djbhash(const char *str); + +unsigned int +uc_elfhash(const char *str, unsigned int len); + +uint64_t +uc_hash64shift(uint64_t key); + +uint32_t +uc_hashuint(uint32_t a); + +uint32_t +uc_murmurmash2(const void *key, int len, uint32_t seed ); + +uint32_t +uc_pjwhash(const char *str,size_t len); + +uint32_t +uc_sax_hash(void *key, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/ucore_heapsort.h b/include/ucore_heapsort.h new file mode 100644 index 0000000..2391e84 --- /dev/null +++ b/include/ucore_heapsort.h @@ -0,0 +1,21 @@ +#ifndef UCORE_HEAPSORT_H_ +#define UCORE_HEAPSORT_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +///compare function. Needs only to return < 0 if +//the first element is less than the second +typedef int (*uc_hs_cmp)(const void *, const void *); + +void +uc_heapsort(void *base, size_t count, size_t width, + uc_hs_cmp cmp); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ucore_logging.h b/include/ucore_logging.h new file mode 100644 index 0000000..81d41d3 --- /dev/null +++ b/include/ucore_logging.h @@ -0,0 +1,252 @@ +#ifndef UCORE_LOGGING_H_ +#define UCORE_LOGGING_H_ + +/** Logging functions. + * All logging functions except uc_log_init are thread safe, + * so logging can be performed from any thread after the logging + * system have been initialized. + * + * The logging system has the concept of 'modules'. Modules are defined + * by the application, and would match the logical parts of an application. + * uc_log_init() tells the logging library about these modules, and would normally + * be used like: + * + * enum { + * POLLER, + * DB, + * IO + *}; + * + * struct uc_log_module modules[] = { + * { + * .id = POLLER, + * .short_name = "POLLER", + * .long_name = "Poller thread", + * .log_level = UC_LL_DEBUG, + * }, + * { + * .id = DB, + * .short_name = "DB", + * .long_name = "Database handler", + * .log_level == UC_LL_DEBUG + * }, + * { + * .id = IO, + * .short_name = "IO", + * .long_name = "I/O worker", + * .log_level == UC_LL_DEBUG + * } + * }; + * struct uc_log_modules m = { + * .mods = modules, + * .cnt = ARRAY_SIZE(modules) + * }; + * + * uc_log_init(&m); + * + * So the application defines 3 modules logging + * will be categorized by. + * Note that the values (the enum in this case) + * defining all the .id memmbers of uc_log_module + * must start at 0 and be concecutive. + * + * Now, the database code in the application can do + * logging as e.g. + * + * UC_LOGF(UC_LL_INFO, DB, "connecting to server %s\n", ip); + * + * And the resulting log line will include the short_name + * modules[DB].short_name + * + */ + +#ifdef __cplusplus +extern "C" { +#endif + +/** The log levels defined by ucore logging*/ +enum UC_LOG_LEVEL { + UC_LL_NONE = 0, + UC_LL_DEBUG = 1, + UC_LL_INFO = 3, + UC_LL_WARNING = 5, + UC_LL_ERROR = 7, +}; + +/** A destination for the logging messages*/ +enum UC_LOG_DESTINATION { + /** Logs using the unix syslog system */ + UC_LDEST_SYSLOG, + + /** Prints log messages to stderr. */ + UC_LDEST_STDERR, + + /** Prints log messages to a file */ + UC_LDEST_FILE, +}; + +/** A module of a program, that will perform logging. + * This is used group logging from parts of a larger program, + * and allow the log message to identigy which module the + * log message originates from + */ +struct uc_log_module { + /** The id of the log module. + * This is the id one specifies in the various log + * functions/macros*/ + int id; + + /** A short name for the module. + * This will appear in log messages */ + const char *short_name; + /** A longer description for the log module*/ + const char *long_name; + /** The log level of this module. Only + * log statements with a level >= the log_level + * are actually logged */ + int log_level; +}; + +/* A collection of struct uc_log_module */ +struct uc_log_modules { + /* Pointer to the first element of the array */ + struct uc_log_module *mods; + /** The number of elements in the mods array. */ + int cnt; +}; + +struct uc_log_destination; + + +/* Returns a string representation of the log level. + * + * @param ll The log level + * @return String representation of the log level. (This will be a string literal) + */ +const char *uc_ll_2_str(enum UC_LOG_LEVEL l); + +/* creates a new uc_log_destination for printing on stderr. + * + * @param log_level log level of this destination. only log messages + * with a log level >= the log level of the destination are actually logged. + * @param log_location whether to log info about the source file and line number + * in a log message. + * + * @return An opaque uc_log_destination that can be added as a destination to + * the ucore logging system + */ +struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location); + +/* creates a new uc_log_destination for logging to syslog + * + * @param ident The ident as used in the syslog openlog() funcion + * @param facility The facility as used in the syslog openlog() function() + * @param log_level log level of this destination. only log messages + * with a log level >= the log level of the destination are actually logged. + * @param log_location whether to log info about the source file and line number + * in a log message. + * @return An opaque uc_log_destination that can be added as a destination to + * the ucore logging system + */ +struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location); + +/* creates a new uc_log_destination for printing on stderr. + * + * @param log_level log level of this destination. only log messages + * with a log level >= the log level of the destination are actually logged. + * @param log_location whether to log info about the source file and line number + * in a log message. + * @param return An opaque uc_log_destination that can be added as a destination to + * the ucore logging system + */ +struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location); + + /** Add a uc_log_destination to the logging system. + * + * @param dest The uc_log_destination to add. + */ +void uc_log_add_destination(struct uc_log_destination *dest); + +/** Remove a log destination. + * Note that this does not free the destination, it can be readded later. + * For file destination, the log file is NOT closed. + * + * @param dest The uc_log_destination to remove. + */ +void uc_log_remove_destination(struct uc_log_destination *dest); + +/** Remove and free a destination. + * This frees the memory allocated to the destination. For + * UC_LDEST_FILE the log file is closed. + * + * If the destination is not already removed, it will be removed first, + * there's no need to call uc_log_remove_destination first. + * The destination cannot be used again after this function has been called. + * + * @param dest The destination to delete. + */ +void uc_log_delete_destination(struct uc_log_destination *dest); + +/** Change the log level of a module. + * + * @param module The module to change, matched against the id member of a struct uc_log_module + * @param level The log level for this module + * + * @return 0 on success, non-zero if the module was not found. + */ +int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level); + +/** Closes and re-opens all the UC_LDEST_FILE log destinations. + * Intended for use when a log file is rotated externally. + * + * @param return 0 on success, non-zero if an error occured when re-opening a file. + */ +int uc_log_reopen_files(void); + +/** Init the logging system. This function must be called before performing any other + * logging action. + * + * @param user_struct containing an array of all the modules defined by the application. + */ +void uc_log_init(struct uc_log_modules *user_modules); + +void uc_logf(int log_level, int module, int raw, + const char *file, int line, const char *fmt, ...) + __attribute__((format(printf, 6, 7))); + +#ifdef DEBUG +# define UC_DEBUGF(mod, fmt, ...)\ + uc_logf(UC_LL_DEBUG, mod,0 , __FILE__, __LINE__, fmt, ## __VA_ARGS__) +# define UC_DEBUGFR(mod, fmt, ...)\ + uc_logf(UC_LL_DEBUG, mod,1 , , __LINE__, fmt, ## __VA_ARGS__) +#else +# define UC_DEBUGF(mod, fmt, ...) +# define UC_DEBUGFR(mod, fmt, ...) +#endif + +/** Main macro that should be used for logging. + * + * For log messages with UC_LL_DEBUG, the UC_DEBUGF() macro can be used, + * UC_DEBUGF will only be compiled in if the DEBUG macro is defined + * + * @param lvl log level of this log message + * @param mod module id of this log messagex. + * @param fmt printf style format string + * @param ... printf style arguments + */ +#define UC_LOGF(lvl, mod, fmt, ...) \ + uc_logf(lvl, mod, 0, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + + +/** Raw logging ,Like UC_LOGF, but only prints the supplied + * data, not timestamp, log level etc. + */ +#define UC_LOGFR(lvl, mod, fmt, ...) \ + uc_logf(lvl, mod, 1, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/include/ucore_math.h b/include/ucore_math.h new file mode 100644 index 0000000..8af110a --- /dev/null +++ b/include/ucore_math.h @@ -0,0 +1,39 @@ +#ifndef UCORE_MATH_H_ +#define UCORE_MATH_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint32_t +uc_gcd_32(uint32_t a, uint32_t b); + +uint64_t +uc_gcd_64(uint64_t a, uint64_t b); + +uint32_t +uc_phi_32(uint32_t N); + +uint64_t +uc_phi_64(uint64_t N); + +static inline uint32_t +uc_nextpow2(uint32_t x) +{ + x--; + x |= x >> 1; + x |= x >> 2; + x |= x >> 4; + x |= x >> 8; + x |= x >> 16; + x++; + + return x; +} + +#ifdef __cplusplus +} +#endif +#endif diff --git a/include/ucore_mersenne_twister.h b/include/ucore_mersenne_twister.h new file mode 100644 index 0000000..1ff4e6f --- /dev/null +++ b/include/ucore_mersenne_twister.h @@ -0,0 +1,27 @@ +#ifndef UCORE_MERSENNE_TWISTER_H +#define UCORE_MERSENNE_TWISTER_H + + +/** Context used for the PRNG*/ +#define MT_RAND_N 624 +typedef struct { + unsigned int x[MT_RAND_N]; + int i; +} MTRand; + +/** Initialize a Mersenne Twister PRNG context. + * @param seed Starter seed for the PRNG + * @param r context for the PRNG + */ +void mtsrand(int seed, MTRand *r); + +/** Generate a new random number. + * Generated range is 0 to UINT_MAX + * + * @param r context for the PRNG + * @return A pseudo random number + */ +unsigned int mtrand(MTRand *r); + +#endif + diff --git a/include/ucore_pack.h b/include/ucore_pack.h new file mode 100644 index 0000000..ed36852 --- /dev/null +++ b/include/ucore_pack.h @@ -0,0 +1,257 @@ +#ifndef UCORE_PACK_H_ +#define UCORE_PACK_H_ + +#include +#ifdef __GNUC__ +# define UC_INLINE inline __attribute__((always_inline)) +#else +# define UC_INLINE inline +#endif + +/** Functions for serializing/de-serializing integers to and from + * byte arrays. + * These functions are independant of the host endian. Only + * thing to care about is the endian format of the data in + * the byte array. + */ + + +/** Serialize a uint16_t to a byte array in little endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 2. + */ +static UC_INLINE void uc_pack_16_le(uint16_t v, uint8_t *r) +{ + r[0] = v; + r[1] = v >> 8; +} + +/** De-serialize a uint16_t from a byte array in little endian format. + * @param r The byte array to containing the integer in. Must be at least of size 2. + * @param return The deserialized integer from the byte array. + */ +static UC_INLINE uint16_t uc_unpack_16_le(const uint8_t *r) +{ + uint32_t v; + + v = r[0]; + v |= r[1] << 8; + + return v; +} + +/** Serialize a uint32_t to a 3 byte(24 bits) array in little endian format. + * Only the bottom 24 bits of the uint32_t are used. + * + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 3. + */ +static UC_INLINE void uc_pack_24_le(uint32_t v, uint8_t *r) +{ + r[0] = v; + r[1] = v >> 8; + r[2] = v >> 16; +} + +/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in little endian format. + * @param r The byte array to containing the integer in. Must be at least of size 3. + * @param return The deserialized integer from the byte array. + */ +static UC_INLINE uint32_t uc_unpack_24_le(const uint8_t *r) +{ + uint32_t v; + + v = r[0]; + v |= r[1] << 8; + v |= r[2] << 16; + + return v; +} + +/** Serialize a uint32_t to a byte array in little endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 4. + */ +static UC_INLINE void uc_pack_32_le(uint32_t v, uint8_t *r) +{ + r[0] = v; + r[1] = v >> 8; + r[2] = v >> 16; + r[3] = v >> 24; +} + +/** De-serialize a uint32_t from a byte array in little endian format. + * @param r The byte array to containing the integer in. Must be at least of size 4. + * @param return The deserialized integer from the byte array. + */ +static UC_INLINE uint32_t uc_unpack_32_le(const uint8_t *r) +{ + uint32_t v; + + v = r[0]; + v |= r[1] << 8; + v |= r[2] << 16; + v |= r[3] << 24; + + return v; +} + +/** Serialize a uint64_t to a byte array in little endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 8 + */ +static UC_INLINE void uc_pack_64_le(uint64_t v, uint8_t *r) +{ + r[0] = v; + r[1] = v >> 8; + r[2] = v >> 16; + r[3] = v >> 24; + r[4] = v >> 32ULL; + r[5] = v >> 40ULL; + r[6] = v >> 48ULL; + r[7] = v >> 56ULL; +} + +/** De-serialize a uint64_t from a byte array in little endian format. + * @param r The byte array to containing the integer in. Must be at least of size 8. + * @param return The deserialized integer from the byte array + */ +static UC_INLINE uint64_t uc_unpack_64_le(const uint8_t *r) +{ + uint64_t v; + + v = r[0]; + v |= r[1] << 8; + v |= r[2] << 16; + v |= (uint32_t)r[3] << 24; + v |= (uint64_t)r[4] << 32ULL; + v |= (uint64_t)r[5] << 40ULL; + v |= (uint64_t)r[6] << 48ULL; + v |= (uint64_t)r[7] << 56ULL; + + return v; +} + +/** Serialize a uint16_t to a byte array in big endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 2. + */ +static UC_INLINE void uc_pack_16_be(uint32_t v, uint8_t *r) +{ + r[0] = v >> 8; + r[1] = v; +} + +/** De-serialize a uint16_t from a byte array in big endian format. + * @param r The byte array to containing the integer in. Must be at least of size 2. + * @param return The deserialized integer from the byte array + */ +static UC_INLINE uint16_t uc_unpack_16_be(const uint8_t *r) +{ + uint16_t v; + + v = r[0] << 8; + v |= r[1]; + + return v; +} + +/** Serialize a uint32_t to a 3 byte(24 bits) array in big endian format. + * Only the bottom 24 bits of the uint32_t are used. + * + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 3. + */ +static UC_INLINE void uc_pack_24_be(uint32_t v, uint8_t *r) +{ + r[0] = v >> 16; + r[1] = v >> 8; + r[2] = v; +} + +/** De-serialize a uint32_t from a 3 byte (24 bit) byte array in big endian format. + * @param r The byte array to containing the integer in. Must be at least of size 3. + * @param return The deserialized integer from the byte array. + */ +static UC_INLINE uint32_t uc_unpack_24_be(const uint8_t *r) +{ + uint32_t v; + + v = r[0] << 16; + v |= r[1] << 8; + v |= r[2]; + + return v; +} + +/** Serialize a uint32_t to a byte array in big endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 4. + */ +static UC_INLINE void uc_pack_32_be(uint32_t v, uint8_t *r) +{ + r[0] = v >> 24; + r[1] = v >> 16; + r[2] = v >> 8; + r[3] = v; +} + +/** De-serialize a uint32_t from a byte array in big endian format. + * @param r The byte array to containing the integer in. Must be at least of size 4. + * @param return The deserialized integer from the byte array + */ +static UC_INLINE uint32_t uc_unpack_32_be(const uint8_t *r) +{ + uint32_t v; + + v = r[0] << 24; + v |= r[1] << 16; + v |= r[2] << 8; + v |= r[3]; + + return v; +} + +/** Serialize a uint16_t to a byte array in big endian format. + * @param v The value to serialize + * @param r The byte array to place the integer in. Must be at least of size 8 + */ +static UC_INLINE void uc_pack_64_be(uint64_t v, uint8_t *r) +{ + r[0] = v >> 56ULL; + r[1] = v >> 48ULL; + r[2] = v >> 40ULL; + r[3] = v >> 32ULL; + r[4] = v >> 24; + r[5] = v >> 16; + r[6] = v >> 8; + r[7] = v; +} + +/** De-serialize a uint64_t from a byte array in big endian format. + * @param r The byte array to containing the integer in. Must be at least of size 4. + * @param return The deserialized integer from the byte array + */ +static UC_INLINE uint64_t uc_unpack_64_be(const uint8_t *r) +{ + uint64_t v; + + v = (uint64_t)r[0] << 56ULL; + v |= (uint64_t)r[1] << 48ULL; + v |= (uint64_t)r[2] << 40ULL; + v |= (uint64_t)r[3] << 32ULL; + v |= (uint32_t)r[4] << 24; + v |= r[5] << 16; + v |= r[6] << 8; + v |= r[7]; + + return v; +} + + + +#undef UC_INLINE + + +#endif + diff --git a/include/ucore_rbtree.h b/include/ucore_rbtree.h new file mode 100644 index 0000000..57aaccd --- /dev/null +++ b/include/ucore_rbtree.h @@ -0,0 +1,42 @@ +#ifndef RBTREE_H_ +#define RBTREE_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum RBColor RBColor; +enum RBColor { + Red, + Black +}; + +typedef struct RBNode RBNode; +struct RBNode { + unsigned char color; //Red/Black + RBNode *parent; + RBNode *right; + RBNode *left; + void *data; +}; + +typedef struct RBTree RBTree; +struct RBTree { + RBNode *node; + int (*compare)(const void *a, const void *b); +}; + +void uc_rb_remove(RBTree *root, RBNode *node); +RBNode *uc_rb_find(RBTree *root, const void *val); +RBNode *uc_rb_insert(RBTree *root, RBNode *child); +RBNode *uc_rb_first(const RBTree *root); +RBNode *uc_rb_next(RBNode *node); +RBNode *uc_rb_last(const RBTree *root); + +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/ucore_read_file.h b/include/ucore_read_file.h new file mode 100644 index 0000000..e86cc9e --- /dev/null +++ b/include/ucore_read_file.h @@ -0,0 +1,20 @@ +#ifndef UCORE_READ_FILE_H_ +#define UCORE_READ_FILE_H_y + +#include + +/** 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 + * is binary or text. The returned length does not include this nul byte. + * + * @param file_name name of the file + * @param length Returned length of the content read + * @param max Fail if the read content length is greater than max. + * @return The content read from the file, or NULL if something failed + * (inspect errno to see why it failed) + */ +char * +uc_read_file(const char *file_name, size_t *length, size_t max); + +#endif diff --git a/include/ucore_salloc.h b/include/ucore_salloc.h new file mode 100644 index 0000000..f9a00f6 --- /dev/null +++ b/include/ucore_salloc.h @@ -0,0 +1,70 @@ +#ifndef SALLOC_H_ +#define SALLOC_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** Sequntial memory allocator + * + * Allocates bigger chunks of memory at a time, to save the amount of malloc call, + * and enables you to free all that memory in one sweep. + * + * This means that once allocated, a piece of memory obtained from the + * allocator cannot be free'd individually, only the entire SAlloc can be free'd. + * + * Memory is allocated using the underlying malloc() in chunk sizes. + * Once a particular SAlloc has given out all memory in a chunk, a new chunk + * is allocated again, using the underlying malloc(). + * + */ + +/** Opaque handle to a SAlloc */ +typedef struct SAlloc SAlloc; + +/** Create a new SAlloc with the given size for each chunk. + * e.g. uc_new_salloc(sizeof(struct Foo) * 1000); will immedeatly + * allocate memory to hold 1000 struct Foo's. Once all that memory is + * handed out from this SAlloc, another piece of memory is allocaterd + * for another 1000 struct Foo's.. All these memory pieces are released + * when the uc_free_salloc() is called. + * + * @param chunksz Size of each piece of memory block allocated. + * @return A new handle for a SAlloc, or NULL. + */ +SAlloc *uc_new_salloc(size_t chunksz); + +/** Allocate memory from a SAlloc. + * @param sz size of the memory. This must be <= the chunksz the SAlloc was + * created with. + * @return The new memory, or NULL if sz > chunksz or an underlying + * malloc call fails. + */ +void * uc_s_alloc(SAlloc *p,size_t sz); + +/** Just like uc_s_alloc, but zero out the memory before returning it. + */ +void * uc_s_allocz(SAlloc *p,size_t sz); +/** Free the SAlloc and all memory associated with this SAlloc. + * The SAlloc is not usable any more after this call. + * + * @param p The SAlloc to free. + */ +void uc_free_salloc(SAlloc *p); + +/** Reset this SAlloc, effectivly releasing all the memory obtained. + * The SAlloc is still usable after this call. + * The actual memory previously allocated from this SAlloc is cached, + * and will be reused by subsequent uc_s_alloc calls. + * + * @param p The SAlloc to reset. + */ +void uc_reset_salloc(SAlloc *p); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/include/ucore_seq.h b/include/ucore_seq.h new file mode 100644 index 0000000..b53340a --- /dev/null +++ b/include/ucore_seq.h @@ -0,0 +1,21 @@ +#ifndef SEQ_H_ +#define SEQ_H_ +#include + +// Check if a is before b, taking care of wrap arounds +static inline int seq_before(uint32_t a, uint32_t b) +{ + return (int32_t)(a - b) < 0; +} + +// check if a is before b, taking care of wrap arounds +#define seq_after(a, b) before(b, a) + +//check if a is between b or c +static inline int seqbetween(uint32_t a, uint32_t b, uint32_t c) +{ + return c - b >= a - b; +} + + +#endif diff --git a/include/ucore_string.h b/include/ucore_string.h new file mode 100644 index 0000000..56eaf73 --- /dev/null +++ b/include/ucore_string.h @@ -0,0 +1,60 @@ +#ifndef UCORE_STRING_H_ +#define UCORE_STRING_H_ + +#include +#include + +#ifdef __cplusplus +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); +uint8_t* +uc_hex_decode(const char *in, size_t maxlen,uint8_t *out); +char* +uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim); + +void +uc_str_tolower(char *s); +void +uc_str_toupper(char *s); + +#define UC_BCD_LEN(ascii_len) ((ascii_len) / 2 + ((ascii_len) % 2)) +#define UC_ASCII_LEN(bcd_len) ((bcd_len) * 2 + 1) + +size_t +uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler); +size_t +uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout); + +char* +uc_sprintb(char *result, unsigned int value); +char* +uc_sprintbc(char *result, unsigned char value); +char* +uc_sprintbll(char *result, unsigned long long value); +char* +uc_sprintbs(char *result, unsigned short value); + +int +getfields(char *str, char **args, int max, int mflag, const char *set); + +//ocnvert bytes to a human representable test, (i.e. 12kB, 160 MB 1.78 GB etc. +///result should be at least of size 12, +///returns the result argument +char * +uc_human_bytesz(uint64_t bytes, char *result, size_t result_len); +#ifdef __cplusplus +} +#endif + + +#endif + diff --git a/include/ucore_threadqueue.h b/include/ucore_threadqueue.h new file mode 100644 index 0000000..a6cfe4c --- /dev/null +++ b/include/ucore_threadqueue.h @@ -0,0 +1,248 @@ +#ifndef _THREADQUEUE_H_ +#define _THREADQUEUE_H_ 1 + +#include + +#ifdef __cplusplus +extern "C" { +#endif +/** + * @defgroup ThreadQueue ThreadQueue + * @{ + * + * Little API for waitable queues, typically used for passing messages + * between threads. + * + * @author Nils O. Selåsdal + */ + + +/** + * A thread message used to add and retrieve messages + * from in a queue. + * An application must not touch this struct + * when a message is present (i.e. it has been added + * to a queue, but not retrieved yet) in a queue. + * + */ +struct uc_threadmsg{ + /** + * A message type the application can use to + * discriminate different messages. + * A negative value will cause a uc_threadmsg to + * be added to the head of a queue. + */ + long msgtype; + + /** + * Internal pointer used by the uc_thread_queue. + * Applications must not use this member. + */ + struct uc_threadmsg *next; +}; + +/** + * Callback function for the walk and destroy functions. + */ +typedef void (*uc_thread_queue_walk_func) (struct uc_threadmsg *msg); + + +/** + * A ThreadQueue + * + * + * You should threat this struct as opaque never ever access any of + * the variables in this struct. + * You have been warned. + * + * The uc_thread_queue_ functions only deal with struct uc_threadmsg + * structs. + * In order for the message passing to be useful, more data needs to be + * associated with a message, it's up to the application to manage this. + * One way is to e.g. add the struct uc_threadmsg as the first member + * of a larger struct, and recover the larger struct after getting a + * struct uc_threadmsg out of the queue. e.g. + * + * @code + * struct my_msg { + * struct uc_threadmsg tmsg; + * int foo; + * char bar[32]; + * }; + * + * struct my_msg *msg = malloc(sizeof *msg); + * msg->tmsg.msgtype = MSGTYP1; + * ... + * uc_thread_queue_add(queue, &msg->tmsg); + * + * The receiver end does e.g. + * + * struct uc_threadmsg *tmsg; + * uc_thread_queue_get(queue, NULL, &tmsg); + * switch(tmsg->msgtype) { + * case MYMSG1; { + * struct my_msg *msg = (struct my_msg*)tmsg; + * ... + * free(msg); + * break + * ... + * } + * } + * + * @endcode + * + * + * + * + */ +struct uc_threadqueue { +/** + * Number of elements in the queue. + * Use #threadqueue_length to read it. + */ + long num_elements; + +/** Max number of elements this queue will hold */ + long max_elements; +/** + * Mutex for the queue. + */ + pthread_mutex_t mutex; +/** + * Condition variable for readers on the queue. + */ + pthread_cond_t read_cond; +/** + * Condition variable for writers on the queue (if the queue is full). + */ + pthread_cond_t write_cond; +/** + * Number of threads blocking on writing to the queue + */ + long num_read_waiters; +/** + * Number of threads blocking on reading from the queue + */ + long num_write_waiters; + +/** + * Internal pointers for the messages in the queue. + */ + struct uc_threadmsg *first,**last; +}; + +/** + * Initializes a queue. + * + * thread_queue_init initializes a new threadqueue. A new queue must always + * be initialized before it is used. + * A max number of elements the queue will hold must be given. + * Adding more elements than a queue will hold will e.g. cause + * uc_thread_queue_add to block until space becomes available. + * + * @param queue Pointer to the queue that should be initialized + * @param max_elements Max number of elements this queue can hold. + * + * @return 0 on success EINVAL if queue is NULL or max_elements <= 0, or + * another errno value if pthread_ functions fails + */ +int uc_thread_queue_init(struct uc_threadqueue *queue, long max_elements); + +/** + * Adds a message to a queue + * + * thread_queue_add adds a "message" to the specified queue. + * It is up to the application to manage the data and memory indicated by the + * struct uc_threadmsg. + * The struct uc_threadmsg is assumed to be an intrusive pointer, + * e.g. it can be the first member of a larger struct actually containing the + * data to be passed over. + * + * Nothing is copied so the application must keep track on (de)allocation of the pointers. + * A message type can also be also specified, to e.g. help discriminate + * messages when messages are received. + * + * If the message_type member of @msg is negative, the message is added to + * the front of the queue, i.e. it can be considered a "priority" message. + * + * @param queue Pointer to the queue on where the message should be added. + * @param data the "message". + * @return 0 on succes ENOMEM if out of memory EINVAL if queue is NULL, or other + * errno values if pthread functions failed. + */ +int uc_thread_queue_add(struct uc_threadqueue *queue, struct uc_threadmsg *msg); + +/** + * Gets a message from a queue + * + * thread_queue_get gets a message from the specified queue, it will block + * the caling thread untill a message arrives, or the (optional) timeout occurs. + * If timeout is NULL, there will be no timeout, and thread_queue_get will wait + * untill a message arrives. + * + * struct timespec is defined as: + * @code + * struct timespec { + * long tv_sec; // seconds + * long tv_nsec; // nanoseconds + * }; + * @endcode + * + * @param queue Pointer to the queue to wait on for a message. + * @param timeout timeout on how long to wait on a message, or NULL for no timeout + * @param msg pointer where the uc_threadmsg* is stored + * + * @return 0 on success EINVAL if queue is NULL ETIMEDOUT if timeout occurs + */ +int uc_thread_queue_get(struct uc_threadqueue *queue, const struct timespec *timeout, struct uc_threadmsg **msg); + + +/** + * Gets the length of a queue + * + * threadqueue_length returns the number of messages waiting in the queue + * + * @param queue Pointer to the queue for which to get the length + * @return the length(number of pending messages) in the queue + */ +long uc_thread_queue_length( struct uc_threadqueue *queue ); + +/** + * Destroy the queue. + * + * If free_func is != NULL, free_func will be called for every item, allowing you to free + * the item. + * You cannot call this if there are someone currently adding or getting messages + * from the queue. + * After a queue have been cleaned, it cannot be used again untill #thread_queue_init + * has been called on the queue. + * + * @param queue Pointer to the queue that should be cleaned + * @param free_func pointer to function that will be called for each item. + * The function must not in anyway interact with the queue. + * @return 0 on success EINVAL if queue is NULL EBUSY if someone is holding any locks on the queue + */ +int uc_thread_queue_destroy(struct uc_threadqueue *queue, uc_thread_queue_walk_func free_func); + +/** + * Walk the elements of the queue, intended for debugging + * + * The supplied function will be called for each item in the queue, internal queue + * locks are held while the function is called, so the supplied function must not + * interact with the queue, else deadlock occors. + * + * @param queue Pointer to the queue to walk + * @param free_func pointer to function that will be called for each item. + * The function must not in anyway interact with the queue. + * @return 0 on success + */ +int uc_thread_queue_walk(struct uc_threadqueue *queue, uc_thread_queue_walk_func walk_func); + +/** + * @}*/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/ucore_timers.h b/include/ucore_timers.h new file mode 100644 index 0000000..72a7879 --- /dev/null +++ b/include/ucore_timers.h @@ -0,0 +1,63 @@ +#ifndef UCORE_TIMERS_H_ +#define UCORE_TIMERS_H_ + +#include +#include +#include +#include "ucore_rbtree.h" + + +struct UCTimer; +struct UCTimers; + +//timer states +enum { + //not running + UC_TIMER_INACTIVE = 0, + //running + UC_TIMER_ACTIVE = 1, + //running and pending to be fired in this run of uc_timers_run + UC_TIMER_PENDING = 2 +}; + +typedef void (*uc_timer_cb)(struct UCTimers *timers, struct UCTimer *timer); +struct UCTimer { + //internal members + RBNode rb_node; //the RBNode will hold a data pointer to the + //the UCTimer it's a member of. We might get rid of that member, and use CONTAINER_OF + //to find the UCTimer from a RBNode + // + //absolute time when the timer should be fired + struct timeval timeout; + size_t seq; //needed to keep timeout unique + //as the rbtree can only handle unique values + unsigned char state; + TAILQ_ENTRY(UCTimer) ready_entry; //entry in ready_list in UCTimers + + //callback function + uc_timer_cb callback; + + //user data for the callback + void *cookie_ptr; + int cookie_int; + int cookie_int2; +}; + + +struct UCTimers { + RBTree timers; + size_t seq; //used to generate unique timers + TAILQ_HEAD(, UCTimer) ready_list; //pending timers to be fired while inside uc_timers_run +}; + + +void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer); +void uc_timers_init(struct UCTimers *t); +void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec); +void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer); +int uc_timers_first(const struct UCTimers *timers, struct timeval *first); +size_t uc_timer_count(const struct UCTimers *timers); +int uc_timer_running(const struct UCTimer *timer); +int uc_timers_run(struct UCTimers *timers, const struct timeval *now); + +#endif diff --git a/include/ucore_utils.h b/include/ucore_utils.h new file mode 100644 index 0000000..0c72564 --- /dev/null +++ b/include/ucore_utils.h @@ -0,0 +1,55 @@ +#ifndef UCORE_UTILS_H_ +#define UCORE_UTILS_H_ +#include + +//Gnerate a compiler error if the compile time +//constant expression fails +#define STATIC_ASSERT(expr) \ + do { \ + enum { assert_static__ = 1/(expr) }; \ + } while (0) + +#ifdef DEBUG + #define TRACEF(fmt, ...)\ + do { \ + fprintf(stderr, "%s:%s(%d)" fmt, __FILE__, __FUNCTION__, __LINE,__VA_ARGS__);\ + } while(0) +#else + #define TRACEF(fmt, ...) +#endif + +//MAX of a and b +#define UC_MAX(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a > _b ? _a : _b; }) + +//min of a and b +#define UC_MIN(a,b) \ + ({ __typeof__ (a) _a = (a); \ + __typeof__ (b) _b = (b); \ + _a < _b ? _a : _b; }) + +#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*a)) + +//given 'ptr' as a pointer to a struct 'member', +//find the struct that ptr is the member of, where +//'type' is the type of the containing struct +//e.g. +//struct foo { +// int i; +// struct bar zap; +//}; +// ... +//struct bar *p = ..; //the local p is a pointer to +//a 'zap' member inside a struct foo. +//give us the struct foo*: +//struct foo *f = CONTAINER_OF(p, struct foo, zap); +#define CONTAINER_OF(ptr, type, member) ({ \ +const typeof( ((type *)0)->member ) *__mptr = (ptr); \ + (type *)( (char *)__mptr - offsetof(type, member) ); }) + +#define UC_ALIGN(val,align) (((val)+(align)-1UL)&~((align)-1UL)) + +#endif + diff --git a/include/ucore_version.c.in b/include/ucore_version.c.in new file mode 100644 index 0000000..482684c --- /dev/null +++ b/include/ucore_version.c.in @@ -0,0 +1,7 @@ + +const int ucore_version_major = @version_major@; +const int ucore_version_minor = @version_minor@; +const int ucore_version_patch = @version_patch@; + +const char ucore_version_str[] = "@version_major@.@version_minor@.@version_patch@.@version_revision@"; + diff --git a/include/ucore_version.h b/include/ucore_version.h new file mode 100644 index 0000000..d4369e7 --- /dev/null +++ b/include/ucore_version.h @@ -0,0 +1,47 @@ +#ifndef UCORE_VERSION_H_ +#define UCORE_VERSION_H_ +/** + * @mainpage + * @htmlonly + *
+ *  Copyright (c) 2002-2012 Nils O. Selåsdal .
+ *  All rights reserved, all wrongs reversed.
+ *  
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions
+ *  are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ *  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ *  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ *  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ *  THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *  
+ * @endhtmlonly + */ + +/* Major version of the ucore library*/ +extern const int ucore_version_major; +/* Minor version of the ucore library*/ +extern const int ucore_version_minor; +/* Patch version of the ucore library*/ +extern const int ucore_version_patch; + +/** The version number as a string. + * Might contain non-numeric suffix indicating + * e.g. development version or similar*/ +extern const char ucore_version_str[]; + +#endif +