/** @brief (SYS6) Retrieve the CPU time of the current process. @return CPU time of the current process. */ EXTERN U32 getCPUTime() { /* Perform a last update of the CPU time */ CurrentProcess->p_cpu_time += getTODLO() - ProcessTOD; ProcessTOD = getTODLO(); return CurrentProcess->p_cpu_time; }
void scheduler() { //Due possibili casi: // -Esiste un processo in esecuzione -> context switch // -Non c'è un processo -> ne carico uno if(currentProcess!=NULL){ //current process è quello che deve essere eseguito timer+=getTODLO()-last_access; last_access=getTODLO(); //#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -> sta su uARMconst //#define SCHED_TIME_SLICE 5000 //#define SCHED_PSEUDO_CLOCK 100000 setTIMER(MIN(SCHED_TIME_SLICE, SCHED_PSEUDO_CLOCK-timer)); LDST(&(currentProcess->s_t)); } else{ //Anche qui due casi possibili, controlliamo se la readyQueue è vuota if(clist_empty(readyQueue)){ //processCount = 0 -> HALT -> non ci sono processi if(processCount == 0) HALT(); //processCount>0 e SBC==0-> qualcosa è andato storto -> deadlock if(processCount>0 && softBlockCount == 0) PANIC(); //caso "normale" -> aspettiamo che un processo necessiti di essere allocato if(processCount>0 && softBlockCount > 0) WAIT(); //qualsiasi altro stato PANIC(); } else{ //semplicemente carico il primo processo in memoria //scherzavo, non è semplice currentProcess = removeProcQ(readyQueue); if(currentProcess == NULL) PANIC(); //qualcosa è andato storto //imposta i timer e altre cose brutte scheduler(); } } }
int main() { pcb_t *init; int i; /* Populate the processor state areas into the ROM Reserved Frame */ populateArea(SYSBK_NEWAREA, (memaddr) sysBpHandler); /* SYS/BP Exception Handling */ populateArea(PGMTRAP_NEWAREA, (memaddr) pgmTrapHandler); /* PgmTrap Exception Handling */ populateArea(INT_NEWAREA, (memaddr) intHandler); /* Interrupt Exception Handling */ populateArea(TLB_NEWAREA, (memaddr) tlbHandler); /* TLB Exception Handling */ /* Initialize data structures */ initPcbs(); initASL(); /* Initialize global variables */ ReadyQueue = mkEmptyProcQ(); CurrentProcess = NULL; ProcessCount = SoftBlockCount = TimerTick = PseudoClock = 0; /* Initialize device semaphores */ for (i = 0; i < DEV_PER_INT; i++) Semaphore.disk[i] = Semaphore.tape[i] = Semaphore.network[i] = Semaphore.printer[i] = Semaphore.terminalR[i] = Semaphore.terminalT[i] = 0; /* Initialize init method */ if (!(init = allocPcb())) PANIC(); /* Anomaly */ /* Enable interrupts; enable Kernel-Mode; disable Virtual Memory */ init->p_s.CP15_Control &= ~(0x1); init->p_s.cpsr = STATUS_SYS_MODE | STATUS_ALL_INT_ENABLE(init->p_s.cpsr); /* Initialize Stack Pointer */ init->p_s.sp = RAM_TOP - BUS_REG_RAM_SIZE; /* Initialize Program Counter with the test process */ init->p_s.pc = (memaddr) test; /* Insert init in ProcQ */ insertProcQ(&ReadyQueue, init); /* Initialize Process Id */ ProcessCount++; /* Start the timer tick */ StartTimerTick = getTODLO(); /* Call the scheduler */ scheduler(); /* Anomaly */ PANIC(); return 0; }
//gestore degli interrupt void int_handler(){ interruptStart = getTODLO(); //tempo in cui comincia la gestione dell'interrupt, da //assegnare poi ad un eventuale processo svegliato dall'interrupt state_t *returnState = (state_t*) INT_OLDAREA; returnState->pc -= 4; if( current_process != NULL){ copy_state( returnState, ¤t_process->p_s ); current_process->userTime += interruptStart - userTimeStart;//se c'è un processo aggiorno il suo userTime current_process->CPUTime += interruptStart - CPUTimeStart; } int cause = getCAUSE(); if(CAUSE_IP_GET(cause, IL_TIMER)){ if( current_timer == PSEUDO_CLOCK ){ while( devSem[CLOCK_SEM] < 0 ){ //Ad ogni pseudo clock tick mi assicuro che il semaforo sia sempre a zero verhogen( &devSem[CLOCK_SEM], 1, 0, getTODLO() - interruptStart); } } else if(current_timer == TIME_SLICE ){ if( current_process != NULL ){ insertProcQ( priority_queue(current_process->priority), current_process); current_process->CPUTime += getTODLO() - interruptStart; //se metto in pausa il processo aggiorno anche il suo CPUTime current_process = NULL; } } } else if(CAUSE_IP_GET(cause, IL_DISK)){ dtnp_interrupt(IL_DISK); } else if(CAUSE_IP_GET(cause, IL_TAPE)){ dtnp_interrupt(IL_TAPE); } else if(CAUSE_IP_GET(cause, IL_ETHERNET)){ dtnp_interrupt(IL_ETHERNET); } else if(CAUSE_IP_GET(cause, IL_PRINTER)){ dtnp_interrupt(IL_PRINTER); } else if(CAUSE_IP_GET(cause, IL_TERMINAL)){ terminal_interrupt(); } scheduler(); }
//disk, tape, network, printer interrupt handler void dtnp_interrupt(int int_line){ dtpreg_t *dev_g; int i; unsigned int status; //valore da far ritornare alla SYS8 memaddr *interrupt_line = (memaddr*) CDEV_BITMAP_ADDR(int_line); //ottengo la linea di interrupt int dev_num = pending_interrupt_device(interrupt_line); //ottengo il device su cui pende l'interrupt dev_g = (dtpreg_t*) DEV_REG_ADDR(int_line, dev_num); dev_g->command = DEV_C_ACK; //passo l'acknowledgement i = devSemIndex(int_line, dev_num) ; if( devSem[i] < 1 ){ //se ci sono dei processi bloccati sul semaforo status = dev_g->status; //li libero e passo loro lo status register e il tempo di gestione verhogen( &devSem[i] , 1 , status, getTODLO() - interruptStart); devStatus[i] = 0; } else{ //se nessuno sta aspettando l'interrupt salvo lo status register e il tempo di gestione dell'interrupt // per quando qualcuno li richiederà devStatus[i] = dev_g->status; interruptTime[i] = getTODLO() - interruptStart; } }
//gestore degli interrupt per i terminali void terminal_interrupt(){ termreg_t *dev_t; int i ; memaddr *interrupt_line = (memaddr*) CDEV_BITMAP_ADDR(IL_TERMINAL); //ottengo la linea di interrupt per i terminali int dev_num = pending_interrupt_device(interrupt_line); //ottengo il terminale su cui pende l'interrupt dev_t = (termreg_t*) DEV_REG_ADDR(IL_TERMINAL, dev_num); //ottengo il registro del terminale unsigned int status ; //valore da far ritornare alla SYS8 status_iprint = dev_t->transm_status; if( (dev_t->transm_status & DEV_TERM_STATUS ) == DEV_TTRS_S_CHARTRSM){ //trattasi di una scrittura, priorità più alta della lettura status = dev_t->transm_status; i = devSemIndex(IL_TERMINAL+1, dev_num); dev_t->transm_command = DEV_C_ACK; //acknowledgement if( devSem[i] < 1 ){ //se ci sono dei processi bloccati sul semaforo verhogen(&devSem[i], 1, status, getTODLO() - interruptStart); //li libero e passo loro lo status register devStatus[i] = 0; } else{ //se nessuno sta aspettando l'interrupt salvo lo status register per quando qualcuno lo richiederà devStatus[i] = dev_t->transm_status; interruptTime[i] = getTODLO() - interruptStart; //tempo impegato a gestire l'interrupt } } else if( (dev_t->recv_status & DEV_TERM_STATUS) == DEV_TRCV_S_CHARRECV ){ //trattasi di una lettura status = dev_t->recv_status; i = devSemIndex(IL_TERMINAL, dev_num); dev_t->recv_command = DEV_C_ACK; //acknowledgement if( devSem[i] < 1 ){ verhogen(&devSem[i], 1,status, getTODLO() - interruptStart); //come sopra devStatus[i] = 0; } else{ devStatus[i] = dev_t->recv_status; interruptTime[i] = getTODLO() - interruptStart; //tempo impegato a gestire l'interrupt } } }
int main() { initExceptionHandlers(); initPcbs(); initASL(); // Initialize device semaphores memset(&semaphores, 0, sizeof(semaphores)); // Create init and start the scheduler pcb_t *init; init = makeInit(); init->p_pid = 1; boot_start=getTODLO(); schedStart(init); return 0; }