pager.c


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



[INDICE CODICE]