/* Down or "P" operation on a semaphore. Waits for SEMA's value * to become positive and then atomically decrements it. * * This function may sleep, so it must not be called within an * interrupt handler. This function may be called with * interrupts disabled, but if it sleeps then the next scheduled * thread will probably turn interrupts back on. */ void sema_down(struct semaphore *sema) { enum intr_level old_level; ASSERT(sema != NULL); ASSERT(!intr_context()); old_level = intr_disable(); while (sema -> value == 0) { /* * 注释掉原有的代码 * list_push_back(&sema -> waiters, &thread_current() -> elem); * thread_block(); */ if (!thread_mlfqs) { donate_priority(); } list_insert_ordered( &sema -> waiters, &thread_current() -> elem, (list_less_func *) &cmp_priority, NULL ); thread_block(); } sema -> value--; intr_set_level(old_level); }
void donate_priority(struct thread *thread_, int priority){ thread_->priority=priority; if(thread_->waiting_lock){ donate_priority(thread_->waiting_lock->holder, priority); } }
void donate_priority(struct thread *thread_, int priority){ thread_->priority=priority; if(nested_priority > 7) return; if(thread_->waiting_lock){ if(thread_->waiting_lock->holder->priority < priority){ nested_priority++; donate_priority(thread_->waiting_lock->holder, priority); } } }
// Refresh donated priorities of all the threads dependent on current threads. void refresh_donated_priority_down (struct thread* acquirer) { int i; for (i=0; i < lock_list_cnt; i++) { struct list_elem* e; struct list* waiter_list = &lock_list[i]->semaphore.waiters; for (e = &waiter_list->head; e != list_end(waiter_list); e = e->next) { if (list_entry(e, struct thread, elem) == acquirer) { if (lock_list[i]->holder->effective_priority < acquirer->effective_priority) donate_priority(lock_list[i]->holder, acquirer->effective_priority); refresh_donated_priority_down (lock_list[i]->holder); break; } } } }
void lock_sema_up (struct semaphore *sema, struct thread* holder) { ASSERT (!thread_mlfqs); enum intr_level old_level; ASSERT (sema != NULL); old_level = intr_disable (); if (!list_empty (&sema->waiters)) { // P2: find out thread with highest priority. struct list_elem* max_elem = list_max(&sema->waiters, priority_less, NULL); list_remove (max_elem); // P2: calculate and assign donate priority. donate_priority (holder, calculate_donated_priority_up(holder)); thread_unblock (list_entry (max_elem, struct thread, elem)); } sema->value++; intr_set_level (old_level); thread_yield(); // p2 }