#include "mmap.h" #include "page.h" #include "threads/vaddr.h" #include "threads/malloc.h" #include "userprog/syscall.h" #include "userprog/pagedir.h" static unsigned mmap_hash (const struct hash_elem *e, void *aux); static bool mmap_less (const struct hash_elem *a_, const struct hash_elem *b_, void *aux); static void mmap_cleanup(struct hash_elem *e, void *aux); /* Initializes the mmap table for the given thread, setting the mmap counter to 0 and initializing the hash table. */ bool mmap_init (struct thread *t) { t->mmap_counter = 0; return hash_init (&t->mmap_files, mmap_hash, mmap_less, NULL); } struct mmap_entry * mmap_get (mapid_t mapping) { struct mmap_entry fake_mmap_entry; fake_mmap_entry.mapping = mapping; struct hash_elem *e = hash_find (&thread_current ()->mmap_files, &fake_mmap_entry.elem); if (e == NULL) return NULL; return hash_entry (e, struct mmap_entry, elem); } /* Inserts a new mmap entry into the mmap table for the current thread. Upage is the start address of the file data in the user VM. */ struct mmap_entry * mmap_insert (struct file *file, void *upage) { if (file == NULL || upage == NULL) return NULL; struct mmap_entry *mmap = malloc (sizeof (struct mmap_entry)); if (mmap == NULL) return NULL; mmap->mapping = thread_current ()->mmap_counter++; mmap->file = file; mmap->upage = upage; hash_insert (&thread_current ()->mmap_files, &mmap->elem); return mmap; } /* Unmaps the given mmap entry from the current thread's mmap table. */ void mmap_unmap (struct mmap_entry *mmap) { if (mmap == NULL) return; /* Free all the pages associated with the mapping, writing back to the file if necessary. */ off_t length = file_length (mmap->file); for (off_t ofs = 0; ofs < length; ofs += PGSIZE) { void *upage = mmap->upage + ofs; /* Get the SPT page entry for this page. */ struct page_entry *page = page_get(upage); if (page == NULL) continue; /* Write the page back to the file if it is dirty. */ if (pagedir_is_dirty (thread_current ()->pagedir, upage)) { lock_acquire (&filesys_lock); file_write_at (mmap->file, upage, page->read_bytes, ofs); lock_release (&filesys_lock); } /* Remove the page from the supplemental page table. */ hash_delete (&thread_current ()->pages, &page->elem); } /* Remove the mapping from the mmap table. Close the file and free the mmap entry. */ hash_delete (&thread_current ()->mmap_files, &mmap->elem); file_close (mmap->file); free(mmap); } /* Destroys the mmap table for the current thread. Frees all the memory allocated for the mmap entries. */ void mmap_destroy (void) { hash_destroy (&thread_current ()->mmap_files, mmap_cleanup); } /* A hash function for the mmap table. Returns a hash for an entry, based on its mapping. */ static unsigned mmap_hash (const struct hash_elem *e, void *aux UNUSED) { return hash_entry (e, struct mmap_entry, elem)->mapping; } /* A comparator function for the mmap table. Compares two entries based on their mappings. */ static bool mmap_less (const struct hash_elem *a_, const struct hash_elem *b_, void *aux UNUSED) { const struct mmap_entry *a = hash_entry (a_, struct mmap_entry, elem); const struct mmap_entry *b = hash_entry (b_, struct mmap_entry, elem); return a->mapping < b->mapping; } /* Cleans up the mmap table for the current thread. Frees the memory allocated for the mmap entry. */ static void mmap_cleanup (struct hash_elem *e, void *aux UNUSED) { struct mmap_entry *mmap = hash_entry (e, struct mmap_entry, elem); file_close (mmap->file); free (mmap); } /* Updates the 'owner' thread's page table entry for virtual address 'upage' to have a present bit of 0 and stores the specified swap slot value in the entry for later retrieval from disk. */ void page_set_swap (struct thread *owner, void *upage, size_t swap_slot) { } /* Given that the page with user address 'upage' owned by 'owner' is flagged to be in the swap disk via the owner's page table, returns its stored swap slot. Otherwise panics the kernel. */ size_t page_get_swap (struct thread *owner, void *upage) { return 0; }