struct frame_entry * find_victim(void) { cursor = list_begin(&frame_table); struct frame_entry *victim = NULL; while(true) { struct frame_entry *temp = list_entry(cursor, struct frame_entry, elem); if(pagedir_is_accessed(temp->t->pagedir, temp->frame)) { pagedir_set_accessed(temp->t->pagedir, temp->frame, false); pagedir_set_accessed(temp->t->pagedir, temp->spe->uaddr, false); } else { victim = temp; cursor = list_next(cursor); if(cursor == list_end(&frame_table)) cursor = list_begin(&frame_table); return victim; } cursor = list_next(cursor); if(cursor == list_end(&frame_table)) cursor = list_begin(&frame_table); } return victim; }
void * frame_evict() { ASSERT(lock_held_by_current_thread(&vm_lock)); uint32_t e_ptr = frametable.evict_ptr; while(1) { if (frametable.frametable[frametable.evict_ptr].pin == false && frametable.frametable[frametable.evict_ptr].pte != (void*) 0xFFFFFFFF) { struct pagetable_entry* old_pte = frametable.frametable[frametable.evict_ptr].pte; struct thread *t = thread_from_tid(frametable.frametable[frametable.evict_ptr].tid); if (old_pte->accessed) { pagedir_set_accessed(t->pagedir, pg_no_to_addr(frametable.frametable[frametable.evict_ptr].virt_address), false); continue; } // First we MUST mark the page as not present so that no // further accesses and modifications of the page content // are possible pagedir_set_not_present(t->pagedir, pg_no_to_addr(frametable.frametable[frametable.evict_ptr].virt_address)); if (old_pte->writable) { struct spage_table_entry ecmp, *e; struct hash_elem *elem; ecmp.vaddr = pg_no_to_addr(frametable.frametable[frametable.evict_ptr].virt_address); elem = hash_find(&t->sup_pagetable, &ecmp.elem); if (elem == NULL) { //swap struct swaptable_entry * st_e = create_swaptable_entry(pagenum_to_page(frametable.evict_ptr)); swap_add(st_e); spage_map_swap(pg_no_to_addr( frametable.frametable[frametable.evict_ptr].virt_address), st_e, t); } else { e = hash_entry(elem, struct spage_table_entry, elem); if (e->flags & SPTE_MMAP && old_pte->dirty) { //flush spage_flush_mmap(e, pagenum_to_page(frametable.evict_ptr)); //reset dirty bit pagedir_set_dirty(t->pagedir, e->vaddr, false); } else if (!(e->flags & SPTE_MMAP)) { //file backed writable entry PANIC("SWAP of page with spage entry!"); } } } frametable.frametable[frametable.evict_ptr].pte = (void*) 0xFFFFFFFF; void* tmp = pagenum_to_page(frametable.evict_ptr); log_debug("### Evict page at 0x%08x ###\n", (uint32_t) tmp); frametable.evict_ptr = (frametable.evict_ptr + 1) % frametable.size; return tmp; } // jump to next position frametable.evict_ptr = (frametable.evict_ptr + 1) % frametable.size; if (e_ptr == frametable.evict_ptr) PANIC("Nothing to evict and nothing swappable"); } }
bool page_load(struct page *p, void *fp_addr) { lock_acquire(&load); p->kpage = get_frame(PAL_USER); lock_release(&load); set_page_frame(p->kpage, p); pin_frame(p->kpage); if(p->kpage == NULL) { unpin_frame(p->kpage); return false; } bool temp = true; if(p->type == S) { temp = swap_load(p->kpage, p); } else if(p->type == F) { temp = file_load(p->kpage, p); } else { temp = zero_load(p->kpage); } if(!temp) { unpin_frame(p->kpage); return false; } pagedir_clear_page(p->dir, fp_addr); if(!pagedir_set_page(p->dir, fp_addr, p->kpage, p->write)) { unpin_frame(p->kpage); return false; } else if(!pagedir_get_page(p->dir, fp_addr)) { unpin_frame(p->kpage); return false; } p->load = true; pagedir_set_dirty(p->dir, fp_addr, false); pagedir_set_accessed(p->dir, fp_addr, true); unpin_frame(p->kpage); return true; }
/*! Use the clock algorithm to select a frame to evict and execute the eviction. */ void * frame_evict(enum palloc_flags flag) { struct list_elem *ce; struct thread *ct; struct frame_table_entry *cf; int i; if (f_table.lock.holder != thread_current()) lock_acquire(&f_table.lock); /* Get frame table lock */ if (list_empty(&f_table.table)) { lock_release(&f_table.lock); /* Nothing to evict */ return NULL; } f_table.hand = f_table.hand % list_size(&f_table.table); ce = list_begin(&f_table.table); /* Begin iteration */ for (i = 0; i < f_table.hand; i++) { /* Find where the "hand" points to: that is where the iteration starts */ ce = list_next(ce); } while (true) { cf = list_entry(ce, struct frame_table_entry, elem); ct = cf->owner; if (!cf->spt->pinned) { /* If pinned, skip this frame */ if (pagedir_is_accessed(ct->pagedir, cf->spt->upage)) /* If accessed, clear accessed bit */ pagedir_set_accessed(ct->pagedir, cf->spt->upage, false); else { /* Swap out the page! */ if (cf->spt->type != SPT_MMAP) { cf->spt->fr = NULL; cf->spt->type = SPT_SWAP; cf->spt->swap_index = swap_out(cf->physical_addr); } /* Write the frame back to the map'd file */ else if (cf->spt->type == SPT_MMAP && pagedir_is_dirty(ct->pagedir, cf->spt->upage)) { cf->spt->fr = NULL; file_write_at(cf->spt->file, cf->physical_addr, cf->spt->read_bytes, cf->spt->ofs); } /* Clear the frame */ list_remove(ce); pagedir_clear_page(ct->pagedir, cf->spt->upage); palloc_free_page(cf->physical_addr); free(cf); lock_release(&f_table.lock); return palloc_get_page(flag); } } ce = list_next(ce); ++f_table.hand; if (ce == list_end(&f_table.table)) { /* Iterate circularly */ ce = list_begin(&f_table.table); f_table.hand = 0; } } }
/** * Check if this page was accessed recently * Returns true if the PTE for virtual page VPAGE in PD has been * accessed recently, that is, between the time the PTE was * installed and the last time it was cleared. Returns false if * PD contains no PTE for VPAGE. */ bool is_page_accessed (struct supplementary_page_table_entry *page) { ASSERT(page -> supplementary_frame_in_memory != NULL) ASSERT( lock_held_by_current_thread ( &page->supplementary_frame_in_memory->this_lock)); bool access = pagedir_is_accessed (page->sup_thread->pagedir, page->vaddr); if (access) { pagedir_set_accessed (page->sup_thread->pagedir, page->vaddr, false); } return access; }
void * frame_evict (enum palloc_flags flags) { lock_acquire (&frame_table_lock); struct list_elem *e = list_begin (&frame_table); while (true) { struct frame_entry *frame_entry = list_entry (e, struct frame_entry, elem); struct SP_entry *page_entry = frame_entry->page_entry; if (!page_entry->pinned) { struct thread *t = frame_entry->thread; if (pagedir_is_accessed (t->pagedir, page_entry->page)) { pagedir_set_accessed (t->pagedir, page_entry->page, false); } else { if (pagedir_is_dirty (t->pagedir, page_entry->page) || page_entry->type == SP_SWAP) { if (page_entry->type == SP_MMAP) { lock_acquire (&filesys_lock); file_write_at (page_entry->file, frame_entry->frame, page_entry->read_bytes, page_entry->offset); lock_release (&filesys_lock); } else { page_entry->type = SP_SWAP; page_entry->swap_index = swap_out (frame_entry->frame); } } page_entry->is_loaded = false; list_remove (&frame_entry->elem); pagedir_clear_page (t->pagedir, page_entry->page); palloc_free_page (frame_entry->frame); free (frame_entry); lock_release (&frame_table_lock); return palloc_get_page (flags); } } e = list_next (e); if (e == list_end (&frame_table)) { e = list_begin (&frame_table); } } }
/* * select one frame to kick out * the page inside it. We implement * Clock Algorithm here. */ struct frame_table_entry* clock_kick(){ struct list_elem *elem; clock: elem = list_begin(&frame_table); while (elem != list_end(&frame_table)) { struct frame_table_entry* fte; fte = list_entry(elem, struct frame_table_entry, elem); ASSERT(fte!=NULL); if(!pagedir_is_accessed(fte->owner->pagedir,fte->pg_vaddr) && fte->pinned == false){ return fte; }else{ pagedir_set_accessed(fte->owner->pagedir,fte->pg_vaddr,0); } elem = list_next(elem); } goto clock; NOT_REACHED(); return NULL; }
struct frame_table_entry* frame_evict_choose_secondchance (void) { struct frame_table_entry *fte = frame_evict_choose_fifo (); if (pagedir_is_accessed (fte->owner->pagedir, fte->uaddr)) { pagedir_set_accessed (fte->owner->pagedir, fte->uaddr, false); lock_acquire (&frame_table_lock); list_remove (&fte->elem); list_push_front (&frame_table, &fte->elem); lock_release (&frame_table_lock); return frame_evict_choose_secondchance (); } else { return fte; } }
/* The implementation of LRU 'clock' algorithm follows.. we make use of the PTE's accessed bit and dirty bit: on any read or write to a page ==> accessed bit = 1; on any write ==> dirty bit = 1; Step 1: We navigate through the pages in a circular order.. i.e., if we hit the end of the frame list, we circle back to the start and continue our processing.. Step 2: If the accessed bit is 'accessed', turn it to 'not accessed', skip the page and proceed to look-up the next one in the list Step 3: If the accessed bit is 'not accessed', we can proceed with our page replacement */ void evict_page() { struct list_elem *e; int count = 0; lock_acquire(&ftable_lock); for (e = list_begin(&frame_list); e != list_end(&frame_list); e = list_next(e)) { struct frame *frame = list_entry(e, struct frame, frame_list_elem); // printf ("\n%d , %d", count, list_size(&frame_list) - 1); if (count != list_size(&frame_list) - 1) { // get the accessed flag for the current page bool accessed_flag = pagedir_is_accessed( frame->page->frame_holder_thread->pagedir, frame->page->addr); if (accessed_flag) pagedir_set_accessed(frame->page->frame_holder_thread->pagedir, frame->page->addr, !accessed_flag); else { // we need to page replace.. i.e., // step 1: remove the existing page from the frame (swap_out call) // step 2: remove the existing page from the page directory // step 3: set the accessed flag of the page to 'accessed' // step 4: free the page and free the frame, for subsequent use list_remove(e); swap_out(frame->page); frame->page->swap_flag = 1; pagedir_clear_page(frame->page->frame_holder_thread->pagedir, frame->page->addr); palloc_free_page(frame->base); free(frame); // frame->page->swap_flag = 1; break; } count++; } else { count = 0; e = list_begin(&frame_list); } } lock_release(&ftable_lock); }
struct frame_table_entry* pick_frame_to_evict( uint32_t *pagedir ) { size_t n = hash_size(&frame_map); if(n == 0) PANIC("Frame table is empty, can't happen - there is a leak somewhere"); size_t it; for(it = 0; it <= n + n; ++ it) // prevent infinite loop. 2n iterations is enough { struct frame_table_entry *e = clock_frame_next(); // if pinned, continue if(e->pinned) continue; // if referenced, give a second chance. else if( pagedir_is_accessed(pagedir, e->upage)) { pagedir_set_accessed(pagedir, e->upage, false); continue; } // OK, here is the victim : unreferenced since its last chance return e; } PANIC ("Can't evict any frame -- Not enough memory!\n"); }
static void clock_daemon(void *aux) { // printf("starting clock\n"); struct frame *head, *tail; bool got_frame = false; /* while(true) thread_yield();*/ // sema_down(&clockwaiting); // int i; while(1) { // printf("locking\n"); lock_acquire(&clocklock); // printf("Checking list is empty\n"); if(list_empty(&clocklist)) { // printf("Releasing lock\n"); lock_release(&clocklock); // printf("Sleeping\n"); timer_msleep(CLOCK_WAIT_MS); // thread_yield(); // printf("Woke up\n"); continue; } // printf("List is not empty\n"); if(clockmodified) { // printf("clockmodified"); head = tail = get_clock_frame(list_begin(&clocklist)); // i = 0; } // printf("clock got lock\n"); for(int i = 0; i < CLOCK_DIFF_COUNT; i++) { // printf("in for loop"); // if(!clockmodified) // i = CLOCK_WAIT_COUNT; // printf("clock on frame %p: checking semaphore at %p\n", current, ¤t->evicting); /* Clear head's accessed bit. */ if(lock_try_acquire(&head->evicting)) { // printf("\t\tgot head sema\n"); pagedir_set_accessed(head->page->thread->pagedir, head->page->vaddr, false);//TODO check if it is being moved lock_release(&head->evicting); } /* If clock hands have reached proper angle, use tail hand. */ if(!clockmodified/*i >= CLOCK_WAIT_COUNT*/) { /* Check if frame has been changed accessed since head passed. */ if(lock_try_acquire(&tail->evicting)) { if(!pagedir_is_writeable/*accessed*/(tail->page->thread->pagedir, tail->page->vaddr)) { /* Wait for clock frame to be cleared then set it to tail. */ // if(sema_try_down(&clockwaiting)) lock_acquire(&clockcondlock); if(clockwaiters > 0 && clockrecieved) { printf("Found non accessed dir\n"); clock_frame = tail; clockrecieved = false; got_frame = true; cond_signal(&clockwaiting, &clockcondlock); } lock_release(&clockcondlock); // sema_up(&clockready); // break; // } } if(!got_frame) { lock_release(&tail->evicting); } else { got_frame = true; } } tail = get_next_clock_frame(tail); } // printf("getting next frame\n"); head = get_next_clock_frame(head); // printf("sleeping\n"); } clockmodified = false; lock_release(&clocklock); timer_msleep(CLOCK_WAIT_MS); // thread_yield(); } PANIC("Frame eviction daemon quit!\n"); }