// 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; struct cpu *c; int i; trace_frame *curr_trace_frm, *last_trace_frm; c = &cpus[cpu()]; for(;;){ // Enable interrupts on this processor. sti(); // Loop over process table looking for process to run. acquire(&proc_table_lock); for(i = 0; i < NPROC; i++){ p = &proc[i]; if(p->state != RUNNABLE) continue; // Switch to chosen process. It is the process's job // to release proc_table_lock and then reacquire it // before jumping back to us. //cprintf("current: %d\n", p->pid); c->curproc = p; setupsegs(p); p->state = RUNNING; swtch(&c->context, &p->context); if (trace_status == TRACE_ON) { last_trace_frm = &trace[(trace_index - 1) % TRACE_SIZE]; if (last_trace_frm->pid != p->pid) { curr_trace_frm = &trace[trace_index % TRACE_SIZE]; curr_trace_frm->pid = p->pid; curr_trace_frm->quantums = 1; trace_index++; } else if (last_trace_frm->pid == p->pid) { curr_trace_frm = &trace[(trace_index - 1) % TRACE_SIZE]; curr_trace_frm->quantums++; } } // Process is done running for now. // It should have changed its p->state before coming back. c->curproc = 0; setupsegs(0); } release(&proc_table_lock); } }
// Bootstrap processor gets here after setting up the hardware. // Additional processors start here. static void mpmain(void) { cprintf("cpu%d: mpmain\n", cpu()); idtinit(); if(cpu() != mp_bcpu()) lapic_init(cpu()); setupsegs(0); xchg(&cpus[cpu()].booted, 1); cprintf("cpu%d: scheduling\n"); scheduler(); }
// Grow current process's memory by n bytes. // Return old size on success, -1 on failure. int growproc(int n) { char *newmem; newmem = kalloc(cp->sz + n); if(newmem == 0) return -1; memmove(newmem, cp->mem, cp->sz); memset(newmem + cp->sz, 0, n); kfree(cp->mem, cp->sz); cp->mem = newmem; cp->sz += n; setupsegs(cp); return cp->sz - n; }
// 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; struct cpu *c; int i; #ifdef STRACE st_init(); #endif c = &cpus[cpu()]; for(;;){ // Enable interrupts on this processor. sti(); acquire(&proc_table_lock); //hold lottery #ifdef LOTTERY if (tickets == 0) { release(&proc_table_lock); continue; } //cprintf("tickets: %d\n", tickets); int winner = rand() / (32767 / tickets + 1); int sum = 0; //cprintf("winner: %d\n", winner); #endif // Loop over process table looking for process to run. for(i = 0; i < NPROC; i++){ p = &proc[i]; if(p->state != RUNNABLE) continue; #ifdef LOTTERY sum += p->tickets; if (sum <= winner) continue; #endif // Switch to chosen process. It is the process's job // to release proc_table_lock and then reacquire it // before jumping back to us. c->curproc = p; setupsegs(p); setstate(p, RUNNING); #ifdef STRACE st_add(p); #endif swtch(&c->context, &p->context); // Process is done running for now. // It should have changed its p->state before coming back. c->curproc = 0; setupsegs(0); #ifdef LOTTERY break; #endif } release(&proc_table_lock); } }