/////// OS.cpp ///////////////////////////////////// /***************************************************** ** Lab 10+ CprE 308 Spring 99 ** ** Section: 4 Thursday 3-6 ** ** ** ** Tim Downs Mullen Chad Whipple ** *****************************************************/ #include "os.h" #include #include #include #include #include #define TIMESLICE 3 #define STACKSIZE 1024 #define MAXPROCS 8 #define EMPTY 0 // process table entry is empty #define RUNNING 1 // this is THE running thread #define READY 2 // this thread is ready to run #define SLEEPING 3 // sleeping until sleep_ticks = 0 #define ZOMBIE 4 // coming or going ... don't run it #define DONE 5 int code_segment; // CS address int new_code_seg; // interrupt CS address int CurrentThread; // global for currentthread running int Suspend_interrupt=0; // OS_Suspend flag clktime current_time; // clock structure struct ptable { char Name[16]; // thread name, in ASCII int Status; // hold stack pointer for this thread int SleepTicksLeft; // if sleeping, this is when it wakes up int CPUticks; // accumulated CPU clock ticks int SliceTicksLeft; // counts down from TIMESLICE to 0 int SP; // Stack Pointer int MemBlock; // Start of Memory Block for malloc/free int Priority; // for future expansion. } ProcessTable[MAXPROCS]; char *p_status(int stat) { static char *what[6] = {"EMPTY ", "RUNNING ", "READY ", "SLEEPING", "ZOMBIE ", "DONE "}; if(stat<0 || stat>5) return "???"; return what[stat]; } void interrupt (*Old_Handler)(...); void interrupt Clock_ISR(...); //void interrupt (*Old_Handler_Suspend)(...); //void interrupt Suspend_ISR(...); void OS_KILL_KILL_KILL(); //////////////////////////////////////////////////////////////////////////// // // // //Initializes the clock ISR and stores the old interrupt // checks for small memory mode and returns 1 //else returns 0 on success // // //////////////////////////////////////////////////////////////////////////// int OS_Startup() { int ds_flag; //for small code module checking int ss_flag; //for small code module checking int i; //happy forloop var char threadname[16] = "main"; //init for main threadname //for BDC conversion char hr, min, sec, temp1, temp2; //grab this code's CS, Data Segment, and Stack Segment for error checking //store in code_segment, ds_flag, and ss_flag respectively asm { mov code_segment, CS mov AX, DS mov ds_flag, AX mov AX, SS mov ss_flag, AX } //small code module check if (ds_flag != ss_flag) { printf("\n\nNot small code mode, Piss off!!!\n\n"); return(1); } // get the current time from DOS asm { MOV AH,2h INT 1Ah MOV hr,CH MOV min,CL MOV sec,DH }; //Convert BCD to int temp1 = hr; temp2 = hr; temp1 = (temp1 >> 4) * 10; //convert tens temp2 = (temp2 & 0x0f); //convert ones hr = temp1 + temp2; //happy int value from BCD temp1 = min; temp2 = min; temp1 = (temp1 >> 4) * 10; temp2 = (temp2 & 0x0f); min = temp1 + temp2; temp1 = sec; temp2 = sec; temp1 = (temp1 >> 4) * 10; temp2 = (temp2 & 0x0f); sec = temp1 + temp2; // Fill in the time structure here current_time.hours = hr; current_time.minutes = min; current_time.seconds = sec; // Use getvect() to obtain the old contents of the clock Interrupt vector Old_Handler = getvect(8); // Set the vector to point to out ISR setvect(8, Clock_ISR); //obtain application old soft interrupt 0x60 //Old_Handler_Suspend = getvect(0x60); //setup main in process table // copy main into 16byte name buffer for (i=0;i<16;i++) { ProcessTable[0].Name[i] = threadname[i]; } ProcessTable[0].Status = RUNNING; ProcessTable[0].CPUticks = 0; ProcessTable[0].SliceTicksLeft = TIMESLICE; ProcessTable[0].SleepTicksLeft = 0; //sets all threads status to EMPTY for(i=1;iName); printf("%-7s ", p_status(pt->Status)); printf("%-7d %-4d %-4d", pt->SleepTicksLeft, pt->CPUticks, pt-> SliceTicksLeft); printf(" %04x\n", pt->SP); } printf("-----------------------------------------------------------------\n\n"); } //////////////////////////////////////////////////////////////// // This is the clock ISR // // it is happy because it gets to count the //18.2 ticks per second that it gets interrupted //this is a pain in the ass because of the extra .2 ticks //the grovie solution for this was a similar bastardization //of the calander screw up with extra days and we implemented //a "leap tick" //BUT WAIT THATS NOT ALL!!!!!!! //look what else you get: //keeps track of CPU ticks spent in thread (yes main is a thread) //round-robin thread switching //AND it doesn't do any of this superkalifragalistic switching //if the interrupted occurs outside of our code segment //////////////////////////////////////////////////////////////// void interrupt Clock_ISR(...) { static unsigned long tick = 0; static int leap = 1; static int tmpSP; int i; //check for suspend interruption and don't increment ticks if that is the case if (Suspend_interrupt == 0) { ProcessTable[CurrentThread].CPUticks++; ProcessTable[CurrentThread].SliceTicksLeft--; tick++; for(i=0; i 59) { current_time.seconds = 0; current_time.minutes ++; } //check minutes if (current_time.minutes > 59) { current_time.minutes = 0; current_time.hours ++; } // check hours if (current_time.hours > 23) current_time.hours = 0; }//end else leap ++; }//end time if }//end Suspend if if (ProcessTable[CurrentThread].SliceTicksLeft <= 0)//checks time left { asm { mov AX, [BP+20] mov new_code_seg, AX } //interrupt CS check if (code_segment == new_code_seg) { //push BP for next return interrupt and save stack pointer asm { push BP mov tmpSP, SP } ProcessTable[CurrentThread].SP = tmpSP; if(ProcessTable[CurrentThread].Status == RUNNING) ProcessTable[CurrentThread].Status = READY; //search for next ready Thread and set time slice do { CurrentThread = (CurrentThread+1)%MAXPROCS; }while(ProcessTable[CurrentThread].Status != READY); tmpSP = ProcessTable[CurrentThread].SP; ProcessTable[CurrentThread].SliceTicksLeft=TIMESLICE; //get new threads stack pointer and old Base Pointer asm { mov SP, tmpSP pop BP } }//end if CS test }//end if timeslice //return old_handler for suspend if (Suspend_interrupt == 1) { Suspend_interrupt = 0; //Set soft interrupt to point to old interrupt //setvect(0x60, Old_Handler_Suspend); } else Old_Handler(); }