/*************************************************************************
* *
* Processo gestore della Paginazione *
* *
* realizzato dal Gruppo 17 di Lab2 Anno Accademico 1995/96 *
* *
* Lorenzo Claudio Valerio Riccardo Emiliano *
* Coronati Lanconelli Paolini Solmi Trentini *
* *
**************************************************************************/
#include "../h/supconst.h"
#include "../h/memory.h"
#include "../h/pagequeue.e"
extern int free_pages; /* numero di pagine libere */
HIDDEN frame_t *pfqueue = NULL; /* coda dei frame di pagina in uso */
/***
* Il page process si occupa di ricevere le richieste di page-fault da parte
* dei gestori della memoria dei T-process e di soddisfarle (eventualmente
* leggendo e/o scrivendo su tamburo).
***/
void
pager()
{
register thr_t *sender; /* R4 */
register pgmsg_t *pgmsg; /* R3 */
register frame_t *fp;
struct {unsigned int beg_free; unsigned int end_free} *imsgp;
/* attende un messaggio dal processo init
* che contiene le info sui frame di pagina disponibili
*/
sender = ANYSENDER;
DO_MSGRECV();
imsgp = pgmsg;
/* inizializzazione dati del processo */
initPage(imsgp->beg_free / PAGESIZE, imsgp->end_free / PAGESIZE);
while(TRUE)
{
sender = ANYSENDER;
DO_MSGRECV();
/* testa se la pagina e` ancora assente. Il caso in cui sia
* presente si puo` verificare quando avviene un page fault sul
* segmento condiviso da parte del t-proc 1, e mentre viene
* elaborata da questo processo vi accede (sempre alla stessa
* pagina non presente) un altro t-proc 2. A questo punto la
* richiesta del gestore del t-proc 2 viene messa in coda; e viene
* elaborata solamente quando quella del t-proc 1 e` terminata,
* cioe` quando la pagina e` resa presente.
*/
if (pgmsg->pd.pd_p == FALSE)
{
/* alloca il frame di pagina */
if ( (fp = allocPage()) != NULL )
insertPage(fp);
else
fp = page_out(FALSE);
/* aggiorna il frame di pagina */
fp->f_pageno = pgmsg->pageno;
fp->f_segidx = pgmsg->segidx;
/* legge la pagina dall'area di scambio (eventualmente) */
page_in(fp, pgmsg->pd);
}
DO_MSGSEND();
#if MINFREEPAGES < MAXFRAMES
while (free_pages < MINFREEPAGES)
page_out(TRUE);
#endif
}
}
/*
* seleziona la pagina da liberare: implementa l'algoritmo di sostituzione
* ovvero l'algoritmo dell'orologio:
* mantiene una lista circolare delle pagine ordinate per anzianita`
* - quarda la prima pagina (la piu` "vecchia"), se il bit R e` 1
* la pagina diventa l'ultima della lista e R e` messo a 0;
* se invece R e` 0 viene restituita al chiamante
* la pagina selezionata (in uscita) sara` quella in testa alla lista
* circolare di modo che possa essere rimossa con removePage(), oppure messa
* in coda con nextPage().
* Notare che se selectPage() e` invocata ci deve essere almeno un frame di
* pagina in uso, percio` si puo` evitare il test se la coda e` vuota.
*/
HIDDEN frame_t *
selectPage()
{
register frame_t *fp = headPage();
/*
* implementa l'algoritmo dell'orologio:
*/
while (fp->f_pd->pd_r == TRUE)
{
fp->f_pd->pd_r = FALSE;
nextPage();
fp = headPage();
}
return fp;
}
/*
* libera un frame di pagina per essere riutilizzata immediatamente
* (free = FALSE) oppure per rimanere disponibile ad una futura
* allocazione (free = TRUE).
*/
HIDDEN frame_t *
page_out(free)
int free;
{
register frame_t *fp;
fp = selectPage();
/*
* la pagina puo` essere riutilizzata subito, oppure aggiunta al
* pool di pagine libere (a seconda che free = F o T).
*/
if (free == TRUE)
freePage(removePage());
else
nextPage();
fp->f_pd->pd_p = FALSE; /* non presente */
if (fp->f_pd->pd_m == TRUE) /* se modificata la salviamo su tamburo */
drum_io(fp, IOWRITE);
return fp;
}
HIDDEN void
page_in(fp, pd)
register frame_t *fp;
register pd_t *pd;
{
/*
* implementando il caricamento "demand paging" il primo page fault
* di una pagina (riconoscibile per il numero del frame a 0)
* NON deve provocare una lettura da tamburo.
* La seconda condizione in cui si puo` evitare di caricare la pagina
* dal tamburo e` quando il contenuto del frame di pagina fp
* corrisponde gia` alla pagina pd. Questo si puo` verificare se si fa
* un page_out senza riutilizzare la pagina ovvero page_out(TRUE).
*/
if (pd->pd_frame != 0 && fp->f_pd != pd)
drum_io(fp, IOREAD);
/* associa il frame alla pagina */
fp->f_pd = pd;
/* aggiorna il descrittore di pagina */
pd->pd_frame = fp->f_frameno;
pd->pd_r = FALSE; /* non riferita */
pd->pd_m = FALSE; /* non modificata */
pd->pd_p = TRUE; /* presente */
}