kern
diff src/timer.c @ 51:b1e8c8251884
lalalala
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Mon, 01 Aug 2011 06:45:29 +0300 |
parents | f65b348780e3 |
children | 88a6c4e192f9 |
line diff
1.1 --- a/src/timer.c Sat Jul 30 07:35:53 2011 +0300 1.2 +++ b/src/timer.c Mon Aug 01 06:45:29 2011 +0300 1.3 @@ -3,6 +3,8 @@ 1.4 #include "intr.h" 1.5 #include "asmops.h" 1.6 #include "timer.h" 1.7 +#include "proc.h" 1.8 +#include "sched.h" 1.9 #include "config.h" 1.10 1.11 /* frequency of the oscillator driving the 8254 timer */ 1.12 @@ -39,9 +41,24 @@ 1.13 #define CMD_MODE_BCD 1 1.14 1.15 1.16 +#define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000) 1.17 + 1.18 +struct timer_event { 1.19 + int dt; /* remaining ticks delta from the previous event */ 1.20 + 1.21 + void (*callback)(void*); 1.22 + void *cbarg; 1.23 + 1.24 + struct timer_event *next; 1.25 +}; 1.26 + 1.27 + 1.28 static void intr_handler(); 1.29 1.30 1.31 +static struct timer_event *evlist; 1.32 + 1.33 + 1.34 void init_timer(void) 1.35 { 1.36 /* calculate the reload count: round(osc / freq) */ 1.37 @@ -62,11 +79,101 @@ 1.38 interrupt(IRQ_TO_INTR(0), intr_handler); 1.39 } 1.40 1.41 +int start_timer(unsigned long msec, timer_func_t cbfunc, void *cbarg) 1.42 +{ 1.43 + int ticks, tsum, istate; 1.44 + struct timer_event *ev, *node; 1.45 + 1.46 + printf("start_timer(%lu)\n", msec); 1.47 + 1.48 + if((ticks = MSEC_TO_TICKS(msec)) <= 0) { 1.49 + cbfunc(cbarg); 1.50 + return 0; 1.51 + } 1.52 + 1.53 + if(!(ev = malloc(sizeof *ev))) { 1.54 + printf("start_timer: failed to allocate timer_event structure\n"); 1.55 + return -1; 1.56 + } 1.57 + ev->callback = cbfunc; 1.58 + ev->cbarg = cbarg; 1.59 + 1.60 + istate = get_intr_state(); 1.61 + disable_intr(); 1.62 + 1.63 + /* insert at the beginning */ 1.64 + if(!evlist || ticks <= evlist->dt) { 1.65 + ev->next = evlist; 1.66 + evlist = ev; 1.67 + 1.68 + ev->dt = ticks; 1.69 + if(ev->next) { 1.70 + ev->next->dt -= ticks; 1.71 + } 1.72 + set_intr_state(istate); 1.73 + return 0; 1.74 + } 1.75 + 1.76 + tsum = evlist->dt; 1.77 + node = evlist; 1.78 + 1.79 + while(node->next && ticks > tsum + node->next->dt) { 1.80 + tsum += node->next->dt; 1.81 + node = node->next; 1.82 + } 1.83 + 1.84 + ev->next = node->next; 1.85 + node->next = ev; 1.86 + 1.87 + /* fix the relative times */ 1.88 + ev->dt = ticks - tsum; 1.89 + if(ev->next) { 1.90 + ev->next->dt -= ev->dt; 1.91 + } 1.92 + 1.93 + set_intr_state(istate); 1.94 + return 0; 1.95 +} 1.96 + 1.97 /* This will be called by the interrupt dispatcher approximately 1.98 * every 1/250th of a second, so it must be extremely fast. 1.99 * For now, just increasing a tick counter will suffice. 1.100 */ 1.101 -static void intr_handler() 1.102 +static void intr_handler(int inum) 1.103 { 1.104 + int istate; 1.105 + struct process *cur_proc; 1.106 + 1.107 nticks++; 1.108 + 1.109 + printf("TICKS: %d\n", nticks); 1.110 + 1.111 + istate = get_intr_state(); 1.112 + disable_intr(); 1.113 + 1.114 + /* find out if there are any timers that have to go off */ 1.115 + if(evlist) { 1.116 + evlist->dt--; 1.117 + 1.118 + while(evlist->dt <= 0) { 1.119 + struct timer_event *ev = evlist; 1.120 + evlist = evlist->next; 1.121 + 1.122 + printf("timer going off!!!\n"); 1.123 + ev->callback(ev->cbarg); 1.124 + free(ev); 1.125 + } 1.126 + } 1.127 + 1.128 + if((cur_proc = get_current_proc())) { 1.129 + if(--cur_proc->ticks_left <= 0) { 1.130 + /* since schedule will not return, we have to notify 1.131 + * the PIC that we're done with the IRQ handling 1.132 + */ 1.133 + end_of_irq(INTR_TO_IRQ(inum)); 1.134 + schedule(); 1.135 + } 1.136 + } 1.137 + 1.138 + set_intr_state(istate); 1.139 }