From e61e868b265efe2f6d51079373588d639fc54d59 Mon Sep 17 00:00:00 2001 From: manuel Date: Thu, 21 Jun 2012 18:14:58 +0200 Subject: full mmap implementation --- vm/mmap.c | 91 +++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 66 insertions(+), 25 deletions(-) (limited to 'vm/mmap.c') diff --git a/vm/mmap.c b/vm/mmap.c index 9e7ae47..55ee91b 100644 --- a/vm/mmap.c +++ b/vm/mmap.c @@ -1,4 +1,6 @@ #include +#include "userprog/pagedir.h" +#include "userprog/process.h" #include "filesys/file.h" #include "threads/thread.h" #include "threads/vaddr.h" @@ -23,18 +25,20 @@ mmap_table_init (struct mmap_table *table) return true; } -/* frees the content of mmap table */ +/* closes all mapped files and frees the content of the table */ void mmap_table_free (struct mmap_table *table) { - //TODO + mapid_t id; + for (id = 0; id <= table->id_max; id++) + mmap_table_remove (table, id); palloc_free_page (table->ids); } -/* inserts a new mmap entry in the mmap table +/* inserts a new mmap entry in the mmap table. returns -1 if entry is invalid or already in the table */ mapid_t -mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, +mmap_table_insert (struct mmap_table *table, uint8_t *upage, struct file *file, off_t len) { off_t ofs = 0; @@ -46,43 +50,49 @@ mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, if (table->id_free >= table->id_cap) return -1; + /* create mmap table entry */ mme = malloc (sizeof *mme); if (mme == NULL) return -1; - mapid = table->id_free++; - mme->addr = addr; + mme->upage = upage; mme->file = file; - table->ids[mapid] = mme; + mme->pages = 0; /* create needed pages in page table */ while (len > 0) { page_read_bytes = (len < PGSIZE) ? len : PGSIZE; - if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs, - addr, page_read_bytes, true)) + upage, page_read_bytes, true)) return -1; /* Advance. */ - len -= PGSIZE; - ofs += page_read_bytes; - addr += PGSIZE; + len -= PGSIZE; + ofs += page_read_bytes; + upage += PGSIZE; + mme->pages++; } + /* insert entry into our table */ + mapid = table->id_free++; + table->ids[mapid] = mme; + /* update index of free/max mapid index */ if (mapid > table->id_max) table->id_max = mapid; while (table->ids[table->id_free] != NULL) - { - table->id_free++; - if (table->id_free >= table->id_cap) - break; - } + { + table->id_free++; + if (table->id_free >= table->id_cap) + break; + } return mapid; } +/* get the mmap table entry associated with the given map id. + return NULL if no mapping is associated with the given id */ static struct mmap_table_entry * mmap_table_get (struct mmap_table *table, mapid_t mapid) { @@ -91,26 +101,57 @@ mmap_table_get (struct mmap_table *table, mapid_t mapid) return table->ids[mapid]; } +/* remove the entry associated with the given map id from the mmap table. + flushes all dirty/modified pages back to disk. return true if successful */ bool mmap_table_remove (struct mmap_table *table, mapid_t mapid) { + struct page_table_entry *pte; + off_t ofs = 0; + struct thread *thread = thread_current (); struct mmap_table_entry *mme = mmap_table_get(table, mapid); if (mme == NULL) return false; - table->ids[mapid] = NULL; + /* fetch pages needed by mapped file and check whether the page is dirty */ + while (mme->pages-- > 0) + { + pte = page_table_remove (&thread->page_table, mme->upage + ofs); + if (pte != NULL && pte->loaded && + pagedir_is_dirty (thread->pagedir, pte->upage)) + { + /* write modified page back to disk */ + ASSERT (pte->segment.file == mme->file); + process_lock_filesys (); + file_seek (pte->segment.file, pte->segment.ofs); + file_write (pte->segment.file, pte->upage, pte->segment.read_bytes); + process_unlock_filesys (); + } + + if (pte != NULL) + free (pte); + + ofs += PGSIZE; + } + + /* close the file */ + process_lock_filesys (); + file_close (mme->file); + process_unlock_filesys (); - //TODO + /* remove mmap entry from mmap table */ + free (mme); + table->ids[mapid] = NULL; - /* update index of free/max file descriptor index */ + /* update index of free/max mapid index */ if (mapid < table->id_free) table->id_free = mapid; while (table->ids[table->id_max] == NULL) - { - table->id_max--; - if (table->id_max < 0) - break; - } + { + table->id_max--; + if (table->id_max < 0) + break; + } return true; } -- cgit v1.2.3