/********************************************************************** TERMINATE Si occupa di: -Uccidere root e tutti i figli ricorsivamente -Rimettere i thread nella lista dei liberi -Togliere i thread dalle varie liste/array in cui sono presenti -Decrementare il valore di thread_count -Pulire la inbox da eventuali messaggi **********************************************************************/ void terminate (tcb_t *target) { msg_t *msg; tcb_t *child; /* Se ha un padre lo elimino dai suoi figli */ outChild(target); /* Caso ricorsivo -> HA figli (su cui viene chiamata la terminate) */ while (TRUE) { if ( (child = removeChild(target)) == NULL ) break; /* Passa al caso base e pulisce thread, liste, messaggi... */ terminate(child); } /* Caso base -> NON ha figli */ /* Se è in qualche lista o è il thread corrente lo elimino */ if (((outThread(&ready_queue, target)) != NULL) || (current_thread == target)) { /* Pulisco la inbox */ while (TRUE) { if ( (msg = popMessage(&(target->t_inbox), NULL)) == NULL ) break; freeMsg(msg); } /* Se è un manager lo elimino dal trap_managers array */ delete_manager(target); if (current_thread == target) current_thread=NULL; /* Restituisco ai thread liberi */ freeTcb(target); thread_count--; } else if (outThread(&wait_queue, target)) { /* Decremento contatore processi in attesa I/O o SSI */ if (target->waiting_for == SSI_tcb) soft_block_count--; /* Tutto come caso precedente*/ while (TRUE) { if ( (msg = popMessage(&(target->t_inbox), NULL)) == NULL ) break; freeMsg(msg); } delete_manager(target); freeTcb(target); thread_count--; } else PANIC(); }
/********************************************************************** SEND Invia un messaggio come richiesto dal sender al destinatario specificato nel registro a1 (receiver), col payload specificato al registro a2 (payload). Operazione NON BLOCCANTE. **********************************************************************/ int send (tcb_t *sender, tcb_t *target, U32 payload){ msg_t *msg; tcb_t *_sender_; /* Protezione SSI */ if (sender == SSI_tcb) _sender_ = (tcb_t *)MAGIC_SSI; else _sender_ = sender; /* Destinatario in ready_queue o thread corrente */ if ( ((thereIsThread(&ready_queue, target)) != NULL ) || (current_thread == target) ) { if ((msg = allocMsg()) == NULL) PANIC(); /* Creazione e compilazione messaggio */ msg->m_sender = _sender_; msg->m_message = payload; /* Priorità allo Pseudo Clock Tick -> Messaggio in testa */ if (_sender_ == (tcb_t*)BUS_INTERVALTIMER) pushMessage(&(target->t_inbox), msg); /* Trattamento normale -> Messaggio in coda */ else insertMessage(&(target->t_inbox), msg); return (MSGGOOD); } /* Destinatario in wait_queue */ else if ((thereIsThread(&wait_queue, target)) != NULL ) { /* Se sta aspettando un messaggio da questo thread o da chiunque sveglio il thread dest togliendolo dalla wait_queue e lo inserisco nella ready_queue passandogli il payload dove mi aveva richiesto e che avevo salvato nel TCB nel campo "reply". */ if ((target->waiting_for == _sender_) || (target->waiting_for == ANYMESSAGE)) { *(target->reply) = payload; /* Risveglio il thread */ insertThread(&ready_queue, outThread(&wait_queue, target)); /* Risettaggio campi per message passing */ target->waiting_for = (tcb_t *)-1; target->reply = (U32 *)-1; /* Decremento soft block count se caso SSI e restituisco sender al destinatario */ if (_sender_ == SSI_tcb) soft_block_count--; target->t_state.reg_v0 = (U32)_sender_; return (MSGGOOD); } /* Destinatario momentaneamente in attesa di un altro mittente */ else { /* Tutto come sopra */ if ((msg = allocMsg()) == NULL) PANIC(); msg->m_sender = _sender_; msg->m_message = payload; if (sender == (tcb_t *)BUS_INTERVALTIMER) pushMessage(&(target->t_inbox), msg); else insertMessage(&(target->t_inbox), msg); return (MSGGOOD); } } /* Nessuno dei casi precedenti --> potrebbe essere stato terminato il thread */ return (MSGNOGOOD); }
/********************************************************************** SYSBP_HANDLER Caricato all'arrivo di una eccezione di tipo SYSCALL/BREAKPOINT. Fornisce principalmente il servizio di message passing. In tutti i casi in cui è sollevata una eccezione diversa da SYSCALL di tipo 1 o 2 in Kernel Mode, questa routine, come le altre due di questo modulo affidano il controllo del thread corrente ad un Trap Manager, se specificato, altrimenti viene terminato tutto il sottoalbero corrispondente. **********************************************************************/ void sysbp_handler(){ int exc_cause; int KUmode; /* 0 se Kernel / 1 se User */ tcb_t *trapped; tcb_t *manager; tcb_t *sender; tcb_t *receiver; U32 payload; U32 *reply; /* Aggiornamento tempo thread */ current_thread->cpu_slice += (GET_TODLOW - current_thread_tod); current_thread->cpu_time += (GET_TODLOW - current_thread_tod); /* Salvo lo stato del processore del thread che ha sollevato l'eccezione, nel campo t_state del suo tcb. Lo stato è salvato nella old area dell'attuale eccezione. Modifico opportunamente il PC per non avere un ciclo nel ritorno dall'eccezione. */ save_state(sysbk_oldarea, &(current_thread->t_state)); current_thread->t_state.pc_epc += WORD_SIZE; /* Recupero il tipo di eccezione avvenuta */ exc_cause = CAUSE_EXCCODE_GET(sysbk_oldarea->cause); /* Controllo se Kernel o User Mode */ KUmode = (sysbk_oldarea->status & STATUS_KUp) >> 3; /* Se l'eccezione è una SYSCALL 1 o 2 ed eseguita in kernel mode */ if (KUmode == 0) { if (exc_cause == EXC_SYSCALL) { /* MsgSend */ if (sysbk_oldarea->reg_a0 == SEND) { sender = current_thread; payload = sysbk_oldarea->reg_a2; /* Protezione SSI e incremento thread in attesa di servizio */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) { receiver = SSI_tcb; soft_block_count++; } else receiver = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* CASO TRAP MANAGER --> Intercettare messaggio TRAPTERMINATE / TRAPCONTINUE */ if ((thereIs_manager(sender)) && (receiver->waiting_for == sender)) { /*** TRAPTERMINATE ***/ if (payload == TRAPTERMINATE) { trapped = receiver; terminate(trapped); /* Termino thread in wait_queue in attesa della decisione del Trap Manager */ scheduler(); } /*** TRAPCONTINUE ***/ if (payload == TRAPCONTINUE) { trapped = receiver; insertThread(&ready_queue, outThread(&wait_queue, trapped)); /* Altrimenti lo risveglio */ scheduler(); } } /* Caso normale di MsgSend (vedi send) */ sender->t_state.reg_v0 = send (sender, receiver, payload); scheduler(); } /* MsgRecv */ if (sysbk_oldarea->reg_a0 == RECV) { receiver = current_thread; reply = (U32 *)sysbk_oldarea->reg_a2; /* Protezione SSI (non decremento qui soft block count ma al momento di ricevimento servizio) */ if (sysbk_oldarea->reg_a1 == MAGIC_SSI) sender = SSI_tcb; else sender = ((tcb_t *)(sysbk_oldarea->reg_a1)); /* MsgRecv (vedi recv) e restituisco sender direttamente (nel caso NON BLOCCANTE e non con SSIRequest) */ current_thread->t_state.reg_v0 = (U32)recv(current_thread, ((tcb_t *)sysbk_oldarea->reg_a1), ((U32 *)sysbk_oldarea->reg_a2)); scheduler(); } } } /* TUTTI gli altri casi*/ manager = current_thread->sysbp_manager_thread; /* Se il thread NON ha specificato un Trap Management thread per questa eccezione viene terminato */ if (manager == NULL) { terminate(current_thread); current_thread = NULL; scheduler(); } /* Se il thread HA invece specificato il gestore viene freezato */ else { /* Invio messaggio al suo Trap manager con registro cause come payload */ send(current_thread, manager, sysbk_oldarea->cause); /* Setto in TCB chi sto aspettando */ current_thread->waiting_for = manager; /* Freeze del thread in attesa della decisione del manager */ insertThread(&wait_queue, current_thread); current_thread = NULL; scheduler(); } }
void ProduceDoc::recupSlot(const QString & text){ emit outThread(text); }