/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); enum intr_level old_state = intr_disable(); // If there is lock holder // Add this thread to donorList of lock holder if (lock->holder != NULL) { // Save lock to this thread thread_current()->tLock = lock; list_push_back(&lock->holder->donorList,&thread_current()->donorElem); } intr_set_level(old_state); sema_down (&lock->semaphore); // This thread is now the holder // Not waiting on any lock thread_current()->tLock = NULL; lock->holder = thread_current (); //intr_set_level(old_state); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { enum intr_level old_level; ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); old_level = intr_disable (); if (lock->holder != NULL) { /* Donate our priority to the thread holding the lock. First, update the data structures. */ struct thread *donor = thread_current (); donor->want_lock = lock; donor->donee = lock->holder; list_push_back (&lock->holder->donors, &donor->donor_elem); /* Now implement the priority donation itself by recomputing the donee's priority and cascading the donation as far as necessary. */ if (donor->donee != NULL) thread_recompute_priority (donor->donee); } sema_down (&lock->semaphore); lock->holder = thread_current (); intr_set_level (old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); struct thread* acquirer = thread_current(); if (!thread_mlfqs) { // P2: add new lock to the lock_list. if (!is_thread(lock->holder)) { // add lock into locklist. bool found = 0; int i; for (i=0;i<lock_list_cnt; i++) if (lock_list[i] == lock) found = 1; if (found == 0) { ASSERT (lock_list_cnt < 64); lock_list[lock_list_cnt++] = lock; } } lock_sema_down (&lock->semaphore, acquirer); } else { sema_down (&lock->semaphore); } // wait for the other to release lock->holder = acquirer; }
/* 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); */ /* 按照降序插入 */ list_insert_ordered( &sema -> waiters, &thread_current() -> elem, (list_less_func *) &priority_cmp_max_to_low, NULL ); /* 阻塞当前线程 */ thread_block(); } sema -> value--; intr_set_level(old_level); }
/* Returns true if the current thread has the console lock, false otherwise. */ static bool console_locked_by_current_thread (void) { return (intr_context () || !use_console_lock || lock_held_by_current_thread (&console_lock)); }
/* -------------------------------------------------------------------- Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. NOTE: if we cannot aquire the lock and we are in regular priority donation scheduling, then we invoke the call to donate our priority. Once we move past the semaphore, we have aquired the lock, and thus add it to our list of locks_held, so that this thread can properly recieve priortity donations. -------------------------------------------------------------------- */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); enum intr_level old_level = intr_disable(); if (!thread_mlfqs) { if (lock->holder != NULL) { thread_current()->lock_waiting_on = lock; //donate_priority(); } } sema_down (&lock->semaphore); if (!thread_mlfqs) { lock->priority = PRI_MIN; list_push_front(&(thread_current()->locks_held), &(lock->elem)); thread_current()->lock_waiting_on = NULL; } lock->holder = thread_current (); intr_set_level(old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); struct thread *holder= lock->holder; /* If the current lock is already locked, then we update the mx_priority, by comparing it * with the current_thread. * We check if the thread holding the lock has less priority than the current priority so it * donates it priority, then we add the current lock to the list of the thread of the donating_locks. */ if(holder != NULL){ if(lock->mx_priority < thread_current()->priority){ lock->mx_priority= thread_current()->priority; } if(thread_current()->priority > holder->priority){ if(!list_exist(&holder->donating_locks, &lock->elem)){ list_push_back(&holder->donating_locks, &lock->elem); } holder->priority= thread_current()->priority; } thread_current()->blocked=lock; nest_donation(holder); } else{ list_push_back(&thread_current()->donating_locks, &lock->elem); } sema_down (&lock->semaphore); lock->holder = thread_current(); }
/* Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. Within an interrupt context, sema_up () always returns. */ void sema_up (struct semaphore *sema) { enum intr_level old_level; bool yield = false; ASSERT (sema != NULL); old_level = intr_disable (); if (!list_empty (&sema->waiters)) { struct thread *t = list_entry (list_pop_front (&sema->waiters), struct thread, elem); thread_unblock (t); /* Yield to the newly unblocked thread if it has higher priority. */ if (t->priority > thread_current ()->priority) yield = true; } sema->value++; intr_set_level (old_level); if (yield) { if (!intr_context ()) thread_yield (); else intr_yield_on_return (); } }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); enum intr_level old_level = intr_disable (); if (lock->holder != NULL) /* If the lock is being held. */ { /* Updates current thread's lock_to_acquire attribute, adds itself to the lock holder's donors list and donates priority. */ thread_current ()->lock_to_acquire = lock; list_push_front (&lock->holder->priority_donors, &thread_current ()->donor); priority_donation (); } sema_down (&lock->semaphore); /* The lock has been acquired: current thread is not waiting for it anymore. */ thread_current ()->lock_to_acquire = NULL; lock->holder = thread_current (); intr_set_level (old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); struct thread *cur_thread = thread_current (); /* If we are not in the multi-level feedback queue scheduler then use priority donation */ if(!thread_mlfqs) { /* donate priority if someone holds the lock we want */ enum intr_level old_level = intr_disable (); if (lock->holder != NULL) { cur_thread->lock_waiting_for = lock; cur_thread->t_donating_to = lock->holder; thread_donate_priority(cur_thread); } intr_set_level (old_level); } sema_down (&lock->semaphore); lock->holder = cur_thread; }
bool grow_stack (void *uaddr) { void *upage = pg_round_down (uaddr); if((size_t)(PHYS_BASE - upage) > (1 << 23)) return false; struct spage_table_entry *spte = malloc (sizeof (struct spage_table_entry)); if (!spte) return false; spte->upage = upage; spte->in_memory = true; spte->writable = true; spte->spage_type = SWAP; spte->inevictable = true; uint8_t *f = frame_alloc (PAL_USER, spte); if (!f) { free (spte); return false; } if (!install_page (spte->upage, f, spte->writable)) { free (spte); frame_free (f); return false; } if (intr_context ()) spte->inevictable = false; return hash_insert (&thread_current ()->spage_table, &spte->elem) == NULL; }
/* Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. */ void sema_up (struct semaphore *sema) { enum intr_level old_level; ASSERT (sema != NULL); old_level = intr_disable (); sema->value++; if (!list_empty (&sema->waiters)) { /* Find highest-priority waiting thread. */ struct thread *max = list_entry (list_max (&sema->waiters, thread_lower_priority, NULL), struct thread, elem); /* Remove `max' from wait list and unblock. */ list_remove (&max->elem); thread_unblock (max); /* Yield to a higher-priority thread, if we're running in a context where it makes sense to do so. Kind of a funny interaction with donation here. We only support donation for locks, and locks turn off interrupts before calling us, so we automatically don't do the yield here, delegating to lock_release(). */ if (!intr_context () && old_level == INTR_ON) thread_yield_to_higher_priority (); } intr_set_level (old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); ASSERT (thread_current ()->waiting_on == NULL); enum intr_level old_level; old_level = intr_disable (); /* If the lock is currently held by someone, then we need to invoke thread_donate_priority to donate our priority to that special someone. */ if (!thread_mlfqs && lock->holder != NULL) { thread_current ()->waiting_on = lock; thread_donate_priority (thread_current ()); } sema_down (&lock->semaphore); lock->holder = thread_current (); thread_current ()->waiting_on = NULL; intr_set_level (old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); /* If the lock is not being held, just grap the lock. */ if (lock->holder == NULL) { sema_down (&lock->semaphore); lock->holder = thread_current (); } /* If the lock is being held and donation is needed (priority is higher than the lock holder), apply donation, set the lock holder as waiting thread and reverse donation afterwards. */ else if (thread_current ()->priority > lock->holder->original_priority) { thread_current ()->thread_waiting_for = lock->holder; apply_donation (thread_current ()); sema_down (&lock->semaphore); lock->holder = thread_current (); recover_priority (thread_current ()->thread_waiting_for); } /* If the lock is being held and donation is not needed (priority is lower than the lock holder), just set the lock holder as waiting thread for possible chain donation and reverse possible chain donation afterwards */ else { thread_current ()->thread_waiting_for = lock->holder; sema_down (&lock->semaphore); lock->holder = thread_current (); } }
/* Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. The thread with the highest priority in the waiting list gets added to the ready_list. If it has a higher priority than the running thread, then the running thread will be preempted. */ void sema_up (struct semaphore *sema) { enum intr_level old_level; ASSERT (sema != NULL); old_level = intr_disable (); struct thread *t = NULL; if (!list_empty (&sema->waiters)) { struct list_elem *next = list_max(&sema->waiters, list_comp_greater, 0); list_remove(next); t = list_entry (next, struct thread, elem); thread_unblock (t); } sema->value++; if(t != NULL && !intr_context()) { check_preempt(t, false); } intr_set_level (old_level); }
/* 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); }
/* 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 (); struct thread *currentThread = thread_current(); while (sema->value == 0) { if(!thread_mlfqs) { thread_donate_priority(); } //list_insert_priority_ordered (&sema->waiters, ¤tThread->elem, currentThread->priority); list_insert_ordered (&sema->waiters, ¤tThread->elem, (list_less_func *) &thread_cmp_priority, NULL); thread_block (); } sema->value--; intr_set_level (old_level); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); //implementing donation //enum intr_level old_level; //old_level = intr_disable(); //PRE:1.HIGHEST PRIORITY THREADS TAKING THE CPU //2.CURRENT->THREAD WHICH HAVE HIGHEST PRIORITY //3.Thus the lock holder must be in the ready list //NEW if (thread_mlfqs) { //roozbeh //in case mlfqs, no need for donations sema_down (&lock->semaphore); lock->holder = thread_current (); } else { //non- mlfqs case, do donation //duc: struct thread *cur = thread_current(); struct thread *lock_holder = lock->holder; if (lock_holder != NULL) donate(lock, cur->priority, MAX_DEPTH); //stick lock to current thread cur->target_lock = lock; sema_down(&lock->semaphore); lock->holder = thread_current(); lock->max_priority = cur->priority; list_insert_ordered(&cur->lock_list, &lock->elem, higher_priority_lock, NULL); cur->target_lock = NULL; } //OLD /*if (lock_holder!=NULL && lock_holder->priority < cur->priority) { cur->donee_priority = lock_holder->priority; //insert into this lock's waiting queue according to it's priority //list_insert_ordered(&lock->semaphore.waiters, &cur->elem, higher_priority, NULL); //lock_holder->donation_times++; //>do we check donation_time initialized as 0? lock_holder->priority=cur->priority; //thread_block(); } sema_down (&lock->semaphore);//try to release the lock lock->holder = thread_current ();*/ //intr_set_level(old_level); }
/* Puts the current thread to sleep. It will not be scheduled again until awoken by thread_unblock(). This function must be called with interrupts turned off. It is usually a better idea to use one of the synchronization primitives in synch.h. */ void thread_block (void) { ASSERT (!intr_context ()); ASSERT (intr_get_level () == INTR_OFF); thread_current ()->status = THREAD_BLOCKED; schedule (); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); sema_down (&lock->semaphore); lock->holder = thread_current (); }
/* Acquires the console lock. */ static void acquire_console (void) { if (!intr_context () && use_console_lock) { if (lock_held_by_current_thread (&console_lock)) console_lock_depth++; else lock_acquire (&console_lock); } }
/* Releases the console lock. */ static void release_console (void) { if (!intr_context () && use_console_lock) { if (console_lock_depth > 0) console_lock_depth--; else lock_release (&console_lock); } }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); sema_down (&lock->semaphore); struct thread *cur = thread_current(); list_push_back (&cur->holding_list, &lock->leHolder); lock->holder = thread_current (); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); if (!lock_try_acquire (lock)) /* Someone else holding the lock. */ { sema_down (&lock->semaphore); lock->holder = thread_current (); } }
/*! 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(); } sema->value--; intr_set_level(old_level); }
/*! Atomically releases LOCK and waits for COND to be signaled by some other piece of code. After COND is signaled, LOCK is reacquired before returning. LOCK must be held before calling this function. The monitor implemented by this function is "Mesa" style, not "Hoare" style, that is, sending and receiving a signal are not an atomic operation. Thus, typically the caller must recheck the condition after the wait completes and, if necessary, wait again. A given condition variable is associated with only a single lock, but one lock may be associated with any number of condition variables. That is, there is a one-to-many mapping from locks to condition variables. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void cond_wait(struct condition *cond, struct lock *lock) { struct semaphore_elem waiter; ASSERT(cond != NULL); ASSERT(lock != NULL); ASSERT(!intr_context()); ASSERT(lock_held_by_current_thread(lock)); waiter.thread = thread_current(); sema_init(&waiter.semaphore, 0); list_push_back(&cond->waiters, &waiter.elem); lock_release(lock); sema_down(&waiter.semaphore); lock_acquire(lock); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread.And also it will take care of the donation of priority. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); enum intr_level old_level; old_level = intr_disable (); /* call a function that will check if the thread can donate its priority */ check_for_donation(lock); intr_set_level(old_level); sema_down (&lock->semaphore); lock->holder = thread_current (); }//end of lock_accquire function
/* Adds BYTE to the end of Q. Q must not be full if called from an interrupt handler. Otherwise, if Q is full, first sleeps until a byte is removed. */ void intq_putc (struct intq *q, uint8_t byte) { ASSERT (intr_get_level () == INTR_OFF); while (intq_full (q)) { ASSERT (!intr_context ()); lock_acquire (&q->lock); wait (q, &q->not_full); lock_release_with_preemption (&q->lock); } q->buf[q->head] = byte; q->head = next (q->head); signal (q, &q->not_empty); }
/* Acquires LOCK, sleeping until it becomes available if necessary. The lock must not already be held by the current thread. This function may sleep, so it must not be called within an interrupt handler. This function may be called with interrupts disabled, but interrupts will be turned back on if we need to sleep. */ void lock_acquire (struct lock *lock) { ASSERT (lock != NULL); ASSERT (!intr_context ()); ASSERT (!lock_held_by_current_thread (lock)); // Check for priority donation struct thread *current_thread = thread_current(); enum intr_level level = intr_disable(); if(lock->holder!=NULL && lock->holder->priority < current_thread->priority){ lock->holder->priority = current_thread->priority; } intr_set_level(level); sema_down (&lock->semaphore); lock->holder = current_thread; }
/*yan*/ void sema_down (struct semaphore *sema) { enum intr_level old_level; ASSERT (sema != NULL); ASSERT (!intr_context ()); old_level = intr_disable(); //disable the interrupts while (sema->value==0) { //insert current thread into waiter list list_insert_ordered(&sema->waiters,&thread_current()->elem,higher_priority,NULL); thread_block(); } sema->value--; intr_set_level (old_level); }