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  }