disk.c


/*************************************************************************
*                                                                        *
*   Processo gestore del disco                                           *
*                                                                        *
*   realizzato dal Gruppo 17 di Lab2 Anno Accademico 1995/96             *
*                                                                        *
*   Lorenzo     Claudio       Valerio    Riccardo    Emiliano            *
*   Coronati    Lanconelli    Paolini    Solmi       Trentini            *
*                                                                        *
**************************************************************************/

#include "../h/disk.h"
#include "../h/ssimsg.h"

extern thr_t *SSI;

#ifdef  DISK_ON

/* array per gestire l'allocazione delle richieste di I/O */
HIDDEN diskq_t diskqTable[MAXDISKQ];
HIDDEN diskq_t *dqfp;

/* lista ordinata per traccia delle richieste di I/O */
HIDDEN diskq_t *dreq_queue = NULL;

/* numero di traccia su cui e` posizionata la testina del disco */
HIDDEN int track_no = -1;

/* operazione in corso (di cui stiamo attendendo la fine) */
HIDDEN int cur_op = NO_OP;

/* buffer di lettura/scrittura del settore */
HIDDEN struct {
    ssimsg_t sm;
    char buffer[SECTORSIZE];
} diskbuf;


/***
 * Processo servente di gestione del disco. Mantiene una lista
 * di richieste di I/O che contengono il numero della traccia e del
 * settore da leggere/scrivere. Tale settore viene letto/scritto
 * nel diskbuf da cui verra` copiato direttamente dal thread che ha
 * richiesto il servizio (di solito SST). Implementa l'algoritmo
 * di scansione (detto dell'ascensore) in una sola direzione.
 ***/ 
void
disk()
{
    register thr_t *sender;     /* R4 */
    register union {dreq_t *req; iores_t *res; void *p} msg;        /* R3 */
    register diskq_t *p;

    /* index: indice dell'ascensore, punta alla richiesta in corso di
     * esecuzione (se cur_op == IOREAD o IOWRITE) oppure alla prossima
     * richiesta da esaudire (se cur_op == IOSEEK o NO_OP).
     * quando index == NULL, significa che non vi e` nessuna 
     * operazione di disco pendente.
     */
    diskq_t *index = NULL;

    /* inizializzazione della coda per le richieste di servizio */
    initDiskQueue();

    /* ciclo di attesa richiesta di servizio e/o terminazione del comando
     * precedente.
     */
    while(TRUE)
    {
        sender = ANYSENDER;
        DO_MSGRECV();

        /* se il mittente e` SSI allora il messaggio indica la terminazione
         * del comando precedente; percio` restituiamo il risultato al
         * richiedente.
         */
        if (sender == SSI)
        {
#ifdef  SUP_DEBUG
            if (cur_op == NO_OP)
                HALT();         /* grave errore!!! */
#endif
            if (cur_op != IOSEEK || msg.res->io_sta != NORMAL)
            {
                /* restituisce il risultato dell'operazione al client */
                sender = index->dq_client;
                DO_MSGSEND();

                p = index;
                /* seleziona la prossima richiesta da eseguire */
                index = nextDiskQueue(p);
                outDiskQueue(p);
                freeDiskQueue(p);

                if (cur_op == IOREAD)
                    /* attende la copia del diskbuffer da parte del client */
                    DO_MSGRECV();
            }
            cur_op = NO_OP;

            /* se ci sono altre richieste pendenti eseguiamo la prossima */
            if (index != NULL)
                doDiskReq(index);
        }
        else        /* richiesta di servizio */
        {
            if ( (p = allocDiskQueue()) == NULL )
            {
                HALT();
                /* panico!! */
            }

            /* inserisce la richiesta in coda */
            p->dq_client = sender;
            p->dq_op = msg.req->dr_op;
            p->dq_track = msg.req->dr_track;
            p->dq_sector = msg.req->dr_sector;
            insDiskReq(p);

            /* se non c'e` nessuna operazione in esecuzione la
             * esegue subito
             */
            if (index == NULL)
            {
                index = headQueue(dreq_queue);
                doDiskReq(index);
            }
        } /* else */
    } /* while */
}

void
doDiskReq(dqp)
diskq_t *dqp;
{
    register thr_t *sender;     /* R4 */
    register void *msg;         /* R3 */
    register diskq_t *p = dqp;

    if (p == NULL)
        HALT();

    if (p->dq_track != track_no)
    {
        adisk_seek(p->dq_track);
        track_no = p->dq_track;
        cur_op = IOSEEK;
    }
    else
    {
        if (p->dq_op == IOWRITE)
        {
            sender = p->dq_client;
            msg = diskbuf.buffer;
            DO_MSGSEND();

            /* attende la copia del settore nel diskbuffer */
            DO_MSGRECV();
        }

        adisk_io(&diskbuf.sm, diskbuf.buffer, p->dq_sector, p->dq_op);
        cur_op = p->dq_op;
    }
}

/*
 * Inserisce la richiesta mantenendo la lista ordinata in ordine
 * crescente per traccia.
 * L'implementazione e` sempre tramite una lista circolare.
 */
void
insDiskReq(p)
register diskq_t *p;
{
    register diskq_t *tp;

    if (dreq_queue == NULL)
        dreq_queue = p->dq_next = p;
    else
    {
        tp = dreq_queue;

        while (p->dq_track >= tp->dq_next->dq_track)
            tp = tp->dq_next;

        p->dq_next = tp->dq_next;
        tp->dq_next = p;
    }
}

#endif



[INDICE CODICE]