Initial import of libucore

This commit is contained in:
Nils O. Selåsdal
2012-10-29 23:07:32 +01:00
commit ed3866e49a
79 changed files with 6181 additions and 0 deletions
+157
View File
@@ -0,0 +1,157 @@
#include <assert.h>
#include "ucore_timers.h"
static int timers_cmp(const void *a_, const void *b_)
{
const struct UCTimer *a = a_;
const struct UCTimer *b = b_;
if(timercmp(&a->timeout, &b->timeout, <)) {
return -1;
} else if (timercmp(&a->timeout, &b->timeout, >)) {
return 1;
} else { //check sequence number
if(a->seq < b->seq) {
return -1;
} else if(a->seq > b->seq) {
return 1;
} else { //should never happen
//assert(0);
return 0;
}
}
//assert(0);
return 0; //silence compiler
}
static void uc_timer_real_add(struct UCTimers *timers, struct UCTimer *timer)
{
uc_timer_remove(timers, timer); //re schedule it if it's already running
timer->state = UC_TIMER_ACTIVE;
timer->seq = timers->seq++;
timer->rb_node.data = timer; //point the data in a RBNode back to the timer that contains it.
uc_rb_insert(&timers->timers, &timer->rb_node);
}
void uc_timers_init(struct UCTimers *t)
{
t->timers.node = NULL;
t->timers.compare = timers_cmp;
t->seq = 0;
TAILQ_INIT(&t->ready_list);
}
void uc_timer_add(struct UCTimers *timers, struct UCTimer *timer, int sec, int usec)
{
struct timeval now;
struct timeval tmp;
assert(timer->callback != NULL);
if(timer->callback == NULL) //must be set.
return;
tmp.tv_sec = sec;
tmp.tv_usec = usec;
gettimeofday(&now, NULL);
timeradd(&now, &tmp, &timer->timeout);
uc_timer_real_add(timers, timer);
}
void uc_timer_remove(struct UCTimers *timers, struct UCTimer *timer)
{
if(timer->state == UC_TIMER_INACTIVE) { //already removed , or never added.
//debugging bandaid
timer->ready_entry.tqe_next = (struct UCTimer *)104;
timer->ready_entry.tqe_prev = (struct UCTimer **)105;
return;
}
uc_rb_remove(&timers->timers, &timer->rb_node); //remove it, safe for the
//callback to re_add it
if(timer->state == UC_TIMER_PENDING) {
//timer is pending for callback, remove it from the list
//so code in uc_timers_run does not touch it.
TAILQ_REMOVE(&timers->ready_list, timer, ready_entry);
}
timer->state = UC_TIMER_INACTIVE;
}
int uc_timers_first(const struct UCTimers *timers, struct timeval *first)
{
const RBNode *n = uc_rb_first(&timers->timers);
if(n) {
struct UCTimer *timer = n->data;
*first = timer->timeout;
return 0;
}
return 1;
}
size_t uc_timer_count(const struct UCTimers *timers)
{
struct RBNode *n;
size_t count = 0;
for(n = uc_rb_first(&timers->timers); n ; n = uc_rb_next(n)) {
count++;
}
return count;
}
int uc_timer_running(const struct UCTimer *timer)
{
return timer->state;
}
int uc_timers_run(struct UCTimers *timers, const struct timeval *now)
{
RBNode *node;
int cnt = 0;
/* First find all the expired nodes, place them in a linked list.
* Callbacks cannot be performed here, as the callback might alter
* the rbtree and timers
*/
assert(TAILQ_EMPTY(&timers->ready_list)); //somethings serious wrong if it isn't already empty
TAILQ_INIT(&timers->ready_list);
for(node = uc_rb_first(&timers->timers); node ; node = uc_rb_next(node)) {
struct UCTimer *t = node->data;
//Note, timercmp does not work for >=
if(!timercmp(now, &t->timeout, <)) {
TAILQ_INSERT_TAIL(&timers->ready_list, t, ready_entry);
t->state = UC_TIMER_PENDING; //so uc_timer_remove knows
//it have to remove it from the ready_list
} else {
break;
}
}
/*run through the list and fire callbacks.
* It is ok for a callback to remove another
* timer that's either running or pending
* Need to always pick the first item in the tail queue
* since a timer callback could remove/free a timer
* we had in the list.
* uc_timer_remove will unlink the timer from this list.
*/
while(!TAILQ_EMPTY(&timers->ready_list)) {
struct UCTimer *t = TAILQ_FIRST(&timers->ready_list);
uc_timer_remove(timers, t);
assert(t->callback != NULL);
t->callback(timers, t); //fire
// callback might have free'd its timer.
// Do not touch 't' after this.
cnt++;
}
return cnt;
}