I have an operating systems project due tonight, and needed clarification on a topic. We are working with the operating system XINU. I am trying to change the default OS scheduler to account for some processes being starved. I was directed towards the clkint.S file, which I think is the clock interrupt handler. My question is, how do I know how often it interrupts? How do I set the time to lets say make a function call every 5 seconds? I have looked at the intel x86 manuals, but they have an absurd amount of information to sift through, and I am short on time If someone can point me in the right direction, I'd be grateful.
Here are a couple of files I think necessary:
clkint.S:
/* clkint.s - _clkint */
#include <icu.s>
.text
count1000: .word 1000
.globl sltop
.globl clkint
clkint:
pushal
cli
movb $EOI,%al
outb %al,$OCW1_2
incl ctr1000
subw $1,count1000
ja cl1
incl clktime
movw $1000,count1000
cl1:
cmpl $0,slnonempty # if no sleeping processes,
je clpreem # skip to preemption check
movl sltop,%eax # decrement key of first
decl (%eax) # sleeping process
jg clpreem # must use jg for signed int
call wakeup # if zero, call wakeup
clpreem: decl preempt # decrement preemption counter
jg clret # must use jg for signed int
call resched # if preemption, call resched
clret: # return from interrupt
sti
popal
iret
clkinit.c:
/* clkinit.c - clkinit */
#include <xinu.h>
#include <interrupt.h>
#include <clock.h>
uint32 clktime; /* seconds since boot */
uint32 ctr1000 = 0; /* milliseconds since boot */
qid16 sleepq; /* queue of sleeping processes */
int32 slnempty; /* zero if the sleep queue is empty; */
/* non-zero otherwise */
int32 *sltop; /* ptr to key in first entry of sleepq */
/* if sleepq is not empty */
uint32 preempt; /* preemption counter */
/*------------------------------------------------------------------------
* clkinit - initialize the clock and sleep queue at startup
*------------------------------------------------------------------------
*/
void clkinit(void)
{
uint16 intv; /* clock rate in KHz */
/* Set interrupt vector for clock to invoke clkint */
set_evec(IRQBASE, (uint32)clkint);
/* clock rate is 1.190 Mhz; this is 10ms interrupt rate */
intv = 1190;
sleepq = newqueue(); /* allocate a queue to hold the delta */
/* list of sleeping processes */
preempt = QUANTUM; /* initial time quantum */
/* Specify that seepq is initially empty */
slnonempty = FALSE;
clktime = 0; /* start counting seconds */
/* set to: timer 0, 16-bit counter, rate generator mode,
counter is binary */
outb(CLKCNTL, 0x34);
/* must write LSB first, then MSB */
outb(CLOCK0, (char)intv);
outb(CLOCK0, intv>>8);
return;
}
clkhandler.c:
/* clkhandler.c - clkhandler */
#include <xinu.h>
/*------------------------------------------------------------------------
* clkhandler - handle clock interrupt and process preemption events
* as well as awakening sleeping processes
*------------------------------------------------------------------------
*/
interrupt clkhandler(void)
{
clkupdate(CLKCYCS_PER_TICK);
/* record clock ticks */
clkticks++;
/* update global counter for seconds */
if (clkticks == CLKTICKS_PER_SEC) {
clktime++;
clkticks = 0;
}
/* If sleep queue is nonempty, decrement first key; when the */
/* key reaches zero, awaken a sleeping process */
if (nonempty(sleepq) && (--firstkey(sleepq) <= 0)) {
wakeup();
}
/* Check to see if this proc should be preempted */
if (--preempt <= 0) {
preempt = QUANTUM;
resched();
}
return;
}
I can add all of the starvation functionality on my own, I just need to figure out how to make the clkint.s handler call my function lets say A every 5 seconds...I don't understand how the clock works or the assembly entirely. I am not asking for someone to give me a solution, I just need some guidance.
intv
is the time slicing granularity (in Khz) for the interrupt timer for scheduling (at least in this code). Every 5 seconds sounds very slow and is likely to make your system barely responsive, try on the order of milliseconds.
To calculate a new interval you need to change this value and do a little math with the frequency. You can probably figure this step out from the calculation done on intv
to get 10ms.
In x86 the timer value can be established by writing the timer interrupt value in KHz to the port 0x40
using the outb
assembly instruction. As shown in the code you have to write the least significant byte followed by the most significant (outb
writes a byte at a time). To enable the timer you write 0x36
to the same port and you must bind an IRQ handler to IRQ0 in order to receive the interrupt. I tried condensing the info for you a bit but this is x86 specific.