Basically, I'm implementing a scheduler for the xv6 kernel that is implementing a multilevel priority queue. I'm having a serious issue I do not understand, the TAs for my course do not understand, and I've missed the deadline for this project, so helping me right now will not gain me any extra points - but I WANT to know why I'm having the following behavior...
First, this is the original scheduler that I'm changing for xv6 (for comparison - this is NOT my implementation):
// Per-CPU process scheduler. // Each CPU calls scheduler() after setting itself up. // Scheduler never returns. It loops, doing: // - choose a process to run // - swtch to start running that process // - eventually that process transfers control // via swtch back to the scheduler. void scheduler(void) { struct proc *p; for(;;){ // Enable interrupts on this processor. sti(); // Loop over process table looking for process to run. acquire(&ptable.lock); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release ptable.lock and then reacquire it // before jumping back to us. proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. proc = 0; } release(&ptable.lock); } }
The new scheduler's idea is this: there is an array filled with proc structs inside ptable. I'll call each of these elements in this proc array 'p', and they hold basic information (like the number of "tickets" they have, or it's state, etc). I need to run all high priority (HP) p's for one time slice and then change their priority level to low. When there are no HP procs, I "randomly" choose a LP proc and run it for TWO time slices. My algorithm is as follows:
scheduler() for(;;) //scheduler NEVER completes //information gathering for (entire proc array) //goes over it once gather how many HP and LP procs count total HP and LP tickets in each proc (for lottery) if #HP > 1 //randomly choose a HP proc hold HP lottery, run one HP proc //afterwards, int rand = random() % num_HP_tickets for (entire array) curr_index_of_tickets += p->num_tickets; if (curr_index_of_tickets >= rand) //we found the right p! run p for one time slice else if #HP == 1 find and run the one HP proc else if #HP < 1 //then no HP procs! Time to run LP if #LP > 1 hold LP lottery, run one LP proc for two time slices, similar to above else if #LP == 1 find the LP proc, run it
Here's the issue... My proc always appears to be equal to 0. It's never seeing information put in p, not gathering proc information from p, etc. I do not know why.
I tested with a crap ton of printout statements. I'll post the output of that here first:
entered scheduler entered INFORMATION loop: iteration 0 Proc is 0 Proc is 0 even after proc gets p from for loop Information 0: found 0 HP procs Information 0: found 0 LP procs Num HP: 0 Num LP: 0 Num HP Tickets: 0 Num LP Tickets: 0 This concludes loop #: 0 entered INFORMATION loop: 1 Proc is 0 entered INFORMATION loop: 2 Proc is 0 entered INFORMATION loop: 3 Proc is 0 etc.....
Again, no idea why this isn't working... I'm sure there are multiple errors, and I have a crap ton of print out statements just to see where things are going wrong. This is also requiring quite a bit of debugging effort, so I'm not too optimistic about if anyone has an answer... For that purposes, and with those warnings, here is my entire scheduler function. Sorry for the length...
void scheduler(void) { struct proc *p; for(;;){ //TODO: Remove statement cprintf("entered scheduler\n"); // Enable interrupts on this processor. sti(); // Loop over process table looking for process to run. acquire(&ptable.lock); //keeps track of number of procs (to be used for lottery RNG) int num_LP_t = 0; int num_HP_t = 0; int num_HP = 0; int num_LP = 0; int rand = 0; int curr_tickets = 0; //goes through once to complete information gathering for HP and LP queue //TODO: remove i - for testing only int i = -1; for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ i++; //TODO: Remove statement cprintf("entered INFORMATION loop: %d\n", i); if (proc == 0) cprintf("Proc is 0\n"); if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release ptable.lock and then reacquire it // before jumping back to us. //TODO: uncomment? proc = p; if (proc == 0) cprintf("Proc is 0 even after proc gets p in INFORMATION LOOP\n"); cprintf("Information %d: found %d HP procs\n", i, num_HP); cprintf("Information %d: found %d LP procs\n", i, num_LP); cprintf("Num HP: %d\n", num_HP); cprintf("Num LP: %d\n", num_LP); cprintf("Num HP Tickets: %d\n", num_HP_t); cprintf("Num LP Tickets: %d\n", num_LP_t); cprintf("This concludes loop #: %d\n", i); if (p->priority_level == 1){ num_HP++; num_HP_t += p->num_tickets; } if (p->priority_level == 0){ num_LP++; num_LP_t += p->num_tickets; } }//end information loop cprintf("Begin HP Queue:\n"); if (num_HP > 1){ cprintf("HP Queue had: %d procs to run\n", num_HP); rand = random() % num_HP_t; cprintf("We choose our random to be: %d\n", rand); for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if (p->state != RUNNABLE) continue; //TODO: uncomment? proc = p; if (proc == 0) cprintf("Proc is 0 even after setting proc = p in HP queue\n"); if (p->priority_level == 1){ cprintf("Found a HP Proc while searching for rand, currently at: %d\n", curr_tickets); curr_tickets += p->num_tickets; if (curr_tickets >= rand){ if (proc == 0) cprintf("proc is 0 while in HP queue 1\n"); //proc = p; switchuvm(p); p->state = RUNNING; /*cprintf("Proc Info:"); cprintf("uint sz: %d", proc->sz); cprintf("enum procstate state: %s", proc->state); cprintf("volatile int pid: %d", proc->pid); cprintf("int killed: %d", proc->killed); cprintf("int priority_level: %d", proc->priority_level);*/ swtch(&cpu->scheduler, proc->context); switchkvm(); if (p->state == RUNNABLE){ cprintf("HP process still runnable after 1 TS.\nHere is the updated information\n"); p->priority_level = 0; num_HP--; num_LP++; num_HP_t -= p->num_tickets; num_LP_t += p->num_tickets; cprintf("Num HP: %d\n", num_HP); cprintf("Num LP: %d\n", num_LP); cprintf("Num HP Tickets: %d\n", num_HP_t); cprintf("Num LP Tickets: %d\n", num_LP_t); } } } } } else if (num_HP == 1){ for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if (p->state != RUNNABLE) continue; //TODO: Uncomment? proc = p; if (proc == 0) cprintf("Proc is 0 even after setting proc = p in HP == 1 queue\n"); if (p->priority_level == 1){ //proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); if (p->state == RUNNABLE){ p->priority_level = 0; num_HP--; num_LP++; num_HP_t -= p->num_tickets; num_LP_t += p->num_tickets; } } } }//end else num_HP = 1 else if (num_HP < 1){ if (num_LP > 1){ rand = random() % num_LP_t; for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if (p->state != RUNNABLE) continue; //TODO: uncomment? proc = p; if (proc == 0) cprintf("Proc is 0 even after setting proc = p in LP > 1 queue\n"); if (p->priority_level == 0){ curr_tickets += p->num_tickets; if (curr_tickets >= rand) { //proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); if (p->state != RUNNABLE){ num_LP--; num_LP_t -= p->num_tickets; } } } } } else if (num_LP == 1){ for(p = ptable.proc; p < &ptable.proc[NPROC]; p++){ if (p->state != RUNNABLE) continue; //TODO: Uncomment? proc = p; if (proc == 0) cprintf("Proc is 0 even after setting proc = p in LP == 1 queue\n"); if (p->priority_level == 0){ //proc = p; switchuvm(p); p->state = RUNNING; swtch(&cpu->scheduler, proc->context); switchkvm(); if (p->state != RUNNABLE){ num_LP_t -= p->num_tickets; } } } } }//end lp proc = 0; release(&ptable.lock); }//end outer for loop (;;) }// end scheduler