Initial import of libucore
This commit is contained in:
@@ -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
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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_ */
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
*/
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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--;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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@";
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user