/*************************************************************************
* *
* Modulo per la gestione dell'albero dei processi e dei relativi *
* thread *
* *
* realizzato dal Gruppo 17 di Lab2 Anno Accademico 1995/96 *
* *
* Lorenzo Claudio Valerio Riccardo Emiliano *
* Coronati Lanconelli Paolini Solmi Trentini *
* *
**************************************************************************/
#include "../h/const.h"
#include "../h/types.h"
#include "../h/nucconst.h"
#include "../h/proctree.h"
#include "../h/globals.e"
#include "../h/queue.e"
#include "../h/msgqueue.e"
#include "../h/thrqueue.e"
#include "../h/procqueue.e"
#define allocProc() ((proc_t *)AllocQueue(&procfp))
#define freeProc(proc) freeQueue(proc, &procfp)
/*
* inserisce l'albero dei processi radicato in child nell'albero
* dei processi di parent come suo figlio
*/
#define insertProc(proc) ins1Queue(&(proc)->p_parent->p_child, proc)
/*
* rimuove l'albero dei processi radicato in proc dall'albero dei processi
* in cui si trova
*/
#define removeProc(proc) outQueue(&(proc)->p_parent->p_child, proc)
/* definizione tabella dei proc e puntatore alla lista dei proc liberi */
HIDDEN proc_t procTable[MAXPROC];
HIDDEN proc_t *procfp;
/* inizializza la free-list dei processi */
void
initProc()
{
procfp = (proc_t *) initQueue(procTable, MAXPROC, sizeof(proc_t));
}
/*
* crea un nuovo processo (e relativo thread) come figlio del processo
* a cui appartiene il thread passato
*/
thr_t *
createProc(thread, state)
thr_t *thread;
state_t *state;
{
register proc_t *newproc;
register thr_t *newthread;
#ifdef NUC_DEBUG
if (state == NULL || state < BEGINKERNEL)
panic("createProc(): bad parameter");
#endif
/* allocazione strutture per il nuovo thread e processo */
if ((newthread = AllocThread()) != NULL)
{
if ((newproc = allocProc()) != NULL)
{
/* inizializzazione campi del thread */
newthread->t_msgqueue = newthread->t_replyqueue = NULL;
newthread->t_waitfrom = NOBODY;
MOVBCK(state, &newthread->t_s, sizeof(state_t));
newthread->t_process = newproc;
/* inizializzazione campi del processo */
newproc->p_cputime = 0L;
newproc->p_child =
newproc->p_prgtrap =
newproc->p_memtrap =
newproc->p_systrap =
newproc->p_waitqueue =
newproc->p_readyqueue = NULL;
/* inserimento nuovo thread in coda pronti */
insertThread(&newproc->p_readyqueue, newthread);
/*
* thread puo` essere NULL solo nel caso di creazione
* del primo processo (SSI)
*/
if (thread != NULL)
{
/* inserimento nell'albero dei processi */
newproc->p_parent = thread->t_process;
insertProc(newproc);
}
else
{
/* creazione radice dell'albero dei processi */
newproc->p_next = newproc;
newproc->p_parent = NULL;
}
/* inserisce il processo in coda pronti */
insRdyQueue(newproc);
}
else
{
FreeThread(newthread);
newthread = NULL;
}
}
return newthread;
}
/* Elimina il sottoalbero di processi radicato in thread->t_process */
void
termProc(thread)
thr_t *thread;
{
register proc_t *tmp, *proc;
register int shut_down = FALSE;
#ifdef NUC_DEBUG
if (thread == NULL || thread < BEGINKERNEL || thread->t_process == NULL)
panic("termProc(): bad parameter");
#endif
/*
* rimuove il processo dalla lista dei processi fratelli se il proc
* in questione non e` la radice (p_parent e' NULL solo nel caso
* della radice)
*/
proc = thread->t_process;
if (proc->p_parent != NULL)
{
/*
* nel caso dell'ultimo processo del sistema (unico figlio
* dell'SSI) fa shutdown, ovvero elimina l'SSI
*/
if (proc->p_parent == SSI->t_process)
shut_down = TRUE;
removeProc(proc);
proc->p_parent = NULL;
}
/* se il processo ha dei figli, elimina il sottoalbero dei processi */
if (proc->p_child != NULL)
{
do
{
if (proc->p_child != NULL)
proc = proc->p_child;
else
{
tmp = (proc->p_next != proc->p_parent->p_child) ?
proc->p_next : proc->p_parent;
removeProc(proc);
deleteProc(proc);
proc = tmp;
}
} while (proc->p_parent != NULL);
}
deleteProc(proc);
if (shut_down)
{
error("Normal shutdown");
deleteProc(SSI->t_process);
}
}
/* Crea un nuovo thread fratello del thread dato */
thr_t *
createThread(thread, state)
thr_t *thread;
state_t *state;
{
register thr_t *newthread;
register proc_t *proc;
#ifdef NUC_DEBUG
if (thread == NULL || thread < BEGINKERNEL ||
state == NULL || state < BEGINKERNEL)
panic("createThread(): bad parameters");
#endif
if ((newthread = AllocThread()) != NULL)
{
proc = thread->t_process;
/* inizializzazione campi del nuovo thread */
newthread->t_msgqueue = newthread->t_replyqueue = NULL;
newthread->t_waitfrom = NOBODY;
MOVBCK(state, &newthread->t_s, sizeof(state_t));
newthread->t_process = proc;
/* se il processo era addormentato lo risvegliamo */
if (EMPTYQUEUE(proc->p_readyqueue))
insRdyQueue(proc);
/* inserimento del nuovo thread in coda pronti */
insertThread(&proc->p_readyqueue, newthread);
}
return newthread;
}
/*
* Termina il thread e se e` l'ultimo elimina anche l'albero dei processi
* radicato in thread->t_process (e' un servizio del SSI)
*/
void
termThread(thread)
register thr_t *thread;
{
register proc_t *proc = thread->t_process;
/*
* se il thread non aspetta messaggi da nessuno significa che e` in
* coda pronti
*/
if (thread->t_waitfrom == NOBODY)
{
outThread(&proc->p_readyqueue, thread);
/* se e` l'ultimo thread pronto metto il processo in attesa */
if (EMPTYQUEUE(proc->p_readyqueue))
outRdyQueue(proc);
}
else
outThread(&proc->p_waitqueue, thread);
/*
* controllo che non sia l'ultimo thread del processo nel qual caso
* richiama terminateProc() N.B. p_readyqueue e` uguale a p_waitqueue
* solo quando sono entrambi NULL
*/
if (proc->p_readyqueue == proc->p_waitqueue)
termProc(thread);
else
{
/*
* se il thread da eliminare e` un gestore delle trap,
* aggiorniamo la struttura del processo
*/
if (thread == proc->p_prgtrap)
proc->p_prgtrap = NULL;
else if (thread == proc->p_memtrap)
proc->p_memtrap = NULL;
else if (thread == proc->p_systrap)
proc->p_systrap = NULL;
}
deleteThread(thread);
}
HIDDEN void
deleteThread(thread)
thr_t *thread;
{
register thr_t *tmp, *thrp = thread;
register int no_node = 1;
/*
* se il thread e` in attesa di un messaggio, va rimosso dalla coda
* del thread da cui attende.
*/
if (thrp->t_waitfrom != NOBODY && thrp->t_waitfrom != ANYSENDER && thrp->t_waitfrom != ANYTRAP)
outWaitThread(&thrp->t_waitfrom->t_replyqueue, thrp);
thrp->t_waitfrom = NOBODY;
/*
* termina tutti i thread che sono ancora in attesa del thread in
* questione
*/
if (thrp->t_replyqueue != NULL)
{
do
{
if (thrp->t_replyqueue != NULL)
{
no_node++;
thrp = thrp->t_replyqueue;
}
else
{
if (thrp->t_nextwait != thrp->t_waitfrom->t_replyqueue)
{
no_node++;
tmp = thrp->t_nextwait;
}
else
tmp = thrp->t_waitfrom;
/* simula una passup */
if (thrp->t_process->p_prgtrap == NULL)
termProc(thrp);
else
{
/*
* il thread in attesa verra`
* risvegliato dal suo gestore delle
* program trap
*/
thrp->t_s.s_ps2.p2_pr.pr_typ = RECVFROMDEADTHR;
msgSend(thrp, thrp->t_process->p_prgtrap, &thrp->t_s);
thrp->t_waitfrom = ANYTRAP;
}
thrp = tmp;
}
} while (thrp->t_waitfrom != NOBODY && no_node <= MAXTHREAD);
}
/*
* se il contatore dei nodi dell'albero supera il numero massimo di
* thread significa che c'e` un ciclo: attesa circolare.
*/
if (no_node > MAXTHREAD)
panic("Wait cycle");
killThread(thread);
}
/* elimina fisicamente il thread */
HIDDEN void
killThread(thread)
register thr_t *thread;
{
register msg_t *msg;
/*
* controllo che il thread da eliminire non abbia richieste di
* servizio ancora in coda all'SSI. Questo si puo` verificare se il
* thread e` terminato dalla passup
*/
while ((msg = keyMessage(&SSI->t_msgqueue, thread)) != NULL)
freeMessage(msg);
/* rimuove eventuali messaggi ricevuti dal thread */
while ((msg = removeMessage(&thread->t_msgqueue)) != NULL)
freeMessage(msg);
/* t_process == NULL segnala che il thread non e` piu` valido */
thread->t_process = NULL;
FreeThread(thread);
}
/* libera la memoria di un processo isolato e dei suoi thread */
HIDDEN void
deleteProc(proc)
proc_t *proc;
{
register proc_t *ssi_proc = SSI->t_process;
/* rimuove processo da coda pronti se ha almeno un thread pronto */
if (!EMPTYQUEUE(proc->p_readyqueue))
outRdyQueue(proc);
/*
* elimina tutti i thread del processo sia quelli in attesa sia
* quelli pronti. deleteThread e` richiamata con il primo thread
* (q->t_next) della lista circolare in modo che non debba scandire
* tutta la lista per trovarlo (vedi outQueue).
*/
while (!EMPTYQUEUE(proc->p_waitqueue))
deleteThread(removeThread(&proc->p_waitqueue));
while (!EMPTYQUEUE(proc->p_readyqueue))
deleteThread(removeThread(&proc->p_readyqueue));
freeProc(proc);
if (proc == ssi_proc)
panic("System halted");
}