diff options
| author | manuel <manuel@mausz.at> | 2012-06-21 18:14:58 +0200 |
|---|---|---|
| committer | manuel <manuel@mausz.at> | 2012-06-21 18:14:58 +0200 |
| commit | e61e868b265efe2f6d51079373588d639fc54d59 (patch) | |
| tree | 035fa9afef57c88ed156909d73cd8c4a91fe4435 | |
| parent | e11b2ef0c606ab516a4344aeea1dbba22cb1fe5d (diff) | |
| download | progos-e61e868b265efe2f6d51079373588d639fc54d59.tar.gz progos-e61e868b265efe2f6d51079373588d639fc54d59.tar.bz2 progos-e61e868b265efe2f6d51079373588d639fc54d59.zip | |
full mmap implementation
| -rw-r--r-- | userprog/process.c | 6 | ||||
| -rw-r--r-- | userprog/syscall.c | 11 | ||||
| -rw-r--r-- | vm/mmap.c | 91 | ||||
| -rw-r--r-- | vm/mmap.h | 13 | ||||
| -rw-r--r-- | vm/page.c | 21 | ||||
| -rw-r--r-- | vm/page.h | 1 |
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 | |||
| 576 | syscall_mmap (void *sp, bool *segfault) | 576 | syscall_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 | } |
| @@ -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 */ |
| 27 | void | 29 | void |
| 28 | mmap_table_free (struct mmap_table *table) | 30 | mmap_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 */ |
| 36 | mapid_t | 40 | mapid_t |
| 37 | mmap_table_insert (struct mmap_table *table, void *addr, struct file *file, | 41 | mmap_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 */ | ||
| 86 | static struct mmap_table_entry * | 96 | static struct mmap_table_entry * |
| 87 | mmap_table_get (struct mmap_table *table, mapid_t mapid) | 97 | mmap_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 */ | ||
| 94 | bool | 106 | bool |
| 95 | mmap_table_remove (struct mmap_table *table, mapid_t mapid) | 107 | mmap_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 | } |
| @@ -10,21 +10,22 @@ | |||
| 10 | struct mmap_table | 10 | struct 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 */ |
| 19 | struct mmap_table_entry | 19 | struct 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 | ||
| 25 | bool mmap_table_init (struct mmap_table *table); | 26 | bool mmap_table_init (struct mmap_table *table); |
| 26 | void mmap_table_free (struct mmap_table *table); | 27 | void mmap_table_free (struct mmap_table *table); |
| 27 | mapid_t mmap_table_insert (struct mmap_table *table, void *addr, | 28 | mapid_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); |
| 29 | bool mmap_table_remove (struct mmap_table *table, mapid_t mapping); | 30 | bool mmap_table_remove (struct mmap_table *table, mapid_t mapping); |
| 30 | 31 | ||
| @@ -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 */ |
| 34 | static bool | 34 | static 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 */ |
| 60 | static bool | 60 | static bool |
| 61 | page_table_insert (struct hash *ht, struct page_table_entry *pte) | 61 | page_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 */ |
| 70 | bool | 70 | bool |
| 71 | page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, | 71 | page_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! */ | ||
| 101 | struct page_table_entry * | ||
| 102 | page_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 */ |
| 101 | bool | 114 | bool |
| 102 | page_load (struct page_table_entry *pte) | 115 | page_load (struct page_table_entry *pte) |
| @@ -26,6 +26,7 @@ struct page_table_entry | |||
| 26 | void page_table_init (struct hash *ht); | 26 | void page_table_init (struct hash *ht); |
| 27 | void page_table_free (struct hash *ht); | 27 | void page_table_free (struct hash *ht); |
| 28 | struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); | 28 | struct page_table_entry *page_table_fetch (struct hash *ht, void *upage); |
| 29 | struct page_table_entry *page_table_remove (struct hash *ht, void *upage); | ||
| 29 | bool page_table_insert_segment (struct hash *ht, struct file *file, off_t ofs, | 30 | bool 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); |
| 31 | bool page_load (struct page_table_entry *pte); | 32 | bool page_load (struct page_table_entry *pte); |
