home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / lxapi32.zip / Lib32 / lxtimer.c < prev    next >
C/C++ Source or Header  |  2002-04-26  |  6KB  |  231 lines

  1. /* $Id: lxtimer.c,v 1.2 2002/04/26 23:09:25 smilcke Exp $ */
  2.  
  3. /*
  4.  * timer.c
  5.  * Autor:               Stefan Milcke
  6.  * Erstellt am:         19.11.2001
  7.  * Letzte Aenderung am: 14.12.2001
  8.  *
  9. */
  10.  
  11. #include <linux/kernel.h>
  12. #include <linux/slab.h>
  13. #include <linux/mm.h>
  14. #include <linux/version.h>
  15. #include <linux/module.h>
  16. #include <linux/delay.h>
  17. #include <linux/types.h>
  18. #include <linux/timer.h>
  19.  
  20. #define TVN_BITS 6
  21. #define TVR_BITS 8
  22. #define TVN_SIZE (1 << TVN_BITS)
  23. #define TVR_SIZE (1 << TVR_BITS)
  24. #define TVN_MASK (TVN_SIZE - 1)
  25. #define TVR_MASK (TVR_SIZE - 1)
  26.  
  27. spinlock_t timerlist_lock = SPIN_LOCK_UNLOCKED;
  28. static unsigned long timer_jiffies;
  29. int volatile timervecs_initialized=0;
  30.  
  31. struct timer_vec
  32. {
  33.  int index;
  34.  struct list_head vec[TVN_SIZE];
  35. };
  36.  
  37. struct timer_vec_root
  38. {
  39.  int index;
  40.  struct list_head vec[TVR_SIZE];
  41. };
  42.  
  43. static struct timer_vec tv5;
  44. static struct timer_vec tv4;
  45. static struct timer_vec tv3;
  46. static struct timer_vec tv2;
  47. static struct timer_vec_root tv1;
  48.  
  49. static struct timer_vec * const tvecs[]={
  50.   (struct timer_vec *)&tv1,&tv2,&tv3,&tv4,&tv5
  51. };
  52. #define NOOF_TVECS (sizeof(tvecs) / sizeof(tvecs[0]))
  53.  
  54. //----------------------------- int timer_pending ------------------------------
  55. int timer_pending(const struct timer_list *timer)
  56. {
  57.  return timer->list.next!=NULL;
  58. }
  59.  
  60. //------------------------------- init_timervecs -------------------------------
  61. int init_timervecs(void)
  62. {
  63.  int i;
  64.  for(i = 0; i < TVN_SIZE; i++)
  65.  {
  66.   INIT_LIST_HEAD(tv5.vec + i);
  67.   INIT_LIST_HEAD(tv4.vec + i);
  68.   INIT_LIST_HEAD(tv3.vec + i);
  69.   INIT_LIST_HEAD(tv2.vec + i);
  70.  }
  71.  for(i = 0; i < TVR_SIZE; i++)
  72.   INIT_LIST_HEAD(tv1.vec + i);
  73.  timervecs_initialized=1;
  74.  return 0;
  75. }
  76.  
  77. //----------------------------- internal_add_timer -----------------------------
  78. static void internal_add_timer(struct timer_list *timer)
  79. {
  80.  // must be cli-ed when calling this
  81.  unsigned long expires = timer->expires;
  82.  unsigned long idx = expires - timer_jiffies;
  83.  struct list_head * vec;
  84.  if (idx < TVR_SIZE)
  85.  {
  86.   int i = expires & TVR_MASK;
  87.   vec = tv1.vec + i;
  88.  }
  89.  else if (idx < 1 << (TVR_BITS + TVN_BITS))
  90.  {
  91.   int i = (expires >> TVR_BITS) & TVN_MASK;
  92.   vec = tv2.vec + i;
  93.  }
  94.  else if (idx < 1 << (TVR_BITS + 2 * TVN_BITS))
  95.  {
  96.   int i = (expires >> (TVR_BITS + TVN_BITS)) & TVN_MASK;
  97.   vec =  tv3.vec + i;
  98.  }
  99.  else if (idx < 1 << (TVR_BITS + 3 * TVN_BITS))
  100.  {
  101.   int i = (expires >> (TVR_BITS + 2 * TVN_BITS)) & TVN_MASK;
  102.   vec = tv4.vec + i;
  103.  }
  104.  else if ((signed long) idx < 0)
  105.  {
  106.   // can happen if you add a timer with expires == jiffies, or you set a timer
  107.   // to go off in the past
  108.   vec = tv1.vec + tv1.index;
  109.  }
  110.  else
  111.  {
  112.   int i = (expires >> (TVR_BITS + 3 * TVN_BITS)) & TVN_MASK;
  113.   vec = tv5.vec + i;
  114.  }
  115.  // Timers are FIFO!
  116.  list_add(&timer->list, vec->prev);
  117. }
  118.  
  119. //--------------------------------- add_timer ----------------------------------
  120. void add_timer(struct timer_list *timer)
  121. {
  122.  unsigned long flags;
  123.  spin_lock_irqsave(&timerlist_lock, flags);
  124.  if(timer_pending(timer))
  125.   goto bug;
  126.  internal_add_timer(timer);
  127.  spin_unlock_irqrestore(&timerlist_lock, flags);
  128.  return;
  129. bug:
  130.  spin_unlock_irqrestore(&timerlist_lock, flags);
  131.  CPK(printk("bug: kernel timer added twice\n"));
  132. }
  133.  
  134. //-------------------------------- detach_timer --------------------------------
  135. static int detach_timer(struct timer_list *timer)
  136. {
  137.  if(!timer_pending(timer))
  138.   return 0;
  139.  list_del(&timer->list);
  140.  return 1;
  141. }
  142.  
  143. //--------------------------------- mod_timer ----------------------------------
  144. int mod_timer(struct timer_list *timer,unsigned long expires)
  145. {
  146.  int ret;
  147.  unsigned long flags;
  148.  spin_lock_irqsave(&timerlist_lock,flags);
  149.  timer->expires=expires;
  150.  ret=detach_timer(timer);
  151.  internal_add_timer(timer);
  152.  spin_unlock_irqrestore(&timerlist_lock,flags);
  153.  return ret;
  154. }
  155.  
  156. //--------------------------------- del_timer ----------------------------------
  157. int del_timer(struct timer_list *timer)
  158. {
  159.  int ret=0;
  160.  unsigned long flags;
  161.  spin_lock_irqsave(&timerlist_lock,flags);
  162.  ret=detach_timer(timer);
  163.  timer->list.next=timer->list.prev=NULL;
  164.  spin_unlock_irqrestore(&timerlist_lock,flags);
  165.  return ret;
  166. }
  167.  
  168. //------------------------------- cascade_timers -------------------------------
  169. static void cascade_timers(struct timer_vec *tv)
  170. {
  171.  // cascade all the timers from tv up one level
  172.  struct list_head *head, *curr, *next;
  173.  head = tv->vec + tv->index;
  174.  curr = head->next;
  175.  // We are removing _all_ timers from the list, so we don't  have to
  176.  // detach them individually, just clear the list afterwards.
  177.  while(curr != head)
  178.  {
  179.   struct timer_list *tmp;
  180.   tmp = list_entry(curr, struct timer_list, list);
  181.   next = curr->next;
  182.   list_del(curr); // not needed
  183.   internal_add_timer(tmp);
  184.   curr = next;
  185.  }
  186.  INIT_LIST_HEAD(head);
  187.  tv->index = (tv->index + 1) & TVN_MASK;
  188. }
  189.  
  190. //------------------------------- run_timer_list -------------------------------
  191. void run_timer_list(void)
  192. {
  193.  if(!timervecs_initialized)
  194.   return;
  195.  spin_lock_irq(&timerlist_lock);
  196.  while ((long)(jiffies - timer_jiffies) >= 0)
  197.  {
  198.   struct list_head *head, *curr;
  199.   if (!tv1.index)
  200.   {
  201.    int n = 1;
  202.    do
  203.    {
  204.     cascade_timers(tvecs[n]);
  205.    } while (tvecs[n]->index == 1 && ++n < NOOF_TVECS);
  206.   }
  207. repeat:
  208.   head = tv1.vec + tv1.index;
  209.   curr = head->next;
  210.   if (curr != head)
  211.   {
  212.    struct timer_list *timer;
  213.    void (*fn)(unsigned long);
  214.    unsigned long data;
  215.    timer = list_entry(curr, struct timer_list, list);
  216.    fn = timer->function;
  217.    data= timer->data;
  218.    detach_timer(timer);
  219.    timer->list.next = timer->list.prev = NULL;
  220. //   timer_enter(timer);
  221.    spin_unlock_irq(&timerlist_lock);
  222.    fn(data);
  223.    spin_lock_irq(&timerlist_lock);
  224. //   timer_exit();
  225.    goto repeat;
  226.   }
  227.   ++timer_jiffies;
  228.   tv1.index = (tv1.index + 1) & TVR_MASK;
  229.  }
  230.  spin_unlock_irq(&timerlist_lock);
  231. }