proctree.c


/*************************************************************************
*                                                                        *
*   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");
}


[INDICE CODICE]