intrpt.c


/*************************************************************************
*                                                                        *
*   Modulo di gestione degli interrupt                                   *
*                                                                        *
*   realizzato dal Gruppo 17 di Lab2 Anno Accademico 1995/96             *
*                                                                        *
*   Lorenzo     Claudio       Valerio    Riccardo    Emiliano            *
*   Coronati    Lanconelli    Paolini    Solmi       Trentini            *
*                                                                        *
**************************************************************************/

/*
 * Alle routine di gestione viene passato in R4 l'indirizzo dell'area old
 * del relativo interrupt ed in R3 il tipo di interrupt
 */

#include "../h/types.h"
#include "../h/nucconst.h"

#include "../h/scheduler.e"
#include "../h/sendrecv.e"
#include "../h/globals.e"

/* gestore interruzione non definito */
onBadIO()
{
    panic("invalid interrupt");
}

#ifdef  NUC_PROFILE
int clk_slice = 0;
int clk_tick = 0;
int clk_null = 0;

#endif

/* gestore interruzione timer */
onClock()
{
    register state_t *sts;   /* R4 */

#ifdef  NUC_PROFILE
    register int r3, r2 = 0;

#endif

    /*
     * evita che il tempo di esecuzione della routine venga addebitato al
     * processo in esecuzione
     */
    ACCOUNT();

    if (time_now >= next_clock)
    {

#ifdef  NUC_PROFILE
        r2 = 1;
        clk_tick++;
#endif

        /*
         * caso in cui l'interrupt indica l'avvenuto pseudoclock
         * tick. Se vi e` una richiesta pendente di WAITCLOCK allora
         * in clock_reply e` memorizzato il thread richiedente, e
         * quindi lo risvegliamo mandandogli un messaggio.
         */
        if (clock_reply != NULL)
        {
            no_wait--;
            msgSend(SSI, clock_reply, EMPTYMSG);
            clock_reply = NULL;
        }
        next_clock += CLOCKINTERVAL;
    }
    /*
     * nel caso in cui sia esaurito il time-slice del thread in
     * esecuzione oppure sia in esecuzione il thread vuoto, richiama lo
     * scheduler
     */
    if (time_left <= 0 || run_proc == NULL)
    {

#ifdef  NUC_PROFILE
        r2 = 1;
        clk_slice++;
#endif

        SAVESTATE();
        schedule();
        NEWSTATE();
    }

#ifdef  NUC_PROFILE
    if (r2 == 0)
        clk_null++;
    STCK(&last_start);
    intr_time += last_start - time_now;
#endif

    LOADTIMER();
    DISPATCH();
}

/*
 * utilizzato per ricavare l'indirizzo del device register dal tipo
 * di dispositivo
 */
HIDDEN devreg_t *dev_addr[] = {
    BEGINDEVREG + TERM0 * sizeof(devreg_t), /* 01400 */
    BEGINDEVREG + PRINT0 * sizeof(devreg_t),    /* 01520 */
    BEGINDEVREG + DISK0 * sizeof(devreg_t), /* 01560 */
    BEGINDEVREG + DRUM0 * sizeof(devreg_t)  /* 01660 */
};

#ifdef  NUC_PROFILE
int io_prima = 0;
int io_dopo = 0;

#endif

#define DEVTYPE ((int)devp)

/* gestore degli interrupt causati dai dispositivi di I/O */
void
onDevIO()
{
    register state_t *sts;   /* R4 */
    register devreg_t *devp;/* R3 in ingresso e` presente il dev.type */
    register ioreply_t *iorp;    /* R2 */

    /*
     * evita che il tempo di esecuzione della routine venga addebitato al
     * processo in esecuzione
     */
    ACCOUNT();

    devp = dev_addr[DEVTYPE] + sts->s_ps2.p2_int.in_dno;
    iorp = io_reply + DEVNO(devp);

    /*
     * controlliamo se c'e` una richiesta pendente di WAITIO
     */
    if (iorp->status == WAIT)
    {

#ifdef  NUC_PROFILE
        io_dopo++;
#endif

        /*
         * risvegliamo il thread richiedente mandandogli lo stato dei
         * registri del dispositivo
         */
        no_wait--;
        iorp->u.r.msg->d.sts = devp->d_stat;
        iorp->u.r.msg->d.len = devp->d_amnt;
        iorp->status = NONE;

        /*
         * si finge l'SSI poiche' il thread richiedente si e' messo
         * in attesa dell'SSI e deve essere risvegliato da
         * quest'ultimo
         */
        msgSend(SSI, iorp->u.r.sender, iorp->u.r.msg);

        /*
         * se non c'era nessun thread in esecuzione scheduliamo il
         * thread risvegliato
         */
        if (run_proc == NULL)
        {
            schedule();
            NEWSTATE();
        }
    }
    else
    {

#ifdef  NUC_PROFILE
        io_prima++;
#endif

#ifdef  NUC_DEBUG
        if (iorp->status == INTR)
            error("interrupt without any WaitIO");
#endif

        /* memorizziamo l'interrupt avvenuto per la prossima WAITIO */

        iorp->u.d.sts = devp->d_stat;
        iorp->u.d.len = devp->d_amnt;
        iorp->status = INTR;
    }

#ifdef  NUC_PROFILE
    STCK(&last_start);
    intr_time += last_start - time_now;
#endif

    LOADTIMER();
    DISPATCH();
}


[INDICE CODICE]