diff --git a/include/pcb/utils.h b/include/pcb/utils.h index 68bc736..cac3ca6 100644 --- a/include/pcb/utils.h +++ b/include/pcb/utils.h @@ -7,12 +7,3 @@ * @param new_parent il nuovo genitore dei figli */ void pcb_SetChildrenParent( pcb_t* old_parent, pcb_t* new_parent ); - -/** - * @brief Dealloca dopo aver rimosso il descrittore fornito e tutta la sua progenie dalla queue della sentinella fornita - * @PostCondition Non avviene alcuna rimozione nella lista dei fratelli e del padre di p. - * - * @param p descrittore del processo da cui partire a rimuovere la progenie - * @param head queue in cui deve essere rimosso p e tutta la sua progenie - */ -void pcb_RemoveProgenyQ( pcb_t* p, struct list_head *head ); \ No newline at end of file diff --git a/include/scheduler/scheduler.h b/include/scheduler/scheduler.h index b12c94c..2e606bc 100644 --- a/include/scheduler/scheduler.h +++ b/include/scheduler/scheduler.h @@ -103,18 +103,18 @@ int scheduler_StateToReady(); int scheduler_StateToWaiting( int* semKey ); /** - * @brief Dealloca il descrittore del processo che era in esecuzione, rimuovendo eventualmente la sua progenie - * + * @brief Dealloca il descrittore del processo associato al pid fornito, rimuovendo eventualmente la sua progenie * @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 * @return int - * * 1 se non c'è alcun processo tracciato dallo scheduler in esecuzione + * * 1 se pid == NULL e non c'è alcun processo tracciato dallo scheduler in esecuzione * * 0 altrimenti se è avvenuto tutto correttamente - * @param b_flag_terminate_progeny Se TRUE rimuove e dealloca dalla ready queue il descrittore del processo in esecuzione e tutta la sua progenie, + * @param pid identificatore del processo da terminare, se == NULL sarà considerato il processo attualmente in esecuzione + * @param b_flag_terminate_progeny Se TRUE rimuove e dealloca dalla ready queue o dalla semd wait queue il descrittore del processo in esecuzione e tutta la sua progenie, * Se FALSE rimuove e dealloca solo il descrittore in esecuzione, ma tutti i suoi figli non avranno padre e ogni figlio non avrà fratelli * cioè saranno indipendenti tra loro */ -int scheduler_StateToTerminate( int b_flag_terminate_progeny ); +int scheduler_StateToTerminate( pcb_t* pid, int b_flag_terminate_progeny ); /** * @brief Restituisce il puntatore dell'attuale pcb_t in esecuzione @@ -143,9 +143,9 @@ void scheduler_AddProcess( pcb_t *p ); int scheduler_RemoveProcess( pcb_t *p ); /** - * @brief wrapper di pcb_RemoveProgenyQ con passata la ready queue dello scheduler - * @PostCondition Se p è il processo in esecuzione allora viene deassociato nella struttura dello scheduler e deallocato. - * Non avviene alcuna rimozione nella lista dei fratelli e del padre di p. + * @brief Dealloca dopo aver rimosso il descrittore fornito e tutta la sua progenie dalla ready queue o dalla wait queue del semaforo associato al pcb + * Non avviene alcuna rimozione nella lista dei fratelli e del padre di p. + * @PostCondition Se p o uno della sua progenie è il processo in esecuzione allora viene deassociato nella struttura dello scheduler e deallocato anche esso. * * @param p descrittore del processo da cui partire a rimuovere la progenie * @return int diff --git a/src/handler/shared.c b/src/handler/shared.c index f7f5c06..a5e63c1 100644 --- a/src/handler/shared.c +++ b/src/handler/shared.c @@ -95,7 +95,7 @@ word Syscaller( state_t *state, word sysNo, word param1, word param2, word param else { b_hasReturnValue = TRUE; *returnValue = -1; - scheduler_StateToTerminate( FALSE ); + scheduler_StateToTerminate( NULL, FALSE ); } break; } @@ -129,41 +129,8 @@ int Sys2_CreateProcess( state_t *child_state, int child_priority, pcb_t **child_ } int Sys3_TerminateProcess( pcb_t *pid ) { - scheduler_t *s = scheduler_Get(); - - if ( pid ) { - if ( outProcQ( &s->ready_queue, pid ) == NULL ) - return (-1); /* se il PCB non esiste ritorna errore */ - } - else - pid = scheduler_GetRunningProcess(); - - /* ogni processo figlio viene rimosso da un'eventuale coda di blocco su semaforo */ - struct list_head *child_iter; - pcb_t *dummy; - - - list_for_each( child_iter, &pid->p_child ) { - dummy = container_of( child_iter, pcb_t, p_sib ); - int *key = dummy->p_semkey; - if ( key ) { - list_del( &dummy->p_next ); /* rimozione del PCB dalla coda dei processi bloccati */ - - /* aumento del valore del semaforo. se positivo si risveglia il primo in coda */ - *key += 1; - if ( *key > 0 ) - scheduler_AddProcess( removeBlocked( key ) ); - } - } - - /* se il processo da terminare è quello corrente, si passa il lavoro allo scheduler; - altrimenti il relativo pcb viene tolto dalla ready queue e inserito nella lista free */ - if ( pid == scheduler_GetRunningProcess() ) - scheduler_StateToTerminate( TRUE ); - else - freePcb( outProcQ( &s->ready_queue, pid ) ); - - return 0; + int b_error = scheduler_StateToTerminate( pid, TRUE ); + return ( b_error ? -1 : 0 ); } void Sys4_Verhogen( int* semaddr ) { @@ -172,11 +139,12 @@ void Sys4_Verhogen( int* semaddr ) { } void Sys5_Passeren( int* semaddr ) { - int status = semaphore_P( semaddr, scheduler_GetRunningProcess() ); + pcb_t *pid = scheduler_GetRunningProcess(); + int status = semaphore_P( semaddr, pid ); // nel caso ritornasse 1 non può accadere perchè ad ogni processo può essere nella ASL al massimo 1 volta // infatti se non fosse disponibile un semd, non esisterebbe neanche questo processo if( status == 1 ) { - scheduler_StateToTerminate( FALSE ); + scheduler_StateToTerminate( pid, FALSE ); } } @@ -186,10 +154,11 @@ void Sys6_DoIO( word command, word *devregAddr, int subdevice ) { device_GetInfo( devreg, &devLine, &devNo ); int *semKey = device_GetSem( devLine, devNo, subdevice ); + pcb_t *pid = scheduler_GetRunningProcess(); // un semaforo di un device è sempre almeno inizializzato a 0, e quindi è sempre sospeso - int b_error = semaphore_P( semKey, scheduler_GetRunningProcess() ); + int b_error = semaphore_P( semKey, pid ); if( b_error ) { - scheduler_StateToTerminate( FALSE ); + scheduler_StateToTerminate( pid, FALSE ); } if( devLine == IL_TERMINAL ) { @@ -211,7 +180,7 @@ int Sys7_SpecPassup( state_t* currState, int type, state_t *old_area, state_t *n return 0; } - scheduler_StateToTerminate( FALSE ); + scheduler_StateToTerminate( NULL, FALSE ); return -1; } diff --git a/src/handler/umps/handler.c b/src/handler/umps/handler.c index 7913ef9..021a599 100644 --- a/src/handler/umps/handler.c +++ b/src/handler/umps/handler.c @@ -144,8 +144,19 @@ void handle_irq(unsigned int line, unsigned int dev){ (line==IL_TERMINAL) ? handle_irq_terminal(dev_reg) : handle_irq_other_dev(dev_reg); int *sem = device_GetSem(line, dev, GET_SEM_OFFSET(dev_reg, line)); /*sem associated with device*/ - pcb_t *p = semaphore_V(sem); - if(p != NULL){ - p->p_s.reg_v0 = dev_status; - } + pcb_t *p = NULL; + + /* + Rispode a tutti i processi in attesa, con lo stesso stato. + Lo status probabilmente andrà in collisione con gli altri se sono > 1 + ora come ora il processo che manda il comando non aspetta che il terminale sia pronto, + a meno che si gestito da un semaforo di livello superiore ( tramite syscall ) + */ + + do { + p = semaphore_V(sem); + if(p != NULL){ + p->p_s.reg_v0 = dev_status; + } + } while( p != NULL && *sem < 0 ); } \ No newline at end of file diff --git a/src/pcb/utils.c b/src/pcb/utils.c index c44ecfa..22b5452 100644 --- a/src/pcb/utils.c +++ b/src/pcb/utils.c @@ -10,32 +10,3 @@ void pcb_SetChildrenParent( pcb_t* old_parent, pcb_t* new_parent ) { } } } - -void pcb_RemoveProgenyQ( pcb_t* p, struct list_head *head ) { - if( p == NULL ) - return; - - /** - * Aggiunge ricorsivamente i figli di ogni processo ad uno stack di lavoro - * e poi elimina il padre sia dalla queue - * che dallo stack stesso, con conseguente deallocazione - */ - LIST_HEAD( pcb_stack ); - list_add( &p->p_next, &pcb_stack ); - - while( !list_empty( &pcb_stack ) ) { - struct list_head *it_parent = list_next( &pcb_stack ); - pcb_t *parent = container_of( it_parent, pcb_t, p_next ); - while( !emptyChild( parent ) ){ - pcb_t* child = removeChild( parent ); - - if( head != NULL ){ - outProcQ( head, parent ); - } - - list_add( &child->p_next, &pcb_stack ); - } - list_del( &parent->p_next ); - freePcb( parent ); - } -} \ No newline at end of file diff --git a/src/scheduler/scheduler.c b/src/scheduler/scheduler.c index f500f23..64d2b6f 100644 --- a/src/scheduler/scheduler.c +++ b/src/scheduler/scheduler.c @@ -110,36 +110,97 @@ int scheduler_StateToWaiting( int* semKey ) { } } -int scheduler_StateToTerminate( int b_flag_terminate_progeny ) { - if( scheduler->running_p == NULL ) { +/** + * @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; + + if( p == scheduler->running_p ) { + scheduler->running_p = NULL; + scheduler->b_force_switch = TRUE; + removed = p; + } + /* Rimuovo dalla wait queue V() */ + else if( p->p_semkey != NULL) { + removed = outBlocked( p ); + if( removed != NULL ) { + ++(*p->p_semkey); + removed->p_semkey = NULL; + } + } + /* Rimuovo dalla ready queue */ + else if( removed == NULL ) { + removed = outProcQ( &(scheduler->ready_queue), p ); + } +} + +int scheduler_StateToTerminate( pcb_t *pid, int b_flag_terminate_progeny ) { + if( pid == NULL ) { + pid = scheduler->running_p; + } + + if( pid == NULL ) { return 1; } + /* Lo scollego dal padre */ + outChild( pid ); if( b_flag_terminate_progeny ) { - /* rimuove la progenie dalla ready queue, poi dealloca e disassocia puntatore */ - scheduler_RemoveProgeny( scheduler->running_p ); + scheduler_RemoveProgeny( pid ); } else { - pcb_SetChildrenParent( scheduler->running_p, NULL ); - freePcb( scheduler->running_p ); - scheduler->running_p = NULL; - scheduler->b_force_switch = TRUE; + scheduler_RemoveProcessFromAnyQ( pid ); + pcb_SetChildrenParent( pid, NULL ); + freePcb( pid ); } return 0; } int scheduler_RemoveProgeny( pcb_t* p ) { - if( p == NULL ) { - return 1; - } - else if( scheduler->running_p == p ) { - scheduler->running_p = NULL; /* Rimuovo il tracciante di questo descrittore attivo */ - scheduler->b_force_switch = TRUE; - } + /* + * asl::outChildBlocked sarebbe inefficiente - + * dovrei processare se stessa, e visitare nuovamente l'intero albero di processi per fare V() e rimuovere ogni PCB + */ + + if( p == NULL ) + return 1; + + LIST_HEAD( pcb_stack ); + pcb_t + *parent = p; + + /* + * Ricorsivamente per ogni processo figlio dell intero albero: + * Ogni processo rimuove da una coda i figli e li aggiunge ad uno stack di lavoro + * e poi elimina il padre appena elaborato dallo stack per deallocarlo + */ + + scheduler_RemoveProcessFromAnyQ( parent ); + list_add( &p->p_next, &pcb_stack ); + + while( !list_empty( &pcb_stack ) ) { + struct list_head *it_parent = list_next( &pcb_stack ); + parent = container_of( it_parent, pcb_t, p_next ); + + /* Aggiungo i figli sullo stack */ + while( !emptyChild( parent ) ){ + pcb_t* child = removeChild( parent ); - pcb_RemoveProgenyQ( p, &scheduler->ready_queue ); + /* Devo elaborarlo qui altrimenti poco dopo lo "stacco" dalla lista in cui risiede */ + scheduler_RemoveProcessFromAnyQ( child ); + list_add( &child->p_next, &pcb_stack ); + } + + /* Elimino il genitore */ + list_del( &parent->p_next ); + freePcb( parent ); + } return 0; } diff --git a/src/utilities/semaphore.c b/src/utilities/semaphore.c index d24d340..088e086 100644 --- a/src/utilities/semaphore.c +++ b/src/utilities/semaphore.c @@ -19,8 +19,10 @@ pcb_t *semaphore_V( int *semkey ) { pcb_t *p = NULL; if( ++(*semkey) <= 0 ) { p = removeBlocked( semkey ); - if( p != NULL ) + if( p != NULL ){ + p->p_semkey = NULL; scheduler_AddProcess( p ); + } } return p; } \ No newline at end of file