int kframe_alloc(int *frame, int frames_wanted) { int rv, id; static int id_cur = 0; // only acquire lock and initialize idgen AFTER booting -- due to kmalloc if (booting){ id = id_cur++; } else { lock_acquire(coremap_lock); if (!q_empty(id_not_used)){ id = (int) q_remhead(id_not_used); } else { id = id_cur++; } } rv = frame_alloc_continuous(frame, KERNEL, 0, id, frames_wanted); if (rv && id_not_used != NULL) { q_addtail(id_not_used, (void*)id); } if (!booting) lock_release(coremap_lock); return rv; }
static int q_grow(struct queue *q, int targetsize) { void **olddata = q->data; int onr = q->nextread; int onw = q->nextwrite; int osize = q->size; int nsize; void **ndata; int i, result; nsize = q->size; while (nsize < targetsize) { nsize *= 2; /* prevent infinite loop */ KASSERT(nsize > 0); } ndata = kmalloc(nsize * sizeof(void *)); if (ndata == NULL) { return ENOMEM; } q->size = nsize; q->data = ndata; q->nextread = q->nextwrite = 0; for (i=onr; i!=onw; i = (i+1)%osize) { result = q_addtail(q, olddata[i]); KASSERT(result==0); } kfree(olddata); return 0; }
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 }
void frame_free(int frame) { KASSERT(frame >= 0 && frame < num_frames); lock_acquire(coremap_lock); int pid = coremap_ptr[frame].pid; int id = coremap_ptr[frame].id; if (pid != 0) { KASSERT(curproc->pid == pid); set_frame(frame, UNALLOCATED, 0,0); ZERO_OUT_FRAME(frame); goto FRAME_FREE_DONE; } for (int i = 0; i < num_frames; i++){ if (coremap_ptr[i].pid != 0 || coremap_ptr[i].id != id) continue; set_frame(i, UNALLOCATED, 0,0); ZERO_OUT_FRAME(i); if (id_not_used != NULL){ // recycle id's for kernel memory q_addtail(id_not_used, (void*)id); } goto FRAME_FREE_DONE; } panic("Invalid freeing of the frame for the unique pair (pid,id)=(%d,%d)\n", pid, id); FRAME_FREE_DONE: lock_release(coremap_lock); }
static void testq(struct queue *q, int n) { int i, result, *x, *r; x = kmalloc(n * sizeof(int)); for (i=0; i<n; i++) { x[i] = i; } assert(q_empty(q)); for (i=0; i<n; i++) { kprintf("queue: adding %d\n", i); result = q_addtail(q, &x[i]); assert(result==0); } for (i=0; i<n; i++) { r = q_remhead(q); assert(r != NULL); kprintf("queue: got %d, should be %d\n", *r, i); assert(*r == i); } assert(q_empty(q)); kfree(x); }
void cv_wait(struct cv *cv, struct lock *lock) { #if OPT_A1 // validate parameter assert (cv != NULL); assert (lock != NULL); // disable interrupts int spl = splhigh(); // release the lock assert (lock->status == 1); lock_release(lock); assert (lock->status == 0); q_addtail(cv->sleeping_list,curthread); // sleep thread_sleep(curthread); lock_acquire(lock); // enable interrupts splx(spl); #else (void) cv; (void) lock; #endif }
/* * Make a thread runnable. * With the base scheduler, just add it to the end of the run queue. */ int make_runnable(struct thread *t) { // meant to be called with interrupts off assert(curspl>0); return q_addtail(runqueue, t); }
int make_runnable(struct thread *t) { // meant to be called with interrupts off assert(curspl>0); // Use the priority of t to determine which queue to add it to. return(q_addtail(runqueue[t->priority], t)); }
/* * Actual scheduler. Returns the next thread to run. Calls cpu_idle() * if there's nothing ready. (Note: cpu_idle must be called in a loop * until something's ready - it doesn't know whether the things that * wake it up are going to make a thread runnable or not.) */ struct thread * scheduler(void) { // meant to be called with interrupts off assert(curspl>0); while (q_empty(runqueue)) { cpu_idle(); } // You can actually uncomment this to see what the scheduler's // doing - even this deep inside thread code, the console // still works. However, the amount of text printed is // prohibitive. // //print_run_queue(); /* We will have a defined variable in scheduler.h that will control the type of scheduling */ if(scheduler_type == SCHEDULER_RANDOM) { /* Random queue method */ // We could manipulate q->next_read, an integer that indexes the next in line // i.e. pick an index based on the size of the queue (q->size), and change // runqueue->next_read to that index // We might also be able to just jump in and get a random index from the queue // queue size is 32 by default int queue_size = q_getsize(runqueue); int random_index; struct thread * temp_thread; // We will have to get the thread number from within the active part // of the queue int start = q_getstart(runqueue); int end = q_getend(runqueue); int random_range = (end - start); // We have a problem if the start and end are the same assert(random_range != 0); // The startup code seems to have issues if you pick it right off the bat if (random_range < 0) random_range = random_range + queue_size; // No need to pick a random thread if there is only 1 in the queue if (random_range == 1) return q_remhead(runqueue); DEBUG(DB_THREADS, "Number of active threads: %u.\n", random_range); DEBUG(DB_THREADS, "Start: %u.\n", start); DEBUG(DB_THREADS, "End: %u.\n", end); random_index = (random() % random_range + start) % queue_size; DEBUG(DB_THREADS, "%u index chosen.\n", random_index); // Now, we have to move our chosen thread to the front of the line // There is probably some other way to do this that is more efficient, but // I had no success with q_getguy() // We start with the next thread in the queue, and work our way to the chosen one while(q_getstart(runqueue) != random_index) { temp_thread = q_remhead(runqueue); q_addtail(runqueue, temp_thread); } DEBUG(DB_THREADS, "New start: %u.\n", q_getstart(runqueue)); DEBUG(DB_THREADS, "New end: %u.\n", q_getend(runqueue)); return q_remhead(runqueue); } else if (scheduler_type == SCHEDULER_MLFQ) { /* MLFQ method */ // We will go through all of our queue, looking for the highest priority thread // By starting at the next read and working up, on a tie we are taking the first in // queue size is 32 by default int queue_size = q_getsize(runqueue); int i; int chosen_index; int priority; int random_choice; struct thread * temp_thread; // We will have to get the thread number from within the active part // of the queue int start = q_getstart(runqueue); int end = q_getend(runqueue); cycles++; if (cycles > 2000) { // reset priorities //kprintf("Resetting priorities"); i = start; while( i != end) { temp_thread = q_getguy(runqueue, i); DEBUG(DB_THREADS, "Setting priority\n"); thread_set_priority(temp_thread, 50); i = (i+1) % queue_size; } cycles = 0; // A bit of randomness to prevent immediate restarving return q_remhead(runqueue); } int highest_priority = -1; // 100 is maximum priority i = start; while( i != end) { temp_thread = q_getguy(runqueue, i); DEBUG(DB_THREADS, "Getting priority\n"); priority = thread_get_priority(temp_thread); DEBUG(DB_THREADS, "Priority: %u.\n", priority); if (priority > highest_priority) { chosen_index = i; highest_priority = priority; } // In the event of a tie, random pick else if (priority == highest_priority) { random_choice == random() % 3; if (random_choice == 0) chosen_index = i; } i = (i+1) % queue_size; } DEBUG(DB_THREADS, "Start: %u.\n", start); DEBUG(DB_THREADS, "End: %u.\n", end); DEBUG(DB_THREADS, "%u index chosen with priority %u.\n", chosen_index, highest_priority); //kprintf("%u index chosen with priority %u.\n", chosen_index, highest_priority); // Now, we have to move our chosen thread to the front of the line // There is probably some other way to do this that is more efficient, but // I had no success with q_getguy() // We start with the next thread in the queue, and work our way to the chosen one while(q_getstart(runqueue) != chosen_index) { temp_thread = q_remhead(runqueue); q_addtail(runqueue, temp_thread); } DEBUG(DB_THREADS, "New start: %u.\n", q_getstart(runqueue)); DEBUG(DB_THREADS, "New end: %u.\n", q_getend(runqueue)); return q_remhead(runqueue); } // Fall through to default FIFO scheduler return q_remhead(runqueue); }
void enter_kitchen(const int creature_type) { /* * Policy: Let any amount of cats try to access any amount of bowls at once, * or let any amount of mice try to access any amount of bowls at once, but * never mix. * * So, if the kitchen is empty, the first creature can enter regardless. If * that creature is a mouse, let all subsequent creatures that are mice enter * without delay. But, as soon as the next creature is a cat, stop letting * all subsequent creatures in, and put them in groups waiting in line. * Idea is to wait until all the mice currently in the kitchen are done, then * let a "burst" of cats in, then wait until all of them are done, then let a * "burst" of mice in, etc. * * For example, if x's are mice, and y's are cats, say we have this stream of * animals (arrived at the kitchen in order from right to left) * * Time | Outside of Kitchen | Inside Kitchen | Done eating * t0 yyyxyyyyyxxxxxxyyyyxx * t1 yyyxyyyyyxxxxxxyyyy xx * t2 yyyxyyyyyxxxxxx yyyy xx * t3 yyyxyyyyy xxxxxx yyyyxx * * * This policy has the objective of being as fair as possible, with efficieny * as an important but secondary objective (we let any amount of 1 creature * type in at once). Besides, we are multithreading to get a huge efficiency * gain in the first place. */ // Want mutual exclusion for group processing lock_acquire(k->kitchen_lock); // First creature in gets to initially set the current_creature flag and enter if (k->current_creature == 2) { k->current_creature = creature_type; } /* * If the queue is not empty, know that there are other groups to go first. * Don't barge ahead of another group even if you match the current creature. */ else if (!q_empty(k->group_list)) { // Inspect the last group in line int index = q_getend(k->group_list) > 0 ? q_getend(k->group_list)-1 : q_getsize(k->group_list) - 1; struct kgroup *g = (struct kgroup *)q_getguy(k->group_list, index); if (g->type == creature_type) { // If the last group is of your type, merge into that group g->amount++; } else { // Otherwise, start a new last group g = kmalloc(sizeof(struct kgroup)); g->type = creature_type; g->amount = 1; // Enqueue new group q_addtail(k->group_list, g); } // Wait cv_wait(k->kitchen_cv, k->kitchen_lock); } /* * If we aren't the first creature, and the queue is empty, check if we match the * creature currently in the kitchen. If not, we are going to start the only group * in the queue. */ else if (k->current_creature != creature_type) { // Create a group struct struct kgroup *g = kmalloc(sizeof(struct kgroup)); // Group is of your type with 1 creature so far g->type = creature_type; g->amount = 1; // Enqueue new group q_addtail(k->group_list, g); // Wait cv_wait(k->kitchen_cv, k->kitchen_lock); } // If here, we have been granted access to the kitchen // Set the creature type currently owning the kitchen k->current_creature = creature_type; // Increment creature count k->creature_count++; /* * Release kitchen lock before accessing the bowls, because we want any amount * of one type of creature to be able to access the bowls at once. */ lock_release(k->kitchen_lock); }
void intersection_before_entry(Direction origin, Direction destination) { /* replace this default implementation with your own implementation */ //(void)origin; /* avoid compiler complaint about unused parameter */ (void)destination; /* avoid compiler complaint about unused parameter */ // KASSERT(intersectionSem != NULL); // P(intersectionSem); KASSERT(intersection_lock != NULL); KASSERT(next_lights != NULL); KASSERT(cv_south_go != NULL); KASSERT(cv_north_go != NULL); KASSERT(cv_east_go != NULL); KASSERT(cv_west_go != NULL); lock_acquire(intersection_lock); // bool check = in_queue(origin); // if (!check){ // check = true; // } // if (q_empty(next_lights)){ // first_dir = origin; // current_light = &first_dir; // } // add the cu // if(!in_queue(origin)){ // q_addtail(next_lights,pointer); // } // current_light = q_peek(next_lights); // q_remhead(next_lights); // if (origin == north){ // // if the light is green // if(!in_queue(origin)){ // q_addtail(next_lights,&north_dir); // } // current_light = q_peek(next_lights); // // q_remhead(next_lights); // if (origin == *current_light) { // if (num_vehicles_waiting_north != 0){ // num_vehicles_waiting_north++; // cv_wait(cv_north_go,intersection_lock); // } // } // else{ // num_vehicles_waiting_north++; // cv_wait(cv_north_go,intersection_lock); // } // } // else if (origin == south){ // // if the light is green // if(!in_queue(origin)){ // q_addtail(next_lights,&south_dir); // } // current_light = q_peek(next_lights); // // q_remhead(next_lights); // if (origin == *current_light) { // if (num_vehicles_waiting_south != 0){ // num_vehicles_waiting_south++; // cv_wait(cv_south_go,intersection_lock); // } // } // else{ // num_vehicles_waiting_south++; // cv_wait(cv_south_go,intersection_lock); // } // } // else if (origin == east){ // // if the light is green // if(!in_queue(origin)){ // q_addtail(next_lights,&east_dir); // } // current_light = q_peek(next_lights); // // q_remhead(next_lights); // if (origin == *current_light) { // if (num_vehicles_waiting_east != 0){ // num_vehicles_waiting_east++; // cv_wait(cv_east_go,intersection_lock); // } // } // else{ // num_vehicles_waiting_east++; // cv_wait(cv_east_go,intersection_lock); // } // } // else if (origin == west){ // // if the light is green // if(!in_queue(origin)){ // q_addtail(next_lights,&west_dir); // } // current_light = q_peek(next_lights); // // q_remhead(next_lights); // if (origin == *current_light) { // if (num_vehicles_waiting_west != 0){ // num_vehicles_waiting_west++; // cv_wait(cv_west_go,intersection_lock); // } // }else{ // num_vehicles_waiting_west++; // cv_wait(cv_west_go,intersection_lock); // } // } if (origin == north) { // if the light is green if(!in_queue(origin)){ q_addtail(next_lights,&north_dir); } current_light = q_peek(next_lights); // q_remhead(next_lights); num_vehicles_waiting_north++; if (origin != *current_light) { cv_wait(cv_north_go,intersection_lock); } } else if (origin == south){ // if the light is green if(!in_queue(origin)){ q_addtail(next_lights,&south_dir); } current_light = q_peek(next_lights); // q_remhead(next_lights); num_vehicles_waiting_south++; if (origin != *current_light) { cv_wait(cv_south_go,intersection_lock); } } else if (origin == east){ // if the light is green if(!in_queue(origin)){ q_addtail(next_lights,&east_dir); } current_light = q_peek(next_lights); num_vehicles_waiting_east++; // q_remhead(next_lights); if (origin != *current_light) { cv_wait(cv_east_go,intersection_lock); } } else if (origin == west){ // if the light is green if(!in_queue(origin)){ q_addtail(next_lights,&west_dir); } num_vehicles_waiting_west++; current_light = q_peek(next_lights); // q_remhead(next_lights); if (origin == *current_light) { cv_wait(cv_west_go,intersection_lock); } } lock_release(intersection_lock); }