Initial import of libucore

This commit is contained in:
Nils O. Selåsdal
2012-10-29 23:07:32 +01:00
commit ed3866e49a
79 changed files with 6181 additions and 0 deletions
+26
View File
@@ -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))
+97
View File
@@ -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
+224
View File
@@ -0,0 +1,224 @@
#include <sys/epoll.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <assert.h>
#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;
}
+139
View File
@@ -0,0 +1,139 @@
#include <stdlib.h>
#include <string.h>
#include <string.h>
#include <assert.h>
#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;
}
+47
View File
@@ -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
+212
View File
@@ -0,0 +1,212 @@
#include <sys/select.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <assert.h>
#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;
}
+741
View File
@@ -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 <provos@citi.umich.edu>
* 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_ */
+14
View File
@@ -0,0 +1,14 @@
#include <execinfo.h>
#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);
}
+8
View File
@@ -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
+52
View File
@@ -0,0 +1,52 @@
#include <stdint.h>
#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;
}
+43
View File
@@ -0,0 +1,43 @@
#include <stdint.h>
#include <stdlib.h>
#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;
}
+55
View File
@@ -0,0 +1,55 @@
#include <ctype.h>
#include <stdint.h>
#include <stddef.h>
#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;
}
+126
View File
@@ -0,0 +1,126 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <limits.h>
#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));
}
+81
View File
@@ -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
+77
View File
@@ -0,0 +1,77 @@
#include <stdlib.h>
#include <string.h>
#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;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef UCORE_BUFFER_H_
#define UCORE_BUFFER_H_
#include <stddef.h>
#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
+71
View File
@@ -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 <stdio.h>
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;
}
*/
+18
View File
@@ -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;
}
+13
View File
@@ -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;
}
+20
View File
@@ -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;
}
+13
View File
@@ -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;
}
+13
View File
@@ -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;
}
+38
View File
@@ -0,0 +1,38 @@
#include <string.h>
#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;
}
+39
View File
@@ -0,0 +1,39 @@
#ifndef UCORE_HASH_H_
#define UCORE_HASH_H_
#include <stddef.h>
#include <stdint.h>
#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
+16
View File
@@ -0,0 +1,16 @@
#include <stdint.h>
#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;
}
+13
View File
@@ -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;
}
+41
View File
@@ -0,0 +1,41 @@
#include <string.h>
#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--;
}
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef UCORE_HEAPSORT_H_
#define UCORE_HEAPSORT_H_
#include <stddef.h>
#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
+77
View File
@@ -0,0 +1,77 @@
#include <stdint.h>
#include <stddef.h>
#include <stdio.h>
#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];
}
+24
View File
@@ -0,0 +1,24 @@
#include <stdio.h>
#include <inttypes.h>
#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;
}
+334
View File
@@ -0,0 +1,334 @@
#include <pthread.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <syslog.h>
#include <sys/queue.h>
#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);
}
+62
View File
@@ -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
+39
View File
@@ -0,0 +1,39 @@
#ifndef UCORE_MATH_H_
#define UCORE_MATH_H_
#include <stdint.h>
#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
+76
View File
@@ -0,0 +1,76 @@
/*Copyright (c) 2004 Nils O. Selåsdal <NOS {on} Utel {dot} no> */
/*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 <stdio.h>
#include <time.h>
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
+27
View File
@@ -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
+55
View File
@@ -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;
}
+257
View File
@@ -0,0 +1,257 @@
#ifndef UCORE_PACK_H_
#define UCORE_PACK_H_
#include <stdint.h>
#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
+20
View File
@@ -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;
}
+20
View File
@@ -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;
}
+19
View File
@@ -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;
}
+336
View File
@@ -0,0 +1,336 @@
#include <stddef.h>
#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;
}
+42
View File
@@ -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
+82
View File
@@ -0,0 +1,82 @@
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#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;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef UCORE_READ_FILE_H_
#define UCORE_READ_FILE_H_y
#include <stddef.h>
/** 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
+146
View File
@@ -0,0 +1,146 @@
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#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);
}
+70
View File
@@ -0,0 +1,70 @@
#ifndef SALLOC_H_
#define SALLOC_H_
#include <stddef.h>
#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
+15
View File
@@ -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;
}
+12
View File
@@ -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;
}
+21
View File
@@ -0,0 +1,21 @@
#ifndef SEQ_H_
#define SEQ_H_
#include <stdint.h>
// 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
+21
View File
@@ -0,0 +1,21 @@
#include <stdint.h>
#include <stddef.h>
#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;
}
+21
View File
@@ -0,0 +1,21 @@
#include <stdint.h>
#include <stddef.h>
#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;
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdint.h>
#include <stddef.h>
#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;
}
+20
View File
@@ -0,0 +1,20 @@
#include <stdint.h>
#include <stddef.h>
#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;
}
+60
View File
@@ -0,0 +1,60 @@
#ifndef UCORE_STRING_H_
#define UCORE_STRING_H_
#include <stddef.h>
#include <stdint.h>
#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
+12
View File
@@ -0,0 +1,12 @@
#include <ctype.h>
#include "ucore_string.h"
void
uc_str_tolower(char *s)
{
while (*s) {
*s = tolower((unsigned char)*s);
s++;
}
}
+12
View File
@@ -0,0 +1,12 @@
#include <ctype.h>
#include "ucore_string.h"
void
uc_str_toupper(char *s)
{
while (*s) {
*s = toupper((unsigned char)*s);
s++;
}
}
+157
View File
@@ -0,0 +1,157 @@
#include <assert.h>
#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;
}
+63
View File
@@ -0,0 +1,63 @@
#ifndef UCORE_TIMERS_H_
#define UCORE_TIMERS_H_
#include <stddef.h>
#include <sys/queue.h>
#include <sys/time.h>
#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
+51
View File
@@ -0,0 +1,51 @@
#include <sys/time.h>
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;
}
+54
View File
@@ -0,0 +1,54 @@
#ifndef UCORE_UTILS_H_
#define UCORE_UTILS_H_
#include <stddef.h>
//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
+7
View File
@@ -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@";
+11
View File
@@ -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