Main Page | Directories | File List | Globals

timers.c

Go to the documentation of this file.
00001 /*
00002  * kernel_super/timers/timers.c
00003  *
00004  * Copyright (c) 2003-2004 Lukasz Dembinski <dembol@nasa.com.pl>
00005  * All Rights Reserved
00006  * 
00007  * Date:        2004/08
00008  * Author:      Lukasz Dembinski
00009  * Info:        timers.c core file
00010  * Contact:     mailto: <dembol@nasa.com.pl>
00011  *
00012  */
00013 
00014 #include <agnix/agnix.h>
00015 #include <agnix/timers.h>
00016 #include <asm/bitops.h>
00017 #include <agnix/spinlock.h>
00018 #include <agnix/queues.h>
00019 #include <agnix/list.h>
00020 #include <agnix/console.h>
00021 
00022 #define MOD_NAME                        "TIMERS: "
00023 
00024 #define TIMER_SET_EXP_BIN(bits)         timer_set_exp_bin(bits)
00025 #define TIMER_SET_EXP(bits)             (TIMER_SET_EXP_BIN(bits) * TIMER_MAX_SET_ENTRIES)
00026 #define TIMER_SET_RATE(bits)            ((TIMER_SET_EXP(bits + 1) - TIMER_SET_EXP(bits)) / TIMER_MAX_SET_ENTRIES)
00027 
00028 int                     timers_initialized = 0;
00029 spinlock_t              timer_lock;
00030 struct timer_set_s      timer_sets[TIMER_MAX_SETS];
00031 
00032 unsigned int timer_set_exp_bin(unsigned long x)
00033 {
00034     if (x - 1 < 0)
00035         return 0;
00036 
00037     return (1 << (x - 1));
00038 }
00039 
00040 int timer_add_lock(struct timer_s *timer, u32 timer_set, u32 timer_idx)
00041 {
00042     list_add(&timer->timer_list, &timer_sets[timer_set].entries[timer_idx].entry_list);
00043     set_bit(timer_idx, timer_sets[timer_set].entries_pending);
00044     timer_sets[timer_set].entries[timer_idx].entry_count++;
00045     timer->timer_set = timer_set;
00046     timer->timer_idx = timer_idx;
00047     
00048     return 0;
00049 }
00050 
00051 int timer_del_lock(struct timer_s *timer)
00052 {
00053     u32 timer_set = timer->timer_set;
00054     u32 timer_idx = timer->timer_idx;
00055     
00056     list_del(&timer->timer_list);
00057     
00058     if (list_empty(&timer_sets[timer_set].entries[timer_idx].entry_list))
00059         clear_bit(timer_idx, timer_sets[timer_set].entries_pending);
00060 
00061     timer_sets[timer_set].entries[timer_idx].entry_count--;
00062     
00063     return 0;
00064 }
00065 
00066 int register_timer_lock(struct timer_s *timer)
00067 {
00068     u32 timer_idx;
00069     u32 timer_set;
00070     u32 i;
00071 
00072     for (i = 0; i < TIMER_MAX_SET_ENTRIES; i++) {
00073         if (timer_sets[i].expire_min <= timer->timer_expire &&
00074             timer_sets[i].expire_max >= timer->timer_expire) {
00075                 timer_set = i;
00076                 timer_idx = (timer->timer_expire - timer_sets[i].expire_min) /
00077                              timer_sets[i].expire_rate;
00078                              
00079                 timer_idx = (timer_idx + timer_sets[i].idx_head) % (TIMER_MAX_SET_ENTRIES - 1);
00080                 timer_add_lock(timer, timer_set, timer_idx);
00081 
00082                 break;
00083         }
00084     }    
00085 
00086     return 0;
00087 }
00088 
00089 int register_timer(struct timer_s *timer)
00090 {
00091     int ret;
00092 
00093     spin_lock_irq(&timer_lock);
00094     ret = register_timer_lock(timer);
00095     spin_unlock_irq(&timer_lock);
00096     
00097     return ret;
00098 }
00099 
00100 int modify_timer(struct timer_s *timer) 
00101 {
00102     return 0;
00103 }
00104 
00105 int unregister_timer_lock(struct timer_s *timer)
00106 {
00107     return timer_del_lock(timer);
00108 }
00109 
00110 int unregister_timer(struct timer_s *timer)
00111 {
00112     int ret;
00113     
00114     spin_lock_irq(&timer_lock);
00115     ret = unregister_timer_lock(timer);
00116     spin_unlock_irq(&timer_lock);
00117 
00118     return ret;
00119 }
00120 
00121 int run_timers_expired(void)
00122 {
00123     struct timer_s *timer;
00124     struct list_head *tmp, *tmp_2;
00125     u32 timer_idx;
00126     
00127     timer_idx = timer_sets[0].idx_head;
00128     
00129     if (test_and_clear_bit(timer_idx, timer_sets[0].entries_pending)) { 
00130         list_for_each_safe(tmp, tmp_2, &timer_sets[0].entries[timer_idx].entry_list) {
00131             timer = list_entry(tmp, struct timer_s, timer_list);
00132 
00133             unregister_timer_lock(timer);
00134 
00135             spin_unlock_irq(&timer_lock);
00136             timer->timer_function(timer->timer_data);
00137             spin_lock_irq(&timer_lock);
00138 
00139             if (!(timer->timer_flags & TIMER_FLAG_ONESHOT))
00140                 register_timer_lock(timer);
00141         }
00142     }
00143 
00144     timer_sets[0].idx_head = (timer_idx + 1) % (TIMER_MAX_SET_ENTRIES - 1);
00145 
00146     return 0;
00147 }
00148 
00149 int run_timers_far(void)
00150 {
00151     int i;
00152     u32 idx_head;
00153     u32 idx_tail_prev;
00154     u32 idx_offset;
00155     u32 idx_offset_back;
00156     u32 expire_rate_prev;
00157     struct timer_s *timer;
00158     struct list_head *entry_list;
00159     struct list_head *tmp, *tmp_2;
00160 
00161     for (i = 1; i < TIMER_MAX_SETS; i++) {
00162         
00163         if ((timer_sets[i].expire_rate > 1) && (timer_sets[0].idx_head % timer_sets[i].expire_rate))
00164             break;
00165 
00166         idx_head = timer_sets[i].idx_head;
00167         
00168         if (test_and_clear_bit(idx_head, timer_sets[i].entries_pending)) {
00169             expire_rate_prev = timer_sets[i - 1].expire_rate;
00170             entry_list       = &(timer_sets[i].entries[idx_head].entry_list);
00171             idx_tail_prev    = (timer_sets[i - 1].idx_head - 1) % (TIMER_MAX_SET_ENTRIES - 1);
00172 
00173             idx_offset_back = 0;
00174             list_for_each_safe(tmp, tmp_2, entry_list) {
00175                 timer = list_entry(tmp, struct timer_s, timer_list);
00176 
00177                 if (i > 1)
00178                     idx_offset_back = ((timer->timer_expire / expire_rate_prev) + 1) % 2;
00179                 
00180                 idx_offset = (idx_tail_prev - idx_offset_back) % (TIMER_MAX_SET_ENTRIES - 1);
00181                 timer_add_lock(timer, i - 1, idx_offset);
00182             }
00183             
00184             INIT_LIST_HEAD(entry_list);
00185             timer_sets[i].entries[idx_head].entry_count = 0;
00186         }
00187         
00188         timer_sets[i].idx_head = (timer_sets[i].idx_head + 1) % (TIMER_MAX_SET_ENTRIES - 1);
00189     }
00190 
00191     return 0;
00192 }
00193 
00194 int run_timers(void)
00195 {
00196     if (!timers_initialized)
00197         return 0;
00198     
00199     spin_lock_irq(&timer_lock);
00200     run_timers_expired();
00201     run_timers_far();
00202     spin_unlock_irq(&timer_lock);
00203 
00204     return 0;
00205 }
00206 
00207 int timers_init(void)
00208 {
00209     int i, j;
00210 
00211     printk(MOD_NAME "Initializing timers\n");
00212 
00213     for (i = 0; i < TIMER_MAX_SETS; i++) {
00214 
00215         timer_sets[i].expire_min  = TIMER_SET_EXP(i);
00216         timer_sets[i].expire_rate = TIMER_SET_RATE(i);
00217         timer_sets[i].expire_max  = timer_sets[i].expire_min + (TIMER_MAX_SET_ENTRIES - 1) * timer_sets[i].expire_rate;
00218         timer_sets[i].idx_head = 0;
00219 
00220         for (j = 0; j < TIMER_MAX_SET_ENTRIES; j++) {
00221             INIT_LIST_HEAD(&timer_sets[i].entries[j].entry_list);
00222             timer_sets[i].entries[j].entry_count = 0;
00223         }
00224     }
00225         
00226     spin_lock_init(&timer_lock);
00227     timers_initialized = 1;
00228     
00229     return 0;
00230 }
Dokumentacje wygenerowano programem Doxygen 1.4.2 dla projektu Agnix