/** * Allocate a new frame, * and return the address of the associated page. */ void* vm_frame_allocate (enum palloc_flags flags, void *upage) { lock_acquire (&frame_lock); void *frame_page = palloc_get_page (PAL_USER | flags); if (frame_page == NULL) { // page allocation failed. /* first, swap out the page */ struct frame_table_entry *f_evicted = pick_frame_to_evict( thread_current()->pagedir ); #if DEBUG printf("f_evicted: %x th=%x, pagedir = %x, up = %x, kp = %x, hash_size=%d\n", f_evicted, f_evicted->t, f_evicted->t->pagedir, f_evicted->upage, f_evicted->kpage, hash_size(&frame_map)); #endif ASSERT (f_evicted != NULL && f_evicted->t != NULL); // clear the page mapping, and replace it with swap ASSERT (f_evicted->t->pagedir != (void*)0xcccccccc); pagedir_clear_page(f_evicted->t->pagedir, f_evicted->upage); bool is_dirty = false; is_dirty = is_dirty || pagedir_is_dirty(f_evicted->t->pagedir, f_evicted->upage); is_dirty = is_dirty || pagedir_is_dirty(f_evicted->t->pagedir, f_evicted->kpage); swap_index_t swap_idx = vm_swap_out( f_evicted->kpage ); vm_supt_set_swap(f_evicted->t->supt, f_evicted->upage, swap_idx); vm_supt_set_dirty(f_evicted->t->supt, f_evicted->upage, is_dirty); vm_frame_do_free(f_evicted->kpage, true); // f_evicted is also invalidated frame_page = palloc_get_page (PAL_USER | flags); ASSERT (frame_page != NULL); // should success in this chance } struct frame_table_entry *frame = malloc(sizeof(struct frame_table_entry)); if(frame == NULL) { // frame allocation failed. a critical state or panic? lock_release (&frame_lock); return NULL; } frame->t = thread_current (); frame->upage = upage; frame->kpage = frame_page; frame->pinned = true; // can't be evicted yet // insert into hash table hash_insert (&frame_map, &frame->helem); list_push_back (&frame_list, &frame->lelem); lock_release (&frame_lock); return frame_page; }
/* Evicte random frame */ struct vm_frame *vm_evict_frame(struct supp_page_entry *s){ ASSERT(!list_empty(&vm_frames_list)); /* Choose frame - FIFO */ lock_acquire(&vm_lock); struct list_elem *e = list_front(&vm_frames_list); struct vm_frame *victim = list_entry(e, struct vm_frame, elem); lock_release(&vm_lock); /* Settings */ pagedir_clear_page(victim->thread->pagedir, victim->spte->upage); victim->spte->type = S; victim->spte->swap_idx = vm_swap_out(victim->page); victim->thread = thread_current(); victim->spte = s; palloc_free_page(victim->page); return victim; }