/* clock.c simple code to provide a simulated clock interrupt, and routines for manipulating them. Winter 1996 Tian Lim 4/6/96 moved atomic_test_and_set to assembly so the interrupt handler can restart it. - tian 4/7/96 renamed functions. 10/5/98 fixed the a bug due to context switches after the store instr in sys.S 11/5/98 fixed a subtle casting error! */ #include #include "clock.h" #include "minithread_md.h" /* Are interrupts enabled? The interruptHandler function be called iff this is true. */ int interrupts; /* global handle to the user's interrupt service routine */ static ClockHandler interruptHandler; /* this routine simulates a periodic clock tick. every PERIOD microseconds it will be called. if interrupts are enabled, it will call your interrupt service routine */ void clock_tick(int sig, int code, struct sigcontext*scp) { /* this is defined in sys.S */ extern char atomic_test_and_set[]; extern char atomic_test_and_set2[]; /* if we were in the middle of an atomic_test_and_set, set the context pc to the start of the routine so it'll be guaranteed atomic. */ /* * BUG FIX here (Manu 10/05/98) * The pc should not be set back if the store instruction * in the the atomic_test_and_set is already executed. Otherwise * it creates a deadlock */ if ((scp->sc_pc > (long)atomic_test_and_set ) && (scp->sc_pc < (long)atomic_test_and_set2)) { scp->sc_pc = (long)atomic_test_and_set; } if (interrupts==ENABLED) { interruptHandler(); } } void enable_interrupts() { interrupts = ENABLED; } void disable_interrupts() { interrupts = DISABLED; } /* setup the interval timer and install interrupt handler. After this routine is called, and after you enable_interrupts(), clock interrupts will begin to be sent. They will call the handler function h specified by the caller. */ void minithread_clock_init(ClockHandler h) { struct itimerval it, temp; interruptHandler = h; signal (SIGALRM, (ClockHandler)&clock_tick); it.it_interval.tv_sec = 0; it.it_interval.tv_usec = PERIOD; it.it_value.tv_sec = 0; it.it_value.tv_usec = PERIOD; disable_interrupts(); setitimer(ITIMER_REAL, &it, &temp); }