summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormanuel <manuel@mausz.at>2012-06-21 18:14:58 +0200
committermanuel <manuel@mausz.at>2012-06-21 18:14:58 +0200
commite61e868b265efe2f6d51079373588d639fc54d59 (patch)
tree035fa9afef57c88ed156909d73cd8c4a91fe4435
parente11b2ef0c606ab516a4344aeea1dbba22cb1fe5d (diff)
downloadprogos-e61e868b265efe2f6d51079373588d639fc54d59.tar.gz
progos-e61e868b265efe2f6d51079373588d639fc54d59.tar.bz2
progos-e61e868b265efe2f6d51079373588d639fc54d59.zip
full mmap implementation
-rw-r--r--userprog/process.c6
-rw-r--r--userprog/syscall.c11
-rw-r--r--vm/mmap.c91
-rw-r--r--vm/mmap.h13
-rw-r--r--vm/page.c21
-rw-r--r--vm/page.h1
6 files changed, 101 insertions, 42 deletions
diff --git a/userprog/process.c b/userprog/process.c
index f399038..80e327d 100644
--- a/userprog/process.c
+++ b/userprog/process.c
@@ -151,13 +151,11 @@ start_process (void *aux)
151 /* If process startup failed, quit. */ 151 /* If process startup failed, quit. */
152 if (thread->process == NULL) { 152 if (thread->process == NULL) {
153 if (process != NULL) { 153 if (process != NULL) {
154 //TODO: free mmap table + page table?
155
156 /* close/free memory mapped files */ 154 /* close/free memory mapped files */
157 //mmap_table_free (&process->mmap_table); 155 mmap_table_free (&process->mmap_table);
158 156
159 /* free page table */ 157 /* free page table */
160 //page_table_free (&thread->page_table); 158 page_table_free (&thread->page_table);
161 159
162 if (process->fd_table.fds != NULL) 160 if (process->fd_table.fds != NULL)
163 palloc_free_page (process->fd_table.fds); 161 palloc_free_page (process->fd_table.fds);
diff --git a/userprog/syscall.c b/userprog/syscall.c
index 14cbaab..9da3044 100644
--- a/userprog/syscall.c
+++ b/userprog/syscall.c
@@ -576,9 +576,10 @@ static int
576syscall_mmap (void *sp, bool *segfault) 576syscall_mmap (void *sp, bool *segfault)
577{ 577{
578 int fd; 578 int fd;
579 void *addr, *offset; 579 uint8_t *addr, *offset;
580 struct file *file, *file2; 580 struct file *file, *file2;
581 off_t len; 581 off_t len;
582 struct thread *thread = thread_current ();
582 583
583 /* get arguments */ 584 /* get arguments */
584 if (! copy_from_user (&fd, STACK_ADDR (sp,1)) || 585 if (! copy_from_user (&fd, STACK_ADDR (sp,1)) ||
@@ -605,11 +606,15 @@ syscall_mmap (void *sp, bool *segfault)
605 if (len <= 0) 606 if (len <= 0)
606 return -1; 607 return -1;
607 608
608 /* check if the pages don't overlap any existing pages */ 609 /* check if the pages don't overlap any existing pages AND mapped pages */
609 offset = addr; 610 offset = addr;
610 while(offset < addr + len) 611 while(offset < addr + len)
611 { 612 {
612 if (page_table_fetch (&thread_current ()->page_table, offset)) 613 /* check for pages either loaded or not */
614 if (page_table_fetch (&thread->page_table, offset))
615 return -1;
616 /* check for already loaded pages not in page table (e.g. stack) */
617 if (pagedir_get_page (thread->pagedir, offset))
613 return -1; 618 return -1;
614 offset += PGSIZE; 619 offset += PGSIZE;
615 } 620 }
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 @@
1#include <string.h> 1#include <string.h>
2#include "userprog/pagedir.h"
3#include "userprog/process.h"
2#include "filesys/file.h" 4#include "filesys/file.h"
3#include "threads/thread.h" 5#include "threads/thread.h"
4#include "threads/vaddr.h" 6#include "threads/vaddr.h"
@@ -23,18 +25,20 @@ mmap_table_init (struct mmap_table *table)
23 return true; 25 return true;
24} 26}
25 27
26/* frees the content of mmap table */ 28/* closes all mapped files and frees the content of the table */
27void 29void
28mmap_table_free (struct mmap_table *table) 30mmap_table_free (struct mmap_table *table)
29{ 31{
30 //TODO 32 mapid_t id;
33 for (id = 0; id <= table->id_max; id++)
34 mmap_table_remove (table, id);
31 palloc_free_page (table->ids); 35 palloc_free_page (table->ids);
32} 36}
33 37
34/* inserts a new mmap entry in the mmap table 38/* inserts a new mmap entry in the mmap table.
35 returns -1 if entry is invalid or already in the table */ 39 returns -1 if entry is invalid or already in the table */
36mapid_t 40mapid_t
37mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, 41mmap_table_insert (struct mmap_table *table, uint8_t *upage, struct file *file,
38 off_t len) 42 off_t len)
39{ 43{
40 off_t ofs = 0; 44 off_t ofs = 0;
@@ -46,43 +50,49 @@ mmap_table_insert (struct mmap_table *table, void *addr, struct file *file,
46 if (table->id_free >= table->id_cap) 50 if (table->id_free >= table->id_cap)
47 return -1; 51 return -1;
48 52
53 /* create mmap table entry */
49 mme = malloc (sizeof *mme); 54 mme = malloc (sizeof *mme);
50 if (mme == NULL) 55 if (mme == NULL)
51 return -1; 56 return -1;
52 57
53 mapid = table->id_free++; 58 mme->upage = upage;
54 mme->addr = addr;
55 mme->file = file; 59 mme->file = file;
56 table->ids[mapid] = mme; 60 mme->pages = 0;
57 61
58 /* create needed pages in page table */ 62 /* create needed pages in page table */
59 while (len > 0) 63 while (len > 0)
60 { 64 {
61 page_read_bytes = (len < PGSIZE) ? len : PGSIZE; 65 page_read_bytes = (len < PGSIZE) ? len : PGSIZE;
62
63 if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs, 66 if (!page_table_insert_segment (&thread_current ()->page_table, file, ofs,
64 addr, page_read_bytes, true)) 67 upage, page_read_bytes, true))
65 return -1; 68 return -1;
66 69
67 /* Advance. */ 70 /* Advance. */
68 len -= PGSIZE; 71 len -= PGSIZE;
69 ofs += page_read_bytes; 72 ofs += page_read_bytes;
70 addr += PGSIZE; 73 upage += PGSIZE;
74 mme->pages++;
71 } 75 }
72 76
77 /* insert entry into our table */
78 mapid = table->id_free++;
79 table->ids[mapid] = mme;
80
73 /* update index of free/max mapid index */ 81 /* update index of free/max mapid index */
74 if (mapid > table->id_max) 82 if (mapid > table->id_max)
75 table->id_max = mapid; 83 table->id_max = mapid;
76 while (table->ids[table->id_free] != NULL) 84 while (table->ids[table->id_free] != NULL)
77 { 85 {
78 table->id_free++; 86 table->id_free++;
79 if (table->id_free >= table->id_cap) 87 if (table->id_free >= table->id_cap)
80 break; 88 break;
81 } 89 }
82 90
83 return mapid; 91 return mapid;
84} 92}
85 93
94/* get the mmap table entry associated with the given map id.
95 return NULL if no mapping is associated with the given id */
86static struct mmap_table_entry * 96static struct mmap_table_entry *
87mmap_table_get (struct mmap_table *table, mapid_t mapid) 97mmap_table_get (struct mmap_table *table, mapid_t mapid)
88{ 98{
@@ -91,26 +101,57 @@ mmap_table_get (struct mmap_table *table, mapid_t mapid)
91 return table->ids[mapid]; 101 return table->ids[mapid];
92} 102}
93 103
104/* remove the entry associated with the given map id from the mmap table.
105 flushes all dirty/modified pages back to disk. return true if successful */
94bool 106bool
95mmap_table_remove (struct mmap_table *table, mapid_t mapid) 107mmap_table_remove (struct mmap_table *table, mapid_t mapid)
96{ 108{
109 struct page_table_entry *pte;
110 off_t ofs = 0;
111 struct thread *thread = thread_current ();
97 struct mmap_table_entry *mme = mmap_table_get(table, mapid); 112 struct mmap_table_entry *mme = mmap_table_get(table, mapid);
98 if (mme == NULL) 113 if (mme == NULL)
99 return false; 114 return false;
100 115
101 table->ids[mapid] = NULL; 116 /* fetch pages needed by mapped file and check whether the page is dirty */
117 while (mme->pages-- > 0)
118 {
119 pte = page_table_remove (&thread->page_table, mme->upage + ofs);
120 if (pte != NULL && pte->loaded &&
121 pagedir_is_dirty (thread->pagedir, pte->upage))
122 {
123 /* write modified page back to disk */
124 ASSERT (pte->segment.file == mme->file);
125 process_lock_filesys ();
126 file_seek (pte->segment.file, pte->segment.ofs);
127 file_write (pte->segment.file, pte->upage, pte->segment.read_bytes);
128 process_unlock_filesys ();
129 }
130
131 if (pte != NULL)
132 free (pte);
133
134 ofs += PGSIZE;
135 }
136
137 /* close the file */
138 process_lock_filesys ();
139 file_close (mme->file);
140 process_unlock_filesys ();
102 141
103 //TODO 142 /* remove mmap entry from mmap table */
143 free (mme);
144 table->ids[mapid] = NULL;
104 145
105 /* update index of free/max file descriptor index */ 146 /* update index of free/max mapid index */
106 if (mapid < table->id_free) 147 if (mapid < table->id_free)
107 table->id_free = mapid; 148 table->id_free = mapid;
108 while (table->ids[table->id_max] == NULL) 149 while (table->ids[table->id_max] == NULL)
109 { 150 {
110 table->id_max--; 151 table->id_max--;
111 if (table->id_max < 0) 152 if (table->id_max < 0)
112 break; 153 break;
113 } 154 }
114 155
115 return true; 156 return true;
116} 157}
diff --git a/vm/mmap.h b/vm/mmap.h
index bee364e..09276a7 100644
--- a/vm/mmap.h
+++ b/vm/mmap.h
@@ -10,21 +10,22 @@
10struct mmap_table 10struct mmap_table
11{ 11{
12 struct mmap_table_entry **ids; 12 struct mmap_table_entry **ids;
13 int id_free; /* lowest-index free */ 13 int id_free; /* lowest-index free */
14 int id_max; /* highest-index used */ 14 int id_max; /* highest-index used */
15 int id_cap; /* mmap table capacity */ 15 int id_cap; /* mmap table capacity */
16}; 16};
17 17
18/* a single entry in the mmap table */ 18/* a single entry in the mmap table */
19struct mmap_table_entry 19struct mmap_table_entry
20{ 20{
21 void *addr; 21 uint8_t *upage; /* virtual address of first page of mmapped file */
22 struct file *file; 22 struct file *file; /* file handle */
23 int pages; /* number of pages the mapping needs */
23}; 24};
24 25
25bool mmap_table_init (struct mmap_table *table); 26bool mmap_table_init (struct mmap_table *table);
26void mmap_table_free (struct mmap_table *table); 27void mmap_table_free (struct mmap_table *table);
27mapid_t mmap_table_insert (struct mmap_table *table, void *addr, 28mapid_t mmap_table_insert (struct mmap_table *table, uint8_t *upage,
28 struct file *file, off_t len); 29 struct file *file, off_t len);
29bool mmap_table_remove (struct mmap_table *table, mapid_t mapping); 30bool mmap_table_remove (struct mmap_table *table, mapid_t mapping);
30 31
diff --git a/vm/page.c b/vm/page.c
index 2853497..98120e5 100644
--- a/vm/page.c
+++ b/vm/page.c
@@ -28,7 +28,7 @@ page_table_hash (const struct hash_elem *e, void *aux UNUSED)
28 return hash_bytes (&pte->upage, sizeof pte->upage); 28 return hash_bytes (&pte->upage, sizeof pte->upage);
29} 29}
30 30
31/* page table comperator needed by the hash table implementation 31/* page table comperator needed by the hash table implementation.
32 returns true if A is less than B, or false if A is greater than 32 returns true if A is less than B, or false if A is greater than
33 or equal to B */ 33 or equal to B */
34static bool 34static bool
@@ -55,7 +55,7 @@ page_table_entry_free (struct hash_elem *e, void *aux UNUSED)
55 free (pte); 55 free (pte);
56} 56}
57 57
58/* inserts a new entry into the page table 58/* inserts a new entry into the page table.
59 returns false if entry is invalid or already in the table */ 59 returns false if entry is invalid or already in the table */
60static bool 60static bool
61page_table_insert (struct hash *ht, struct page_table_entry *pte) 61page_table_insert (struct hash *ht, struct page_table_entry *pte)
@@ -65,7 +65,7 @@ page_table_insert (struct hash *ht, struct page_table_entry *pte)
65 return (hash_insert (ht, &pte->elem) == NULL); 65 return (hash_insert (ht, &pte->elem) == NULL);
66} 66}
67 67
68/* inserts a new entry of type segment into the page table 68/* inserts a new entry of type segment into the page table.
69 returns false if entry is invalid or already in the table */ 69 returns false if entry is invalid or already in the table */
70bool 70bool
71page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, 71page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs,
@@ -96,7 +96,20 @@ page_table_fetch (struct hash *ht, void *upage)
96 return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL); 96 return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL);
97} 97}
98 98
99/* load the page referenced by the page table entry 99/* remove an entry from the page table. returns the element or NULL if not found.
100 the caller is responsible for freeing the element! */
101struct page_table_entry *
102page_table_remove (struct hash *ht, void *upage)
103{
104 struct page_table_entry pte;
105 struct hash_elem *e;
106
107 pte.upage = upage;
108 e = hash_delete (ht, &pte.elem);
109 return ((e != NULL) ? hash_entry (e, struct page_table_entry, elem) : NULL);
110}
111
112/* load the page referenced by the page table entry.
100 returns true on success or already loaded, false otherwise */ 113 returns true on success or already loaded, false otherwise */
101bool 114bool
102page_load (struct page_table_entry *pte) 115page_load (struct page_table_entry *pte)
diff --git a/vm/page.h b/vm/page.h
index da1398c..c78ab65 100644
--- a/vm/page.h
+++ b/vm/page.h
@@ -26,6 +26,7 @@ struct page_table_entry
26void page_table_init (struct hash *ht); 26void page_table_init (struct hash *ht);
27void page_table_free (struct hash *ht); 27void page_table_free (struct hash *ht);
28struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); 28struct page_table_entry *page_table_fetch (struct hash *ht, void *upage);
29struct page_table_entry *page_table_remove (struct hash *ht, void *upage);
29bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, 30bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs,
30 uint8_t *upage, uint32_t read_bytes, bool writable); 31 uint8_t *upage, uint32_t read_bytes, bool writable);
31bool page_load (struct page_table_entry *pte); 32bool page_load (struct page_table_entry *pte);