osmo-cc-misdn-endpoint/src/libmisdnuser/misc/mtimer.c

177 lines
3.6 KiB
C

/* mtimer.c
*
* Author Karsten Keil <kkeil@novell.com>
*
* Copyright 2007 by Karsten Keil <kkeil@novell.com>
*
* This code is free software; you can redistribute it and/or modify
* it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE
* version 2.1 as published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU LESSER GENERAL PUBLIC LICENSE for more details.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include "mtimer.h"
#include "layer3.h"
#include "helper.h"
//#define DEBUG_TIMERS
#ifdef DEBUG_TIMERS
void debug_list(struct timer_base *tb)
{
struct mtimer *mt;
printf("list all timers of tb=%p:\n", tb);
list_for_each_entry(mt, &tb->pending_timer, list) {
printf(" - timer %p\n", mt);
}
}
#endif
int
init_timer(struct mtimer *mt, struct timer_base *tb, void *data, mtimer_func_t *f)
{
#ifdef DEBUG_TIMERS
printf("init timer %p\n", mt);
#endif
mt->tb = tb;
mt->id = 0;
mt->data = data;
mt->function = f;
return 0;
}
static int nextid = 1;
int
add_timer(struct mtimer *mt, int tout)
{
int ret, para;
struct mtimer *check;
/* hack to be sure that timer will fire even when no or negative time was given */
if (tout < 1)
tout = 1;
#ifdef DEBUG_TIMERS
printf("add timer %p (timeout=%d ms)\n", mt, tout);
debug_list(mt->tb);
#endif
mt->timeout = tout;
para = tout;
if (mt->tb->tdev) {
ret = ioctl(mt->tb->tdev, IMADDTIMER, (long)&para);
if (ret < 0)
return ret;
mt->id = para;
} else {
static struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
mt->expires = (double)tv.tv_sec + (double)tv.tv_nsec / 1000000000.0;
mt->expires += (double)tout / 1000.0;
ret = 0;
mt->id = nextid++;
}
list_for_each_entry(check, &mt->tb->pending_timer, list) {
if (check == mt) {
eprint("%s: timer already in list!\n", __func__);
return ret;
}
}
list_add_tail(&mt->list, &mt->tb->pending_timer);
#ifdef DEBUG_TIMERS
printf("add timer done\n");
debug_list(mt->tb);
#endif
return ret;
}
int
del_timer(struct mtimer *mt)
{
int ret = 0;
#ifdef DEBUG_TIMERS
printf("del timer %p id=%d\n", mt, mt->id);
debug_list(mt->tb);
#endif
if (mt->id) {
list_del(&mt->list);
ret = ioctl(mt->tb->tdev, IMDELTIMER, (long)&mt->id);
mt->id = 0;
}
#ifdef DEBUG_TIMERS
printf("del timer done\n");
debug_list(mt->tb);
#endif
return ret;
}
int
timer_pending(struct mtimer *mt)
{
return mt->id;
}
int expire_timer(struct timer_base *tb, int id)
{
struct mtimer *mt;
double now = 0.0;
int work = 0;
/* if id is < 0, then check for expired timer */
if (id < 0) {
static struct timespec tv;
clock_gettime(CLOCK_REALTIME, &tv);
now = (double)tv.tv_sec + (double)tv.tv_nsec / 1000000000.0;
}
again:
list_for_each_entry(mt, &tb->pending_timer, list) {
#ifdef DEBUG_TIMERS
// printf("check timer in list %p\n", mt);
#endif
if (id >= 0 && mt->id == id) {
work |= 1;
list_del(&mt->list);
mt->id = 0;
#ifdef DEBUG_TIMERS
printf("calling expire function\n");
debug_list(tb);
#endif
mt->function(mt->data);
#ifdef DEBUG_TIMERS
printf("expire functiion finished\n");
debug_list(tb);
#endif
return work;
}
if (id < 0 && now >= mt->expires) {
work |= 1;
list_del(&mt->list);
mt->expires = 0.0;
#ifdef DEBUG_TIMERS
printf("calling expire function\n");
debug_list(tb);
#endif
mt->function(mt->data);
#ifdef DEBUG_TIMERS
printf("expire functiion finished\n");
debug_list(tb);
#endif
goto again;
}
}
return work;
}