commit ed3866e49aa84dde8f07ddbb665527a85ffdd3d5 Author: Nils O. SelÃ¥sdal Date: Mon Oct 29 23:07:32 2012 +0100 Initial import of libucore diff --git a/SConstruct b/SConstruct new file mode 100644 index 0000000..afe9616 --- /dev/null +++ b/SConstruct @@ -0,0 +1,82 @@ +import os +import platform + +#version info of the library +revision = svn_version = os.popen('svnversion').read()[:-1] + +version_info = { + 'version_major': 1 , + 'version_minor': 0 , + 'version_patch': 0 , + 'version_revision': revision, +} + +AddOption('--build_type', + dest = 'build_type', + type = 'string', + nargs = 1, + action='store', + default='debug', + metavar='TYPE', + help = 'debug|release - Build a Debug (default) or Release variant' +) +AddOption('--prefix', + dest='prefix', + type='string', + nargs=1, + action='store', + metavar='DIR', + default='/usr', + help='installation prefix' +) + +AddOption('--test_xml', + dest='test_xml', + action='store_true', + help='Create a result.xml when running the testsuite' +) + + +build_type = GetOption('build_type') +test_xml = GetOption('test_xml') +prefix = GetOption('prefix') +if not (build_type in ['debug', 'release']): + print "Error: expected 'debug' or 'release', found: " + build_type + Exit(1) + +def InstallPerm(env, dest, files, perm): + obj = env.Install(dest, files) + for i in obj: + env.AddPostAction(i, Chmod(str(i), perm)) + return dest + + +env = Environment(tools = ['default', 'textfile']) +env.AddMethod(InstallPerm) +Export('env', 'build_type', 'prefix', 'version_info', 'test_xml') + +env['CFLAGS'] = ['-Wall', '-Wextra', '-pipe', '-ggdb'] +env['LINKFLAGS'] = ['-O2'] +env['CPPDEFINES'] = ['_FILE_OFFSET_BITS=64'] + +if build_type == 'release': + env['CFLAGS'] += ['-O2'] + + #this will turn off assert() + env['CPPDEFINES'] += ['NDEBUG'] + +elif build_type == 'debug': + env['CPPDEFINES'] += ['DEBUG'] + +#put all .sconsign files in one place +env.SConsignFile() + +subdirs = [ +'src', +'test' +] + +for subdir in subdirs: + SConscript(subdir + '/SConscript', variant_dir='#build/' + subdir, src_dir='#'+subdir, duplicate=0) + +env.Default('src') diff --git a/src/SConscript b/src/SConscript new file mode 100644 index 0000000..d5dff4d --- /dev/null +++ b/src/SConscript @@ -0,0 +1,26 @@ +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) + +sources = ucore_env.Glob('*.c') +headers = ucore_env.Glob('*.h') + +#print 'ucore_env', dir(ucore_env) +#print ucore_env.Dump() +#print 'sources:', sources[len(sources)-2] + +#Build library +ucore_lib = ucore_env.StaticLibrary(target='ucore_' + build_type , source=sources) + +#install targets +ucore_env.Alias('install', + ucore_env.Install(os.path.join(prefix, 'lib'), ucore_lib)) + +ucore_env.Alias('install', + ucore_env.InstallPerm(os.path.join(prefix, 'include', 'ucore'), headers, 0644)) + diff --git a/src/iomux.h b/src/iomux.h new file mode 100644 index 0000000..3f66ae7 --- /dev/null +++ b/src/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 is 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/src/iomux_epoll.c b/src/iomux_epoll.c new file mode 100644 index 0000000..229d445 --- /dev/null +++ b/src/iomux_epoll.c @@ -0,0 +1,224 @@ +#include +#include +#include +#include +#include +#include +#include "iomux_impl.h" + +//epoll (linux specific) IO mux. +//We stuff the struct IOMuxFD pointer in the event.data.ptr slot +//for the kernel to keep track of, so we don't have to. +///we do not use edge triggered mode + +//number of events we wait for in one go +#define EPOLL_WAIT_EVENTS (256) + +struct IOMuxEpoll { + //number of file descriptors we're watching + size_t num_descriptors; + //the epoll file descriptor + int epoll_fd; + + struct epoll_event pending_events[EPOLL_WAIT_EVENTS]; + //number of pending events + int pending; +}; + +static inline uint32_t mux_2_epoll_events(unsigned int events) +{ + uint32_t epoll_events = 0; + + if(events & MUX_EV_READ) + epoll_events |= EPOLLIN; + + if(events & MUX_EV_WRITE) + epoll_events |= EPOLLOUT; + + return epoll_events; +} + +static inline unsigned int epoll_2_mux_events(uint32_t events) +{ + unsigned int mux_events = 0; + + //epoll always waits for EPOLLHUP and EPOLLERR , we map + //those to read events which will hopefully do the right thing + if(events & (EPOLLIN | EPOLLHUP | EPOLLERR)) + mux_events |= MUX_EV_READ; + + if(events & EPOLLOUT) + mux_events |= MUX_EV_WRITE; + + return mux_events; +} + +static int iomux_epoll_update_events(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxEpoll *mux = mux_->instance; + struct epoll_event e_event = {0, {0}}; + int rc; + + //if we EPOLL_CTL_MOD with events of 0, epoll + //will still wait for HUP/ERR , which can lead to + //strange things. (e.g. updating fd->what to 0 on a pipe + //in order to try to "pause" reading can lead to missing or false + //read events. + assert(fd->what != 0); + if(fd->what == 0) + return EINVAL; + + + e_event.events = mux_2_epoll_events(fd->what); + e_event.data.ptr = fd; + + rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_MOD, fd->fd, &e_event); + assert(rc == 0); + if(rc != 0) + return errno; + + return 0; +} + +static int iomux_epoll_register_fd(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxEpoll *mux = mux_->instance; + struct epoll_event e_event = {0, {0}}; + int rc; + + if(fd->what == 0 || fd->callback == NULL) + return EINVAL; + + e_event.events = mux_2_epoll_events(fd->what); + e_event.data.ptr = fd; + + rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_ADD, fd->fd, &e_event); + assert(rc == 0); + if(rc != 0) { + return errno; + } + + mux->num_descriptors++; + + return 0; +} +static int iomux_epoll_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxEpoll *mux = mux_->instance; + struct epoll_event e_event = {0,{ 0}}; + int i; + int rc; + + rc = epoll_ctl(mux->epoll_fd, EPOLL_CTL_DEL, fd->fd, &e_event); + assert(rc == 0); + if(rc != 0) + return errno; + + //if the fd is pending, remove it from pending_events + //This ensures that it's safe to unregister a descriptor + //that is currently pending a callback + for(i = 0; i < mux->pending; i++) { + struct IOMuxFD *fdi = mux->pending_events[i].data.ptr; + if(fdi == NULL) + continue; + + if(fd == fdi) { + mux->pending_events[i].data.ptr = NULL; + break; + } + } + + mux->num_descriptors--; + + return rc; +} +static inline int timeval_to_ms(const struct timeval *t) +{ + int ms = t->tv_sec * 1000; + + ms += (t->tv_usec + 999) / 1000; //round upwards + + return ms; +} + +static int iomux_epoll_run(struct IOMux *mux_, struct timeval *timeout) +{ + int i; + struct IOMuxEpoll *mux = mux_->instance; + int rc; + int timeout_ms; + int event_cnt; + + if(mux->num_descriptors == 0 && timeout == NULL) + return 0; + + //epoll takes the timeout in miliseconds + if(timeout) + timeout_ms = timeval_to_ms(timeout); + else + timeout_ms = -1; + + rc = epoll_wait(mux->epoll_fd, mux->pending_events, EPOLL_WAIT_EVENTS, timeout_ms); + assert(rc >= 0); + if(rc < 0) + return errno; + + mux->pending = rc; + + event_cnt = iomux_timers_run(mux_); //process timers + + if(rc == 0) //Just the timeout + return event_cnt; + + for(i = 0; i < rc; i++) { + struct IOMuxFD *fd = mux->pending_events[i].data.ptr; + if(fd != NULL) { //calling _unregister from a callback could have removed it + unsigned int events; + + events = epoll_2_mux_events(mux->pending_events[i].events); + assert(fd->callback != NULL); + fd->callback(mux_, fd, events); + //be sure not to use fd after the callback, it might been removed. + + event_cnt++; + } + } + + mux->pending = 0; + + return event_cnt; +} + +static void iomux_epoll_delete(struct IOMux *mux) +{ + assert(mux != NULL && mux->instance != NULL); + if(mux != NULL && mux->instance != NULL) { + struct IOMuxEpoll *mux_epoll = mux->instance; + close(mux_epoll->epoll_fd); + free(mux_epoll); + mux->instance = NULL; + } +} + +int iomux_epoll_init(struct IOMux *mux) +{ + struct IOMuxEpoll *mux_epoll = calloc(1, sizeof *mux_epoll); + if(mux_epoll == NULL) + return ENOMEM; + + mux_epoll->epoll_fd = epoll_create(128); + if(mux_epoll->epoll_fd == -1) { + free(mux_epoll); + return errno; + } + + mux->instance = mux_epoll; + mux->run_impl = iomux_epoll_run; + mux->delete_impl = iomux_epoll_delete; + mux->register_fd_impl = iomux_epoll_register_fd; + mux->unregister_fd_impl = iomux_epoll_unregister_fd; + mux->update_events_impl = iomux_epoll_update_events; + + return 0; +} + diff --git a/src/iomux_impl.c b/src/iomux_impl.c new file mode 100644 index 0000000..b4c9124 --- /dev/null +++ b/src/iomux_impl.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include "iomux_impl.h" + + +//dispatchers for the IOMux implementations */ + +struct IOMux *iomux_create(enum IOMUX_TYPE type) +{ + struct IOMux *mux = calloc(1, sizeof *mux); + int rc = -1; + + + switch(type) { + case IOMUX_TYPE_DEFAULT: + case IOMUX_TYPE_EPOLL: + rc = iomux_epoll_init(mux); + break; + case IOMUX_TYPE_SELECT: + rc = iomux_select_init(mux); + break; + } + + if(rc != 0) { + //try fallback to select + rc = iomux_select_init(mux); + } + + if(rc == 0) { + rc = gettimeofday(&mux->now, NULL); + assert(rc == 0); + uc_timers_init(&mux->timers); + } else { + free(mux); + mux = NULL; + } + + return mux; +} + +void iomux_delete(struct IOMux *mux) +{ + mux->delete_impl(mux); + memset(mux, 0xfa, sizeof *mux); + free(mux); +} + +//convert the difference between future and now +static inline void future_to_interval(struct timeval *future, const struct timeval *now, struct timeval *result) +{ + if(timercmp(future, now, >)) { + timersub(future, now, result); + } else { + result->tv_sec = 0; + result->tv_usec = 0; + } +} + +int iomux_run(struct IOMux *mux) +{ + for(;;) { + int rc; + struct timeval first_timer; + struct timeval timeout; + struct timeval *timeoutp;; + int has_timers = 0; + + + rc = gettimeofday(&mux->now, NULL); + assert(rc == 0); + + if(uc_timers_first(&mux->timers, &first_timer) == 0) { + future_to_interval(&first_timer, &mux->now, &timeout); + timeoutp = &timeout; + /* fprintf(stdout, "now %d %d future %d %d interval %d %d\n", mux->now.tv_sec, mux->now.tv_usec, + first_timer.tv_sec, first_timer.tv_usec, + timeout.tv_sec, timeout.tv_usec); + fflush(stdout); + */ + + assert(timeout.tv_sec >= 0); + assert(timeout.tv_usec >= 0); + + has_timers = 1; + } else { + timeoutp = NULL; //no timeout + } + rc = mux->run_impl(mux, timeoutp); + if(rc < 0) + return rc; + + if(rc == 0 && !has_timers) //no more events, ever + return 0; + } + + return 0; +} + +int iomux_timers_run(struct IOMux *mux) +{ + int event_cnt; + gettimeofday(&mux->now, NULL); + + event_cnt = uc_timers_run(&mux->timers, &mux->now); + assert(event_cnt >= 0); + + return event_cnt; +} + +int iomux_register_fd(struct IOMux *mux, struct IOMuxFD *fd) +{ + assert(mux != NULL); + assert(fd != NULL); + assert(fd->callback != NULL); + return mux->register_fd_impl(mux, fd); +} + +int iomux_unregister_fd(struct IOMux *mux, struct IOMuxFD *fd) +{ + assert(mux != NULL); + assert(fd != NULL); + return mux->unregister_fd_impl(mux, fd); +} + +int iomux_update_events(struct IOMux *mux, struct IOMuxFD *fd) +{ + assert(mux != NULL); + assert(fd != NULL); + assert(fd->callback != NULL); + return mux->update_events_impl(mux, fd); +} + +struct UCTimers *iomux_get_timers(struct IOMux *mux) +{ + return &mux->timers; +} + diff --git a/src/iomux_impl.h b/src/iomux_impl.h new file mode 100644 index 0000000..685fe9b --- /dev/null +++ b/src/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) + * + * @mux The IOMux instance + * @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/src/iomux_select.c b/src/iomux_select.c new file mode 100644 index 0000000..a69f721 --- /dev/null +++ b/src/iomux_select.c @@ -0,0 +1,212 @@ +#include +#include +#include +#include +#include +#include +#include +#include "iomux_impl.h" +#include "ucore_utils.h" + +#define IOMUX_GROW_CHUNK (32) + +struct IOMuxSelect { + fd_set master_read_set; + fd_set master_write_set; + + struct IOMuxFD **descriptors; // array of pointers to the user IOMuxFD's + size_t alloc_descriptors; //allocated descriptors in 'descriptors' + size_t num_descriptors; //number of descriptors we're watching + size_t deleted_cnt; //used to rebuild the descriptors array + int max_fd; //keeps track of the max fd for select() +}; + +static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd); + +//grows the descriptor array. We never shrink it. +static int iomux_select_grow(struct IOMuxSelect *mux) +{ + void *tmp = realloc(mux->descriptors, (mux->num_descriptors + IOMUX_GROW_CHUNK) * sizeof *mux->descriptors); + assert(tmp != NULL); + if(tmp == NULL) + return ENOMEM; + + mux->alloc_descriptors += IOMUX_GROW_CHUNK; + mux->descriptors = tmp; + + return 0; +} + +static void iomux_select_remove(struct IOMuxSelect *mux, size_t idx) +{ + if(mux->num_descriptors > 1) { + //move last element into the empty slot + size_t last_idx = mux->num_descriptors - 1; + mux->descriptors[idx] = mux->descriptors[last_idx]; + mux->descriptors[last_idx] = NULL; + } + + mux->num_descriptors--; +} + +static void iomux_select_rebuild(struct IOMuxSelect *mux) +{ + size_t i; + + mux->max_fd = -1; + for(i = 0; i < mux->num_descriptors; ) { + if(mux->descriptors[i] == NULL) { + iomux_select_remove(mux, i); + //a deleted fd slot needs to be rechecked, no i++ here + } else { + mux->max_fd = UC_MAX(mux->descriptors[i]->fd, mux->max_fd); + i++; + } + } +} + +//sets or clears the events. +static int iomux_select_update_events(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxSelect *mux = mux_->instance; + + if(fd->what & MUX_EV_READ) + FD_SET(fd->fd, &mux->master_read_set); + else + FD_CLR(fd->fd, &mux->master_read_set); + + if(fd->what & MUX_EV_WRITE) + FD_SET(fd->fd, &mux->master_write_set); + else + FD_CLR(fd->fd, &mux->master_write_set); + + return 0; +} + +static int iomux_select_register_fd(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxSelect *mux = mux_->instance; + if(fd->what == 0 || fd->callback == NULL) + return EINVAL; + + if(mux->num_descriptors == mux->alloc_descriptors) { + if(iomux_select_grow(mux) != 0) + return ENOMEM; + } + + mux->descriptors[mux->num_descriptors] = fd; + mux->num_descriptors++; + + iomux_select_update_events(mux_, fd); + + mux->max_fd = UC_MAX(fd->fd, mux->max_fd); + + return 0; +} + +static int iomux_select_unregister_fd(struct IOMux *mux_, struct IOMuxFD *fd) +{ + struct IOMuxSelect *mux = mux_->instance; + int rc = ENOENT; + + size_t i; + for(i = 0; i < mux->num_descriptors; i++) { + if(fd == mux->descriptors[i]) { + int what = fd->what; //make sure we don't alter 'what' as seen from the user + fd->what &= ~MUX_EV_MASK; + iomux_select_update_events(mux_, fd); + mux->descriptors[i] = NULL; //set the slot to NULL, the event loop needs to rebuild it. + mux->deleted_cnt++; + fd->what = what; + rc = 0; + break; + } + } + + return rc; +} + +static int iomux_select_run(struct IOMux *mux_, struct timeval *timeout) +{ + struct IOMuxSelect *mux = mux_->instance; + + int rc; + size_t i; + int event_cnt = 0; + + if(mux->deleted_cnt) { + iomux_select_rebuild(mux); + mux->deleted_cnt = 0; + } + + if(mux->max_fd == -1 && timeout == NULL) + return 0; + + fd_set read_set = mux->master_read_set; + fd_set write_set = mux->master_write_set; + + rc = select(mux->max_fd + 1, &read_set, &write_set, NULL, timeout); //we can use timeout directly + assert(rc >= 0); + if(rc < 0) + return -1; + + event_cnt = iomux_timers_run(mux_); //fire the timers + + if(rc == 0) //Just the timeout + return event_cnt; + + for(i = 0; rc >= 0 && i < mux->num_descriptors; i++) { + unsigned int events = 0; + + if(mux->descriptors[i] == NULL) { //callback might have deleted it + continue; + } + + if(FD_ISSET(mux->descriptors[i]->fd, &read_set)) { + events |= MUX_EV_READ; + } + + if(FD_ISSET(mux->descriptors[i]->fd, &write_set)) { + events |= MUX_EV_WRITE; + } + + if(events) { + assert(mux->descriptors[i]->callback != NULL); + mux->descriptors[i]->callback(mux_, mux->descriptors[i], events); + rc--; + event_cnt++; + } + } + + return event_cnt; +} + +static void iomux_select_delete(struct IOMux *mux) +{ + if(mux != NULL && mux->instance != NULL) { + struct IOMuxSelect *mux_select = mux->instance; + free(mux_select->descriptors); + mux_select->descriptors = NULL; + free(mux_select); + mux->instance = NULL; + } +} + +int iomux_select_init(struct IOMux *mux) +{ + struct IOMuxSelect *mux_select = calloc(1, sizeof *mux_select); + if(mux_select == NULL) + return ENOMEM; + + mux_select->max_fd = -1; + + mux->instance = mux_select; + mux->run_impl = iomux_select_run; + mux->delete_impl = iomux_select_delete; + mux->register_fd_impl = iomux_select_register_fd; + mux->unregister_fd_impl = iomux_select_unregister_fd; + mux->update_events_impl = iomux_select_update_events; + + return 0; +} + diff --git a/src/tree.h b/src/tree.h new file mode 100644 index 0000000..d044f98 --- /dev/null +++ b/src/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/src/ucore_backtrace.c b/src/ucore_backtrace.c new file mode 100644 index 0000000..07c1e61 --- /dev/null +++ b/src/ucore_backtrace.c @@ -0,0 +1,14 @@ +#include + +#define MAX_BACKTRACE_SYMBOLS 96 + +void uc_backtrace_fd(int fd) +{ + void *buffer[MAX_BACKTRACE_SYMBOLS]; + int ptrs; + + ptrs = backtrace(buffer, MAX_BACKTRACE_SYMBOLS); + backtrace_symbols_fd(buffer, ptrs, fd); +} + + diff --git a/src/ucore_backtrace.h b/src/ucore_backtrace.h new file mode 100644 index 0000000..7de6b72 --- /dev/null +++ b/src/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/src/ucore_base64_dec.c b/src/ucore_base64_dec.c new file mode 100644 index 0000000..d2afc66 --- /dev/null +++ b/src/ucore_base64_dec.c @@ -0,0 +1,52 @@ +#include +#include "ucore_string.h" + +static const uint8_t basecode[128] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 62, 0xff, 0xff, 0xff, 63, + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +#define deccode(c) ((c > 127) ? 0xff : basecode[(c)]) + +size_t +uc_base64_dec(const unsigned char *data, size_t len, unsigned char *result) +{ + size_t i = 0, j = 0, pad; + uint8_t c[4]; + + while ((i + 3) < len) { + + pad = 0; + c[0] = deccode(data[i ]); pad += (c[0] == 0xff); + c[1] = deccode(data[i+1]); pad += (c[1] == 0xff); + c[2] = deccode(data[i+2]); pad += (c[2] == 0xff); + c[3] = deccode(data[i+3]); pad += (c[3] == 0xff); + switch (pad) { + case 1: + result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); + result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2); + result[j] = (c[2] & 0x03) << 6; + break; + case 2: + result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); + result[j] = (c[1] & 0x0f) << 4; + break; + default: + result[j++] = (c[0] << 2) | ((c[1] & 0x30) >> 4); + result[j++] = ((c[1] & 0x0f) << 4) | ((c[2] & 0x3c) >> 2); + result[j++] = ((c[2] & 0x03) << 6) | (c[3] & 0x3f); + } + + i += 4; + } + + return j; +} + diff --git a/src/ucore_base64_enc.c b/src/ucore_base64_enc.c new file mode 100644 index 0000000..0538bf5 --- /dev/null +++ b/src/ucore_base64_enc.c @@ -0,0 +1,43 @@ +#include +#include +#include "ucore_string.h" + +static const char basecode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#define PAD '=' + +size_t +uc_base64_enc(const unsigned char *data,size_t len,unsigned char *result) +{ + + size_t i = 0, j = 0; + size_t pad; + + + while (i < len) { + pad = 3 - (len - i); + switch(pad) { + case 2: + result[j] = basecode[data[i]>>2]; + result[j+1] = basecode[(data[i] & 0x03) << 4]; + result[j+2] = PAD; + result[j+3] = PAD; + break; + case 3: + result[j ] = basecode[data[i]>>2]; + result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)]; + result[j+2] = basecode[(data[i+1] & 0x0f) << 2]; + result[j+3] = PAD; + break; + default: + result[j ] = basecode[data[i]>>2]; + result[j+1] = basecode[((data[i] & 0x03) << 4) | ((data[i+1] & 0xf0) >> 4)]; + result[j+2] = basecode[((data[i+1] & 0x0f) << 2) | ((data[i+2] & 0xc0) >> 6)]; + result[j+3] = basecode[data[i+2] & 0x3f]; + break; + } + j += 4; + i += 3; + } + + return j; +} diff --git a/src/ucore_bcd.c b/src/ucore_bcd.c new file mode 100644 index 0000000..374594e --- /dev/null +++ b/src/ucore_bcd.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include "ucore_string.h" + +size_t +uc_ascii2bcd(const char *ascii, unsigned char *bcdout, unsigned char filler) +{ + unsigned char *bcdp = bcdout; + int shift = 0; + + *bcdp = 0; + + for(; *ascii; ascii++) { + if(*ascii < '0' || *ascii > '9') { + continue; + } + + *bcdp |= (*ascii - '0') << shift; + + if(shift) { + bcdp++; + *bcdp = 0; + } + + shift = 4 - shift; + } + + if(shift) { + *bcdp |= (filler & 0xf) << 4; + bcdp++; + } + + return bcdp - bcdout; +} + +static const char hex[] = "0123456789ABCDEF"; +size_t +uc_bcd2ascii(const unsigned char *bcd, size_t bcdlen, char *asciiout) +{ + size_t i; + size_t idx = 0; + + for(i = 0; i < bcdlen; i++) { + asciiout[idx] = hex[bcd[i] & 0xf]; + idx++; + asciiout[idx] = hex[(bcd[i] & 0xf0) >> 4]; + idx++; + } + + asciiout[idx] = 0; + + return idx; +} + diff --git a/src/ucore_bitvec.c b/src/ucore_bitvec.c new file mode 100644 index 0000000..f410bcf --- /dev/null +++ b/src/ucore_bitvec.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include +#include "ucore_bitvec.h" + +#ifdef __GNUC__ +#define likely(expr) __builtin_expect((expr), 1) +#define unlikely(expr) __builtin_expect((expr), 0) +#else +#define likely(expr) (expr) +#define unlikely(expr) (expr) +#endif + +static inline int bit_index(int b) +{ + return b / (sizeof(unsigned long) * CHAR_BIT); +} + +static inline int bit_offset(int b) +{ + return b % (sizeof(unsigned long) * CHAR_BIT); +} + +struct bitvec *bitvec_new(size_t nbits) +{ + struct bitvec *v = malloc(sizeof *v); + + if(v == NULL) + return NULL; + v->vec_len = BITVEC_VEC_LEN(nbits); + v->vec = malloc(v->vec_len * sizeof(unsigned long)); + if(v->vec == NULL) { + free(v); + return NULL; + } + + clear_all(v); + + return v; +} + +void bitvec_free(struct bitvec *v) +{ + if(v) { + free(v->vec); + free(v); + } +} + + +void clear_bit(struct bitvec *v,int b) +{ + v->vec[bit_index(b)] &= ~(1UL << (bit_offset(b))); +} + +int get_bit(const struct bitvec *v,int b) +{ + return !!(v->vec[bit_index(b)] & (1UL << bit_offset(b))); +} + +void set_bit(struct bitvec *v,int b) +{ + v->vec[bit_index(b)] |= 1UL << (bit_offset(b)); +} + +void set_bit_s(struct bitvec *v,int b) +{ + size_t idx = (size_t)bit_index(b); + assert(b >= 0); + assert(v->vec_len > (size_t)idx); + + if(likely(idx < v->vec_len)) + v->vec[idx] |= 1UL << (bit_offset(b)); +} + +void clear_bit_s(struct bitvec *v,int b) +{ + size_t idx = (size_t)bit_index(b); + + assert(b >= 0); + assert(v->vec_len > (size_t)idx); + + if(likely(idx < v->vec_len)) + v->vec[idx] &= ~(1UL << (bit_offset(b))); +} + +int get_bit_s(const struct bitvec *v,int b) +{ + size_t idx = (size_t)bit_index(b); + + assert(b >= 0); + assert(v->vec_len > (size_t)idx); + + if(likely(idx < v->vec_len)) + return !!(v->vec[idx] & (1UL << bit_offset(b))); + else + return 0; +} + +void set_bits_from_array(struct bitvec *v,char *array,size_t array_len) +{ + size_t i; + + for(i = 0; i < array_len; i++) { + size_t idx = (size_t)bit_index(array_len); + if(unlikely(idx >= v->vec_len)) + break; + + if(array[i]) + set_bit(v,i); + else + clear_bit(v,i); + } +} + +void clear_all(struct bitvec *v) +{ + memset(v->vec,0, v->vec_len * sizeof(unsigned long)); +} + +void set_all(struct bitvec *v) +{ + memset(v->vec,0xff,v->vec_len * sizeof(unsigned long)); +} + diff --git a/src/ucore_bitvec.h b/src/ucore_bitvec.h new file mode 100644 index 0000000..7a88f30 --- /dev/null +++ b/src/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/src/ucore_buffer.c b/src/ucore_buffer.c new file mode 100644 index 0000000..a111646 --- /dev/null +++ b/src/ucore_buffer.c @@ -0,0 +1,77 @@ +#include +#include +#include "ucore_buffer.h" + +GBuf* +uc_new_gbuf(size_t initsz) +{ + GBuf *p; + p = malloc(sizeof *p); + if(p == NULL) + return NULL; + + p->used = 0; + p->len = initsz; + p->buf = NULL; + p->ref_cnt = 1; + + if(initsz != 0 && (p->buf = malloc(initsz)) == NULL) { + free(p); + return NULL; + } + + return p; +} + +void +uc_gbuf_ref(GBuf *buf) +{ + buf->ref_cnt++; +} + +void +uc_gbuf_unref(GBuf *buf) +{ + buf->ref_cnt--; + + if(buf->ref_cnt == 0) { + free(buf->buf); + free(buf); + } +} + +int +uc_gbuf_append(GBuf *buf,void *data,size_t len) +{ + unsigned char *d = data; + unsigned char *gbuf; + + if(buf->len - buf->used < len) + if(uc_grow_gbuf(buf, len + len/2)) + return -1; + + gbuf = buf->buf; + memcpy(gbuf + buf->used,d,len); + buf->used += len; + + return 0; +} + +int +uc_grow_gbuf(GBuf *buf, size_t addlen) +{ + void *tmp; + size_t newsz; + + newsz = buf->len + addlen; + + tmp = realloc(buf->buf,newsz); + if(tmp == NULL) + return -1; + + buf->buf = tmp; + buf->len = newsz; + + return 0; +} + diff --git a/src/ucore_buffer.h b/src/ucore_buffer.h new file mode 100644 index 0000000..9a169b5 --- /dev/null +++ b/src/ucore_buffer.h @@ -0,0 +1,40 @@ +#ifndef UCORE_BUFFER_H_ +#define UCORE_BUFFER_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct GBuf GBuf; +struct GBuf { + size_t len; + size_t used; + size_t ref_cnt; + void *buf; +}; + +GBuf* +uc_new_gbuf(size_t initsz); + +void +uc_gbuf_ref(GBuf *buf); + +void +uc_gbuf_unref(GBuf *buf); + +int +uc_gbuf_append(GBuf *buf,void *data,size_t len); + +int +uc_grow_gbuf(GBuf *buf, size_t addlen); + + +#ifdef __cplusplus +} +#endif + +#endif + + diff --git a/src/ucore_crc32.c b/src/ucore_crc32.c new file mode 100644 index 0000000..1621a2c --- /dev/null +++ b/src/ucore_crc32.c @@ -0,0 +1,71 @@ +#include "ucore_hash.h" + +static const uint32_t crc32_table[256] = { +0x0,0x4C11DB7,0x9823B6E,0xD4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,0x2608EDB8,0x22C9F00F,0x2F8AD6D6, +0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD,0x4C11DB70,0x48D0C6C7,0x4593E01E,0x4152FDA9,0x5F15ADAC, +0x5BD4B01B,0x569796C2,0x52568B75,0x6A1936C8,0x6ED82B7F,0x639B0DA6,0x675A1011,0x791D4014,0x7DDC5DA3,0x709F7B7A, +0x745E66CD,0x9823B6E0,0x9CE2AB57,0x91A18D8E,0x95609039,0x8B27C03C,0x8FE6DD8B,0x82A5FB52,0x8664E6E5,0xBE2B5B58, +0xBAEA46EF,0xB7A96036,0xB3687D81,0xAD2F2D84,0xA9EE3033,0xA4AD16EA,0xA06C0B5D,0xD4326D90,0xD0F37027,0xDDB056FE, +0xD9714B49,0xC7361B4C,0xC3F706FB,0xCEB42022,0xCA753D95,0xF23A8028,0xF6FB9D9F,0xFBB8BB46,0xFF79A6F1,0xE13EF6F4, +0xE5FFEB43,0xE8BCCD9A,0xEC7DD02D,0x34867077,0x30476DC0,0x3D044B19,0x39C556AE,0x278206AB,0x23431B1C,0x2E003DC5, +0x2AC12072,0x128E9DCF,0x164F8078,0x1B0CA6A1,0x1FCDBB16,0x18AEB13,0x54BF6A4,0x808D07D,0xCC9CDCA,0x7897AB07, +0x7C56B6B0,0x71159069,0x75D48DDE,0x6B93DDDB,0x6F52C06C,0x6211E6B5,0x66D0FB02,0x5E9F46BF,0x5A5E5B08,0x571D7DD1, +0x53DC6066,0x4D9B3063,0x495A2DD4,0x44190B0D,0x40D816BA,0xACA5C697,0xA864DB20,0xA527FDF9,0xA1E6E04E,0xBFA1B04B, +0xBB60ADFC,0xB6238B25,0xB2E29692,0x8AAD2B2F,0x8E6C3698,0x832F1041,0x87EE0DF6,0x99A95DF3,0x9D684044,0x902B669D, +0x94EA7B2A,0xE0B41DE7,0xE4750050,0xE9362689,0xEDF73B3E,0xF3B06B3B,0xF771768C,0xFA325055,0xFEF34DE2,0xC6BCF05F, +0xC27DEDE8,0xCF3ECB31,0xCBFFD686,0xD5B88683,0xD1799B34,0xDC3ABDED,0xD8FBA05A,0x690CE0EE,0x6DCDFD59,0x608EDB80, +0x644FC637,0x7A089632,0x7EC98B85,0x738AAD5C,0x774BB0EB,0x4F040D56,0x4BC510E1,0x46863638,0x42472B8F,0x5C007B8A, +0x58C1663D,0x558240E4,0x51435D53,0x251D3B9E,0x21DC2629,0x2C9F00F0,0x285E1D47,0x36194D42,0x32D850F5,0x3F9B762C, +0x3B5A6B9B,0x315D626,0x7D4CB91,0xA97ED48,0xE56F0FF,0x1011A0FA,0x14D0BD4D,0x19939B94,0x1D528623,0xF12F560E, +0xF5EE4BB9,0xF8AD6D60,0xFC6C70D7,0xE22B20D2,0xE6EA3D65,0xEBA91BBC,0xEF68060B,0xD727BBB6,0xD3E6A601,0xDEA580D8, +0xDA649D6F,0xC423CD6A,0xC0E2D0DD,0xCDA1F604,0xC960EBB3,0xBD3E8D7E,0xB9FF90C9,0xB4BCB610,0xB07DABA7,0xAE3AFBA2, +0xAAFBE615,0xA7B8C0CC,0xA379DD7B,0x9B3660C6,0x9FF77D71,0x92B45BA8,0x9675461F,0x8832161A,0x8CF30BAD,0x81B02D74, +0x857130C3,0x5D8A9099,0x594B8D2E,0x5408ABF7,0x50C9B640,0x4E8EE645,0x4A4FFBF2,0x470CDD2B,0x43CDC09C,0x7B827D21, +0x7F436096,0x7200464F,0x76C15BF8,0x68860BFD,0x6C47164A,0x61043093,0x65C52D24,0x119B4BE9,0x155A565E,0x18197087, +0x1CD86D30,0x29F3D35,0x65E2082,0xB1D065B,0xFDC1BEC,0x3793A651,0x3352BBE6,0x3E119D3F,0x3AD08088,0x2497D08D, +0x2056CD3A,0x2D15EBE3,0x29D4F654,0xC5A92679,0xC1683BCE,0xCC2B1D17,0xC8EA00A0,0xD6AD50A5,0xD26C4D12,0xDF2F6BCB, +0xDBEE767C,0xE3A1CBC1,0xE760D676,0xEA23F0AF,0xEEE2ED18,0xF0A5BD1D,0xF464A0AA,0xF9278673,0xFDE69BC4,0x89B8FD09, +0x8D79E0BE,0x803AC667,0x84FBDBD0,0x9ABC8BD5,0x9E7D9662,0x933EB0BB,0x97FFAD0C,0xAFB010B1,0xAB710D06,0xA6322BDF, +0xA2F33668,0xBCB4666D,0xB8757BDA,0xB5365D03,0xB1F740B4}; + +uint32_t +uc_crc32(const uint8_t *buf, size_t len) +{ + const uint8_t *p; + uint32_t crc; + + crc = 0xffffffff; /* preload shift register, per CRC-32 spec */ + for (p = buf; len > 0; ++p, --len) + crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *p]; + return ~crc; /* transmit complement, per CRC-32 spec */ +} + +/* the above table is built with this: +#define CRC32_POLY 0x04c11db7 // AUTODIN II, Ethernet, & FDDI + +init_crc32() +{ + int i, j; + unsigned long c; + + for (i = 0; i < 256; ++i) { + for (c = i << 24, j = 8; j > 0; --j) + c = c & 0x80000000 ? (c << 1) ^ CRC32_POLY : (c << 1); + crc32_table[i] = c; + } +} +#include +int main() +{ + int i; + init_crc32(); + for(i = 0; i < 256; i++) { + printf("0x%X,",crc32_table[i]); + if(i%10 == 0) + putchar('\n'); + } + + return 0; + +} +*/ diff --git a/src/ucore_dayofweek.c b/src/ucore_dayofweek.c new file mode 100644 index 0000000..6f73fa6 --- /dev/null +++ b/src/ucore_dayofweek.c @@ -0,0 +1,18 @@ +int +uc_day_of_week(int day, int month, int year) +{ + int cent; + + /* adjust months so February is the last one */ + month -= 2; + if (month < 1) { + month += 12; + --year; + } + /* split by century */ + cent = year / 100; + year %= 100; + return ((26 * month - 2) / 10 + day + year + + year / 4 + cent / 4 + 5 * cent) % 7; +} + diff --git a/src/ucore_djbhash.c b/src/ucore_djbhash.c new file mode 100644 index 0000000..0baaeb6 --- /dev/null +++ b/src/ucore_djbhash.c @@ -0,0 +1,13 @@ +#include "ucore_hash.h" + +uint32_t +uc_djbhash(const char *str) +{ + uint32_t hash = 5381; + int c; + while ((c = *str++)) + hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ + + return hash; +} + diff --git a/src/ucore_elfhash.c b/src/ucore_elfhash.c new file mode 100644 index 0000000..dae1e43 --- /dev/null +++ b/src/ucore_elfhash.c @@ -0,0 +1,20 @@ +#include "ucore_hash.h" + +uint32_t +uc_elfhash(const char *str, uint32_t len) +{ + uint32_t hash = 0; + uint32_t x = 0; + uint32_t i = 0; + + for (i = 0; i < len; str++, i++) { + hash = (hash << 4) + (*str); + if ((x = hash & 0xF0000000L) != 0) { + hash ^= (x >> 24); + hash &= ~x; + } + } + + return hash; +} + diff --git a/src/ucore_gcd32.c b/src/ucore_gcd32.c new file mode 100644 index 0000000..1105b64 --- /dev/null +++ b/src/ucore_gcd32.c @@ -0,0 +1,13 @@ +#include "ucore_math.h" + +uint32_t +uc_gcd_32(uint32_t a, uint32_t b) +{ + while(b != 0) { + uint32_t t = b; + b = a%b; + a = t; + } + + return a; +} diff --git a/src/ucore_gcd64.c b/src/ucore_gcd64.c new file mode 100644 index 0000000..fff0521 --- /dev/null +++ b/src/ucore_gcd64.c @@ -0,0 +1,13 @@ +#include "ucore_math.h" + +uint64_t +uc_gcd_64(uint64_t a, uint64_t b) +{ + while(b != 0) { + uint64_t t = b; + b = a%b; + a = t; + } + + return a; +} diff --git a/src/ucore_getfields.c b/src/ucore_getfields.c new file mode 100644 index 0000000..030e5e6 --- /dev/null +++ b/src/ucore_getfields.c @@ -0,0 +1,38 @@ +#include +#include "ucore_string.h" + +int +getfields(char *str, char **args, int max, int mflag, const char *set) +{ + char r; + int intok, narg; + + if(max <= 0) + return 0; + + narg = 0; + args[narg] = str; + if(!mflag) + narg++; + intok = 0; + for(;; str++) { + r = *str; + if(r == 0) + break; + if(strchr(set, r)) { + if(narg >= max) + break; + *str = 0; + intok = 0; + args[narg] = str + 1; + if(!mflag) + narg++; + } else { + if(!intok && mflag) + narg++; + intok = 1; + } + } + return narg; +} + diff --git a/src/ucore_hash.h b/src/ucore_hash.h new file mode 100644 index 0000000..392740d --- /dev/null +++ b/src/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 +sax_hash(void *key, size_t len); + +#ifdef __cplusplus +} +#endif + +#endif + diff --git a/src/ucore_hash64int.c b/src/ucore_hash64int.c new file mode 100644 index 0000000..7356cd1 --- /dev/null +++ b/src/ucore_hash64int.c @@ -0,0 +1,16 @@ +#include +#include "ucore_hash.h" + +uint64_t +uc_hash64shift(uint64_t key) +{ + key = (~key) + (key << 21); // key = (key << 21) - key - 1; + key = key ^ (key >> 24); + key = (key + (key << 3)) + (key << 8); // key * 265 + key = key ^ (key >> 14); + key = (key + (key << 2)) + (key << 4); // key * 21 + key = key ^ (key >> 28); + key = key + (key << 31); + + return key; +} diff --git a/src/ucore_hashint.c b/src/ucore_hashint.c new file mode 100644 index 0000000..2e4c8b8 --- /dev/null +++ b/src/ucore_hashint.c @@ -0,0 +1,13 @@ +#include "ucore_hash.h" + +uint32_t +uc_hashint(uint32_t a) +{ + a = (a ^ 61) ^ (a >> 16); + a = a + (a << 3); + a = a ^ (a >> 4); + a = a * 0x27d4eb2d; + a = a ^ (a >> 15); + + return a; +} diff --git a/src/ucore_heapsort.c b/src/ucore_heapsort.c new file mode 100644 index 0000000..e723073 --- /dev/null +++ b/src/ucore_heapsort.c @@ -0,0 +1,41 @@ +#include +#include "ucore_heapsort.h" + +static void +uc_sift(unsigned char *base, size_t start, size_t count, size_t width, + uc_hs_cmp cmp) +{ + size_t root = start, child; + + while ((root * 2 + 1) < count) { + child = root * 2 + 1; + if (child < (count - 1) + && cmp(&base[child * width], &base[(child + 1) * width]) < 0) + child++; + + if (cmp(&base[root * width], &base[child * width]) < 0) { + memcpy(base + root * width, base + child * width, width); + root = child; + } else + return; + } +} + +void +uc_heapsort(void *base_, size_t count, size_t width, + uc_hs_cmp cmp) +{ + int start = count / 2 - 1, end = count - 1; + unsigned char *base = base_; + + while (start >= 0) { + uc_sift(base, start, count, width, cmp); + start--; + } + + while (end > 0) { + memcpy(base + end * width, base, width); + uc_sift(base, 0, end, width, cmp); + end--; + } +} diff --git a/src/ucore_heapsort.h b/src/ucore_heapsort.h new file mode 100644 index 0000000..2391e84 --- /dev/null +++ b/src/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/src/ucore_hex.c b/src/ucore_hex.c new file mode 100644 index 0000000..8fb074f --- /dev/null +++ b/src/ucore_hex.c @@ -0,0 +1,77 @@ +#include +#include +#include +#include "ucore_string.h" + +static const char hx_chars[] = "0123456789ABCDEF" ; + +char* +uc_hex_encode(const uint8_t *in, size_t len, char *out) +{ + unsigned int i, t, hn, ln; + + for (i = 0, t = 0; i < len; ++i,t+=2) { + + hn = (in[i] & 0xF0) >> 4 ; + ln = in[i] & 0x0F ; + + out[t] = hx_chars[hn]; + out[t+1] = hx_chars[ln]; + } + + out[t] = 0; + + return out; +} + +char* +uc_hex_encode_delim(const uint8_t *in, size_t inlen, char *out, int outlen, char *delim) +{ + unsigned int i; + char *outp = out; + + out[0] = 0; + + for (i = 0; i < inlen && outlen > 0; i++) { + int rc = snprintf(outp, outlen, "%02X%s", in[i], delim); + if(rc <= 0) + break; + outp += rc; + outlen -= rc; + } + + return outp; +} + +/* ASCII only */ +static inline int char_to_bin(char c) +{ + if(c >='0' && c <='9') + return c - '0'; + else if(c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if(c >= 'a' && c <= 'f') + return c - 'a' + 10; + + return -1; + +} + +uint8_t* +uc_hex_decode(const char *in, size_t maxlen,uint8_t *out) +{ + size_t i, t; + + for (t = 0,i = 0; i + 1 < maxlen && in[i] && in[i + 1]; i+=2 , ++t) { + int hn, ln; + hn = char_to_bin(in[i]); + ln = char_to_bin(in[i + 1]); + if(hn == -1 || ln == -1) + return NULL; + + out[t] = (hn << 4 ) | ln; + } + + return &out[t]; +} + diff --git a/src/ucore_human_bytesz.c b/src/ucore_human_bytesz.c new file mode 100644 index 0000000..19b7e78 --- /dev/null +++ b/src/ucore_human_bytesz.c @@ -0,0 +1,24 @@ +#include +#include +#include "ucore_string.h" + +char * +uc_human_bytesz(uint64_t bytes, char *result, size_t result_len) +{ + if(bytes < 1000) { + snprintf(result, result_len, "%" PRIu64 " b", bytes); + } else if (bytes < 1000000) { + snprintf(result, result_len, "%.2f kB", bytes/1000.0); + } else if (bytes < 1000000000ULL) { + snprintf(result, result_len, "%.2f MB", bytes/1000000.0); + } else if (bytes < 1000000000000ULL) { + snprintf(result, result_len, "%.2f GB", bytes/1000000000.0); + } else if (bytes < 1000000000000000ULL) { + snprintf(result, result_len, "%.2f TB", bytes/1000000000000.0); + } else { + snprintf(result, result_len, "%.2f PB", bytes/1000000000000000.0); + } + + return result; +} + diff --git a/src/ucore_logging.c b/src/ucore_logging.c new file mode 100644 index 0000000..0e04d26 --- /dev/null +++ b/src/ucore_logging.c @@ -0,0 +1,334 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include "ucore_logging.h" + + +struct uc_log_destination { + SLIST_ENTRY(uc_log_destination) entry; + enum UC_LOG_DESTINATION dest_type; + int log_level; + int log_location; + union { + //for syslog + struct { + const char *ident; + int facility; + } syslog; + //for stderr and files + struct { + FILE* file; + char *file_name; //NULL for stderr destinaton + } file; + } type; +}; + +struct uc_log_args { + struct uc_log_destination *dest; + const struct uc_log_module *module; + int log_level; + const char *file; + int line; +}; + + +//Global lock for the logging system, as logging could be performed from any thread. All operations must grab +//this lock before accessing any the global data. +static pthread_mutex_t log_lock = PTHREAD_MUTEX_INITIALIZER; + +static struct uc_log_modules modules; + +static const struct uc_log_module unknown_module = { + .id = -1, + .short_name = "UNKNOWN", + .long_name = "Unknown log module", + .log_level = UC_LL_DEBUG, +}; + + +static SLIST_HEAD(, uc_log_destination) destinations; + +inline const char *uc_ll_2_str(enum UC_LOG_LEVEL l) +{ + switch(l) { + case UC_LL_NONE: + return "NONE"; + case UC_LL_DEBUG: + return "DEBUG"; + case UC_LL_INFO: + return "INFO"; + case UC_LL_WARNING: + return "WARNING"; + case UC_LL_ERROR: + return "ERROR"; + } + + return ""; +} + +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: + return LOG_INFO; + case UC_LL_WARNING: + return LOG_WARNING; + case UC_LL_ERROR: + return LOG_ERR; + } + + return LOG_INFO; +} + +struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location) +{ + struct uc_log_destination *dest = calloc(1, sizeof *dest); + + if(dest == NULL) + return NULL; + + dest->dest_type = UC_LDEST_STDERR; + dest->type.file.file = stderr; + dest->log_level = log_level;; + dest->log_location = log_location; + + return dest; +} + +struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location) +{ + struct uc_log_destination *dest = calloc(1, sizeof *dest); + + if(dest == NULL) + return NULL; + + openlog(ident, LOG_NDELAY | LOG_PID, facility); + + dest->dest_type = UC_LDEST_SYSLOG; + dest->type.syslog.ident = ident; + dest->type.syslog.facility = facility; + dest->log_level = log_level;; + dest->log_location = log_location; + + return dest; +} + +struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location) +{ + struct uc_log_destination *dest = calloc(1, sizeof *dest); + FILE *f; + char *name; + + if(dest == NULL) + return NULL; + + name = strdup(filename); + if(name == NULL) { + free(dest); + return NULL; + } + + f = fopen(filename, "a"); + if(f == NULL) { + free(name); + free(dest); + return NULL; + } + + dest->dest_type = UC_LDEST_FILE; + dest->type.file.file = f; + dest->type.file.file_name = name; + dest->log_level = log_level;; + dest->log_location = log_location; + + return dest; +} + +void uc_log_add_destination(struct uc_log_destination *dest) +{ + struct uc_log_destination *it; + + pthread_mutex_lock(&log_lock); + + //make sure the destination isn't added twice. + SLIST_FOREACH(it, &destinations, entry) { + if(dest == it) + break; + } + + //add if it isn't already in the list + if(it == NULL) { + SLIST_INSERT_HEAD(&destinations, dest, entry); + } + + pthread_mutex_unlock(&log_lock); +} + +void uc_log_remove_destination(struct uc_log_destination *dest) +{ + pthread_mutex_lock(&log_lock); + + SLIST_REMOVE(&destinations, dest, uc_log_destination, entry); + + pthread_mutex_unlock(&log_lock); +} + +int uc_log_reopen_files(void) +{ + struct uc_log_destination *dest; + int rc = 0; + + pthread_mutex_lock(&log_lock); + + SLIST_FOREACH(dest, &destinations, entry) { + + if(dest->dest_type == UC_LDEST_FILE) { + + if(dest->type.file.file != NULL) { + fclose(dest->type.file.file); + dest->type.file.file = NULL; + } + + if(dest->type.file.file_name != NULL) { + dest->type.file.file = fopen(dest->type.file.file_name, "a"); + + if(dest->type.file.file == NULL) + rc = errno; + } + } + } + + pthread_mutex_unlock(&log_lock); + + return rc; +} + +void uc_log_init(struct uc_log_modules *user_modules) +{ + modules = *user_modules; +} + +int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level) +{ + int rc = -1; + int i; + + pthread_mutex_lock(&log_lock); + + for(i = 0; i < modules.cnt; i++) { + if(modules.mods[i].id == module) { + modules.mods[i].log_level = level; + rc = 0; + break; + } + } + + pthread_mutex_unlock(&log_lock); + + return rc; +} + +static inline void uc_vlog_internal(const struct uc_log_args *args, const char *fmt, va_list ap) +{ + struct uc_log_destination *dest = args->dest; + + if(dest->dest_type != UC_LDEST_SYSLOG && dest->type.file.file != NULL) { + char time_buf[48]; + time_t now; + struct tm tmbuf; + + now = time(NULL); + localtime_r(&now, &tmbuf); + strftime(time_buf, sizeof time_buf, "%d %b %Y %H:%M:%S %Z", &tmbuf); + + if(dest->log_location) { + fprintf(dest->type.file.file, "[%s] %s %s:%d [%s] : ", uc_ll_2_str(args->log_level), + time_buf, args->file, args->line, args->module->short_name); + } else { + fprintf(dest->type.file.file, "[%s] %s [%s]: ", + uc_ll_2_str(args->log_level), time_buf, args->module->short_name); + } + + + vfprintf(dest->type.file.file, fmt, ap); + + fflush(dest->type.file.file); //strictly not needed for stderr + // though stderr could be redirected to a file + + } else if(dest->dest_type == UC_LDEST_SYSLOG) { + int pri = uc_ll_2_syslog(args->log_level); + + //go via a buffer as we must do just 1 syslog call + char buf[4096]; + int len = 0; + + if(dest->log_location) { + len = snprintf(buf, sizeof buf, "%s:%d ", args->file, args->line); + + } + + len += snprintf(&buf[len], sizeof buf - (size_t)len, "[%s] ", args->module->short_name); + + vsnprintf(&buf[len], sizeof buf - (size_t)len, fmt, ap); + + syslog(pri, "%s", buf); + + } +} + +void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...) +{ + va_list ap; + struct uc_log_destination *dest; + const struct uc_log_module *log_module; + + va_start(ap, fmt); + + pthread_mutex_lock(&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 < modules.cnt) + log_module = &modules.mods[module]; + else + log_module = &unknown_module; + + //Check if the module should not be logged + if(log_level < log_module->log_level) + goto out; + + //do logging for each destination + SLIST_FOREACH(dest, &destinations, entry) { + va_list apc; + + if(log_level >= dest->log_level) { + const struct uc_log_args args = { + .dest = dest, + .module = log_module, + .log_level = log_level, + .file = file, + .line = line, + }; + + //log func will mess with the va_list, + //so make a copy + va_copy(apc, ap); + uc_vlog_internal(&args, fmt, apc); + va_end(apc); + } + } + +out: + pthread_mutex_unlock(&log_lock); + va_end(ap); +} + diff --git a/src/ucore_logging.h b/src/ucore_logging.h new file mode 100644 index 0000000..9173e4e --- /dev/null +++ b/src/ucore_logging.h @@ -0,0 +1,62 @@ +#ifndef UCORE_LOGGING_H_ +#define UCORE_LOGGING_H_ + +enum UC_LOG_LEVEL { + UC_LL_NONE = 0, + UC_LL_DEBUG = 1, + UC_LL_INFO = 3, + UC_LL_WARNING = 5, + UC_LL_ERROR = 7, +}; + +enum UC_LOG_DESTINATION { + UC_LDEST_SYSLOG, + UC_LDEST_STDERR, + UC_LDEST_FILE, +}; + +struct uc_log_module { + int id; + const char *short_name; + const char *long_name; + int log_level; +}; + +struct uc_log_modules { + struct uc_log_module *mods; + int cnt; +}; + +struct uc_log_destination; + + +const char *uc_ll_2_str(enum UC_LOG_LEVEL l); + +struct uc_log_destination *uc_log_new_stderr(int log_level, int log_location); + +struct uc_log_destination *uc_log_new_syslog(const char *ident, int facility, int log_level, int log_location); + +struct uc_log_destination *uc_log_new_file(const char *filename, int log_level, int log_location); + +void uc_log_add_destination(struct uc_log_destination *dest); + +void uc_log_remove_destination(struct uc_log_destination *dest); + +int uc_log_module_set_loglevel(int module, enum UC_LOG_LEVEL level); + +int uc_log_reopen_files(void); + +void uc_log_init(struct uc_log_modules *user_modules); + +void uc_logf(int log_level, int module, const char *file, int line, const char *fmt, ...) __attribute__((format(printf, 5, 6))); + +#ifdef DEBUG +# define UC_DEBUGF(mod, fmt, ...) uc_logf(UC_LL_DEBUG, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__) +#else +# define UC_DEBUGF(mod, fmt, ...) +#endif + +#define UC_LOGF(lvl, mod, fmt, ...) uc_logf(lvl, mod, __FILE__, __LINE__, fmt, ## __VA_ARGS__) + +#endif + diff --git a/src/ucore_math.h b/src/ucore_math.h new file mode 100644 index 0000000..8af110a --- /dev/null +++ b/src/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/src/ucore_mersenne_twister.c b/src/ucore_mersenne_twister.c new file mode 100644 index 0000000..a1bea9b --- /dev/null +++ b/src/ucore_mersenne_twister.c @@ -0,0 +1,76 @@ +/*Copyright (c) 2004 Nils O. Selåsdal */ +/*Straight forward attempt at a Mersenne Twister PRNG */ + +#include "ucore_mersenne_twister.h" + + +/*Beware , pollution. But the names are from the spec */ +enum { + N = MT_RAND_N, + w = 32, + M = 387, + R = 19, + U = 0x80000000, + LL= 0x7FFFFFFF, + a = 0x9908B0DF, + s = 7, + t = 15, + b = 0x9D2C5680, + c = 0xEFC60000, + l = 18, + u = 11, +}; + + +void mtsrand(int seed, MTRand *r) +{ + int j; + for(j = 0 ; j < N ; j++) { + r->x[j] = seed * ((j+1)<< 3)|0x1; + } + r->i = 0; + +} + +unsigned int mtrand(MTRand *r) +{ + unsigned int y; + unsigned int ch[] = {0, a}; + + y = r->x[r->i] & U; + y |= r->x[r->i % N]; + y &= LL; + + r->x[r->i] = r->x[(r->i + M ) %N]; + r->x[r->i] ^= y >> 1; + + r->x[r->i] ^= ch[y&0x1]; + + y = r->x[r->i]; + y ^= y >> u; + y ^= (y << s) & b; + y ^= (y << t) & c; + y ^= y >> l; + + r->i = (r->i + 1) % N; + + return y; +} +#ifdef TEST_MT +#include +#include +int main(int argc,char *argv[]) +{ + MTRand r; + mtsrand(time(NULL),&r); + for(;;){ + unsigned int _y = mtrand(&r); + + if(_y < 100) + printf("%u \n",_y); + } + + return 0; +} + +#endif diff --git a/src/ucore_mersenne_twister.h b/src/ucore_mersenne_twister.h new file mode 100644 index 0000000..eaa9c8f --- /dev/null +++ b/src/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. + * @seed Starter seed for the PRNG + * @r context for the PRNG + */ +void mtsrand(int seed, MTRand *r); + +/** Generate a new random number. + * Generated range is 0 to UINT_MAX + * + * @r context for the PRNG + * @return A pseudo random number + */ +unsigned int mtrand(MTRand *r); + +#endif + diff --git a/src/ucore_murmurhash.c b/src/ucore_murmurhash.c new file mode 100644 index 0000000..9e1a8f1 --- /dev/null +++ b/src/ucore_murmurhash.c @@ -0,0 +1,55 @@ +#include "ucore_hash.h" + +// 'm' and 'r' are mixing constants generated offline. +// They're not really 'magic', they just happen to work well. +#define m 0x5bd1e995 +#define r 24 + +uint32_t +uc_murmurmash2(const void *key, int len, uint32_t seed ) +{ + + + // Initialize the hash to a 'random' value + + uint32_t h = seed ^ len; + + // Mix 4 bytes at a time into the hash + + const unsigned char * data = (const unsigned char *)key; + + while(len >= 4) + { + uint32_t k = *(uint32_t *)data; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + data += 4; + len -= 4; + } + + // Handle the last few bytes of the input array + + switch(len) + { + case 3: h ^= data[2] << 16; + case 2: h ^= data[1] << 8; + case 1: h ^= data[0]; + h *= m; + }; + + // Do a few final mixes of the hash to ensure the last few + // bytes are well-incorporated. + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + diff --git a/src/ucore_pack.h b/src/ucore_pack.h new file mode 100644 index 0000000..f67c89a --- /dev/null +++ b/src/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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 2. + * @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. + * + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 3. + * @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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 4. + * @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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 8. + * @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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 2. + * @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. + * + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 3. + * @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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 4. + * @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. + * @v The value to serialize + * @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. + * @r The byte array to containing the integer in. Must be at least of size 4. + * @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/src/ucore_phi32.c b/src/ucore_phi32.c new file mode 100644 index 0000000..c683561 --- /dev/null +++ b/src/ucore_phi32.c @@ -0,0 +1,20 @@ +#include "ucore_math.h" + +/* +Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows: +phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N. +*/ +uint32_t +uc_phi_32(uint32_t N) +{ + uint32_t phi = 1; + uint32_t i; + for (i = 2 ; i < N ; ++i){ + if (uc_gcd_32(i, N) == 1){ + ++phi; + } + } + + return phi; +} + diff --git a/src/ucore_phi64.c b/src/ucore_phi64.c new file mode 100644 index 0000000..8601612 --- /dev/null +++ b/src/ucore_phi64.c @@ -0,0 +1,20 @@ +#include "ucore_math.h" + +/* +Euler's Totient Function is denoted by the Greek letter phi, and is defined as follows: +phi(N) = how many numbers between 1 and N - 1 which are relatively prime to N. +*/ +uint64_t +uc_phi_64(uint64_t N) +{ + uint64_t phi = 1; + uint64_t i; + for (i = 2 ; i < N ; ++i){ + if (uc_gcd_64(i, N) == 1){ + ++phi; + } + } + + return phi; +} + diff --git a/src/ucore_pjwhash.c b/src/ucore_pjwhash.c new file mode 100644 index 0000000..5f33cc8 --- /dev/null +++ b/src/ucore_pjwhash.c @@ -0,0 +1,19 @@ +#include "ucore_hash.h" + +uint32_t +uc_pjwhash(const char *str,size_t len) +{ + + unsigned h = 0, g; + + while (len--) { + h = (h << 4) + *str++; + if ((g = h & 0xf0000000)) { + h ^= (g >> 24); + h ^= g; + } + } + + return h; +} + diff --git a/src/ucore_rbtree.c b/src/ucore_rbtree.c new file mode 100644 index 0000000..ae22c1e --- /dev/null +++ b/src/ucore_rbtree.c @@ -0,0 +1,336 @@ +#include +#include "ucore_rbtree.h" +//modified from generated code of tree.h + +static void +rotateleft(RBTree *root, RBNode *node) +{ + RBNode *right = node->right; + + node->right = right->left; + if (right->left) + right->left->parent = node; + right->left = node; + + right->parent = node->parent; + if (node->parent) { + if (node == node->parent->left) + node->parent->left = right; + else + node->parent->right = right; + } else + root->node = right; + node->parent = right; +} + +static void +rotateright(RBTree *root, RBNode *node) +{ + RBNode *left = node->left; + + node->left = left->right; + if (left->right) + left->right->parent = node; + left->right = node; + + left->parent = node->parent; + if (node->parent) { + if (node == node->parent->right) + node->parent->right = left; + else + node->parent->left = left; + } else + root->node = left; + node->parent = left; +} + +static void +rb_insertcolor(RBTree *root, RBNode *node) +{ + RBNode *parent, *gparent; + + while ((parent = node->parent) && parent->color == Red) { + gparent = parent->parent; + + if (parent == gparent->left) { + RBNode *uncle = gparent->right; + if (uncle && uncle->color == Red) { + uncle->color = Black; + parent->color = Black; + gparent->color = Red; + node = gparent; + continue; + } + + if (parent->right == node) { + RBNode *tmp; + rotateleft(root, parent); + tmp = parent; + parent = node; + node = tmp; + } + + parent->color = Black; + gparent->color = Red; + rotateright(root, gparent); + } + + else { + RBNode *uncle = gparent->left; + if (uncle && uncle->color == Red) { + uncle->color = Black; + parent->color = Black; + gparent->color = Red; + node = gparent; + continue; + } + + if (parent->left == node) { + RBNode *tmp; + rotateright(root, parent); + tmp = parent; + parent = node; + node = tmp; + } + + parent->color = Black; + gparent->color = Red; + rotateleft(root, gparent); + } + } + + root->node->color = Black; +} + +static void +removecolor(RBTree *root, RBNode *node, RBNode *parent) +{ + RBNode *other; + + while ((!node || node->color == Black) && node != root->node) { + if (parent->left == node) { + other = parent->right; + if (other->color == Red) { + other->color = Black; + parent->color = Red; + rotateleft(root, parent); + other = parent->right; + } + if ((!other->left || other->left->color == Black) + && (!other->right + || other->right->color == Black)) { + other->color = Red; + node = parent; + parent = node->parent; + } else { + if (!other->right + || other->right->color == Black) { + RBNode *o_left; + if ((o_left = other->left)) + o_left->color = Black; + other->color = Red; + rotateright(root, other); + other = parent->right; + } + other->color = parent->color; + parent->color = Black; + if (other->right) + other->right->color = Black; + rotateleft(root, parent); + node = root->node; + break; + } + } + + else { + other = parent->left; + if (other->color == Red) { + other->color = Black; + parent->color = Red; + rotateright(root, parent); + other = parent->left; + } + if ((!other->left || other->left->color == Black) + && (!other->right + || other->right->color == Black)) { + other->color = Red; + node = parent; + parent = node->parent; + } else { + if (!other->left + || other->left->color == Black) { + RBNode *o_right; + if ((o_right = other->right)) + o_right->color = Black; + other->color = Red; + rotateleft(root, other); + other = parent->left; + } + other->color = parent->color; + parent->color = Black; + if (other->left) + other->left->color = Black; + rotateright(root, parent); + node = root->node; + break; + } + } + } + + if (node) + node->color = Black; +} + +void +uc_rb_remove(RBTree *root, RBNode *node) +{ + RBNode *child, *parent; + int color; + + if (!node->left) + child = node->right; + else if (!node->right) + child = node->left; + else { + RBNode *old = node, *left; + + node = node->right; + while ((left = node->left)) + node = left; + child = node->right; + parent = node->parent; + color = node->color; + + if (child) + child->parent = parent; + if (parent) { + if (parent->left == node) + parent->left = child; + else + parent->right = child; + } else + root->node = child; + + if (node->parent == old) + parent = node; + node->parent = old->parent; + node->color = old->color; + node->right = old->right; + node->left = old->left; + + if (old->parent) { + if (old->parent->left == old) + old->parent->left = node; + else + old->parent->right = node; + } else + root->node = node; + + old->left->parent = node; + if (old->right) + old->right->parent = node; + goto finish; + } + + parent = node->parent; + color = node->color; + + if (child) + child->parent = parent; + if (parent) { + if (parent->left == node) + parent->left = child; + else + parent->right = child; + } else + root->node = child; + + finish: + if (color == Black) + removecolor(root, child, parent); +} + +RBNode* +uc_rb_find(RBTree *root, const void *val) +{ + RBNode *n = root->node; + while (n) { + int d = root->compare(val,n->data); + if (d < 0) + n = n->left; + else if (d > 0) + n = n->right; + else + return n; + } + return NULL; +} + +RBNode* +uc_rb_insert(RBTree *root, RBNode *child) +{ + RBNode **p = &root->node; + RBNode *parent = NULL; + int d; + while (*p) { + parent = *p; + d = root->compare(child->data, parent->data); + if (d < 0) + p = &(*p)->left; + else if (d > 0) + p = &(*p)->right; + else + return parent; + } + + child->parent = parent; + child->color = Red; + child->left = child->right = NULL; + *p = child; + rb_insertcolor(root, child); + return NULL; +} + +RBNode *uc_rb_first(const RBTree *root) +{ + RBNode *n = root->node; + if(n == NULL) + return NULL; + + while(n->left) + n = n->left; + + return n; +} + +RBNode *uc_rb_next(RBNode *node) +{ + if(node->right) { //down and left of the right branch + node = node->right; + + while(node->left) + node = node->left; + + } else { //up until we are not the right node + + while(node->parent && node == node->parent->right) + node = node->parent; + + node = node->parent; + } + + return node; +} + +RBNode *uc_rb_last(const RBTree *root) +{ + RBNode *n = root->node; + + if(n == NULL) + return NULL; + + while(n->right) + n = n->right; + + return n; +} diff --git a/src/ucore_rbtree.h b/src/ucore_rbtree.h new file mode 100644 index 0000000..57aaccd --- /dev/null +++ b/src/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/src/ucore_read_file.c b/src/ucore_read_file.c new file mode 100644 index 0000000..8436508 --- /dev/null +++ b/src/ucore_read_file.c @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include "ucore_read_file.h" + +#define CHUNK_SZ 1024 + +char * +uc_read_file(const char *f, size_t *length, size_t max) +{ + int fd; + char *s = NULL; + char *p; + struct stat statb; + size_t alloc_sz; + + *length = 0; + + if ((fd = open(f, O_RDONLY)) == -1) + return NULL; + + if (fstat(fd, &statb) == -1) { + goto out_close; + } + + if ((statb.st_mode & S_IFMT) == S_IFREG) { + if((size_t)statb.st_size > max) { + errno = EMSGSIZE; + goto out_close; + } + alloc_sz = (size_t) statb.st_size + 1; // + 1 to avoid one realloc + s = malloc((size_t) alloc_sz + 1); //+1 for nul terminator + } else { + alloc_sz = CHUNK_SZ; + s = malloc(alloc_sz + 1); //+1 for nul terminator + } + + if (s == NULL) { + goto out_close; + } + + p = s; + + for(;;) { + ssize_t rc = read(fd, p, alloc_sz - (p - s)); + if(rc == 0) { + *p = 0; // nul terminate. all malloc calls adds room for this byte + goto out_close; + } else if (rc == -1) { + goto out_err_free; + } else if(*length + rc > max) { + errno = EMSGSIZE; + goto out_err_free; + } + + if(p + rc == s + alloc_sz) { //reached end of allocated memory, grow it. + char *tmp = realloc(s, alloc_sz + CHUNK_SZ + 1); + if(tmp == NULL) { + goto out_err_free; + } + + s = tmp; + p = s + alloc_sz; + alloc_sz += CHUNK_SZ; + } else { + p += rc; + } + + *length += rc; + } + +out_err_free: + free(s); + s = NULL; +out_close: + close(fd); + return s; +} + diff --git a/src/ucore_read_file.h b/src/ucore_read_file.h new file mode 100644 index 0000000..a96a8a4 --- /dev/null +++ b/src/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. + * + * @file_name name of the file + * @length Returned length of the content read + * @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/src/ucore_salloc.c b/src/ucore_salloc.c new file mode 100644 index 0000000..4e4838c --- /dev/null +++ b/src/ucore_salloc.c @@ -0,0 +1,146 @@ +#include +#include +#include +#include +#include "ucore_salloc.h" + +typedef struct Chunk Chunk; +struct Chunk { + Chunk *next; + size_t firstfree; //index to the first free byte in this chunk + union data { //for alignment + long long ll; + void *p; + double d; + size_t sz; + int i; + char data[1]; + } data; +}; + +struct SAlloc { + size_t chunksz; //data size of each chunk + Chunk *first; //head of the chunk list + Chunk *current; +}; + +static Chunk * +add_chunk(SAlloc *p) +{ + Chunk *newchunk; + + newchunk = malloc(sizeof *newchunk + p->chunksz - (sizeof *newchunk - offsetof(Chunk, data.data))); + if(newchunk == NULL) + return NULL; + + if(p->current != NULL) + p->current->next = newchunk; + + newchunk->next = NULL; + newchunk->firstfree = 0; + + return newchunk; +} + +static Chunk * +next_chunk(SAlloc *p) +{ + Chunk *newchunk; + + if(p->current->next) { + newchunk = p->current->next; + newchunk->firstfree = 0; + } else + newchunk = add_chunk(p); + + if(newchunk) + p->current = newchunk; + + return newchunk; +} + +SAlloc * +uc_new_salloc(size_t chunksz) +{ + SAlloc *p; + Chunk *first; + p = malloc(sizeof *p); + if(p == NULL) + return NULL; + + p->chunksz = chunksz; + p->current = NULL; + + if((first = add_chunk(p)) == NULL) { + free(p); + return NULL; + } + + p->first = p->current = first; + + return p; +} + +void +uc_reset_salloc(SAlloc *p) +{ + Chunk *tmp; + + for(tmp = p->first; tmp; tmp = tmp->next) + tmp->firstfree = 0; + + p->current = p->first; +} + +void * +uc_s_alloc(SAlloc *p,size_t sz) +{ + Chunk *chunk; + void *newmem; + + chunk = p->current; + if(chunk->firstfree + sz > p->chunksz) { + if(sz > p->chunksz) + return NULL; + + chunk = next_chunk(p); + if(chunk == NULL) + return NULL; + } + + newmem = &chunk->data.data[chunk->firstfree]; + chunk->firstfree += sz; + + return newmem; +} + +void * +uc_s_allocz(SAlloc *p,size_t sz) +{ + void *newmem = uc_s_alloc(p, sz); + + if(newmem != NULL) + memset(newmem, 0, sz); + + return newmem; +} + +static void +free_chunks(Chunk *chunk) +{ + Chunk *next; + + for(next = NULL; chunk != NULL; chunk = next) { + next = chunk->next; + free(chunk); + } +} + +void +uc_free_salloc(SAlloc *p) +{ + free_chunks(p->first); + free(p); + +} + diff --git a/src/ucore_salloc.h b/src/ucore_salloc.h new file mode 100644 index 0000000..fcd88c4 --- /dev/null +++ b/src/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. + * + * @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. + * @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. + * + * @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. + * + * @p The SAlloc to reset. + */ +void uc_reset_salloc(SAlloc *p); + +#ifdef __cplusplus +} +#endif + + +#endif diff --git a/src/ucore_saxhash.c b/src/ucore_saxhash.c new file mode 100644 index 0000000..310a008 --- /dev/null +++ b/src/ucore_saxhash.c @@ -0,0 +1,15 @@ +#include "ucore_hash.h" + +uint32_t +sax_hash(void *key, size_t len) +{ + unsigned char *p = key; + unsigned h = 0; + size_t i; + + for ( i = 0; i < len; i++ ) + h ^= ( h << 5 ) + ( h >> 2 ) + p[i]; + + return h; +} + diff --git a/src/ucore_sdmhash.c b/src/ucore_sdmhash.c new file mode 100644 index 0000000..2b3f038 --- /dev/null +++ b/src/ucore_sdmhash.c @@ -0,0 +1,12 @@ +unsigned long +sdbmhash(const unsigned char *str) +{ + unsigned long hash = 0; + unsigned int c; + + while ((c = *str++)) + hash = c + (hash << 6) + (hash << 16) - hash; + + return hash; +} + diff --git a/src/ucore_seq.h b/src/ucore_seq.h new file mode 100644 index 0000000..b53340a --- /dev/null +++ b/src/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/src/ucore_sprintb.c b/src/ucore_sprintb.c new file mode 100644 index 0000000..8be6c67 --- /dev/null +++ b/src/ucore_sprintb.c @@ -0,0 +1,21 @@ +#include +#include +#include "ucore_string.h" + + +char* +uc_sprintb(char *result, unsigned int value) +{ + char *s = result; + unsigned mask = ~((unsigned) (~0) >> 1); + + if (s) { + while (mask) { + *s++ = (mask & value) ? '1' : '0'; + mask >>= 1; + } + *s = '\0'; + } + + return result; +} diff --git a/src/ucore_sprintbc.c b/src/ucore_sprintbc.c new file mode 100644 index 0000000..0326bfe --- /dev/null +++ b/src/ucore_sprintbc.c @@ -0,0 +1,21 @@ +#include +#include +#include "ucore_string.h" + +char* +uc_sprintbc(char *result, unsigned char value) +{ + char *s = result; + unsigned char mask = ~((unsigned char) (~0) >> 1); + + if (s) { + while (mask) { + *s++ = (mask & value) ? '1' : '0'; + mask >>= 1; + } + *s = '\0'; + } + + return result; +} + diff --git a/src/ucore_sprintbll.c b/src/ucore_sprintbll.c new file mode 100644 index 0000000..6bd3a67 --- /dev/null +++ b/src/ucore_sprintbll.c @@ -0,0 +1,20 @@ +#include +#include +#include "ucore_string.h" + +char* +uc_sprintbll(char *result, unsigned long long value) +{ + char *s = result; + unsigned long long mask = ~((unsigned long long) (~0) >> 1); + + if (s) { + while (mask) { + *s++ = (mask & value) ? '1' : '0'; + mask >>= 1; + } + *s = '\0'; + } + + return result; +} diff --git a/src/ucore_sprintbs.c b/src/ucore_sprintbs.c new file mode 100644 index 0000000..80795b5 --- /dev/null +++ b/src/ucore_sprintbs.c @@ -0,0 +1,20 @@ +#include +#include +#include "ucore_string.h" + +char* +uc_sprintbs(char *result, unsigned short value) +{ + char *s = result; + unsigned short mask = ~((unsigned short) (~0) >> 1); + + if (s) { + while (mask) { + *s++ = (mask & value) ? '1' : '0'; + mask >>= 1; + } + *s = '\0'; + } + + return result; +} diff --git a/src/ucore_string.h b/src/ucore_string.h new file mode 100644 index 0000000..56eaf73 --- /dev/null +++ b/src/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/src/ucore_strtolower.c b/src/ucore_strtolower.c new file mode 100644 index 0000000..58ccd74 --- /dev/null +++ b/src/ucore_strtolower.c @@ -0,0 +1,12 @@ +#include +#include "ucore_string.h" + +void +uc_str_tolower(char *s) +{ + while (*s) { + *s = tolower((unsigned char)*s); + s++; + } +} + diff --git a/src/ucore_strtoupper.c b/src/ucore_strtoupper.c new file mode 100644 index 0000000..f71b1d7 --- /dev/null +++ b/src/ucore_strtoupper.c @@ -0,0 +1,12 @@ +#include +#include "ucore_string.h" + +void +uc_str_toupper(char *s) +{ + while (*s) { + *s = toupper((unsigned char)*s); + s++; + } +} + diff --git a/src/ucore_timers.c b/src/ucore_timers.c new file mode 100644 index 0000000..2b6e284 --- /dev/null +++ b/src/ucore_timers.c @@ -0,0 +1,157 @@ +#include +#include "ucore_timers.h" + + +static int timers_cmp(const void *a_, const void *b_) +{ + const struct UCTimer *a = a_; + const struct UCTimer *b = b_; + + if(timercmp(&a->timeout, &b->timeout, <)) { + return -1; + } else if (timercmp(&a->timeout, &b->timeout, >)) { + return 1; + } else { //check sequence number + if(a->seq < b->seq) { + return -1; + } else if(a->seq > b->seq) { + return 1; + } else { //should never happen + //assert(0); + return 0; + } + } + //assert(0); + return 0; //silence compiler +} + +static void uc_timer_real_add(struct UCTimers *timers, struct UCTimer *timer) +{ + uc_timer_remove(timers, timer); //re schedule it if it's already running + timer->state = UC_TIMER_ACTIVE; + timer->seq = timers->seq++; + timer->rb_node.data = timer; //point the data in a RBNode back to the timer that contains it. + uc_rb_insert(&timers->timers, &timer->rb_node); +} + +void uc_timers_init(struct UCTimers *t) +{ + t->timers.node = NULL; + t->timers.compare = timers_cmp; + t->seq = 0; + TAILQ_INIT(&t->ready_list); +} + +void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec) +{ + struct timeval now; + struct timeval tmp; + + assert(timer->callback != NULL); + if(timer->callback == NULL) //must be set. + return; + + tmp.tv_sec = sec; + tmp.tv_usec = usec; + + gettimeofday(&now, NULL); + timeradd(&now, &tmp, &timer->timeout); + uc_timer_real_add(timers, timer); +} + +void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer) +{ + if(timer->state == UC_TIMER_INACTIVE) { //already removed , or never added. + //debugging bandaid + timer->ready_entry.tqe_next = (struct UCTimer *)104; + timer->ready_entry.tqe_prev = (struct UCTimer **)105; + return; + } + + uc_rb_remove(&timers->timers, &timer->rb_node); //remove it, safe for the + //callback to re_add it + if(timer->state == UC_TIMER_PENDING) { + //timer is pending for callback, remove it from the list + //so code in uc_timers_run does not touch it. + TAILQ_REMOVE(&timers->ready_list, timer, ready_entry); + } + timer->state = UC_TIMER_INACTIVE; +} + +int uc_timers_first(const struct UCTimers *timers, struct timeval *first) +{ + const RBNode *n = uc_rb_first(&timers->timers); + if(n) { + struct UCTimer *timer = n->data; + *first = timer->timeout; + return 0; + } + + return 1; +} + +size_t uc_timer_count(const struct UCTimers *timers) +{ + struct RBNode *n; + size_t count = 0; + + for(n = uc_rb_first(&timers->timers); n ; n = uc_rb_next(n)) { + count++; + } + + return count; +} + +int uc_timer_running(const struct UCTimer *timer) +{ + return timer->state; +} + + +int uc_timers_run(struct UCTimers *timers, const struct timeval *now) +{ + RBNode *node; + int cnt = 0; + + /* First find all the expired nodes, place them in a linked list. + * Callbacks cannot be performed here, as the callback might alter + * the rbtree and timers + */ + assert(TAILQ_EMPTY(&timers->ready_list)); //somethings serious wrong if it isn't already empty + TAILQ_INIT(&timers->ready_list); + for(node = uc_rb_first(&timers->timers); node ; node = uc_rb_next(node)) { + struct UCTimer *t = node->data; + //Note, timercmp does not work for >= + if(!timercmp(now, &t->timeout, <)) { + TAILQ_INSERT_TAIL(&timers->ready_list, t, ready_entry); + t->state = UC_TIMER_PENDING; //so uc_timer_remove knows + //it have to remove it from the ready_list + } else { + break; + } + } + + /*run through the list and fire callbacks. + * It is ok for a callback to remove another + * timer that's either running or pending + * Need to always pick the first item in the tail queue + * since a timer callback could remove/free a timer + * we had in the list. + * uc_timer_remove will unlink the timer from this list. + */ + while(!TAILQ_EMPTY(&timers->ready_list)) { + struct UCTimer *t = TAILQ_FIRST(&timers->ready_list); + + uc_timer_remove(timers, t); + assert(t->callback != NULL); + t->callback(timers, t); //fire + // callback might have free'd its timer. + // Do not touch 't' after this. + + cnt++; + } + + + return cnt; +} + diff --git a/src/ucore_timers.h b/src/ucore_timers.h new file mode 100644 index 0000000..72a7879 --- /dev/null +++ b/src/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/src/ucore_tval.c b/src/ucore_tval.c new file mode 100644 index 0000000..42272fc --- /dev/null +++ b/src/ucore_tval.c @@ -0,0 +1,51 @@ +#include + +struct timeval * +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; + + return dst; +} + +struct timeval * +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; + + return dst; +} + +int +uc_tvcmp(const struct timeval *a, const struct timeval *b) +{ + if(a->tv_sec < b->tv_sec) + return -1; + else if(a->tv_sec > b->tv_sec) + return 1; + + if (a->tv_usec < b->tv_usec) + return -1; + else if (a->tv_usec > b->tv_usec) + return 1; + + return 0; +} + +struct timeval * +uc_to2tv(struct timeval *dst, unsigned long ms) +{ + dst->tv_sec = ms / 1000; + dst->tv_usec = ms % 1000 * 1000; + + return dst; +} + diff --git a/src/ucore_utils.h b/src/ucore_utils.h new file mode 100644 index 0000000..d378e53 --- /dev/null +++ b/src/ucore_utils.h @@ -0,0 +1,54 @@ +#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) ); }) + + +#endif + diff --git a/src/ucore_version.c.in b/src/ucore_version.c.in new file mode 100644 index 0000000..482684c --- /dev/null +++ b/src/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/src/ucore_version.h b/src/ucore_version.h new file mode 100644 index 0000000..86f6d9d --- /dev/null +++ b/src/ucore_version.h @@ -0,0 +1,11 @@ +#ifndef UCORE_VERSION_H_ +#define UCORE_VERSION_H_ + +extern const int ucore_version_major; +extern const int ucore_version_minor; +extern const int ucore_version_patch; + +extern const char ucore_version_str[]; + +#endif + diff --git a/test/SConscript b/test/SConscript new file mode 100644 index 0000000..037e1e6 --- /dev/null +++ b/test/SConscript @@ -0,0 +1,22 @@ +import os +Import('env', 'build_type', 'prefix', 'version_info', 'test_xml') + +test_env = env.Clone() +test_env.Append(LIBPATH = ['#build/src']); +test_env.Append(CPPPATH = ['#src']) +test_env.Append(LIBS = ['ucore_' + build_type, 'check']) + +tests = test_env.Glob('test_*.c') + +test_executable = 'test_runner' +#run test_runner --xml to produce an xml result file +if test_xml: + test_executable += ' --xml' + +prog = test_env.Program('test_runner', tests) +cmd = test_env.Command(target='test_phony' , + source = None, + action= test_env.Dir('.').abspath + '/' + test_executable) +test_env.Depends(cmd, prog) +test_env.AlwaysBuild(cmd) + diff --git a/test/iomux_test.c b/test/iomux_test.c new file mode 100644 index 0000000..1ceb6a1 --- /dev/null +++ b/test/iomux_test.c @@ -0,0 +1,33 @@ +#include +#include +#include "iomux.h" + +extern struct IOMuxFD s_fd; + +void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + char buf[64]; + ssize_t len = read(fd->fd, buf, sizeof buf); + printf("Read %d bytes\n", len); + iomux_unregister_fd(mux, fd); + if(len > 0) { + s_fd.what = MUX_EV_READ; + iomux_register_fd(mux, &s_fd); + } +} + +struct IOMuxFD s_fd = { + .fd = 0, + .what = MUX_EV_READ, + .callback = stdin_read_cb, + +}; + +int main(int argc, char *argv[]) +{ + struct IOMux *mux = iomux_create(IOMUX_TYPE_DEFAULT); + iomux_register_fd(mux, &s_fd); + iomux_run(mux); + + return 0; +} diff --git a/test/iomux_test2.c b/test/iomux_test2.c new file mode 100644 index 0000000..a64d55f --- /dev/null +++ b/test/iomux_test2.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include "iomux.h" + +extern struct IOMuxFD s_fd; + +void stdin_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + char buf[4096]; + ssize_t len = read(fd->fd, buf, sizeof buf); + if(len <= 0) { + perror("read"); + fprintf(stderr,"Unregister stdin fd %d\n", fd->fd); + iomux_unregister_fd(mux, fd); + close(fd->fd); + close(fd->cookie_int); + } + else + write(fd->cookie_int, buf, len); +} + +void pipe_read_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + char buf[4095]; + ssize_t len = read(fd->fd, buf, sizeof buf); + if(len <= 0) { + perror("pipe read"); + printf("Unregister pipe fd %d [stdout]\n", fd->fd); + fprintf(stderr,"Unregister pipe fd %d[stderr]\n", fd->fd); + iomux_unregister_fd(mux, fd); + close(fd->cookie_int); + fclose(fd->cookie_ptr); + + } else { + fwrite(buf, 1 , len, fd->cookie_ptr); + fflush(fd->cookie_ptr); + } +} + +void *writer(void *arg) +{ + struct IOMux *mux = arg; + iomux_run(mux); + printf("writer mux returned\n"); + + return NULL; +} + + +int main(int argc, char *argv[]) +{ + struct IOMux *mux1 = iomux_create(IOMUX_TYPE_DEFAULT); + struct IOMux *mux2 = iomux_create(IOMUX_TYPE_DEFAULT); + int pfd[2]; + int rc; + struct IOMuxFD fd1 = {0}; + struct IOMuxFD fd2 = {0}; + pthread_t tid; + pipe(pfd); + + fd1.fd = 0; + fd1.what = MUX_EV_READ; + fd1.cookie_int = pfd[1]; + fd1.callback = stdin_read_cb; + + fd2.fd = pfd[0]; + fd2.what = MUX_EV_READ; + fd2.cookie_ptr = fopen("out", "wb"); + fd2.callback = pipe_read_cb; + + + rc = iomux_register_fd(mux1, &fd1); + if(rc != 0) + printf("Cannot register fd1: %s\n", strerror(rc)); + rc = iomux_register_fd(mux2, &fd2); + if(rc != 0) + printf("Cannot register fdw: %s\n", strerror(rc)); + pthread_create(&tid,NULL,writer,mux2); + iomux_run(mux1); + printf("reader mux returned\n"); + pthread_join(tid, NULL); + iomux_delete(mux1); + iomux_delete(mux2); + + return 0; +} diff --git a/test/iomux_test3.c b/test/iomux_test3.c new file mode 100644 index 0000000..9bcc9cc --- /dev/null +++ b/test/iomux_test3.c @@ -0,0 +1,140 @@ +#include +#include +#include +#include +#include +#include +#include "iomux.h" + + +#define BUFLEN (4098*66) + +struct Copy { + struct IOMuxFD in; + struct IOMuxFD out; + + char buffer[BUFLEN]; + size_t w_idx; + size_t r_idx; + int out_running; +}; + + +void in_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + struct Copy *copy_ctx = fd->cookie_ptr; + size_t left = BUFLEN - copy_ctx->w_idx; + ssize_t rc; + left /= 2; + if(left == 0) + left++; + + + rc = read(fd->fd, ©_ctx->buffer[copy_ctx->w_idx], left); + if(rc <= 0) { + if(rc == -1 && errno == EAGAIN) { + return; + } else if(rc == -1) { + perror("read"); + } + iomux_unregister_fd(mux, fd); + return; + } + + copy_ctx->w_idx += rc; + + if(!copy_ctx->out_running) { + copy_ctx->out.what = MUX_EV_WRITE; + iomux_register_fd(mux, ©_ctx->out); + copy_ctx->out_running = 1; + } + + if(copy_ctx->w_idx == BUFLEN) { + iomux_unregister_fd(mux, fd); + } +} + +void out_cb(struct IOMux *mux, struct IOMuxFD *fd, unsigned int event) +{ + struct Copy *copy_ctx = fd->cookie_ptr; + ssize_t rc; + size_t len = copy_ctx->w_idx - copy_ctx->r_idx; + + rc = write(1, ©_ctx->buffer[copy_ctx->r_idx], len); + if(rc <= 0) { + if(rc == -1 && errno == EAGAIN) { + return; + } else { + perror("write"); + iomux_unregister_fd(mux, ©_ctx->in); + } + iomux_unregister_fd(mux, fd); + copy_ctx->out_running = 0; + } else { + copy_ctx->r_idx += rc; + if(copy_ctx->r_idx == copy_ctx->w_idx) { + iomux_unregister_fd(mux, fd); + copy_ctx->out_running = 0; + if(copy_ctx->w_idx == BUFLEN) { + copy_ctx->w_idx = 0; + copy_ctx->r_idx = 0; + iomux_register_fd(mux, ©_ctx->in); + + } + } + } +} + +int set_nonblocking(int fd) +{ + int flags = fcntl(fd,F_GETFL,NULL); + if(flags < 0 ) { + return flags; + } + return fcntl(fd,F_SETFL,flags | O_NONBLOCK); +} + +void timer_cb(struct UCTimers *timers, struct UCTimer *timer) +{ + fprintf(stderr, "Timer %d fired\n", timer->cookie_int); + struct UCTimer *t = calloc(1, sizeof *t); + t->callback = timer_cb; + t->cookie_int = timer->cookie_int + 1; + uc_timer_add(timers, t, 5,5); + t = calloc(1, sizeof *t); + t->callback = timer_cb; + t->cookie_int = timer->cookie_int + 2; + uc_timer_add(timers, t, 5,4); + +} + +int main(int argc, char *argv[]) +{ + struct Copy copy_ctx = { + .in = { + .fd = 0, + .what = MUX_EV_READ, + .callback = in_cb, + .cookie_ptr = ©_ctx, + }, + .out = { + .fd = 1, + .callback = out_cb, + .cookie_ptr = ©_ctx, + } + }; + struct UCTimer timer = { + .callback = timer_cb, + }; + set_nonblocking(0); + set_nonblocking(1); + + struct IOMux *mux = iomux_create(IOMUX_TYPE_EPOLL); + iomux_register_fd(mux, ©_ctx.in); + uc_timer_add(iomux_get_timers(mux), &timer, 5, 0); + + iomux_run(mux); + + return 0; +} + diff --git a/test/logging.c b/test/logging.c new file mode 100644 index 0000000..5d92464 --- /dev/null +++ b/test/logging.c @@ -0,0 +1,53 @@ +#include "ucore_logging.h" +#include "ucore_utils.h" +#include +enum { + MAIN, + CC, + HO +}; +struct uc_log_module module_arr[] = { + { + MAIN, + "MAIN", + "Main module", + UC_LL_WARNING + }, + { + CC, + "CC", + "Call Control module", + UC_LL_DEBUG, + }, + { + HO, + "HO", + "Handover module", + UC_LL_DEBUG + + } +}; + +struct uc_log_modules modules = { + .mods = module_arr, + .cnt = ARRAY_SIZE(module_arr), +}; + +int main(int argc, char *argv[]) +{ + struct uc_log_destination *dest = uc_log_new_stderr(UC_LL_INFO, 0); + uc_log_init(&modules); + uc_log_add_destination(dest); + dest = uc_log_new_file("test.log", UC_LL_INFO, 1); + uc_log_add_destination(dest); + dest = uc_log_new_syslog("log.test", LOG_DAEMON, UC_LL_INFO, 0); + uc_log_add_destination(dest); + UC_LOGF( UC_LL_INFO, CC, "Test cc info %d\n", 2); + UC_LOGF( UC_LL_WARNING, HO, "Test HO warning%d\n", 2); + UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN info \n" ); + UC_LOGF( UC_LL_WARNING, MAIN, "Test MAIN warning\n" ); + uc_log_module_set_loglevel(MAIN, UC_LL_INFO); + UC_LOGF( UC_LL_INFO, MAIN, "Test MAIN warning 2\n" ); + + return 1; +} diff --git a/test/salloc_vg.c b/test/salloc_vg.c new file mode 100644 index 0000000..7917814 --- /dev/null +++ b/test/salloc_vg.c @@ -0,0 +1,27 @@ +#include +#include "ucore_salloc.h" + +// Intended to be run under valgrind. Should show no errors + + +int main(int argc, char *argv) +{ + size_t i; + SAlloc *s = uc_new_salloc(36 * 100); + for(i = 0; i < 100; i++) { + void *p = uc_s_alloc(s, 36); + memset(p,7,36); + } + + uc_free_salloc(s); + + s = uc_new_salloc(85 * 100); + for(i = 0; i < 100 * 3; i++) { + void *p = uc_s_alloc(s, 85); + memset(p,7,85); + } + + uc_free_salloc(s); + + return 0; +} diff --git a/test/seq.c b/test/seq.c new file mode 100644 index 0000000..bd02623 --- /dev/null +++ b/test/seq.c @@ -0,0 +1,27 @@ +#include +#include "ucore_seq.h" + + +void check_before(uint32_t a, uint32_t b) +{ + printf("%lu before %lu = %d\n", a ,b, seq_before(a, b)); +} + +int main(int argc, char *argv[]) +{ + check_before(0, 1); + check_before(1, 0); + check_before(0, 0xffffffff); + check_before(0, 0xffff); + check_before(0, 0x1ffff); + check_before(0xffff, 0xffffffff); + check_before(0x7fffffffU - 1, 0xffffffff); + check_before(0x7fffffffU + 1, 0xffffffff); + check_before(0x7fffffffU + 1, 0x7fffffffU); + check_before(0x7fffffffU - 1, 0x7fffffffU); + check_before(0x7fffffffU, 0x7fffffffU - 1); + check_before(0x7fffffffU, 0x7fffffffU + 1); + + + return 1; +} diff --git a/test/test_bcd.c b/test/test_bcd.c new file mode 100644 index 0000000..a122145 --- /dev/null +++ b/test/test_bcd.c @@ -0,0 +1,151 @@ +#include +#include "ucore_string.h" + + +START_TEST (test_2bcd_1234567890) + char ascii[] = "1234567890"; + unsigned char bcd[5]; + size_t len = uc_ascii2bcd(ascii, bcd, 0); + + fail_if(len != 5, "len is %zu", len); + fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]); + fail_if(bcd[1] != 0x43,"was 0x%x",bcd[1]); + fail_if(bcd[2] != 0x65,"was 0x%x",bcd[2]); + fail_if(bcd[3] != 0x87,"was 0x%x",bcd[3]); + fail_if(bcd[4] != 0x09,"was 0x%x",bcd[4]); +END_TEST + +START_TEST (test_2bcd_empty) + char ascii[] = ""; + unsigned char bcd[1]; + size_t len = uc_ascii2bcd(ascii, bcd, 3); + + fail_if(len != 0, "len is %zu", len); +END_TEST + +START_TEST (test_2bcd_1_filler) + char ascii[] = "1"; + unsigned char bcd[1]; + size_t len = uc_ascii2bcd(ascii, bcd, 0xa); + + fail_if(len != 1, "len is %zu", len); + fail_if(bcd[0] != 0xa1,"was 0x%x",bcd[0]); +END_TEST + +START_TEST (test_2bcd_2_filler) + char ascii[] = "123"; + unsigned char bcd[2]; + size_t len = uc_ascii2bcd(ascii, bcd, 0xf); + + fail_if(len != 2, "len is %zu", len); + fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]); + fail_if(bcd[1] != 0xf3,"was 0x%x",bcd[1]); +END_TEST + +START_TEST (test_2bcd_3_filler) + + char ascii[] = "123"; + unsigned char bcd[2]; + size_t len = uc_ascii2bcd(ascii, bcd, 0x0); + + fail_if(len != 2, "len is %zu", len); + fail_if(bcd[0] != 0x21,"was 0x%x",bcd[0]); + fail_if(bcd[1] != 0x03,"was 0x%x",bcd[1]); +END_TEST + +START_TEST (test_2bcd_non_digits) + + char ascii[] = "a,b{ }="; + unsigned char bcd[10]; + size_t len = uc_ascii2bcd(ascii, bcd, 0x0); + + fail_if(len != 0, "len is %zu", len); +END_TEST + +START_TEST (test_2bcd_phoneno) + + char ascii[] = "0047-3233-4"; + unsigned char bcd[24]; + size_t len = uc_ascii2bcd(ascii, bcd, 0xf); + + fail_if(len != 5, "len is %zu", len); + fail_if(bcd[0] != 0x00,"was 0x%x",bcd[0]); + fail_if(bcd[1] != 0x74,"was 0x%x",bcd[1]); + fail_if(bcd[2] != 0x23,"was 0x%x",bcd[1]); + fail_if(bcd[3] != 0x33,"was 0x%x",bcd[1]); + fail_if(bcd[4] != 0xf4,"was 0x%x",bcd[1]); +END_TEST + +START_TEST (test_2bcd_binary) + + char ascii[] = {0x32,0x01,0xAF,0xFF,0x00}; + unsigned char bcd[24]; + size_t len = uc_ascii2bcd(ascii, bcd, 0xf); + + fail_if(len != 1, "len is %zu", len); + fail_if(bcd[0] != 0xf2,"0 was 0x%x",bcd[0]); +END_TEST + +START_TEST (test_2hex_1) + + unsigned char bcd[] = {0x21, 0x43 }; + char ascii[sizeof bcd * 2 + 1]; + size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii); + + fail_if(len != 4, "len is %zu", len); + fail_if(ascii[0] != '1',"0 was %c",ascii[0]); + fail_if(ascii[1] != '2',"1 was %c",ascii[1]); + fail_if(ascii[2] != '3',"2 was %c",ascii[2]); + fail_if(ascii[3] != '4',"3 was %c",ascii[3]); + fail_if(ascii[4] != 0, "4 was %c",ascii[4]); +END_TEST + +START_TEST (test_2hex_2) + + unsigned char bcd[] = {0xF0, 0xFF, 0x00}; + char ascii[sizeof bcd * 2 + 1]; + size_t len = uc_bcd2ascii(bcd, sizeof bcd, ascii); + + fail_if(len != 6, "len is %zu", len); + fail_if(ascii[0] != '0',"0 was %c",ascii[0]); + fail_if(ascii[1] != 'F',"1 was %c",ascii[1]); + fail_if(ascii[2] != 'F',"2 was %c",ascii[2]); + fail_if(ascii[3] != 'F',"3 was %c",ascii[3]); + fail_if(ascii[4] != '0', "4 was %c",ascii[4]); + fail_if(ascii[5] != '0', "5 was %c",ascii[5]); + fail_if(ascii[6] != 0, "6 was %c",ascii[6]); +END_TEST + +START_TEST (test_2hex_empty) + + unsigned char bcd[] = {0xF0, 0xFF, 0x00}; + char ascii[sizeof bcd * 2 + 1]; + ascii[0] = 0xFF; + size_t len = uc_bcd2ascii(bcd, 0, ascii); + + fail_if(len != 0, "len is %zu", len); + fail_if(ascii[0] != 0, "0 was %c",ascii[0]); +END_TEST + +Suite *bcd_suite(void) +{ + Suite *s = suite_create("bcd"); + TCase *tc = tcase_create("bcd tests"); + tcase_add_test(tc, test_2bcd_1234567890); + tcase_add_test(tc, test_2bcd_empty); + tcase_add_test(tc, test_2bcd_1_filler); + tcase_add_test(tc, test_2bcd_2_filler); + tcase_add_test(tc, test_2bcd_3_filler); + tcase_add_test(tc, test_2bcd_non_digits); + tcase_add_test(tc, test_2bcd_phoneno); + tcase_add_test(tc, test_2bcd_binary); + + tcase_add_test(tc, test_2hex_1); + tcase_add_test(tc, test_2hex_2); + tcase_add_test(tc, test_2hex_empty); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_bitvec.c b/test/test_bitvec.c new file mode 100644 index 0000000..65aaa6b --- /dev/null +++ b/test/test_bitvec.c @@ -0,0 +1,84 @@ +#include +#include "ucore_bitvec.h" + + +START_TEST (test_bitvec_1) + unsigned long s[3] = {0}; + struct bitvec v = BITVEC_STATIC_INIT(s); + size_t i; + + for(i = 0; i < sizeof s * 8; i++) + fail_if(get_bit(&v, i), "bit %zu is not 0", i); +END_TEST + +START_TEST (test_bitvec_2) + unsigned long s[3] = {0}; + struct bitvec v = BITVEC_STATIC_INIT(s); + size_t i; + + for(i = 0; i < sizeof s * 8; i++) + set_bit(&v, i); + + for(i = 0; i < sizeof s * 8; i++) + fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i); +END_TEST + +START_TEST (test_bitvec_clearbit) + unsigned long s[3] = {-1, -1, -1}; + struct bitvec v = BITVEC_STATIC_INIT(s); + size_t i; + + for(i = 0; i < sizeof(unsigned long) * 8; i++) + fail_if(get_bit(&v, i) != 1 , "bit %zu is not 1", i); + + for(i = 0; i < sizeof(unsigned long) * 8; i++) + clear_bit(&v, i); + + for(i = 0; i < sizeof(unsigned long) * 8; i++) + fail_if(get_bit(&v, i) != 0 , "bit %zu is not 0", i); + +END_TEST + +START_TEST (test_bitvec_set_bits_from_array) + struct bitvec *v = bitvec_new(5); + char a[] = {1, 0,1 ,0, 1}; + + set_bits_from_array(v,a , 5); + fail_if(get_bit(v, 0) != 1 , "bit 0 is wrong"); + fail_if(get_bit(v, 1) != 0 , "bit 1 is wrong"); + fail_if(get_bit(v, 2) != 1 , "bit 2 is wrong"); + fail_if(get_bit(v, 3) != 0 , "bit 3 is wrong"); + fail_if(get_bit(v, 4) != 1 , "bit 4 is wrong"); +END_TEST + + +START_TEST (test_bitvec_setall_clearall) + struct bitvec *v = bitvec_new(511); + size_t i; + + set_all(v); + + for(i = 0; i < 511; i++) + fail_if(get_bit(v, i) != 1 , "bit %zu is not 1", i); + + clear_all(v); + + for(i = 0; i < sizeof(unsigned long) * 8; i++) + fail_if(get_bit(v, i) != 0 , "bit %zu is not 0", i); + +END_TEST + +Suite *bitvec_suite(void) +{ + Suite *s = suite_create("bitvec"); + TCase *tc = tcase_create("bitvec tests"); + tcase_add_test(tc, test_bitvec_1); + tcase_add_test(tc, test_bitvec_2); + tcase_add_test(tc, test_bitvec_set_bits_from_array); + tcase_add_test(tc, test_bitvec_clearbit); + tcase_add_test(tc, test_bitvec_setall_clearall); + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_containerof.c b/test/test_containerof.c new file mode 100644 index 0000000..6d11e33 --- /dev/null +++ b/test/test_containerof.c @@ -0,0 +1,43 @@ +#include +#include "ucore_utils.h" + + +struct Inner { + int x; + int y; +}; + +struct Outer { + int tag1; + int tag2; + struct Inner inner; + int tag3; +}; + +START_TEST (test_container_of) + struct Outer outer = { + .tag1 = 1, + .tag2 = 2, + .inner = { + .x = 1234, + .y = 5678 + } + }; + + struct Inner *innerp = &outer.inner; + struct Outer *outerp = CONTAINER_OF(innerp, struct Outer, inner); + + fail_if(outerp != &outer); + +END_TEST + +Suite *container_of_suite(void) +{ + Suite *s = suite_create("container_of"); + TCase *tc = tcase_create("container_of tests"); + tcase_add_test(tc, test_container_of); + + suite_add_tcase(s, tc); + + return s; +} diff --git a/test/test_hex.c b/test/test_hex.c new file mode 100644 index 0000000..d77ede9 --- /dev/null +++ b/test/test_hex.c @@ -0,0 +1,193 @@ +#include +#include +#include "ucore_string.h" + + +START_TEST (test_uc_hex_encode_1) + uint8_t binary[] = {0xff}; + char hex[3] = ""; + + uc_hex_encode(binary, 1, hex); + + fail_if(strcmp(hex,"FF") != 0); + +END_TEST + +START_TEST (test_uc_hex_encode_2) + uint8_t binary[] = {127, 128, 129}; + char hex[4] = ""; + + uc_hex_encode(binary, sizeof binary, hex); + + fail_if(strcmp(hex,"7F8081") != 0, "was %s", hex); + +END_TEST + +START_TEST (test_uc_hex_encode_3) + uint8_t binary[] = {0, 1, 9, 11}; + char hex[5] = ""; + + uc_hex_encode(binary, sizeof binary, hex); + + fail_if(strcmp(hex,"0001090B") != 0, "was %s", hex); + +END_TEST + +START_TEST (test_uc_hex_encode_zero_len) + uint8_t binary[1] = {0xff}; + char hex[3] = "aa"; + + uc_hex_encode(binary, 0, hex); + + fail_if(hex[0] != 0); + fail_if(hex[1] != 'a'); + +END_TEST + +START_TEST (test_uc_hex_decode_1) + char hex[] = "1F"; + uint8_t binary[2] = {0x11,0x22}; + uint8_t *res; + + res = uc_hex_decode(hex, 2, binary); + + fail_if(binary[0] != 0x1f); + fail_if(binary[1] != 0x22); + fail_if(res != binary + 1, "binary %p, res %p", &binary[0], res); + +END_TEST + +START_TEST (test_uc_hex_decode_2) + char hex[] = "00FF80"; + uint8_t binary[4] = {0x11, 0x11, 0x11}; + uint8_t *res; + + res = uc_hex_decode(hex, 6, binary); + + fail_if(binary[0] != 0x00); + fail_if(binary[1] != 0xFF); + fail_if(binary[2] != 0x80); + fail_if(res != binary + 3, "binary %p, res %p", &binary[0], res); + +END_TEST + +START_TEST (test_uc_hex_decode_zero_length) + char hex[] = "00FF80"; + uint8_t binary[4] = {0x11, 0x11, 0x11}; + uint8_t *res; + + res = uc_hex_decode(hex, 0, binary); + + fail_if(binary[0] != 0x11); + fail_if(binary[1] != 0x11); + fail_if(binary[2] != 0x11); + fail_if(res != binary); + +END_TEST + +START_TEST (test_uc_hex_decode_empty_string) + char hex[] = ""; + uint8_t binary[4] = {0x11, 0x11, 0x11}; + uint8_t *res; + + res = uc_hex_decode(hex, 2, binary); + + fail_if(binary[0] != 0x11); + fail_if(binary[1] != 0x11); + fail_if(binary[2] != 0x11); + fail_if(res != binary); + +END_TEST + +START_TEST (test_uc_hex_decode_odd_length) + char hex[] = "33FF80"; + uint8_t binary[4] = {0x11, 0x11, 0x11}; + uint8_t *res; + + res = uc_hex_decode(hex, 3, binary); + + fail_if(binary[0] != 0x33); + fail_if(binary[1] != 0x11); + fail_if(binary[2] != 0x11); + fail_if(res != &binary[1]); + +END_TEST + +START_TEST (test_uc_hex_decode_invalid) + char hex[] = "TEST "; + uint8_t binary[4] = {0x11, 0x11, 0x11}; + uint8_t *res; + + res = uc_hex_decode(hex, 3, binary); + + fail_if(binary[0] != 0x11); + fail_if(binary[1] != 0x11); + fail_if(binary[2] != 0x11); + fail_if(res != NULL); + +END_TEST + +START_TEST (test_uc_hex_encode_delim_1) + uint8_t binary[4] = {0xFF, 0x00, 0x7F, 0x0A}; + char hex[17] = ""; + char *res; + + res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " "); + + fail_if(strcmp(hex, "FF 00 7F 0A ") != 0, "hex was '%s'", hex); + fail_if(res != hex + 12); + +END_TEST + +START_TEST (test_uc_hex_encode_delim_2) + uint8_t binary[] = {0xFF, 0x00}; + char hex[8] = ""; + char *res; + + res = uc_hex_encode_delim(binary, sizeof binary, hex, sizeof hex, " \n"); + + fail_if(strcmp(hex, "FF \n00 ") != 0, "hex was '%s'", hex); + fail_if(res != hex + 8); + +END_TEST + +START_TEST (test_uc_hex_encode_delim_zero_len) + uint8_t binary[] = {0xFF, 0x00}; + char hex[8] = "......"; + char *res; + + res = uc_hex_encode_delim(binary, 0, hex, sizeof hex, " \n"); + + fail_if(strcmp(hex, "") != 0, "hex was '%s'", hex); + fail_if(res != hex); + +END_TEST + + +Suite *hex_suite(void) +{ + Suite *s = suite_create("hex"); + TCase *tc = tcase_create("hex tests"); + tcase_add_test(tc, test_uc_hex_encode_1); + tcase_add_test(tc, test_uc_hex_encode_2); + tcase_add_test(tc, test_uc_hex_encode_3); + tcase_add_test(tc, test_uc_hex_encode_zero_len); + + tcase_add_test(tc, test_uc_hex_encode_delim_1); + tcase_add_test(tc, test_uc_hex_encode_delim_2); + tcase_add_test(tc, test_uc_hex_encode_delim_zero_len); + + + tcase_add_test(tc, test_uc_hex_decode_1); + tcase_add_test(tc, test_uc_hex_decode_2); + tcase_add_test(tc, test_uc_hex_decode_zero_length); + tcase_add_test(tc, test_uc_hex_decode_odd_length); + tcase_add_test(tc, test_uc_hex_decode_invalid); + tcase_add_test(tc, test_uc_hex_decode_empty_string); + + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_pack.c b/test/test_pack.c new file mode 100644 index 0000000..4aae6bc --- /dev/null +++ b/test/test_pack.c @@ -0,0 +1,403 @@ +#include +#include "ucore_pack.h" + + +START_TEST (test_pack16_le_1) + uint16_t v = 0x1234; + uint8_t r[2]; + + uc_pack_16_le(v,r); + + fail_if(r[0] != 0x34,"was 0x%x",r[0]); + fail_if(r[1] != 0x12,"was 0x%x",r[1]); +END_TEST + +START_TEST (test_pack16_le_2) + uint16_t v = 0xFEEF; + uint8_t r[2]; + + uc_pack_16_le(v,r); + + fail_if(r[0] != 0xEF,"was 0x%x",r[0]); + fail_if(r[1] != 0xFE,"was 0x%x",r[1]); +END_TEST + +START_TEST (test_pack16_be_1) + uint16_t v = 0x1234; + uint8_t r[2]; + + uc_pack_16_be(v,r); + + fail_if(r[0] != 0x12,"was 0x%x",r[0]); + fail_if(r[1] != 0x34,"was 0x%x",r[1]); +END_TEST + +START_TEST (test_pack16_be_2) + uint16_t v = 0xFEEF; + uint8_t r[2]; + + uc_pack_16_be(v, r); + + fail_if(r[0] != 0xFE,"was 0x%x",r[0]); + fail_if(r[1] != 0xEF,"was 0x%x",r[1]); +END_TEST + +START_TEST (test_unpack16_le_1) + uint16_t v; + uint8_t r[2] = {0x12, 0x34}; + + v = uc_unpack_16_le(r); + + fail_if(v != 0x3412,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack16_le_2) + uint16_t v; + uint8_t r[2] = {0xFE, 0xEF}; + + v = uc_unpack_16_le(r); + + fail_if(v != 0xEFFE,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack16_be_1) + uint16_t v; + uint8_t r[2] = {0x12, 0x34}; + + v = uc_unpack_16_be(r); + + fail_if(v != 0x1234,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack16_be_2) + uint16_t v; + uint8_t r[2] = {0xFE, 0xEF}; + + v = uc_unpack_16_be(r); + + fail_if(v != 0xFEEF,"was 0x%x",v); +END_TEST + +START_TEST (test_pack24_le_1) + uint32_t v = 0x123456; + uint8_t r[3]; + + uc_pack_24_le(v,r); + + fail_if(r[0] != 0x56,"was 0x%x",r[0]); + fail_if(r[1] != 0x34,"was 0x%x",r[1]); + fail_if(r[2] != 0x12,"was 0x%x",r[2]); +END_TEST + +START_TEST (test_pack24_le_2) + uint32_t v = 0xF8F7F6; + uint8_t r[3]; + + uc_pack_24_le(v,r); + + fail_if(r[0] != 0xF6,"was 0x%x",r[0]); + fail_if(r[1] != 0xF7,"was 0x%x",r[1]); + fail_if(r[2] != 0xF8,"was 0x%x",r[2]); +END_TEST + +START_TEST (test_pack24_be_1) + uint32_t v = 0x123456; + uint8_t r[3]; + + uc_pack_24_be(v,r); + + fail_if(r[0] != 0x12,"was 0x%x",r[0]); + fail_if(r[1] != 0x34,"was 0x%x",r[1]); + fail_if(r[2] != 0x56,"was 0x%x",r[2]); +END_TEST + +START_TEST (test_pack24_be_2) + uint32_t v = 0xF8F7F6; + uint8_t r[3]; + + uc_pack_24_be(v,r); + + fail_if(r[0] != 0xF8,"was 0x%x",r[0]); + fail_if(r[1] != 0xF7,"was 0x%x",r[1]); + fail_if(r[2] != 0xF6,"was 0x%x",r[2]); +END_TEST + +START_TEST (test_pack32_le_1) + uint32_t v = 0x12345678; + uint8_t r[4]; + + uc_pack_32_le(v,r); + + fail_if(r[0] != 0x78,"was 0x%x",r[0]); + fail_if(r[1] != 0x56,"was 0x%x",r[1]); + fail_if(r[2] != 0x34,"was 0x%x",r[2]); + fail_if(r[3] != 0x12,"was 0x%x",r[3]); +END_TEST + +START_TEST (test_pack32_le_2) + uint32_t v = 0xF8F7F6F4; + uint8_t r[4]; + + uc_pack_32_le(v,r); + + fail_if(r[0] != 0xF4,"was 0x%x",r[0]); + fail_if(r[1] != 0xF6,"was 0x%x",r[1]); + fail_if(r[2] != 0xF7,"was 0x%x",r[2]); + fail_if(r[3] != 0xF8,"was 0x%x",r[3]); +END_TEST + +START_TEST (test_pack32_be_1) + uint32_t v = 0x12345678; + uint8_t r[4]; + + uc_pack_32_be(v,r); + + fail_if(r[3] != 0x78,"was 0x%x",r[3]); + fail_if(r[2] != 0x56,"was 0x%x",r[2]); + fail_if(r[1] != 0x34,"was 0x%x",r[1]); + fail_if(r[0] != 0x12,"was 0x%x",r[0]); +END_TEST + +START_TEST (test_pack32_be_2) + uint32_t v = 0xF8F7F6F4; + uint8_t r[4]; + + uc_pack_32_be(v,r); + + fail_if(r[3] != 0xF4,"was 0x%x",r[3]); + fail_if(r[2] != 0xF6,"was 0x%x",r[2]); + fail_if(r[1] != 0xF7,"was 0x%x",r[1]); + fail_if(r[0] != 0xF8,"was 0x%x",r[0]); +END_TEST + +START_TEST (test_unpack24_le_1) + uint32_t v; + uint8_t r[3] = {0x12, 0x34, 0x56 }; + + v = uc_unpack_24_le(r); + + fail_if(v != 0x563412,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack24_le_2) + uint32_t v; + uint8_t r[4] = {0xF8, 0xF7, 0xF6}; + + v = uc_unpack_24_le(r); + + fail_if(v != 0xF6F7F8,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack24_be_1) + uint32_t v; + uint8_t r[3] = {0x12, 0x34, 0x56 }; + + v = uc_unpack_24_be(r); + + fail_if(v != 0x123456,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack24_be_2) + uint32_t v; + uint8_t r[4] = {0xF8, 0xF7, 0xF6}; + + v = uc_unpack_24_be(r); + + fail_if(v != 0xF8F7F6,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack32_le_1) + uint32_t v; + uint8_t r[4] = {0x12, 0x34, 0x56, 0x78}; + + v = uc_unpack_32_le(r); + + fail_if(v != 0x78563412,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack32_le_2) + uint32_t v; + uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 }; + + v = uc_unpack_32_le(r); + + fail_if(v != 0xF4F6F7F8,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack32_be_1) + uint32_t v; + uint8_t r[4] = {0x12, 0x34, 0x56, 0x78}; + + v = uc_unpack_32_be(r); + + fail_if(v != 0x12345678,"was 0x%x",v); +END_TEST + +START_TEST (test_unpack32_be_2) + uint32_t v; + uint8_t r[4] = {0xF8, 0xF7, 0xF6, 0xF4 }; + + v = uc_unpack_32_be(r); + + fail_if(v != 0xF8F7F6F4,"was 0x%x",v); +END_TEST + +START_TEST (test_pack64_le_1) + uint64_t v = 0x1122334455667788ULL; + uint8_t r[8] = {}; + + uc_pack_64_le(v, r); + + fail_if(r[0] != 0x88,"was 0x%x",r[0]); + fail_if(r[1] != 0x77,"was 0x%x",r[1]); + fail_if(r[2] != 0x66,"was 0x%x",r[2]); + fail_if(r[3] != 0x55,"was 0x%x",r[3]); + fail_if(r[4] != 0x44,"was 0x%x",r[4]); + fail_if(r[5] != 0x33,"was 0x%x",r[5]); + fail_if(r[6] != 0x22,"was 0x%x",r[6]); + fail_if(r[7] != 0x11,"was 0x%x",r[7]); +END_TEST + +START_TEST (test_pack64_le_2) + uint64_t v = 0xFFFEFDFCFBFAF9F8ULL; + uint8_t r[8] = {}; + + uc_pack_64_le(v, r); + + fail_if(r[0] != 0xF8,"was 0x%x",r[0]); + fail_if(r[1] != 0xF9,"was 0x%x",r[1]); + fail_if(r[2] != 0xFA,"was 0x%x",r[2]); + fail_if(r[3] != 0xFB,"was 0x%x",r[3]); + fail_if(r[4] != 0xFC,"was 0x%x",r[4]); + fail_if(r[5] != 0xFD,"was 0x%x",r[5]); + fail_if(r[6] != 0xFE,"was 0x%x",r[6]); + fail_if(r[7] != 0xFF,"was 0x%x",r[7]); +END_TEST + +START_TEST (test_unpack64_le_1) + uint64_t v; + uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + + v = uc_unpack_64_le(r); + + fail_if(v != 0x8877665544332211ULL,"was 0x%llx",v); +END_TEST + + +START_TEST (test_unpack64_le_2) + uint64_t v; + uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8}; + + v = uc_unpack_64_le(r); + + fail_if(v != 0xF8F9FAFBFCFDFEFFULL,"was 0x%llx",v); +END_TEST + +START_TEST (test_pack64_be_1) + uint64_t v = 0x1122334455667788ULL; + uint8_t r[8] = {}; + + uc_pack_64_be(v, r); + + fail_if(r[0] != 0x11,"was 0x%x",r[0]); + fail_if(r[1] != 0x22,"was 0x%x",r[1]); + fail_if(r[2] != 0x33,"was 0x%x",r[2]); + fail_if(r[3] != 0x44,"was 0x%x",r[3]); + fail_if(r[4] != 0x55,"was 0x%x",r[4]); + fail_if(r[5] != 0x66,"was 0x%x",r[5]); + fail_if(r[6] != 0x77,"was 0x%x",r[6]); + fail_if(r[7] != 0x88,"was 0x%x",r[7]); +END_TEST + +START_TEST (test_pack64_be_2) + uint64_t v = 0xFFFEFDFCFBFAF9F8ULL; + uint8_t r[8] = {}; + + uc_pack_64_be(v, r); + + fail_if(r[0] != 0xFF,"was 0x%x",r[0]); + fail_if(r[1] != 0xFE,"was 0x%x",r[1]); + fail_if(r[2] != 0xFD,"was 0x%x",r[2]); + fail_if(r[3] != 0xFC,"was 0x%x",r[3]); + fail_if(r[4] != 0xFB,"was 0x%x",r[4]); + fail_if(r[5] != 0xFA,"was 0x%x",r[5]); + fail_if(r[6] != 0xF9,"was 0x%x",r[6]); + fail_if(r[7] != 0xF8,"was 0x%x",r[7]); +END_TEST + +START_TEST (test_unpack64_be_1) + uint64_t v; + uint8_t r[8] = {0x11 ,0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + + v = uc_unpack_64_be(r); + + fail_if(v != 0x1122334455667788ULL,"was 0x%llx",v); +END_TEST + +START_TEST (test_unpack64_be_2) + uint64_t v; + uint8_t r[8] = {0xFF ,0xFE, 0xFD, 0xFC, 0xFB, 0xFA, 0xF9, 0xF8}; + + v = uc_unpack_64_be(r); + + fail_if(v != 0xFFFEFDFCFBFAF9F8ULL,"was 0x%llx",v); +END_TEST + +Suite *pack_suite(void) +{ + Suite *s = suite_create("pack"); + TCase *tc = tcase_create("pack tests"); + + tcase_add_test(tc, test_pack16_le_1); + tcase_add_test(tc, test_pack16_le_2); + + tcase_add_test(tc, test_pack16_be_1); + tcase_add_test(tc, test_pack16_be_2); + + tcase_add_test(tc, test_unpack16_le_1); + tcase_add_test(tc, test_unpack16_le_2); + + tcase_add_test(tc, test_unpack16_be_1); + tcase_add_test(tc, test_unpack16_be_2); + + tcase_add_test(tc, test_pack24_le_1); + tcase_add_test(tc, test_pack24_le_2); + + tcase_add_test(tc, test_pack24_be_1); + tcase_add_test(tc, test_pack24_be_2); + + tcase_add_test(tc, test_unpack24_le_1); + tcase_add_test(tc, test_unpack24_le_2); + + tcase_add_test(tc, test_unpack24_be_1); + tcase_add_test(tc, test_unpack24_be_2); + + tcase_add_test(tc, test_pack32_le_1); + tcase_add_test(tc, test_pack32_le_2); + + tcase_add_test(tc, test_pack32_be_1); + tcase_add_test(tc, test_pack32_be_2); + + tcase_add_test(tc, test_unpack32_le_1); + tcase_add_test(tc, test_unpack32_le_2); + + tcase_add_test(tc, test_unpack32_be_1); + tcase_add_test(tc, test_unpack32_be_2); + + tcase_add_test(tc, test_pack64_le_1); + tcase_add_test(tc, test_pack64_le_2); + + tcase_add_test(tc, test_unpack64_le_1); + tcase_add_test(tc, test_unpack64_le_2); + + tcase_add_test(tc, test_pack64_be_1); + tcase_add_test(tc, test_pack64_be_2); + + tcase_add_test(tc, test_unpack64_be_1); + tcase_add_test(tc, test_unpack64_be_2); + + suite_add_tcase(s, tc); + + return s; +} + diff --git a/test/test_read_file.c b/test/test_read_file.c new file mode 100644 index 0000000..5c67fbe --- /dev/null +++ b/test/test_read_file.c @@ -0,0 +1,106 @@ +#include +#include +#include +#include +#include +#include +#include +#include "ucore_read_file.h" + + +START_TEST (test_read_file_non_existing_file) + char *content; + size_t len; + int saved_errno; + + content = uc_read_file("non existing file 123765", &len, 1000000000); + saved_errno = errno; + + fail_if(content != NULL); + fail_if(saved_errno == 0); +END_TEST + +START_TEST (test_read_file_simple) + char *content; + const char *filename = "test_read_file_simple"; + size_t len; + ssize_t rc; + + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); + fail_if(fd == -1); + + rc = write(fd, "hello", 5); + fail_if(rc != 5, "rc was %ld", (long)rc); + + close(fd); + + content = uc_read_file(filename, &len, 1000000000); + unlink(filename); + + fail_if(content == NULL); + fail_if(len != 5); + fail_if(strlen(content) != 5); + fail_if(strcmp("hello", content) != 0); +END_TEST + +START_TEST (test_read_file_greater_than_max) + char *content; + const char *filename = "test_read_file_simple"; + size_t len; + ssize_t rc; + int saved_errno; + + 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); + saved_errno = errno; + unlink(filename); + + fail_if(content != NULL); + fail_if(saved_errno != EMSGSIZE, "was %d", saved_errno); +END_TEST + +START_TEST (test_read_file_boundary) + char *content; + const char *filename = "test_read_file_boundary"; + size_t len; + ssize_t rc; + char buf[1030] = ""; + strcpy(&buf[1022], "foobar"); + + int fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0664); + fail_if(fd == -1); + + rc = write(fd, buf, sizeof buf); + fail_if(rc != sizeof buf, "rc was %ld", (long)rc); + + close(fd); + + content = uc_read_file(filename, &len, 1000000000); + unlink(filename); + + fail_if(content == NULL); + fail_if(len != sizeof buf); + fail_if(strcmp("foobar", &content[1022]) != 0); + free(content); +END_TEST + +Suite *read_file_suite(void) +{ + Suite *s = suite_create("read_file"); + TCase *tc = tcase_create("read_file tests"); + tcase_add_test(tc, test_read_file_non_existing_file); + 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); + + suite_add_tcase(s, tc); + + return s; +} diff --git a/test/test_runner.c b/test/test_runner.c new file mode 100644 index 0000000..7157462 --- /dev/null +++ b/test/test_runner.c @@ -0,0 +1,40 @@ +#include +#include +#include +#include + +extern Suite *bitvec_suite(void); +extern Suite *bcd_suite(void); +extern Suite *hex_suite(void); +extern Suite *container_of_suite(void); +extern Suite *read_file_suite(void); +extern Suite *pack_suite(void); + +int +main (int argc, char *argv[]) +{ + int xml_output = argc > 1 && strcmp(argv[1], "--xml") == 0; + + int number_failed = 0; + + SRunner *sr = srunner_create (NULL); + if(xml_output) + srunner_set_xml(sr, "result.xml"); + + srunner_add_suite(sr, bitvec_suite()); + srunner_add_suite(sr, bcd_suite()); + srunner_add_suite(sr, hex_suite()); + srunner_add_suite(sr, container_of_suite()); + srunner_add_suite(sr, read_file_suite()); + srunner_add_suite(sr, pack_suite()); + + + srunner_run_all (sr, CK_VERBOSE); + number_failed = srunner_ntests_failed (sr); + srunner_free (sr); + + if(number_failed) + printf("ERROR: %d tests failed\n", number_failed); + + return (number_failed != 0) ; +} diff --git a/test/tree_splay_test.c b/test/tree_splay_test.c new file mode 100644 index 0000000..1567a97 --- /dev/null +++ b/test/tree_splay_test.c @@ -0,0 +1,111 @@ +#include +#include +#include "tree.h" + +struct descriptor { + int fd; + SPLAY_ENTRY(descriptor) entry; +}; + +int descriptor_cmp(struct descriptor *a, struct descriptor *b); + +SPLAY_HEAD(descriptors, descriptor); +SPLAY_PROTOTYPE(descriptors, descriptor, entry, descriptor_cmp); +SPLAY_GENERATE(descriptors, descriptor, entry, descriptor_cmp); + +struct descriptors entries; + +int descriptor_cmp(struct descriptor *a, struct descriptor *b) +{ + if(a->fd < b->fd) + return -1; + if(a->fd > b->fd) + return 1; + + return 0; +} + +void add(int fd) +{ + struct descriptor *des = malloc(sizeof *des); + des->fd = fd; + SPLAY_INSERT(descriptors, &entries, des); +} + + +void find(int fd) +{ + struct descriptor des; + struct descriptor *found; + + des.fd = fd; + found = SPLAY_FIND(descriptors, &entries, &des); + + if(found == NULL) + printf("Not found fd %d\n", fd); + else + printf("Found fd %d (%d)\n", found->fd, fd); +} + +void rem(int fd) +{ + struct descriptor des; + + des.fd = fd; + SPLAY_REMOVE(descriptors, &entries, &des); +} + +void iter(void){ + struct descriptor *bd; + SPLAY_FOREACH(bd, descriptors, &entries) { + printf("foreach fd %d\n", bd->fd); + } +} + +void rem_iter(void){ + struct descriptor *bd; + + while (!SPLAY_EMPTY(&entries)) { + bd = SPLAY_ROOT(&entries); + SPLAY_REMOVE(descriptors, &entries, bd); + printf("removed fd %d\n", bd->fd); + free(bd); + } +} + +void fd_min_max(void) +{ + struct descriptor *min_des, *max_des; + + min_des = SPLAY_MIN(descriptors, &entries); + max_des = SPLAY_MAX(descriptors, &entries); + + if(min_des && max_des) + printf("min fd = %d max fd = %d\n", min_des->fd, max_des->fd); + +} + +int main(int argc, char *argv[]) +{ + SPLAY_INIT(&entries); + add(3); + add(4); + add(5); + add(11); + add(64); + add(9); + add(12); + + find(11); + find(13); + + rem(11); + find(11); + fd_min_max(); + iter(); + rem_iter(); + fd_min_max(); + + + return 0; +} diff --git a/test/ucore_phi.c b/test/ucore_phi.c new file mode 100644 index 0000000..bf983fc --- /dev/null +++ b/test/ucore_phi.c @@ -0,0 +1,17 @@ +#include +#include +#include "ucore_math.h" + +int main(int argc, char *argv[]) +{ + unsigned int a,N; + if(argc < 2) { + printf("Usage %s interger1\n",argv[0]); + return 1; + } + a = atoi(argv[1]); + N = uc_phi_32(a); + printf("phi of %u is %u\n",a,N); + + return 0; +}