/*************************************************************************
* *
* 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