minix/lib/libddekit/src/timer.c
Thomas Cort e67fc5771d libc: add clock_getres()/clock_gettime() system calls.
In order to make it more clear that ticks should be used for timers
and realtime should be used for timestamps / displaying the date/time,
getuptime() was renamed to getticks() and getuptime2() was renamed to
getuptime().

Servers, drivers, libraries, tests, etc that use getuptime()/getuptime2()
have been updated. In instances where a realtime was calculated, the
calculation was changed to use realtime.

System calls clock_getres() and clock_gettime() were added to PM/libc.
2013-04-04 15:04:53 +02:00

315 lines
8.6 KiB
C

#include "common.h"
#include <ddekit/memory.h>
#include <ddekit/semaphore.h>
#include <ddekit/thread.h>
#include <ddekit/timer.h>
#ifdef DDEBUG_LEVEL_TIMER
#undef DDEBUG
#define DDEBUG DDEBUG_LEVEL_TIMER
#endif
#include "debug.h"
#include "thread.h"
#define DDEBUG_MSG_TIMER(t) \
DDEBUG_MSG_VERBOSE("id: %d, exp: %d, fn: %d, now %d", \
(t)->id, (t)->exp, (t)->fn, jiffies)
typedef clock_t myclock_t;
struct ddekit_timer_s {
void (*fn)(void *);
void *args;
int id;
myclock_t exp;
struct ddekit_timer_s * next;
};
static ddekit_sem_t *pending_timer_ints;
/* are we currently expecting a alarm notify? */
int _ddekit_timer_pending = 0;
unsigned long long jiffies;
unsigned long HZ;
static struct ddekit_timer_s list = {0,0,-1,1,0};
static int _id = 0 ;
static ddekit_thread_t *th;
static ddekit_lock_t lock;
static void lock_timer(void);
static void unlock_timer(void);
static clock_t get_current_clock(void);
static void remove_timer(int id);
static int insert_timer(struct ddekit_timer_s *t);
static struct ddekit_timer_s * get_next( myclock_t exp );
static void ddekit_timer_thread(void *data);
/****************************************************************************
* Private funtions *
****************************************************************************/
/*****************************************************************************
* lock_timer *
****************************************************************************/
static void lock_timer()
{
ddekit_lock_lock(&lock);
}
/*****************************************************************************
* unlock_timer *
****************************************************************************/
static void unlock_timer()
{
ddekit_lock_unlock(&lock);
}
/*****************************************************************************
* get_current_clock *
****************************************************************************/
static myclock_t get_current_clock()
{
/* returns the current clock tick */
myclock_t ret;
getticks(&ret);
return ret;
}
/*****************************************************************************
* remove_timer *
****************************************************************************/
static void remove_timer(int id)
{
/* removes a timer from the timer list */
struct ddekit_timer_s *l,*m;
lock_timer();
for (l = &list; l && l->next && l->next->id!=id; l = l->next )
;
if (l && l->next) {
m = l->next;
DDEBUG_MSG_VERBOSE(
"deleting timer at for tick: %d fn: %p, (now: %d)\n",
m->exp, m->fn, jiffies);
l->next = m->next;
DDEBUG_MSG_TIMER(m);
ddekit_simple_free(m);
}
unlock_timer();
}
/*****************************************************************************
* insert_timer *
****************************************************************************/
static int insert_timer(struct ddekit_timer_s *t)
{
/* inserts a timer to the timer list */
int ret;
lock_timer();
struct ddekit_timer_s *l;
for (l = &list; l->next && l->next->exp <= t->exp; l = l->next) {
}
t->next = l->next;
l->next = t;
t->id = ret = _id;
_id++;
if (_id==0) {
DDEBUG_MSG_WARN("Timer ID overflow...");
}
DDEBUG_MSG_TIMER(t);
unlock_timer();
return ret;
}
/*****************************************************************************
* get_next *
****************************************************************************/
static struct ddekit_timer_s * get_next( myclock_t exp )
{
/*
* this one get the next timer, which's timeout expired,
* returns NULL if no timer is pending
*/
struct ddekit_timer_s * ret = 0;
lock_timer();
if (list.next)
{
if (list.next->exp <= exp)
{
ret = list.next;
list.next = ret->next;
}
}
unlock_timer();
return ret;
}
/*****************************************************************************
* ddekit_timer_thread *
****************************************************************************/
static void ddekit_timer_thread(void * data)
{
struct ddekit_timer_s * l;
/* rock around the clock! */
for ( ; ; )
{
/* wait for timer interrupts */
ddekit_sem_down(pending_timer_ints);
DDEBUG_MSG_VERBOSE("handling timer interrupt");
/* execute all expired timers */
while( (l = get_next(jiffies)) != 0 ) {
DDEBUG_MSG_TIMER(l);
if (l->fn) {
l->fn(l->args);
}
ddekit_simple_free(l);
}
}
}
/****************************************************************************
* Public functions (ddekit/timer.h) *
****************************************************************************/
/*****************************************************************************
* ddekit_add_timer *
****************************************************************************/
int ddekit_add_timer
(void (*fn)(void *), void *args, unsigned long timeout)
{
struct ddekit_timer_s *t;
t = (struct ddekit_timer_s *)
ddekit_simple_malloc(sizeof(struct ddekit_timer_s ));
t->fn = fn;
t->args = args;
t->exp = (myclock_t) timeout;
return insert_timer(t);
}
/*****************************************************************************
* ddekit_del_timer *
****************************************************************************/
int ddekit_del_timer(int timer)
{
remove_timer(timer);
return 0;
}
/*****************************************************************************
* ddekit_timer_pending *
****************************************************************************/
int ddekit_timer_pending(int timer)
{
int ret=0;
struct ddekit_timer_s *t;
lock_timer();
for (t=list.next; t; t = t->next) {
if (t->id==timer) {
ret = 1;
}
}
unlock_timer();
return ret;
}
/*****************************************************************************
* ddekit_init_timers *
****************************************************************************/
void ddekit_init_timers(void)
{
static int first_time=0;
if (!first_time)
{
ddekit_lock_init(&lock);
jiffies = get_current_clock();
HZ = sys_hz();
pending_timer_ints = ddekit_sem_init(0);
th = ddekit_thread_create(ddekit_timer_thread, 0, "timer");
first_time=1;
DDEBUG_MSG_INFO("DDEkit timer subsustem initialized");
}
}
/*****************************************************************************
* ddekit_get_timer_thread *
****************************************************************************/
ddekit_thread_t *ddekit_get_timer_thread(void)
{
return th;
}
/****************************************************************************
* ddekit_internal (src/timer.h) *
****************************************************************************/
/*****************************************************************************
* _ddekit_timer_interrupt *
****************************************************************************/
void _ddekit_timer_interrupt(void)
{
jiffies = get_current_clock();
DDEBUG_MSG_VERBOSE("now: %d", jiffies);
ddekit_sem_up(pending_timer_ints);
}
/*****************************************************************************
* _ddekit_timer_update *
****************************************************************************/
void _ddekit_timer_update()
{
lock_timer();
static myclock_t next_timout;
if(list.next)
{
if(!_ddekit_timer_pending || list.next->exp < next_timout) {
unsigned to = list.next->exp - jiffies;
_ddekit_timer_pending = 1;
if (list.next->exp <= jiffies) {
DDEBUG_MSG_WARN("Timeout lies in past to %d, now: %d",
list.next->exp, jiffies);
to = 1;
}
sys_setalarm(to, 0 /* REL */);
DDEBUG_MSG_VERBOSE("requesting alarm for clock tick %d , now %d",
list.next->exp, jiffies);
}
next_timout = list.next->exp;
}
unlock_timer();
}