void cv_wait(struct cv *cv, struct lock *lock) { int spl; //We must complete an unconditional wait once an unlock occurs and we can then take the lock. We will check the conditions now. assert(cv != NULL); assert(lock !=NULL); assert (lock_do_i_hold(lock)); //If these steps above are valid we can now release the lock, sleep and then lock again. //This must be done atomically. //Like locks and semaphores, we want to make sure before we disable interrupts that we are not currently in the interrupt handler. assert(in_interrupt == 0); spl = splhigh(); //Disable All Interrupts lock_release(lock); //Unlock cv->count++; //Add one to the count since we have one more thread waiting now. q_preallocate(cv->thread_queue,cv->count); // not sure about this. q_addtail(cv->thread_queue, curthread); //add the currently waiting thread in the queue; thread_sleep(curthread); // now that the thread is in the queue, it can sleep. lock_acquire(lock); //When awoken, reacquire the lock if available. If not available, the thread will go back to bed inside lock_acquire(); splx(spl); //Re-enable interrupts (void)cv; // suppress warning until code gets written (void)lock; // suppress warning until code gets written }
int scheduler_preallocate(int nthreads) { int ret = 0; // Value returned. int i; assert(curspl>0); for(i = 0; i < NUM_PRIORITIES; i++) { ret = q_preallocate(runqueue[i], nthreads); if(ret) break; } return(ret); }
/* * Ensure space for handling at least NTHREADS threads. * This is done only to ensure that make_runnable() does not fail - * if you change the scheduler to not require space outside the * thread structure, for instance, this function can reasonably * do nothing. */ int scheduler_preallocate(int nthreads) { assert(curspl>0); return q_preallocate(runqueue, nthreads); }