//PAGEBREAK: 42 // 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 = mycpu(); c->proc = 0; 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. c->proc = p; switchuvm(p); p->state = RUNNING; swtch(&(c->scheduler), p->context); switchkvm(); // Process is done running for now. // It should have changed its p->state before coming back. c->proc = 0; } release(&ptable.lock); } }
// Start the non-boot (AP) processors. static void startothers(void) { extern uchar _binary_obj_entryother_start[], _binary_obj_entryother_size[]; uchar *code; struct cpu *c; char *stack; // Write entry code to unused memory at 0x7000. // The linker has placed the image of entryother.S in // _binary_entryother_start. code = P2V(0x7000); memmove(code, _binary_obj_entryother_start, (uint)_binary_obj_entryother_size); for(c = cpus; c < cpus+ncpu; c++){ if(c == mycpu()) // We've started already. continue; // Tell entryother.S what stack to use, where to enter, and what // pgdir to use. We cannot use kpgdir yet, because the AP processor // is running in low memory, so we use entrypgdir for the APs too. stack = kalloc(); *(void**)(code-4) = stack + KSTACKSIZE; *(void**)(code-8) = mpenter; *(int**)(code-12) = (void *) V2P(entrypgdir); lapicstartap(c->apicid, V2P(code)); // wait for cpu to finish mpmain() while(c->started == 0) ; } }
// Common CPU setup code. static void mpmain(void) { cprintf("cpu%d: starting %d\n", cpuid(), cpuid()); idtinit(); // load idt register xchg(&(mycpu()->started), 1); // tell startothers() we're up scheduler(); // start running processes }
// Enter scheduler. Must hold only ptable.lock // and have changed proc->state. Saves and restores // intena because intena is a property of this // kernel thread, not this CPU. It should // be proc->intena and proc->ncli, but that would // break in the few places where a lock is held but // there's no process. void sched(void) { int intena; struct proc *p = myproc(); if(!holding(&ptable.lock)) panic("sched ptable.lock"); if(mycpu()->ncli != 1) panic("sched locks"); if(p->state == RUNNING) panic("sched running"); if(readeflags()&FL_IF) panic("sched interruptible"); intena = mycpu()->intena; swtch(&p->context, mycpu()->scheduler); mycpu()->intena = intena; }
// Disable interrupts so that we are not rescheduled // while reading proc from the cpu structure struct proc* myproc(void) { struct cpu *c; struct proc *p; pushcli(); c = mycpu(); p = c->proc; popcli(); return p; }
void mp_set_mm_pagetable(struct mm_struct *mm) { struct cpu *cpu = mycpu(); uintptr_t new_cr3; if (mm != NULL && mm->pgdir != NULL) new_cr3 = PADDR(mm->pgdir); else new_cr3 = boot_cr3; mp_lcr3(new_cr3); }
static int hwloc_aix_get_thisthread_last_cpu_location(hwloc_topology_t topology, hwloc_bitmap_t hwloc_set, int flags __hwloc_attribute_unused) { cpu_t cpu; if (topology->pid) { errno = ENOSYS; return -1; } cpu = mycpu(); if (cpu < 0) return -1; hwloc_bitmap_only(hwloc_set, cpu); return 0; }
int lapic_init(void) { static int bsp = 1; if(bsp){ __lapic_chip = x2apic_lapic_init(); if(!__lapic_chip) __lapic_chip = xapic_lapic_init(); if(!__lapic_chip) panic("ERROR: No LAPIC found\n"); } struct lapic_chip* chip = lapic_get_chip(); assert(chip != NULL); chip->cpu_init(chip); if(bsp){ // not necessary mycpu()->hwid = chip->id(chip); bsp = 0; } return 0; }
// Must be called with interrupts disabled int cpuid() { return mycpu()-cpus; }