diff --git a/include/pcb/pcb.h b/include/pcb/pcb.h index ea3f89f..7ab7f67 100644 --- a/include/pcb/pcb.h +++ b/include/pcb/pcb.h @@ -25,4 +25,6 @@ void insertChild(pcb_t *prnt, pcb_t *p); pcb_t *removeChild(pcb_t *p); pcb_t *outChild(pcb_t *p); +/* Inizializza un singolo pcb con valori NULL/0 e liste vuote */ +void pcb_init( pcb_t *p ); #endif diff --git a/include/scheduler/scheduler.h b/include/scheduler/scheduler.h index 49c3093..c3fba54 100644 --- a/include/scheduler/scheduler.h +++ b/include/scheduler/scheduler.h @@ -33,6 +33,10 @@ struct scheduler_t { /* booleano indicante se il processo attuale non può continuare lo scheduling (TRUE) oppure continuare mantenere il processo schedulato (FALSE) */ int b_force_switch; + /* Pcb utilizzato per mettere la macchina in stato di idle */ + pcb_t idlePcb; + int b_has_idle; + }; typedef struct scheduler_t scheduler_t; @@ -92,15 +96,17 @@ int scheduler_StateToReady(); /** * @brief aggiunge il processo corrente alla ASL con associato la chiave fornita * - * @PreCondition Prima di chiamare questa funzione, è necessario chiamare scheduler_UpdateContext() per aggiornare il contesto del processo attuale - * @PostCondition Dopo questo stato è necessario richiamare scheduler_schedule per procedere con la schedulazione dei processi + * @PreCondition Prima di chiamare questa funzione, è necessario chiamare scheduler_UpdateContext() per aggiornare il contesto del processo attuale. + * Inoltre il processo deve essere nella ready queue oppure o deve essere il processo in esecuzione + * @PostCondition se p == NULL sarà preso in considerazione il processo corrente. Dopo questo stato è necessario richiamare scheduler_schedule per procedere con la schedulazione dei processi * @param semKey chiave da associare al semaforo + * @param p processo da sospendere sulla coda del semaforo * @return int * * -1 se nessun processo è attualmente assegnato come processo corrente * * 0 se l'operazione è stata effettuata correttamente * * 1 se non è stato possibile aggiungere il processo corrente alla ASL (impossibile allocare semaforo) */ -int scheduler_StateToWaiting( int* semKey ); +int scheduler_StateToWaiting( pcb_t* p, int* semKey ); /** * @brief Dealloca il descrittore del processo associato al pid fornito, rimuovendo eventualmente la sua progenie diff --git a/include/system/shared/device/device.h b/include/system/shared/device/device.h index f048628..aff4e85 100644 --- a/include/system/shared/device/device.h +++ b/include/system/shared/device/device.h @@ -37,8 +37,14 @@ // #define GET_SEM_OFFSET(dev_reg,line) (line!=IL_TERMINAL ? (0) : (IS_TERM_READY(dev_reg->term.transm_status)? (0) : (1))) // -#define GET_SEM_INDEX(dev_reg,line,device) (N_DEV_PER_IL*(line-N_EXT_IL+GET_SEM_OFFSET(dev_reg,line))+device) -#define GET_SEM_INDEX_SUBDEV(line,device,subdevice) (N_DEV_PER_IL*(line-N_EXT_IL+ ( line!=IL_TERMINAL ? 0 : subdevice ) )+device) +#define GET_SEM_INDEX(dev_reg,line,device) (N_DEV_PER_IL*(line-DEV_IL_START+GET_SEM_OFFSET(dev_reg,line))+device) +/* + matrice vettorizzata in righe x colonne + riga i: semafori della stessa (i-DEV_IL_START)-esima interrupt line + (riga i+s: semafori della stessa interrupt line ma contenente i s-esimi dei subdevice ) + colonna j: semaforo dell j-esimo device di un interrupt line +*/ +#define GET_SEM_INDEX_SUBDEV(line,device,subdevice) (N_DEV_PER_IL*(line - DEV_IL_START + ( line!=IL_TERMINAL ? 0 : subdevice ) )+device) // #define GET_DEV_STATUS(dev_reg, line) (line!=IL_TERMINAL ?(dev_reg->dtp.status):(GET_SEM_OFFSET(dev_reg,line) ?(dev_reg->term.recv_status):(dev_reg->term.transm_status)) ) @@ -63,6 +69,17 @@ void device_GetInfo( devreg_t *devreg, int *devline, int *devNo ); */ int *device_GetSem( int devline, int devNo, int subDev ); +/** + * @brief indica se ci sono processi in attesa su qualche coda di un semaforo associata ad un device + * + * @PostCondition se sem == NULL saranno controllati tutti i semafori dei device, invece che solo su sem + * @param sem + * @return int + * - TRUE se c'è almeno un processo in attesa + * - FALSE altrimenti + */ +int device_IsAnyProcessWaiting( int *sem ); + #endif diff --git a/include/utilities/semaphore.h b/include/utilities/semaphore.h index ceb8941..321aaed 100644 --- a/include/utilities/semaphore.h +++ b/include/utilities/semaphore.h @@ -7,12 +7,12 @@ * @brief Decrementa il valore del semaforo, se diventa < 0, allora il processo indicato viene sospeso; * cioè rimosso dalla ready queue dello scheduler e posto in attesa sulla coda del semaforo specificato * @PreCondition semkey != NULL - * + * @PostCondition se p == NULL, sarà preso in considerazione il processo corrente * @param semkey * @param p * @return int - * FALSE se è stato sospeso correttamente - * TRUE se p == NULL oppure se non è stato possibile allocare un semd per il processo specificato + * * 0 se è stato sospeso correttamente + * * !=0 se p == NULL e non c'è alcun processo in esecuzione, oppure se non è stato possibile allocare un semd per il processo specificato */ int semaphore_P( int *semkey, pcb_t * p ); diff --git a/src/handler/shared.c b/src/handler/shared.c index ffe1fbe..70f7398 100644 --- a/src/handler/shared.c +++ b/src/handler/shared.c @@ -172,7 +172,7 @@ void Sys6_DoIO( word command, word *devregAddr, int subdevice ) { // un semaforo di un device è sempre almeno inizializzato a 0, e quindi è sempre sospeso if( *semKey >= 0 ){ if( devLine == IL_TERMINAL ) { - if( subdevice ) { + if( !subdevice ) { devreg->term.transm_command = command; } else { diff --git a/src/p1.5test_bikaya_v0.c b/src/p1.5test_bikaya_v0.c index a74892c..ad430ba 100644 --- a/src/p1.5test_bikaya_v0.c +++ b/src/p1.5test_bikaya_v0.c @@ -81,6 +81,11 @@ void termprint(char *str) { #define termprint(str) tprint(str); #endif + +// extern void print( char *msg ); +// #undef termprint +// #define termprint(str) print(str); + char *toprint[] = { "1 \n", "2 _nnnn_ \n", "3 dGGGGMMb \n", "4 @p~qp~~qMb \n", "5 M|@||@) M| \n", "6 @,----.JM| \n", diff --git a/src/pcb/pcb.c b/src/pcb/pcb.c index a320251..885241f 100644 --- a/src/pcb/pcb.c +++ b/src/pcb/pcb.c @@ -100,8 +100,17 @@ void insertProcQ(struct list_head *head, pcb_t *p){ l’elemento rimosso. */ pcb_t *allocPcb(void){ - pcb_t *new; - new = removeProcQ(pcbFree_h); + pcb_t *new = removeProcQ(pcbFree_h); + pcb_init( new ); + return new; +} + +/* + inizializza + tutti i campi (NULL/0) + e le liste come liste vuote +*/ +void pcb_init( pcb_t *new ){ if(new != NULL){ //inizializzazione pcb INIT_LIST_HEAD(&(new->p_child)); @@ -151,7 +160,6 @@ pcb_t *allocPcb(void){ new->p_s.TOD_Low = 0; #endif } - return new; } /* PCB QUEUE HANDLING */ diff --git a/src/scheduler/scheduler.c b/src/scheduler/scheduler.c index f1727f6..3f70354 100644 --- a/src/scheduler/scheduler.c +++ b/src/scheduler/scheduler.c @@ -24,13 +24,38 @@ #include #include #include +#include +#include HIDDEN scheduler_t *scheduler; +/** + * @brief Rimuove il processo come processo corrente, altrimenti dalla wait queue, altrimenti ancora se non è presente lo rimuove dalla ready queue + * @PostCondition Se viene rimosso dalla wait queue di un semaforo, incrementa il valore del semaforo stesso, quindi il suo p_semkey diventa NULL + * + * @param p il processo da rimuovere + */ +void scheduler_RemoveProcessFromAnyQ( pcb_t *p ); + +void idle_entry(){ while( TRUE ) WAIT(); } + void scheduler_init() { HIDDEN scheduler_t scheduler_struct; /* Tutte le funzioni di questo Header fanno riferimento implicito a questa struttura */ mkEmptyProcQ( &scheduler_struct.ready_queue ); scheduler_struct.running_p = NULL; + + scheduler_struct.b_has_idle = FALSE; + pcb_t *idlePcb = &scheduler_struct.idlePcb; + pcb_init( idlePcb ); + idlePcb->original_priority = DEFAULT_PRIORITY; + idlePcb->priority = idlePcb->original_priority; + SetStatus( &idlePcb->p_s, STATUS_NULL); + EnableInterrupts( &idlePcb->p_s, TRUE); + EnableKernelMode( &idlePcb->p_s, TRUE); + EnableVirtualMemory( &idlePcb->p_s, FALSE); + SetPC( &idlePcb->p_s, (memaddr)idle_entry ); + SetSP( &idlePcb->p_s, RAM_TOP ); + scheduler = &scheduler_struct; } @@ -51,12 +76,33 @@ void scheduler_DoAging() { int scheduler_schedule( int b_force_switch ) { + if( scheduler->b_has_idle ) { + scheduler_RemoveProcessFromAnyQ( &scheduler->idlePcb ); + scheduler->b_has_idle = FALSE; + } int b_should_switch = b_force_switch || scheduler->b_force_switch || scheduler->running_p == NULL; + + scheduler->b_force_switch = FALSE; /* resetto */ if( scheduler->running_p == NULL && emptyProcQ( &scheduler->ready_queue ) ) { - HALT(); + /* tutti i processi potrebbero essere in attesa su una coda di qualche semaforo */ + + /* se non ci sono processi in attesa su qualche semaforo dei device, + allora o tutti i processi sono terminati oppure può essere deadlock */ + if( !device_IsAnyProcessWaiting( NULL ) ) { + HALT(); + } + /* altrimenti metto nella ready queue un processo che fa solo WAIT, mettendo il sitema in stato di idle */ + else { + scheduler->b_force_switch = TRUE; /* preparo già per il prossimo scheduling, così in caso si sia riempita la ready queue, procede con cambiare processo */ + b_should_switch = TRUE; + + scheduler_AddProcess( &scheduler->idlePcb ); + scheduler->b_has_idle = TRUE; + scheduler_StartProcessChronometer(); // giusto per non ottenere valori strani nelle tempistiche + } } - + if( b_should_switch ) { scheduler_DoAging(); /* Incrementa priorità per evitare starvation dei processi */ @@ -75,17 +121,17 @@ int scheduler_schedule( int b_force_switch ) { // TODO: Re-impostare time slice rimanente oppure ignorare ? } - LDST( &scheduler->running_p->p_s ); /* mette in esecuzione il processo */ return -1; } void scheduler_UpdateContext( state_t* state ) { - if( scheduler->running_p != NULL ) + if( scheduler->running_p != NULL ){ moveState( state, &scheduler->running_p->p_s ); - scheduler_UpdateProcessRunningTime(); - scheduler_StartProcessChronometer(); + scheduler_UpdateProcessRunningTime(); + scheduler_StartProcessChronometer(); + } } int scheduler_StateToReady() { @@ -104,23 +150,18 @@ int scheduler_StateToReady() { } -int scheduler_StateToWaiting( int* semKey ) { - pcb_t* p = scheduler->running_p; - if( p == NULL ) { - return -1; - } - scheduler_StateToReady(); +int scheduler_StateToWaiting( pcb_t *p, int* semKey ) { + if( p == NULL ) + p = scheduler->running_p; + if( p == NULL ) return -1; + + if( p == scheduler->running_p ) + scheduler_StateToReady(); scheduler_RemoveProcess( p ); int b_result = insertBlocked( semKey, p ); return b_result; } -/** - * @brief Rimuove il processo come processo corrente, altrimenti dalla wait queue, altrimenti ancora se non è presente lo rimuove dalla ready queue - * @PostCondition Se viene rimosso dalla wait queue di un semaforo, incrementa il valore del semaforo stesso, quindi il suo p_semkey diventa NULL - * - * @param p il processo da rimuovere - */ void scheduler_RemoveProcessFromAnyQ( pcb_t *p ) { pcb_t *removed = NULL; @@ -147,7 +188,7 @@ int scheduler_StateToTerminate( pcb_t *pid, int b_flag_terminate_progeny ) { if( pid == NULL ) { pid = scheduler->running_p; } - + if( pid == NULL ) { return 1; } @@ -160,7 +201,8 @@ int scheduler_StateToTerminate( pcb_t *pid, int b_flag_terminate_progeny ) { else { scheduler_RemoveProcessFromAnyQ( pid ); pcb_SetChildrenParent( pid, NULL ); - freePcb( pid ); + if( pid != &scheduler->idlePcb ) + freePcb( pid ); } return 0; @@ -235,6 +277,8 @@ int scheduler_RemoveProcess( pcb_t *p ) { void scheduler_StartProcessChronometer() { pcb_t *p = scheduler->running_p; /* rende più leggibile il codice */ + if( p == NULL ) return; + unsigned int *todlo = (unsigned int *) BUS_REG_TOD_LO; p->chrono_start_tod = *todlo; /* il processo inizia la sua esecuzione in kernel mode */ diff --git a/src/system/shared/device/device.c b/src/system/shared/device/device.c index 076cf53..bded176 100644 --- a/src/system/shared/device/device.c +++ b/src/system/shared/device/device.c @@ -1,5 +1,6 @@ #include #include +#include HIDDEN int _semdev[SEM_DEV_N]; @@ -33,3 +34,16 @@ void device_GetInfo( devreg_t *devreg, int *_line, int *_devNo ) { int *device_GetSem( int devline, int devNo, int subDev ) { return &_semdev[ GET_SEM_INDEX_SUBDEV(devline, devNo, subDev) ]; } + +int device_IsAnyProcessWaiting( int *sem ) { + if( sem != NULL ) { + return headBlocked( sem ) != NULL; + } + + int i = 0; + while( i < SEM_DEV_N && _semdev[ i ] >= 0 ) + i++; + /* se è arrivato in fondo, avrà indice uguale al numero dei semafori */ + + return i != SEM_DEV_N; +} \ No newline at end of file diff --git a/src/test.c b/src/test.c index 2dbce69..8b8d606 100644 --- a/src/test.c +++ b/src/test.c @@ -25,8 +25,8 @@ void test_1_5(); void test_init(void){ - test_1_5(); - return; + // test_1_5(); + // return; pcb_t *test_pcb = allocPcb(); state_t *state = &(test_pcb->p_s); diff --git a/src/utilities/semaphore.c b/src/utilities/semaphore.c index 0768897..f1dd612 100644 --- a/src/utilities/semaphore.c +++ b/src/utilities/semaphore.c @@ -4,18 +4,9 @@ #include int semaphore_P( int *semkey, pcb_t * p ) { - int b_error = FALSE; - if( p == NULL ) - return !b_error; - + int b_error = 0; if( --(*semkey) < 0 ) { - if( p == scheduler_GetRunningProcess() ){ - b_error = scheduler_StateToWaiting( semkey ); - } - else { - scheduler_RemoveProcess( p ); - b_error = insertBlocked( semkey, p ); - } + b_error = scheduler_StateToWaiting( p, semkey ); } return b_error; }