home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
lxapi32.zip
/
Lib32
/
lxtimer.c
< prev
next >
Wrap
C/C++ Source or Header
|
2002-04-26
|
6KB
|
231 lines
/* $Id: lxtimer.c,v 1.2 2002/04/26 23:09:25 smilcke Exp $ */
/*
* timer.c
* Autor: Stefan Milcke
* Erstellt am: 19.11.2001
* Letzte Aenderung am: 14.12.2001
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/timer.h>
#define TVN_BITS 6
#define TVR_BITS 8
#define TVN_SIZE (1 << TVN_BITS)
#define TVR_SIZE (1 << TVR_BITS)
#define TVN_MASK (TVN_SIZE - 1)
#define TVR_MASK (TVR_SIZE - 1)
spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
static unsigned long timer_jiffies;
int volatile timervecs_initialized=0;
struct timer_vec
{
int index;
struct list_head vec[TVN_SIZE];
};
struct timer_vec_root
{
int index;
struct list_head vec[TVR_SIZE];
};
static struct timer_vec tv5;
static struct timer_vec tv4;
static struct timer_vec tv3;
static struct timer_vec tv2;
static struct timer_vec_root tv1;
static struct timer_vec * const tvecs[]={
(struct timer_vec *)&tv1,&tv2,&tv3,&tv4,&tv5
};
#define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
//----------------------------- int timer_pending ------------------------------
int timer_pending(const struct timer_list *timer)
{
return timer->list.next!=NULL;
}
//------------------------------- init_timervecs -------------------------------
int init_timervecs(void)
{
int i;
for(i = 0; i < TVN_SIZE; i++)
{
INIT_LIST_HEAD(tv5.vec + i);
INIT_LIST_HEAD(tv4.vec + i);
INIT_LIST_HEAD(tv3.vec + i);
INIT_LIST_HEAD(tv2.vec + i);
}
for(i = 0; i < TVR_SIZE; i++)
INIT_LIST_HEAD(tv1.vec + i);
timervecs_initialized=1;
return 0;
}
//----------------------------- internal_add_timer -----------------------------
static void internal_add_timer(struct timer_list *timer)
{
// must be cli-ed when calling this
unsigned long expires = timer->expires;
unsigned long idx = expires - timer_jiffies;
struct list_head * vec;
if (idx < TVR_SIZE)
{
int i = expires & TVR_MASK;
vec = tv1.vec + i;
}
else if (idx < 1 << (TVR_BITS + TVN_BITS))
{
int i = (expires >> TVR_BITS) & TVN_MASK;
vec = tv2.vec + i;
}
else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS))
{
int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
vec = tv3.vec + i;
}
else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS))
{
int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
vec = tv4.vec + i;
}
else if ((signed long) idx < 0)
{
// can happen if you add a timer with expires == jiffies, or you set a timer
// to go off in the past
vec = tv1.vec + tv1.index;
}
else
{
int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
vec = tv5.vec + i;
}
// Timers are FIFO!
list_add(&timer->list, vec->prev);
}
//--------------------------------- add_timer ----------------------------------
void add_timer(struct timer_list *timer)
{
unsigned long flags;
spin_lock_irqsave(&timerlist_lock, flags);
if(timer_pending(timer))
goto bug;
internal_add_timer(timer);
spin_unlock_irqrestore(&timerlist_lock, flags);
return;
bug:
spin_unlock_irqrestore(&timerlist_lock, flags);
CPK(printk("bug: kernel timer added twice\n"));
}
//-------------------------------- detach_timer --------------------------------
static int detach_timer(struct timer_list *timer)
{
if(!timer_pending(timer))
return 0;
list_del(&timer->list);
return 1;
}
//--------------------------------- mod_timer ----------------------------------
int mod_timer(struct timer_list *timer,unsigned long expires)
{
int ret;
unsigned long flags;
spin_lock_irqsave(&timerlist_lock,flags);
timer->expires=expires;
ret=detach_timer(timer);
internal_add_timer(timer);
spin_unlock_irqrestore(&timerlist_lock,flags);
return ret;
}
//--------------------------------- del_timer ----------------------------------
int del_timer(struct timer_list *timer)
{
int ret=0;
unsigned long flags;
spin_lock_irqsave(&timerlist_lock,flags);
ret=detach_timer(timer);
timer->list.next=timer->list.prev=NULL;
spin_unlock_irqrestore(&timerlist_lock,flags);
return ret;
}
//------------------------------- cascade_timers -------------------------------
static void cascade_timers(struct timer_vec *tv)
{
// cascade all the timers from tv up one level
struct list_head *head, *curr, *next;
head = tv->vec + tv->index;
curr = head->next;
// We are removing _all_ timers from the list, so we don't have to
// detach them individually, just clear the list afterwards.
while(curr != head)
{
struct timer_list *tmp;
tmp = list_entry(curr, struct timer_list, list);
next = curr->next;
list_del(curr); // not needed
internal_add_timer(tmp);
curr = next;
}
INIT_LIST_HEAD(head);
tv->index = (tv->index + 1) & TVN_MASK;
}
//------------------------------- run_timer_list -------------------------------
void run_timer_list(void)
{
if(!timervecs_initialized)
return;
spin_lock_irq(&timerlist_lock);
while ((long)(jiffies - timer_jiffies) >= 0)
{
struct list_head *head, *curr;
if (!tv1.index)
{
int n = 1;
do
{
cascade_timers(tvecs[n]);
} while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);
}
repeat:
head = tv1.vec + tv1.index;
curr = head->next;
if (curr != head)
{
struct timer_list *timer;
void (*fn)(unsigned long);
unsigned long data;
timer = list_entry(curr, struct timer_list, list);
fn = timer->function;
data= timer->data;
detach_timer(timer);
timer->list.next = timer->list.prev = NULL;
// timer_enter(timer);
spin_unlock_irq(&timerlist_lock);
fn(data);
spin_lock_irq(&timerlist_lock);
// timer_exit();
goto repeat;
}
++timer_jiffies;
tv1.index = (tv1.index + 1) & TVR_MASK;
}
spin_unlock_irq(&timerlist_lock);
}